多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
### 3.1.3 数据库键空间(key space) `server.h/redisDb`结构中的dict称为数据库键空间,保存了数据库的所有键值对,键为字符串对象,值为任意对象 ```c typedef struct redisDb { dict *dict; // 数据库键空间,保存所有键值对,键为字符串对象,值为任意对象 dict *expires; /* Timeout of keys with a timeout set */ dict *blocking_keys; /* Keys with clients waiting for data (BLPOP)*/ dict *ready_keys; /* Blocked keys that received a PUSH */ dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */ int id; /* Database ID */ long long avg_ttl; /* Average TTL, just for stats */ list *defrag_later; /* List of key names to attempt to defrag one by one, gradually. */ } redisDb; ``` 键空间的增删改查都同dict操作,此外还有: - 清空键空间:`FlushDb` - 从键空间随机返回一个键:`RandomKey` - 返回数据库键数量:`DbSize` - 还有`Exists`、`Rename`、`Keys`等 ---- 读写键空间时的维护操作如下: - 读取一个键后(读写操作都会对键进行读取),服务器会根据键是否存在,更新`hit`(命中)和`miss`(未命中),这两个值可以通过`info status`命令查看 - 在读取一个键后,服务器会更新键的`lru`(最后一次更新时间)属性,可以通过`object idleime <key>`命令查看某个键的闲置时间 - 读取一个键时,如果发现其已过期,会先删除再进行其他操作 - 每次修改一个键后,会对`dirty`(脏计数器)加1,这个计数器会触发服务器的持久化以及复制操作 - 如果开启了服务器通知功能,在对键进行修改之后,服务器将按照配置发送相应的数据库通知 ---- 设置键的生存时间和过期时间: - 通过`Expire`和`PExpire`,客户端能以秒或毫秒的精度为数据库中的某个键设置`ttl`(Time To Live,生存时间),服务器会自动删除生存时间为0的键 - 与此类似,可以通过`ExpireAt`和`PExpireAt`设置过期时间,过期时间是一个UNIX时间戳,当过期时间来临时,服务器会自动删除该键。 - `ttl`和`pttl`接收一个带有生存时间或过期时间的键,返回这个键的剩余生存时间。 - `setex` 命令可以再设置一个字符串键的同时为键设置过期时间,这是一个类型限定的命令,其原理与`Expire`完全一样。 其中,`EXPIRE`命令将转成`PEXPIRE`命令,`PEXPIRE`和`EXPIREAT`都将转成`PEXPIREAT`命令。 ---- redisDb结构的expires字典保存了数据库中所有键的过期时间,称为`过期字典` - 过期字典的键是一个指针,指向键空间的某个对象 - 过期字典的值是一个`long long`类型的整数,保存了过期时间(毫秒精度的UNIX时间戳) ---- `PPERSIST`命令可以移除一个键的过期时间,如`PERSIST <key>`,底层是将字典中的key移除。 ---- 过期时间的判定: - 检查给定键是否存在于过期字典,如果存在则取得其过期时间 - 检查当前UNIX时间戳是否大于键的过期时间:如果是的话,那么键已过期,否则的话,键未过期。 ---- 过期键的删除策略: - 定时删除:在设置键的过期时间的同时,创建一个定时器(Timer),让定时器在键的过期时间来临时,立即执行对键的删除操作。 - 对内存最友好,对CPU最不友好 - 惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除键。 - 对CPU最友好,对内存最不友好 - 由`db.c/expireIfNeed`函数实现 - 定期删除:每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键,具体由算法决定。 - 难点是确定删除操作执行的时长和频率 - 由`server.c/activeExpireCycle`函数实现