单机数据库实现
九、数据库
1.服务器中的数据库
一个redis服务器保存多个数据库。
struct redisServer {
//一个数组,多个数据库
redisDb *db;
}
当执行select 1
,就是切换数据库到db[1]
,具体就是会修改redisClient.db指针到redisServer.db[1]
2.数据库键空间
typedef struct redisDb{
dict *dict;//数据库键空间
dict *expires;//过期时间
}
这里的dict就是上面说的字典数据结构。
这个字典的key就是redis里面的key,每个key都是字符串对象
值就是数据库的值,可以是字符串对象,列表对象,哈希对象,集合对象,游戏集合对象。
3.键的过期时间
如果我们对一个键设置过期时间
redis就会在字典expires里面,加上key=过期的时间戳(精确到毫秒)。
执行ttl,redis会比较expires里面的时间戳和当前时间的差值,然后返回差值。
过期key的判定
- 当访问key时,redis会检查key是否过期,如果是,删除key,并报错key不存在
- 对于一直没有访问的key,redis会定期扫描expires里面的key,判定key是否过期,如果是,就删除key
十、RDB持久化
存在内存中的数据,称为数据库状态
持久化就是把数据库状态,保存为RDB文件,RDB文件是存在硬盘的。
1.客户端发起保存
执行命令save,bgsave,可以立刻把数据库状态保存为RDB文件。
- save命令是阻塞的,即执行过程中,服务器不能处理其他客户端的请求。
- bgsave是异步的,redis会启动一个新进程,把内存的数据都复制到新进程,然后执行保存数据到RDB文件的工作,而原进程就继续处理客户端的请求
2.服务端定期保存
redis也会定期执行保存操作
服务器的配置:
save 900 1
表示服务器在900秒内,对数据库执行了至少一次修改,服务器就会执行保存操作
如果有多个svae配置,它们直接的关系是或的关系,即满足其中一个,就会执行保存
struct redisServer{
long long dirty;
time_t lastsave
}
数据库对象中,有两个属性:
- dirty,记录距离上一次保存操作后,数据库执行了多少次修改。
- lastsave,上一次保存操作的时间戳
redis通过这两个属性来实现定期保存的机制
3.RDB文件结构
RDB文件由
REDIS db_version databases EOF cehcks_sum
构成
- redis是一个字符串,
- db_version是一个4字节的int类型,表示数据库的版本号
- databases 表示数据库数据
- EOF 1字节表示文件的结束
- check_sum表示前面的数据的md5
1.数据库数据
databases部分的构成:
SELECTDB db_number PAIRS
- SELECTDB是1字节,常量
- db_number 是数据库编号
- PAIRS是数据库数据里面的键值对
2.键值对
键值对构成
EXPIRETIME_MS ms TYPE KEY VALUE
- EXPIRETIME_MS 1字节常量,表示这个键有超时时间,可选
- ms 超时时间的时间戳
- TYPE 1字节常量,表示键的类型,redis会根据这个常量,来决定怎么解析后面的KEY和VALUE
- KEY 是一个字符串对象,存储方法和VALUE的字符串对象一样
- 值的对象
3.VALUE编码
redis会根据TYPE这个常量,来决定怎么读取VALUE的数据。
KEY肯定就是字符串类型了。
3.1字符串对象
如果TYPE=REDIS_ENCODING_STRING,表示这个对象是数值字符串对象
字符串对象有以下三种存储类型
int类型
构成:
ENCODING int
- ENCODING 1字节常量,表示int类型,例如16位还是32位
- int 数字
无压缩字符串
如果TYPE=REDIS_ENCODING_RAW,表示这个是普通字符串
len string
- len 字符串的长度
- string 字符串的值
压缩字符串
如果字符串的长度大于20字节,就会压缩字符串。
REDIS_RDB_ENC_LZF compressed_len origin_len compressed_string
- REDIS_RDB_ENC_LZF 1字节常量,压缩的算法
- compressed_len 压缩后的长度
- origin_len 原字符串长度
- compressed_string 压缩后的内容
问题:
程序怎么知道这是int类型,还是无压缩字符串,还是压缩字符串的?
3.2列表对象
当TYPE=REDIS_RDB_TYPE_LIST 表示这是一个列表对象
list_length item1 item2 itemN
- list_length 列表的长度
- item1-N 列表的元素,都是字符串对象
3.3集合对象
如果TYPE=REDIS_RDB_TYPE_SET 那么表示这是一个集合对象
set_size elem1 ... elemN
- set_size集合的长度
- elem1 表示集合的元素,字符串对象
3.4哈希表对象
如果TYPE=REDIS_RDB_TYPE_HASH 那么表示这是一个哈希表对象
hash_size key_value_pair1 。。。。。。key_value_pairN
- hash_size 哈希表的键值对数量
- key_value_pair1 键值对的值
键值对的构成
key1 value1 key2 value2
- key1 键值对的键,字符串对象
- value1 键值对的值,字符串对象
3.5 有序集合对象
如果TYPE=REDIS_RDB_TYPE_ZSET,表示这是一个有序集合对象
sorted_set_size element1 。。。。 elementN
- sorted_set_size元素的数量
- element1 元素
每个元素的构成
member1 score1
- member1 元素的内容,字符串对象
- score1 元素的分值,redis会把int类型或者float类型转换为字符串类型保存
4.RDB文件例子
REDIS 0 0 0 6 376 003 MSG 005 HELLO 377 207z=304fTL
343
- REDIS
- 0006是版本号
- 376是SELECTDB常量