一、数据结构
1.简单动态字符串SDS
rdis没有直接使用C语言传统的字符串类型,而是自己构建了一种简单动态字符串SDS的类型,原因:
1.常数复杂度获取字符串长度
2.修改的时候会重新计算所需的空间,拒绝溢出
3.减少了内存分配,free记录空间字节数
4.二进制安全,可以保存二进制数据
5.兼容部分C字符串
2.链表:
双向链表
3.字典dict
1.使用哈希表作为底层实现,每个字典使用两个哈希表,一个平时使用,一个rehash时使用。
2.使用链地址法来解决键冲突,一个索引上的多个键值对使用单链表链接。
3.渐进式rehash到另外一个哈希表
4.跳跃表
1.跳跃表是有序集合的底层实现之一
2.redis跳跃表由zskiplist和zskiplistNode两个结构组成,zskilist用于保存跳跃表信息(比如表头节点、表位节点、长度),而zskiplistnode用于跳跃表节点
3.每个跳跃表的节点的层高都是1至32之间随机数。
4.同一跳跃表,多个节点分值可以相同,但节点的成员对象必须是唯一的
5.节点按照分值大小排序,分值相同,则按照对象的大小排序
5.整数集合
整数集合是集合键的底层实现之一
6.压缩列表
一种为节约内存儿开发的顺序数据结构
二、对象
1.字符串对象
字符串对象的编码可以是int、raw、embstr
1.int:字符串保存的是整数值,并且可以用long类型来标识
2.embstr:保存小于32字节的字符串,只读修改后转换成int或者embstr
3.raw使用SDS来保存
2.列表对象
列表对象的编码可以是压缩列表zipList或者双端链接linkedlist
当满足以下两个条件时,使用ziplist编码:
1.列表对象保存的所有字符串元素长度小于64
2.元素的个数小于512个
1.ziplist使用压缩列表来作为底层实现
2.linkedlist使用双端链接作为底层实现
3.哈希对象
哈希对象编码可以是压缩列表ziplist或者字典hashtable
当哈希对象满足以下两个条件时,哈希对象使用ziplist编码
1.哈希对象所有键值对键和值的字符串长度都小于64字节
2.哈希对象所有键值对的个数小于512个
1.哈希对象使用压缩列表ziplist作为实现
2.hashtable使用字典作为实现
4.集合对象
集合对象编码可以是整数集合intset或者字典hashtable
当集合对象可以同时满足以下两个条件时,使用整数集合intset作为实现:
1.集合对象保存的所有元素是整数时
2.集合元素的数量小于512个
1.集合对象使用整数集合intset作为实现
1.集合对象使用整数集合字典hashtable作为实现,键为字符串集合元素,值则为null
5.有序集合对象
有序集合对象编码可以是压缩列表ziplist或者跳表skiplist
当有序集合对象可以同时满足以下两个条件时,使用整数集合ziplist作为实现
1.有序集合保存的元素数量小于128个
2.有序集合保存的所有元素成员的长度小于64字节
1.有序集合对象使用压缩列表ziplis作为底层实现,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点为元素的成员member,第二个元素则保存元素的值score,元素并按照从小到大的排序
2.有序集合使用跳跃表skiplist作为底层实现
三、数据库实现
1.过期删除策略:Redis采用惰性删除和定期删除实现
1.定时删除:在设置过期时间的时候,创建一个定时器timer,让定时器在键的过期时间来临时,立即执行对键的删除操作
2.惰性删除:每次获取键的时候,判断是否过期,过期则删除。
3.定期删除:每间隔一段时间,程序就对数据库进行一次检查,删除过期键
2.持久化RDB和AOF
RDB:
1.保存数据库所有键值对数据,经过压缩生成二进制文件
2.通过SAVE或BGSAVE命令执行保存操作,SAVE会阻塞服务器,BGSAVE通过子进程执行保存不会阻塞
AOF(append only file ):
1.通过保存所有修改数据库的写命令请求来记录数据库的状态
2.命令先写到AOF缓冲区,然后定期的同步到AOF文件
3.AOF重写通过BGREWRITEAOF命令重新读取数据库中键值对来生成一个体积更小的AOF文件
4.执redis会维护一个AOF重写缓冲区,会记录子进程在执行行BGREWRITEAOF命令重写AOF文件期间记录所有数据库写命令,并在重写完成后追加到新的AOF文件中
3.事件
Redis服务器是一个事件驱动程序:文件事件处理服务器与客户端的通信,时间时间处理服务器中的定时操作,例如serverCron函数
1.文件事件处理器采用I/O多路复用程序同事监听多个套接字,并根据套接字目前执行的任务来关联不同的文件处理器
2.I/O多路复用程序总是会将产生文件事件的套接字放在一个队列里面,以有序、同步、每次一个套接字的方式向文件事件套接字传送套接字
文件事件分派期根据I/O多路复用程序传来的套接字产生的事件类型调用相应的处理器
3.服务器轮流处理文件事件和时间事件,时间事件的处理会比设定到达的时间要晚一些
四、多机数据库的实现
1.主从复制
在redis中,用户通过执行SLAVEOF命令或者设置slaveof选项,让一个从服务器去复制一个主服务器,称为主从复制
阶段一 :同步
1.从服务器发送SYNC命令给主服务器,主服务器执行BGSAVE命令生成RDB文件,并通过缓冲区记录期间的写命令
2.主服务器BGSAVE命令执行完后,将生成的RDB文件发送给从服务器,从服务器载入RDB文件
3.主服务器将缓冲区的所有写命令发送给从服务器,至此主从服务器状态一致
阶段二 :命令传播
主服务器将接受到写命令传播发送给从服务执行,使数据保持一致。命令传播阶段,从服务器会以每秒一次的频率发送心跳消息。
redis2.8版本后使用PSYNC命令的完整重同步、部分重同步优化主从断线后的同步问题:
1.完整重同步和SYNC执行的步骤一样
2.部分重同步,主服务器维护一个复制积压缓冲区,从服务重连后通过PSYNC命令发送复制偏移量,主服务器判断丢失的数据在复制积压区的范围内,则进行部分重同步,将缓冲区的命令发送给从服务器
2.sentinel哨兵
sentinel哨兵是Redis实现高可用的解决方案:由一个或者多个sentinel实例组成的sentinel系统可以监控任意多个主服务器,以及这些主服务器下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线的主服务器下的某个从服务器升级为新的主服务器
1.sentinel本质上是一个运行在特殊模式下的Redis服务器
2.sentinel将成为主服务器的客户端,可以向主服务器发送命令
3.sentinel会创建两个连向主服务器的连接:命令连接(用来发送命令)、订阅连接
4.sentinel默认会以每十秒一次的频率向主服务器发送info命令,获取主服务器的信息及其下从服务器的信息,并创建两个连向从服务器的连接:命令连接(用来发送命令)、订阅连接,通过每十秒一次的频率向从服务器发送info命令,获取从服务器的信息
5.sentinel默认会以两秒一次的频率通过命令连接向所有监视的主服务器和从服务器的sentinel:hello频道发送一条消息,消息内容包含sentinel自身信息以及主服务器信息,其他监听此频道的sentinel会解析消息,来更新主服务器信息以及sentinel系统信息,并创建向其他sentinel的命令连接,组成sentinel互联的网络
下线:
1.sentinel默认会以每秒一次的频率向它创建的了命令连接的实例(主服务器、从服务器、其他sentinel)发送ping命令判断是否在线
2.sentinel发现实例下线会被sentinel标记为主观下线,多个sentinel配置的下线时长可能不一致
3.sentinel发现主服务器主观下线后,发送命令询问其他sentinel是否也判断此主机为主观下线,当从其他sentinel接受到足够多的下线判断后,sentinel将从服务器标记为客观下线,并对主服务器执行故障转移工作
4.sentinel选举领头sentinel对下线服务器进行故障转移工作。
3.Redis集群
redis集群是redis分布式数据库方案,集群通过分片(sharding)来进行数据共享,并提供复制和故障转移功能。