之前已经介绍了一些redis的基本特性。这里介绍下主从复制与集群工作方式。

主从复制

为保证redis的高可用性,一般都会跟其他中间件一样进行主从复制。比如kafka是把消息传递、mysql使用binlog。

既然涉及到分布式,就不得不提及CAP理论。

CAP理论有三点

  • C-Consistent 一致性
  • A-Availability 可用性
  • P-Partition tolerance 分区容忍性

也就是说在一个分布式系统中,不能同时保证这三个特性。即,网络分区发生时,一致性和可用性两难全。

因此大多数中间件都是妥协:保证最终一致性。

简单来说同步有三种方式:

快照同步:即全量同步复制,SYNC

  • 主节点进行一次BGSAVE,数据放入磁盘文件。
  • 快照文件传递给从节点
  • 从节点接收完快照文件后,清空自己,并进行一次全量加载
  • 从节点全量加载完成后,通知主节点进行增量同步

增量同步:即PSYNC,利用复制积压缓冲区来完成的

  • 主节点将修改指令存入buffer中,异步同步到从节点
  • 从节点指向同步指令,并反馈偏移量

无盘复制

不生成文件的复制,其实就是把文件的生成和发送改成直接网络发送的方式。

  • 主节点一边遍历内存,一边将序列号内容发送到从节点。
  • 从节点收到内容存入磁盘文件,完成后,一次性加载。

无盘复制是2.8版本引入的:主服务器直接通过套接字 将快照内容发送到从节点:主节点会一边遍历内存,一遍将序 列化的内容发送到从节点。

从节点还是跟之前一样,先将接收到的内容存储到磁盘文件中, 再进行一次性加载。

 

Cluster

Redis将所有数据划分为16394 个 槽位,然后让每个节点负责一部分槽位。这样所有的机器就构成了一个哈希环。

槽位定位也很简单:

hash = crc32(key)
slot_index = hash % 16384

分槽就带来两个问题;请求跳转、迁移

请求跳转

客户端向错误节点发出指令,节点会向客户端返回特殊的跳转指令,并携带目标节点的地址。简单来说客户端client 向 serverA 请求 key,而key实际上再 serviceB上。此时serverA就会返回一个错误命令

-MOVED slot_num IP:port

注意:- 在redis中代表返回错误,slot_num 代表请求的key所在的槽位编号,IP:port 就是目标机器地址。

客户端收到该错误返回就会再次请求 IP:port 。

迁移

因为是集群工作方式,就会涉及扩容,即所谓的迁移。注意,这里迁移的是哈希槽,也就是说迁移的单位就是槽。一个槽一个槽的迁移。

redis集群一致性协议 redis集群如何保证一致性_redis

Redis Cluster 提供 redis-trib 手动调整槽位。

迁移的单位是槽。中间过渡状态时,在原节点状态是 migrating ,在目标节点状态是 importing。

  • 设置中间状态
  • 利用keysinslot 获取所有的key 列表
  • 每个key,原节点执行 dump 得到序列号内容,通过客户端向目标节点发送 restore指令及序列化内容
  • 目标节点反序列化即可恢复,并回复 OK
  • 原节点收到 OK后,再删除 key

迁移过程中,目标节点执行 restore 到 原节点收到 OK 期间,原节点的主线程处于阻塞状态。

迁移中,某客户端请求原节点时,

  • 若 请求 key 存在,则直接返回
  • 若不存在,则原节点返回 -ASK targetNodeAddr 的重定向指令
  • 客户端收到后,先向 targetNodeAddr 发送 asking 指令,再发送执行原先的指令

因为迁移中,该槽位依旧属于原节点。不发送 asking 的话,目标节点会向客户端返回 -MOVED 重定向指令,就会形成重定向循环。

Sentinel哨兵

一般由 3~5 个节点组成,负责监视主从节点的健康。