redis-doc-集群

主从复制

为什么要使用主从复制?

  • redis-server单点故障
  • 单节点QPS有限
  • 持久化,从处理持久化,避免对主性能影响

主从复制应用场景分析

  • 读写分离场景,规避redis单机瓶颈
  • 故障切换, master出问题后还有slave节点可以使用
  • slave服务器设定为只读,可以用在数据安全的场景下。

数据同步方式

  • PDB:通过磁盘文件的方式进行同步
  • AOF:通过网络以命令的方式进行同步

PDB与AOF的方法通过修改redis.conf配置切换,repl-diskless-sync no,yes表示AOF

主从复制流程

  • 从服务器通过psync命令发送服务器已有的同步进度(同步源ID、同步进度offset)
  • master收到请求,同步源为当前master,则根据偏移量增量同步
  • 同步源非当前master,则进入全量同步: master生成rdb,传输到slave,加载到slave内存
  • 可以使用主从复制来避免 master 持久化造成的开销。 master 关闭持久化, slave 配置为不定期保存或是启用 AOF。(注意: 重新启动的 master 程序将从一个空数据集开始,如果一个 slave试图与它同步,那么这个 slave 也会被清空。 )

主从复制核心知识

  • Redis 默认使用异步复制, slave 和 master 之间异步地确认处理的数据量
  • 一个 master 可以拥有多个 slave
  • slave 可以接受其他 slave 的连接。 slave 可以有下级sub slave
  • 主从同步过程在 master 侧是非阻塞的
  • slave初次同步需要删除旧数据,加载新数据,会阻塞到来的连接请求

主从复制的注意事项

读写分离场景:

  • 数据复制延时导致读到过期数据或者读不到数据(网络原因、 slave阻塞)
  • 从节点故障(多个client如何迁移)

全量复制情况下:

  • 第一次建立主从关系或者runid不匹配会导致全量复制
  • 故障转移的时候也会出现全量复制

复制风暴:

  • master故障重启,如果slave节点较多,所有slave都要复制,对服务器的性能,网络的压力都有很大影响。
  • 如果一个机器部署了多个master

写能力有限

  • 主从复制还是只有一台master,提供的写服务能力有限

master故障情况下:

  • 如果是master无持久化, slave开启持久化来保留数据的场景,建议不要配置redis自动重启。
  • 启动redis自动重启, master启动后,无备份数据,可能导致集群数据丢失的情况。

带有效期的key:

  • slave不会让key过期,而是等待 master 让 key 过期
  • 在Lua脚本执行期间,不执行任何 key 过期操作

步骤

命令实现

1
2
3
4
5
6
7
8
9
10
11
# 启动redis客户端
redis-cli

# 从服务器使用slaveof命令实现从功能
slaveof [ip] [port]

# 退出集群
Slaveof no one

# 查看主从信息
info replication

配置实现

1
2
3
4
5
6
7
8
# 打开配置
vim redis.conf

# 配置文件中增加
slaveof [ip] [port]

# 从服务器是否只读(默认yes)
slave-read-only yes

哨兵(sentinel)

例子参考docker的常用归纳

哨兵如何知道Redis主从信息

哨兵配置文件中,保存着主从集群中master的信息,可以通过info命令,进行主从信息自动发现。

主观下线(sdown)

  • 主观下线:单个哨兵自身认为redis实例已经不能提供服务

  • 检测机制:哨兵向redis发送ping请求, +PONG、 -LOADING、 -MASTERDOWN这三种情况视为正常,其他回复均视为无效。

  • 对应配置文件的配置项: sentinel down-after-milliseconds mymaster 1000

客观下线(odown)

  • 客观下线:一定数量值的哨兵认为master已经下线。

  • 检测机制:当哨兵主观认为master下线后,则会通过 SENTINEL is-master-down-by-addr命令 询问其他哨兵是否认为master已经下线,如果达成共识(达到quorum个数),就会认为master节点客观下线,开始故障转移流程。

  • 对应配置文件的配置项: sentinel monitor mymaster 60.205.209.106 6380 2

slave选举方案

  • 根据salve节点状态
    非 S_DOWN,O_DOWN,DISCONNECTED
    判断规则: (down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state

  • 优先级
    redis.conf中的一个配置项: slave-priority 值越小,优先级越高

  • 数据同步情况
    Replication offset processed

  • 最小的run id
    run id 比较方案: 字典顺序, ASCII码

主从切换过程

  • 针对即将成为master的slave节点,将其撤出主从集群,自动执行: slaveof NO ONE
  • 针对其他slave节点,使它们成为新master的从属,自动执行: slaveof new_master_host new_master_port

哨兵之间如何通信

  • 哨兵之间的自动发现
  • 哨兵之间通过命令进行通信
  • 哨兵之间通过订阅发布进行通信

哨兵领导选举机制

基于Raft算法实现的选举机制,流程简述如下:

  1. 拉票阶段:每个哨兵节点希望自己成为领导者;
  2. sentinel节点收到拉票命令后,如果没有收到或同意过其他sentinel节点的请求,就同意该sentinel
    节点的请求(每个sentinel只持有一个同意票数);
  3. 如果sentinel节点发现自己的票数已经超过一半的数值,那么它将成为领导者,去执行故障转移;
  4. 投票结束后,如果超过failover-timeout的时间内,没进行实际的故障转移操作,则重新拉票选举。

http://thesecretlivesofdata.com/raft/

集群分片(cluster)

为什么要分片存储

假如公司用户量3千万,用户基本信息缓存到redis中,需要内存10G。

  1. 3千万用户,各种业务场景对用户信息的访问量很大。(单台redis示例的读写瓶颈凸显)
  2. 单redis实例管理10G内存,必然影响处理效率。
  3. redis的内存需求可能超过机器的最大内存。 (一台机器不够用)

官方集群方案

redis cluster是Redis的分布式集群解决方案, 在3.0版本推出后有效地解决了redis分布式方面的需求实现了数据在多个Redis节点之间自动分片、 故障自动转移、 扩容机制等功能。

官方集群方案

官方集群方案

cluster问题

  • 增加了slot槽的计算,是不是比单机性能差?
    共16384个槽, slots槽计算方式公开的, HASH_SLOT = CRC16(key) mod 16384 。
    为了避免每次都需要服务器计算重定向,优秀的java客户端都实现了本地计算,并且缓存服务器slots分配,有变动时再更新本地内容,从而避免了多次重定向带来的性能损耗。(结合画图过程理解)

  • redis集群大小,到底可以装多少数据?
    理论是可以做到16384个槽,每个槽对应一个实例,但是redis官方建议是最大1000个实例。存储足够大了

  • 集群节点间是怎么通信的?
    每个Redis群集节点都有一个额外的TCP端口,每个节点使用TCP连接与每个其他节点连接。检测和故障转移这些步骤基本和哨兵模式类似。

  • ask和moved重定向的区别
    重定向包括两种情况:
    若确定slot不属于当前节点,redis会返回moved。
    若当前redis节点正在处理slot迁移,则代表此处请求对应的key暂时不在此节点,返回ask,告诉客户端本次请求重定向

  • cluster meet命令中的bus-port是什么?
    MEET [bus-port]
    每个Redis群集节点都有一个额外的TCP端口,用于接收来自其他Redis群集节点的传入连接

  • 数据倾斜和访问倾斜的问题
    倾斜导致集群中部分节点数据多,压力大。解决方案分为前期和后期:
    前期是业务层面提前预测,哪些key是热点,在设计的过程中规避。
    后期是slot迁移,尽量将压力分摊(slot调整有自动rebalance、 reshard和手动)。

  • 节点之间会交换信息,传递的消息包括槽的信息,带来带宽消耗。
    注意:避免使用大的一个集群,可以分多个集群。

  • Pub/Sub发布订阅机制
    注意:对集群内任意的一个节点执行publish发布消息,这个消息会在集群中进行传播,其他节点接收到发布的消息。

  • 读写分离
    redis-cluster默认所有从节点上的读写,都会重定向到key对接槽的主节点上。
    可以通过readonly设置当前连接可读,通过readwrite取消当前连接的可读状态。
    注意:主从节点依然存在数据不一致的问题

集群slot迁移

迁移过程如下,大致描述如下:

  • 在迁移目的节点执行cluster setslot IMPORTING 命令,指明需要迁移的slot和迁移源节点。
  • 在迁移源节点执行cluster setslot MIGRATING 命令,指明需要迁移的slot和迁移目的节点。
  • 在迁移源节点执行cluster getkeysinslot获取该slot的key列表。
  • 在迁移源节点执行对每个key执行migrate命令,该命令会同步把该key迁移到目的节点。
  • 在迁移源节点反复执行cluster getkeysinslot命令,直到该slot的列表为空。
  • 在迁移源节点和目的节点执行cluster setslot NODE ,完成迁移操作。

集群从节点迁移

Redis集群实现了一个叫做复制(从节点)迁移的概念,以提高系统的可用性。

假设集群有三个主节点 A, B, C。 A、 B都各有一个从节点, A1 和 B1。 节点C有两个从节点: C1 和 C2迁移过程如下,大致描述如下:

  • 主节点 A 失效。 A1 被提升为主节点。
  • 节点 C2 迁移成为节点 A1 的从节点,要不然 A1 就没有任何从节点。
  • 三个小时后节点 A1 也失效了。
  • 节点 C2 被提升为取代 A1 的新主节点。
  • 集群仍然能继续正常工作

命令

sentinel

命令 描述
info sentinel 获取监控的所有主节点的基本信息。
sentinel masters 获取监控的所有主节点的详细信息。
sentinel master mymaster 获取监控的主节点mymaster的详细信息。
sentinel slaves mymaster 获取监控的主节点mymaster的从节点的详细信息。
sentinel sentinels mymaster 获取监控的主节点mymaster的哨兵节点的详细信息。
sentinel get-master-addr-by-name mymaster 获取监控的主节点mymaster的地址信息,前文已有介绍。
sentinel is-master-down-by-addr 哨兵节点之间可以通过该命令询问主节点是否下线,从而对是否客观下线做出判断。