1、数据库
1.1、服务器中的数据库
1 | struct redisServer { |
数据库的数量由dbnum属性决定,默认情况下,Redis会创建16个数据库。
1.2、切换数据库
默认情况下,redis客户端的目标数据库为0号数据库,可以通过SELECT
命令来切换目标数据库。
1 | typde struct redisClient { |
redis-cli客户端会在输入符旁边提示当前所使用的数据库:
redis[1] > SELECT 2
但是其他语言客户端却没有,为了避免操作错误数据库,执行Redis命令(如FLUSHDB)之前,最好先执行以下SELECT
命令。
1.3、数据库键空间
1 | typedef struct redisDb { |
数据库键操作
添加新键
redis> SET data “2016.07.31”
redis> RPUSH list “a” “b” “c”
redis> HSET hashTable name “test”删除键
redis> DEL book更新键
redis> SET data “2016.08.01”对键取值
redis> GET str
redis> LRANGE list 0 -1
读写键空间时的维护操作
- 记录命中和没命中次数(INFO stat的keyspace_hits和keyspace_missess属性);
- 更新键的LRU时间(OBJECT idletime
查看闲置时间); - WATCH监视的键有改动,键会被标为脏,让事务程序注意到这个键已经被修改了;
- 服务器每修改一个键之后,都会对脏键计数值加1,这个计数器会触发服务器的持久化和复制操作;
- 数据库通知功能相关处理。
1.4、设置键的生存时间或过期时间
EXPIRE和PEXPIRE命令
redis> EXPIRE KEY 5 // 缓存5秒
redis> EXPIREAT key 1377252100
TTL和PTTL命令
返回距离这个键被服务器自动删除还有多长时间。
redisDb中的expires字典保存了所有键的过期时间。
PERSIST
在过期字典中查找给定的键,并解除键和值在过期字典的关联。
1.5、过期键删除策略
定时删除
会对服务器的响应时间和吞吐量造成影响。
惰性删除
如果一个过期的键一直没被访问到,那么永远也不会被删除。
定期删除
每个一段时间进行一次删除操作,限制删除操作执行的时长和频率减少删除操作对CPU时间的影响。
1.6、Redis的过期键删除策略
Redis使用惰性和定期删除两种策略。
1.7、AOF、RDB和复制功能对过期键的处理
执行SAVE或者BGSAVE命令创建一个新的RDB文件时,程序会对键进行检查,已过期的键不会被保存到新创建的RDB文件中。
载入的过程中,如果是主服务器,只会载入未过期的键;如果是从服务器模式,所有键都会被载入,不过在进行数据同步的时候,从服务器的数据库就会被清空,所以过期键对RDB文件的从服务器不会造成影响。
如果以AOF模式持久化数据,当过期键被惰性或者定期删除的时候,会向AOF文件追加一条DEL命令。
复制
主服务器删除一个过期键之后,会显示地向所有从服务器发送一个DEL命令。
从服务器存在过期的键,客户端从该从服务器继续获取该键,仍可以获取到;但是从主服务器获取,主服务器发现该键已过期,向客户端返回空回复,并向从服务器发送DEL message
命令。
1.8、数据通知
键空间通知
获取0号数据库中针对message键执行的所有命令:
redis> SUBSCRIBE _ keyspace@0 :message
获取0号数据库中所有执行DEL命令的键:
redis> SUBSCRIBE keyevent@0 _:del
服务器配置的notify-keyspace-events选项决定了服务器所发送通知的类型
发送通知
void notifyKeyspaceEvent(int type, char event robj key, int dbid)
程序会根据type这个值来判断通知是否就是服务器配置notify-keyspace-events选项所选定的通知类型,如果是。
例如:notifyKeyspaceEvent(REDIS_NOTIFY_SET, “sadd”, c->argv[1], c->db->id);
当SADD命令向集合成功的添加元素,命令就会发送。
发送通知的实现
2、RDB持久化
2.1、RDB文件的创建与载入
生成RDB文件的命令:
- SAVE:会阻塞服务器进程,直到RDB文件创建完为止,阻塞期间,服务器不能处理任何请求命令;
- BGSAVE:会派生子进程负责创建RDB文件
实际由rdb.c/rdbSave
函数完成
RDB文件的载入是在服务器启动时自动执行的,期间服务器一直会处于阻塞
状态。Redis没有专门用于载入RDB文件的命令。
如何选择载入方式?
如果开启了AOF持久化功能,服务器会优先使用AOF文件还原数据;
AOF持久化功能处于关闭的情况下,服务器使用RDB文件来还原数据库状态;
相关函数:rdb.c/rdbLoad
;
SAVE,BGSAVE和BGREWRITEAOF有什么区别?
SAVE
命令执行会阻塞服务器,客户端所有命令都会被拒绝;BGSAVE
命令有子进程执行,创建RDB文件过程中仍然可以继续处理客户端命令请求,但是此时,客户端发送的SAVE命令会被服务器拒绝,避免父进程和子进程同事执行两个rdbSave调用,防止产生竞争条件。同事,客户端再发送BGSAVE命令也会被拒绝。BGREWRITEAOF
he BGSAVE命令不能同时执行,执行BGSAVE期间发送的BGREWRITEAOF命令会被延迟到BGSAVE命令执行完毕之后执行。执行BGREWRITEAOF期间,BGSAVE命令会被服务器拒绝。(BGSAVE和BGREWRITEAOF虽然都是在子进程里面执行的,不能同时执行是出于服务器性能考虑的)
2.2、自动间隔性保存
Redis运行用户通过设置服务器配置的save选项,让服务器每隔一段时间自动执行一次BGSAVE命令:
save 900 1
save 300 10
save 60 10000 # 服务器在60秒内,对数据库进行了至少10000次修改,则执行BGSAVE命令
2.3、RDB文件结构
固定REDIS开头,0006是版本号,最后是文件校验和。
key_value_pairs保存了数据库中所有键值对数据。
key_value_pairs具体是如何存储键值对的?
可分为不带过期和带过期时间的键值对:
其中type表示编码类型,key是一个字符串,value因type的不同结构也会不一样。
key_value_pairs中的value是如何选择编码的
字符串对象:如果是REDIS_ENCODING_RAW,又可根据长度是否大于20字节分为压缩和不压缩两种方式。(需要打开RDB文件压缩功能:redis.conf的rdbcompression),压缩格式如下:
列表对象:
REDIS_ENCODING_LINKEDLIST:
每一个item又是一个字符串对象。
集合对象:
REDIS_ENCODING_HT:
有序集合对象:
REDIS_ENCODING_SKIPLIST:
哈希表对象:
REDIS_ENCODING_HT:
ZIPLIT编码的列表、哈希表或者有序集合
将压缩列表转换成一个字符串对象,保存到RDB文件中。
2.4、分析RDB文件
可以通过od命令来分析RDB文件
redis> od -c dump.rdb
3、AOF持久化
AOF即:Append Only File。
RDB持久化与AOF持久化有什么不同?
RDB通过保存数据库中的键值对来记录数据库状态的不同,AOF持久化通过保存Redis服务器所执行的命令来记录数据库状态。
3.1、实现
AOF持久化实现分为:命令追加(追加到aof_buf),文件写入,文件同步。
Redis是如何实现AOF文件的写入和同步的?
Redis在一个事件循环里,每次都做判断,根据服务器的appendfsync配置选择对应的策略来进行AOF文件的写入和同步。
3.2、AOF文件的载入与数据还原
- 创建fake client
- 从AOF文件分析并取出一条写命令
- 使用伪客户端执行被读出的命令
- 循环上面三步
3.3、AOF重写
什么是AOF重写,为什么要执行AOF重写?
为了节省AOF文件的空间,去除冗余的命令。
通过调用aof_rewrite
函数进行重写,在子进程中进行重写,重写过程新发送的命令按如下处理:
4、事件
Redis是一个事件驱动程序,服务器处理文件事件和时间时间两类事件。
4.1、文件事件
基于Reactor模式开发的网络事件处理器。使用IO多路复用同时监听多个套接字,根据套接字执行的任务为套接字关联不同的事件处理器。
IO多路复用程序所有功能都是通过封装常见的select、epoll、evport、kqueue这些I/O多路复用函数库来实现的。
常用的文件事件处理器?
连接应答处理器:对连接服务器监听套接字的客户端进行应答,Redis服务器进行初始化的时候,程序会将这个连接应答处理器和服务器监听套接字的AE_READABLE事件关联起来,引发连接应答处理器执行,并执行相应的套接字应答操作。
命令请求处理器:从套接字中读入客户端发送的命令请求内容,当一个客户端通过连接应答处理器成功连接到服务器之后,服务器会将客户端套接字的AE_READABLE事件和命令请求处理器关联起来,当客户端向服务器发送命令请求的时候,套接字就会产生AE_READABLE事件,引发命令请求处理器执行,并执行相应的套接字读入操作。
命令回复处理器:当服务器有命令回复需要传送给客户端的时候,服务器会将客户端套接字的AE_WRITEABLE事件和命令回复处理器关联起来,当客户端准备好接受服务器传回的命令回复时,就会产生AE_WRITEABLE事件,引发命令回复处理器执行,并执行相应的套接字写入操作。