redis是一个开源的、key-value的内存数据库
redis数据库
每个redis服务器都会创建一个
redisServer结构体
类型的变量,存储服务器的各种信息。数据库相关的信息保存在redisServer中的 redisDb *db 数组中,数组中的每个元素都是一个
redisDb结构体
变量,代表一个数据库。db数组中有多少个元素,就代表该redisServer有多少个数据库,一般默认16个。一般情况下,默认使用0号数据库。
数据库redisDb结构:
typedef struct redisDb{
//字典类型,保存数据库的所有键值对(即数据),称作键空间
//键空间的键就是数据库的键,每个键都是一个字符串对象
//键空间的值就是数据库的值,每个值可以是字符串对象,列表对象,哈希表对象,集合对象,有序集合对象
dict *dict;
//字典类型,保存数据库键的过期时间,成为过期字典
//过期字典的键是一个指针,指向键空间的某个键对象(数据库键)
//过期字典的值是一个long long类型的整数,保存了键所指向的数据库键的过期时间(ms精度的unix时间戳)
dict *expires;
...
}
redis过期策略
redis采用惰性删除
和定期删除
相结合的过期键删除策略。
惰性删除
是指,每次从键空间获取键时,都检查该建是否过期,如果过期就删除,没过期就返回。
定期删除
是指,每隔一段时间,就检查数据库,删除里面的过期键。删除多少过期键以及检查多少数据库,则由算法决定。redise的策略是,在规定时间内,分多次遍历服务器中的各个数据库,从数据库的expires字典中随机检查一部分键的过期时间,并删除其中的过期键。
redis持久化
RDB持久化
- RDB持久化功能可以将redis某个时间点上的数据库状态保存到一个RDB文件中,该文件是一个经过压缩的二进制文件;
- RDB持久化可以手动触发,也可以根据服务器配置定期执行。手动触发的话,SAVE命令会阻塞Redis服务器进程,BGSAVE命令会fork一个子进程来创建RDB文件,不会影响服务器进程处理命令。
- 服务器启动时,会先检查是否开启了AOF持久化功能(AOF文件的更新频率通常比RDB高),如果开启,优先使用AOF文件还原数据库状态,如果未开启,再载入RDB文件。
AOF持久化
- AOF(Append Only FIle)持久化是通过保存Redis服务器所执行的
写命令
来记录数据库状态的; - AOF文件中的所有命令都以Redis命令请求协议的格式保存;
- AOF重写——读取数据库中的键值对,然后用一条命令记录键值对,代替之前记录这个键值对的多条命令,这就是重写原理。
redis复制
旧版复制功能
分为同步
和命令传播
两个阶段:
-
slave向master发送SYNC命令,master生成RDB文件,同时从现在开始记录命令到缓冲区;
-
slave接收RDB文件,根据RDB文件同步数据;
-
master将缓冲区中的命令发送给slave,slave状态同步至与master状态一致;
-
后续master执行命令后,同步传送给slave——命令传播
缺点
:
这种方式的缺点是,如果slave在命令传播阶段突然断开与master的连接,几秒后又重新建立连接,那么这时候需要重新执行上述过程,同步所有数据。其实,断开连接之前的数据是没必要再同步的。这样浪费了cpu、IO、带宽等资源。
新版复制功能
新增了部分重同步的功能
,就是说,上述slave断开重连的情况,可以只同步断开后的命令。
新版复制用PSYNC命令代替SYNC命令,支持完整重同步
和部分重同步
。其中,完整重同步
与老的同步机制类似。这里主要说下部分重同步
。
部分重同步
部分重同步通过主从服务器的复制偏移量
、主服务器的复制积压缓冲区
、服务器运行ID
这3部分实现。
-
主从服务器都会维护一个复制偏移量offset,主服务器每传播N个字节,offset值加N,从服务器收到这N个字节后,也把自己的offset加N;
-
主服务器维护一个
固定长度
的先进先出队列,默认1MB,近期传播的命令会保存在这里,并且队列中的每个字节都有一个编号,就是复制偏移量offset。 -
从服务器重新连接后,会发送之前保存的主服务器的ID,如果与当前连接的主服务器ID相同,则进行部分重同步,如果不同,则说明当前主服务器并不是之前的,所以需要从新全部同步(ps: 每个redis服务器都有自己的运行ID,是在服务器启动时自动生成的,有40个随机的十六进制字符组成)
另外,如果在命令传播过程中,master发送的命令slave没有收到怎么办?比如,master这边的offset偏移了40,而slave没收到这40字节,所以offset就不会偏移,这时主从服务器的状态就不一致了。
为了解决这个问题,redis2.8版本新增了心跳检查
功能,slave以每秒一次的频率向master发送REPLCONF ACK 命令,告诉master自己当前的offset是多少,如果master发现slave和自己的offset不一致,就会把丢掉的那些命令重新发送一次。