Redis

Redis

  1. 字符串:int、raw、embstr
  2. 列表:ziplist和linkedlist
  3. 哈希表:ziplist和hashtable
  4. 集合:intset和hashtable
  5. 有序集合:ziplist和skiplist

ziplist是一种经过特殊编码的双向链表,不同于普通的双向链表,ziplist存储在一块连续的内存中。ziplist的特殊编码节省了数据所占用的内存。ziplist的每个数据项上都保存有本项的数据长度和上一项的数据长度。这样可以通过指针的运算跳到上一个或者下一个数据项。

由于ziplist在一块连续内存上,对ziplist的追加操作就需要重新分配一块新的内存空间,并把旧数据搬移到新内存。

且对ziplist的查找操作需要遍历,效率较低,所以在数据量比较小的时候适合使用ziplist。

过期策略

惰性删除+定期删除

惰性删除:获取键之前检测是否过期

RDB持久

生成RDB:SAVE和BGSAVE这两个命令都可以生成RDB文件。SAVE会阻塞服务,BGSAVE会fork子进程,在子进程中进行生成RDB。可以设置满足一定条件自动执行BGSAVE。

同时满足两个条件可触发BGSAVE:距离上次SAVE已经过去的时间 && 距离上次SAVE修改的次数

系统启动时,会优先载入AOF文件,若不存在则载入RDB文件。

AOF持久化

AOF文件保存客户端发来的请求。先保存在程序中的缓冲区中

  1. 写请求命令保存在程序中的aof_buf缓冲区中;
  2. 在服务器每个循环事件的结束阶段,调用flushAppendOnlyFile函数将aof写入磁盘中;
  3. 由于第二步是调用系统函数write进行写操作,会写到操作系统的page cache中。落盘需要调用fsync函数,具体什么时候落盘,可以通过设置appendfsync来实现。

aof重写

aof文件会随着Redis的使用慢慢变大,我们可以通过aof重写来减小aof文件的大小。aof重写通过读取数据库现有数据来实现。

aof重写是后台进程,Redis在重写过程中,客户端可能会有新的写请求进来,这些写请求会被放到重写缓存区中。等到后台aof重写完成后,再把重写缓存区中的写请求追加到重写完成的aof文件中。

系统启动时,会优先载入AOF文件,若不存在则载入RDB文件。

复制

Redis2.8之前的复制

  1. 从服务器向主服务器发送SYNC命令;
  2. 主服务器收到SYNC命令后开始执行BGSAVE命令以生成RDB文件,并在缓存区中记录生成过程中的写请求;
  3. 将RDB文件和缓冲区中的写请求发送给从服务器;
  4. 对于后续的写请求,都会传送至从服务器

Redis2.8之后的复制

针对2.8之前版本较为低效的复制,2.8之后的新版本做了改进。

在2.8之前的版本中,如果从服务器因为网络问题断线后重连,那么没有办法只补断线阶段的写请求,需要重新给主服务器发送SYNC命名,重新走一遍流程。主从服务器可以通过各自的偏移量来确定主从是否一致。

在2.8之后的版本中,引入了PSYNC部分同步的命令,从服务器断线重连后,发送PSYNC命令给主服务器。主服务器会将断线期间的命令从缓冲区捞出发给从服务器,若断线期间的数据量太大,导致缓冲区放不下,那么就需要发送SYNC命令,重新开始同步。

心跳检测

从服务器会定期向主服务器发送心跳包进行心跳检测,有三个作用:

  1. 检测主从之间的网络状态;
  2. 实现min-slaves,即如果少于特定数量的从服务器或者时延太大,主服务器就拒绝写入,只能读;
  3. 若由于主从包丢失造成的主从不一致,可进行补发。

主从模式

在Redis中,用户可以通过执行SLAVEOF命令或者设置slaveof选项,让一个服务器去复制另一个服务器,被复制的服务器为主服务器,而对主服务器进行复制的服务器则被称为从服务器。

哨兵模式

哨兵是Redis高可用的解决方案。哨兵系统由一个或多个哨兵节点组成。可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。

在主从模式下,若主机发生故障,Redis就无法对外提供服务。这时需要引入哨兵模式。

集群模式

Redis Cluster是Redis 3.0之后推出的分布式集群方案。提供数据分片、主从复制、故障转移等功能。若选用Redis Cluster方案,就不需要哨兵了。

一个集群由多个节点组成,整个集群的数据被分为16384个槽,不同的节点分担不同的槽。

在一个完成分片的集群中,我们可以通过命令重新分片。源节点会将相应的槽逐步迁移至目标节点。

由于集群是去中心化的,客户端可以向其中任意一个节点发起请求。客户端请求一个key,若key不在该节点上,该节点会返回MOVED错误,并把正确的节点告知客户端。客户端之后需向正确的节点再次发起请求。

如果请求的节点是重新分片中的源节点且没有发现相应的key,那么该节点会返回ASK错误,并返回目标节点,告知客户端可以去目标节点查询。