Hello Redis,我有7个问题想请教你( 五 )

Quicklist 数据结构是 Redis 在 3.2 才引入的一个双向链表的数据结构,确实来说是一个 Ziplist 的双向链表 。
Quicklist 的每一个数据节点是一个 Ziplist,Ziplist 本身就是一个紧凑列表 。
假使,Quicklist 包含了 5 个 Ziplist 的节点,每个 Ziplist 列表又包含了 5 个数据,那么在外部看来,这个 Quicklist 就包含了 25 个数据项 。

Hello Redis,我有7个问题想请教你

文章插图
 
Quicklist 的结构设计简单总结起来,是一个空间和时间的折中方案:
  • 双向链表可以在两端进行 Push 和 Pop 操作,但是它在每一个节点除了保存自身的数据外,还要保存两个指针,增加额外的内存开销 。
其次是由于每个节点都是独立的,在内存地址上并不连续,节点多了容易产生内存碎片 。
  • Ziplist 本身是一块连续的内存,存储和查询效率很高,但是,它不利于修改操作,每次数据变动时都会引发内存 Realloc,如果 Ziplist 长度很长时,一次 Realloc 会导致大批量数据拷贝 。
所以,结合 Ziplist 和双向链表的优点,Quciklist 就孕育而生 。
对象共享
Redis 在自己的对象系统中构建了一个引用计数方法,通过这个方法程序可以跟踪对象的引用计数信息,除了可以在适当的时候进行对象释放,还可以用来作为对象共享 。
举个例子,假使键 A 创建了一个整数值 100 的字符串作为值对象,这个时候键 B 也创建保存同样整数值 100 的字符串对象作为值对象 。
Hello Redis,我有7个问题想请教你

文章插图
 
那么在 Redis 的操作时:
  • 讲数据库键的指针指向一个现有的值对象 。
  • 讲被共享的值对象引用计数加一 。
假使,我们的数据库中指向整数值 100 的键不止键 A 和键 B,而是有几百个,那么 Redis 服务器中只需要一个字符串对象的内存就可以保存原本需要几百个字符串对象的内存才能保存的数据 。
Redis 是如何实现主从复制
Hello Redis,我有7个问题想请教你

文章插图
 
几个定义:
  • runID:服务器运行的 ID 。
  • Offset:主服务器的复制偏移量和从服务器复制的偏移量 。
  • Replication backlog:主服务器的复制积压缓冲区 。
在 Redis 2.8 之后,使用 Psync 命令代替 Sync 命令来执行复制的同步操作 。
Psync 命令具有完整重同步和部分重同步两种模式:
  • 完整同步用于处理初次复制情况:完整重同步的执行步骤和 Sync 命令执行步骤一致,都是通过让主服务器创建并发送 RDB 文件,以及向从服务器发送保存在缓冲区的写命令来进行同步 。
  • 部分重同步是用于处理断线后重复制情况:当从服务器在断线后重新连接主服务器时,主服务可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处的状态 。

Hello Redis,我有7个问题想请教你

文章插图
 
完整重同步:
  • Slave 发送 Psync 给 Master,由于是第一次发送,不带上 runID 和 Offset 。
  • Master 接收到请求,发送 Master 的 runID 和 Offset 给从节点 。
  • Master 生成保存 RDB 文件 。
  • Master 发送 RDB 文件给 Slave 。
  • 在发送 RDB 这个操作的同时,写操作会复制到缓冲区 Replication Backlog Buffer 中,并从 Buffer 区发送到 Slave 。
  • Slave 将 RDB 文件的数据装载,并更新自身数据 。
如果网络的抖动或者是短时间的断链也需要进行完整同步就会导致大量的开销,这些开销包括了,Bgsave 的时间,RDB 文件传输的时间,Slave 重新加载 RDB 时间,如果 Slave 有 AOF,还会导致 AOF 重写 。
这些都是大量的开销,所以在 Redis 2.8 之后也实现了部分重同步的机制 。
Hello Redis,我有7个问题想请教你

文章插图
 
部分重同步: