高可靠性:
一是数据尽量少丢失(AOF 和 RDB )
二是服务尽量少中断(增加副本冗余量,将一份数据同时保存在多个实例上)
主从库模式

以保证数据副本的一致,主从库之间采用的是读写分离的方式。
- 主库:可读可写
- 从库:只能读操作
好处:分担全量复制时的主库压力
问题:全量复制,对于主库来说,需要完成两个耗时的操作:生成 RDB 文件和传输 RDB 文件,从库数量很多
解决:通过“主-从-从”模式将主库生成 RDB 和传输 RDB 的压力,以级联的方式分散到从库上。基于长连接的命令传播,可以避免频繁建立连接的开销。
问题:网络断连或阻塞
解决:采用增量复制,把主从库网络断连期间主库收到的命令,同步给从库。使用repl_backlog_buffer 环形缓冲区,主库会记录自己写到的位置,从库则会记录自己已经读到的位置。
问题:如果从库的读取速度慢,可能导致从库还未读取的操作被主库新写的操作覆盖了,会触发全量复制
解决:
- 1.调整 repl_backlog_size = 缓冲空间大小 * 2 ,缓冲空间大小 = 主库写入命令速度 * 操作大小 - 主从库间网络传输命令速度 * 操作大小
- 2.考虑使用切片集群来分担单个主库的请求压力
哨兵机制:主库故障后,从库无法服务写操作
解决:哨兵机制(实现主从库自动切换),哨兵主要负责三个任务:监控、选主(选择主库)和通知。

监控
心跳检测:周期性地给所有的主从库发送 PING 命令,没有在规定时间内响应哨兵的 PING 命令,判定主观下线
主观下线:哨兵发现主库或从库对 PING 命令的响应超时了。
如果检测的是从库,哨兵简单地把它标记为“主观下线”就行了,因为从库的下线影响一般不太大,集群的对外服务不会间断。
如果检测的是主库,通常会采用多实例组成的集群模式进行部署(哨兵集群),大多数的哨兵实例,都判断主库已经“主观下线”了,主库才会被标记为“客观下线”。
客观下线:当有 N 个哨兵实例时,最好要有 N/2 + 1 个实例判断主库为“主观下线”。
目的:以减少误判的概率,也能避免误判带来的无谓的主从库切换
误判:一般会发生在集群网络压力较大、网络拥塞,或者是主库本身压力较大的情况下。
选主(选择主库)(会带来额外的计算和通信开销)
一定规则:先检查从库的当前在线状态 和 判断它之前的网络连接状态: down-after-milliseconds (主从库断连的最大连接超时时间)* 10(发生断连的次数)
- 从库优先级最高:通过 slave-priority 配置项,,会被选为新主库。
- 主从库复制进度最接近:主库会用master_repl_offset 记录当前的最新写操作在 repl_backlog_buffer 中的位置,而从库会用 slave_repl_offset 这个值记录当前的复制进度,从库的 slave_repl_offset 最接近 master_repl_offset,会被选为新主库。
- 从库 ID 号最小:在优先级和复制进度都相同的情况下,ID 号最小的从库得分最高,会被选为新主库。
通知(会带来额外的计算和通信开销)
- 执行 replicaof 命令,和新主库建立连接,并进行数据复制
- 通知给客户端,连接新主库
在这个切换过程中,客户端能否正常地进行请求操作呢?如何做到客户端无感知?
- a:主库下线,可读(读写分离)不可写,写失败的时间=哨兵切换主从的时间+客户端感知新主库时间
- b:主库下线无感知,需要客户端与哨兵配合改造:
– 1:哨兵主动通知:哨兵需要将最新的主库地址写入自己的pubsub中,客户端需要订阅这个pubsub,当这个pubsub有数据时,客户端就能感知到
– 2:客户端主动获取:客户端不将主从库写死,而是从哨兵集群中获取,从而始终获取最新的主从地址 - c:集群分片模式的Redis集群,可以不使用哨兵机制(我们项目组就是这样的)
哨兵集群:为了避免单个哨兵故障后无法进行主从切换,以及为了减少误判率

- 哨兵之间互通机制:基于Redis 提供的 pub/sub 机制。订阅主库的同一频道
- 哨兵与主从互通机制:哨兵向主库发送INFO指令,获取所有从库信息,实现对主从库控
- 哨兵判定主库异常机制:任意一个哨兵实例都可发起主库异常“投票仲裁”流程
哨兵投票机制:
- a:哨兵实例只有在自己判定主库下线时,才会给自己投票,而其他的哨兵实例会把票投给第一个来要票的请求,其后的都拒绝
- b:如果出现多个哨兵同时发现主库下线并给自己投票,导致投票选举失败,就会触发新一轮投票,直至成功
哨兵Leader切换主从库的机制:
哨兵成为Leader的必要条件:
a:获得半数以上的票数,
b:得到的票数要达到配置的quorum阀值(主观下线)
主从切换只能由Leader执行,而成为Leader有两个必要的条件,所以当哨兵集群中实例异常过多时,会导致主从库无法切换
经验:要保证所有哨兵实例的配置是一致的,尤其是主观下线的判断值 down-after-milliseconds。因为这个值在不同的哨兵实例上配置不一致,导致哨兵集群一直没有对有故障的主库形成共识,也就没有及时切换主库,最终的结果就是集群服务不稳定。
数据增多了,是该加内存还是加实例?
- 纵向扩展:升级单个 Redis 实例的资源配置;实施起来简单、直接;受到硬件和成本的限制;
- 当使用 RDB 对数据进行持久化时,如果数据量增加,需要的内存也会增加,主线程 fork 子进程时就可能会阻塞。内存过大在大数据备份时会导致redis性能下降。
- 横向扩展:横向增加当前 Redis 实例的个数,切片集群解决大数据量,高性能设计。
切片集群问题:
1.数据分片与实例如何建立对应关系
2.客户端如何获取哪个实例数据
Redis Cluster 的方案,用于实现切片集群。采用哈希槽来处理数据和实例之间的映射关系。集群中有N个实例,每个实例上的槽个数为16384/N 个。
基于哈希槽计算时,虽然也要记录哈希槽和实例的对应关系,但是哈希槽的个数要比键值对的个数少很多,无论是修改哈希槽和实例的对应关系,还是使用额外空间存储哈希槽和实例的对应关系,都比直接记录键值对和实例的关系的开销小得多。
好处:
- 引入哈希槽,将key的分布与具体的Redis实例解耦,有利于Redis数据的均衡分布。
- 不采用哈希槽的话,Redis实例的扩容和缩容,需要针对无规则的key进行处理,实现数据迁移。此外,需要引入负载均衡中间件来协调各个Redis实例的均衡响应,确保数据的均匀分布;中间件需要保存key的分布状态,保证key的查询能够得到响应。增加了Redis系统的复杂性 与 可维护性。
- 要点1:数据分片和实例的对应关系建立:按照CRC16算法计算一个key的16bit的值,在将这值对16384取模
- 要点2:一个切片集群的槽位是固定的16384个,可手动分配每个实例的槽位,但必须将槽位全部分完
- 要点3:客户端如何确定要访问那个实例获取数据:1.从任意个实例获取并缓存在自己本地,2.重定向机制
- 要点4:重定向机制:客户端访问的实例没有数据,被访问实例响应move命令,告诉客户端指向新的实例地址
- 要点5:ASK命令:1,表明数据正在迁移 2,告知客户端数据所在的实例
- 要点6:ASK命令和MOVE命令的区别:move命令是在数据迁移完毕后被响应,客户端会更新本地缓存。ASK命令是在数据迁移中被响应,不会让客户端更新缓存
689

被折叠的 条评论
为什么被折叠?



