Redis——数据库

  • Post author:
  • Post category:其他




服务器中的数据库

struct redisServer {
  	// 一个数组,保存着服务器中的所有数据库
    redisDb *db;
    
    // 服务器的数据库数量
    // 值由服务器配置的database选项决定,默认情况下是16个数据库
    int dbnum;
};



切换数据库

默认情况下,redis客户端的目标数据库为0号数据库,可以通过

SELECT

命令来切换数据库

redis> SET msg "hello world"
OK

redis> GET msg
"hello world"

redis> SELECT 2
OK

redis[2]> GET msg
(nil)

客户端状态

redisClient

结构的db属性记录了客户端当前的目标数据库,这是属性是一个指向

redisDb

结构的指针

typedef struct redisClient {
    // 记录客户端当前正在使用的数据库
    redisDb *db;
} redisClient;

通过修改

redisClient.db

指针,可以实现数据库的切换,即

SELECT

命令的实现



数据库键空间


redisDb

结构的dict字典保存了数据库中所有键值对

typedef struct redisDb {
    dict *dict;
}

键空间和用户所见的数据库是直接对应的:

  • 键空间的键也就是数据库的键, 每个键都是一个

    字符串对象。
  • 键空间的值也就是数据库的值, 每个值可以是字符串对象、列表对象、哈希表对象、集合对象和有序集合对象在内的任意一种 Redis 对象。



添加新键

添加一个新键值对到数据库,实际上就是将一个新键值对添加到键空间字典里面



删除键

删除数据库中的一个键,实际上就是在键空间里面删除键所对应的键值对对象

DEL key [...]



其他键空间操作


FLUSHDB

:清空整个数据库


RANDOMKEY

:随机返回一个键


DBSIZE

:数据库键数量



读写键空间时的维护操作

  • 在读取一个键之后(读操作和写操作都要对键进行读取), 服务器会根据键是否存在, 以此来更新服务器的键空间命中(hit)次数或键空间不命中(miss)次数, 这两个值可以在 INFO stats 命令的

    keyspace_hits

    属性和

    keyspace_misses

    属性中查看。
  • 在读取一个键之后, 服务器会更新键的 LRU (最后一次使用)时间, 这个值可以用于计算键的闲置时间, 使用命令 OBJECT idletime 命令可以查看键

    key

    的闲置时间。
  • 如果服务器在读取一个键时, 发现该键已经过期, 那么服务器会先删除这个过期键, 然后才执行余下的其他操作。
  • 如果有客户端使用 WATCH 命令监视了某个键, 那么服务器在对被监视的键进行修改之后, 会将这个键标记为脏(dirty), 从而让事务程序注意到这个键已经被修改过。
  • 服务器每次修改一个键之后, 都会对脏(dirty)键计数器的值增一, 这个计数器会触发服务器的持久化以及复制操作执行。
  • 如果服务器开启了数据库通知功能, 那么在对键进行修改之后, 服务器将按配置发送相应的数据库通知。



设置键的生存时间或过期时间


EXPIRE

:设置生存时间,单位:秒。

EXPIRE <key> <ttl>

SET key value
// 五秒的生存时间
EXPIRE key 5


PEXPIRE

:设置生存时间,单位:毫秒。

PEXPIRE <key> <ttl>


EXPIREAT

:设置过期时间,单位秒(时间戳)

EXPIREAT <key> <timestamp>


PEXPIREAT

:设置过期时间,单位毫秒。

PEXPIREAT <key> <timestamp>


上面四个命令最后都是使用

PEXPIREAT

命令来实现的


TTL

:接受一个带有生存时间的键,返回这个键的剩余生存时间


PTTL

:接受一个带有过期时间的键,返回这个键的剩余生存时间



保存过期时间

redisDb结构的

expires

字典保存了数据库中所有键的过期时间

  • 过期字典的键是一个指针,指向键空间中某个键对象。
  • 过期字典的值是一个long long类型的整数,即过期时间,是一个毫秒精度的UNIX时间戳
typedef struct redisDb {
    // 过期字典,保存键的过期时间
    dict *expires;
} redisDb;



移除过期时间


PERSIST <key>



过期键的判定

通过过期字典,检查以下步骤

  1. 判断键是否在过期字典中,如果存在则返回过期时间
  2. 判断当前UNIX时间戳是否大于键的过期时间,如果是,那么键已经过期



过期键删除策略



定时删除

在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作

  1. 对内存友好,尽快释放过期键占用的内存
  2. 对CPU不友好,特别在过期键比较多的情况下



惰性删除

每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键,如果没过期,就返回该键

  1. 对CPU友好
  2. 对内存不友好,特别是有很多过期键但又没有访问的时候



定期删除

每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键。

最主要的是合理地设置删除操作的执行时长和执行频率



Redis的过期键删除策略



惰性删除策略的实现

过期键的惰性删除策略由

db.c/expireIfNeeded

函数实现,所有读写数据库的Redis命令在执行之前都会调用该函数对输入键进行检查:


参考:Redis设计与实现



版权声明:本文为Zheng_junming原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。