Redis集群理解以及Tendis的优化
主从模式
主从同步
- 同步过程:
- 全量同步(第一次连接):RDB文件加缓冲区,主节点fork子进程,保存RDB,发送RDB到从节点磁盘,从节点清空数据,从节点加载RDB到内存
- 增量同步(断连后连接,且缓冲区没有满,满的话触发全量):发送缓冲区数据
主从复制
- 同步过后就是主从之间的复制
- redis的主从复制是异步(即主节点写完立刻返回客户端,主节点再将命令发给它的从)的,主从之间彼此都有心跳检测保证异步传输的数据可靠,主ping从以判断存活,从上报偏移量以保证数据丢失时再从主节点的复制缓冲区中拉取丢失数据。
- 主从复制的延迟问题:repl-disable-tcp-nodelay配置可以设置马上同步或者等待缓冲区满再同步
- 故障问题:主节点挂了需要手动处理
从节点的强一致性读
基于以上,从节点和主节点会有一定的延迟,但是有些业务需要保证二者数据是强一致的,有两个办法可以做到从节点的强一致性读
通过全局序列号实现“强一致性读”
- 主节点为每个写操作生成一个递增的全局序列号(Sequence Number)。
- 主节点会同步这个序列号给所有从节点。
- 从节点在处理读请求时,先向主节点请求最新序列号,然后等待 自身数据同步至该序列号后,再返回数据。
实现方式
- 主节点使用 Redis INCR 作为序列号:
INCR sequence_number
- 主节点在 每次写入时,更新这个序列号:
INCR sequence_number
SET my_key value
- 从节点执行读操作时,向主节点查询当前最新的 sequence_number:
GET sequence_number
等待自身数据同步至该序列号,然后再返回数据。这里可能需要对redis内部进行定制开发
WAIT 命令确保写入传播
Redis 提供了 WAIT 命令,可以用于 确保主节点的写操作至少同步到指定数量的从节点,从而 提升数据一致性:
WAIT 1 500
- 1 表示至少等 1 个从节点接收到最新写入的数据。
- 500 表示最多等待 500ms。
哨兵模式
故障恢复过程:
1. Raft选举主sentinel(选举后则一直存在,除非下线):如果被PING的数据库或者节点超时未回复,哨兵认为其主观下线。如果下线的是master,哨兵会向其它哨兵发送命令询问它们是否也认为该master主观下线,如果达到一定数目(即配置文件中的quorum)投票,哨兵会认为该master已经客观下线
2. 主sentinel来选择优先级最高的slave升为master
哨兵的主要问题还是由于中心架构,仅存在一个master节点引起的,因为主从,只能主节点进行写。
脑裂:比如一个主节点和其他所有的sentiel极其从节点隔离,主节点继续接受请求,而另一片区域会出现新的主节点。。
1. 问题1:当网络解决后,原主节点会变成slave,但是在同步之前会清空自己的数据,导致数据丢失,
2. 问题2:两个分区的数据不一致
脑裂的解决:设置最少slave存活数和主从复制的超时时间,如果存活数量太少或者超时,主节点禁止写操作,比如可以设置过半存活就可以避免脑裂,但是不能完美解决,大概是原主成为的slave的时候会丢失数据
分片集群
特点
- Cluster模式集群节点最小配置6个节点(3主3从,因为需要半数以上),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。
- 槽位分散
- 扩容和删除的槽位手动分配
- pinpong的请求包括所有节点的健康状态(是否下线),槽位分配的状态
- 节点下线的时候广播,主从切换,这里是raft,但是总的来看集群中没有中心节点,非raft算法
集群操作详细说明
-
Redis集群的槽位迁移:实际上每个key依次用MIGRATE命令转移数据,是同步的,但是一般key的空间不大,主线程依然可以接受其他请求(但与迁移槽相关的请求可能需要额外处理逻辑,引发额外的重定向或转发),所以不会影响正常的运行
-
Redis集群中出现节点下线:当A在指定时间内未收到B的pong,会将B认为疑似下线,当超过半数的持有 Slot(槽)的主节点都将某个主节点 X 报告为疑似下线,那么,主节点 X 将被标记为下线(Fail),并广播出去,所有收到这条 Fail 消息的节点都会立即将主节点 X 标记为 Fail,接下来就需要主节点X的从节点来选举成为新的主节点,若没有从节点,集群的部分数据会出现不可用的状态
-
Redis集群中节点扩容和删除:删除时,需要释放槽位到其他节点再下线,扩容时,先开启节点,再手动进行槽位的分配,并通过槽位迁移实现扩容
Tendis的改进
Tendis架构:存储层使用RocksDB(gossip最终一致性),缓存层redis分片集群,通过RDB和AOF实现两个层的同步,中间用多个Queue保证同一个slot的操作落在同一个Queue中,保持时序一致,即同步层,并且使用rcoksDB,天然支持aof这种增量写的日志处理
和mysql的优点:
1. 缓存一致性无需保证,Tendis是同步层用aof持续持久化到存储层,并定期检查aof的指针位置
2. 部分内存数据可以落盘,避免内存占用,传统的redis为了RDB的子进程fork,需要预留一半的内存用于copyonright
3. 冷热数据的处理,有智能淘汰(只淘汰内存)和加载策略(避免一次scan加载所有数据,而是一段时间内访问多的)
解决的Redis本身的问题:
1. 主从同步,传统的当缓冲区的指针越界时,会发送全量RDB,引入Version机制,Master 将大于等于 Version 的数据生成增量 RDB。并且version可以保证AOF的幂等性,避免网络抖动,拉取到同样的aof(特指的是同步层,redis的主从根据指针来的,应该不会有幂等的问题)
2. 扩容缩容不再用传统的migrating 和importing ,基于Key,一次穿一个或者多个key,多次IO,且大key会阻塞主线程。故Tendis使用RDB+Aof的机制扩缩容,类似于主从同步,但是是源节点生成指定 slot 数据的一致性快照全量数据(RDB)
相关文章
https://blog.csdn.net/qq_34556414/article/details/106105820 主从同步总结
https://zhuanlan.zhihu.com/p/151740247 复制,主从同步机制详细
https://blog.csdn.net/weixin_45433817/article/details/137209295 脑裂问题
https://cloud.tencent.com/developer/article/1831202 Tendis理解