单实例有以下几个痛点
- 单点故障
- 容量有限
- 并发
这三个问题引出了, 微服务的 (AKF 原则)[https://baijiahao.baidu.com/s?id=1632326446570197886&wfr=spider&for=pc]
主从
主从和主备的概念是有区别的
- 主从, 一主,N个从, 从负责读取, 主负责读写
- 主备,一主,N个备,备机不负责任务,主要任务是主挂掉以后,备机 代替主来工作
这里为了方便 主暂称【master】备暂称【standby server】 从暂称【slave】代理【proxy】
以下是主从解决方案
从一台redis变成多台,这里就出现数据一致性的问题
解决方案3种
- 强一致性【同步】
客户端等到 mater和slave都写完成功以后, 才返回
缺点: 严重影响性能
- 弱一致性【异步】
master 接受到客户端完成写操作以后, 马上返回, 再同步给slave
缺点:
- master挂了会丢数据
- 数据可能不一致,出现脏读
- 最终一致性【代理】
master 接受到客户端完成写操作以后,同步给proxy,然后返回。由proxy同步给slave
缺点:
- 数据可能不一致,出现脏读
- 代理也存在单点故障
redis 采用的是第二种方案
涉及的主要配置如下:# 追随的masterip 和 端口 replicaof 127.0.0.1 6379 # 主从复制的时候, 是否阻塞其他请求 replica-serve-stale-data yes # slave 只读 replica-read-only yes # 默认不使用diskless同步方式 repl-diskless-sync no # 无磁盘diskless方式在进行数据传递之前会有一个时间的延迟,以便slave端能够进行到待传送的目标队列中,这个时间默认是5秒 repl-diskless-sync-delay 5 # slave端向server端发送pings的时间区间设置,默认为10秒 repl-ping-replica-period 10 # slave和master之间的复制超时时间 # a) slave角度,如果在repl-timeout时间内没有收到master SYNC传输的rdb snapshot数据, # b) slave角度,在repl-timeout没有收到master发送的数据包或者ping。 # c) master角度,在repl-timeout时间没有收到REPCONF ACK确认信息。 repl-timeout 60 # 是否启用TCP_NODELAY,如果启用则会使用少量的TCP包和带宽去进行数据传输到slave端,当然速度会比较慢;如果不启用则传输速度比较快,但是会占用比较多的带宽。 repl-disable-tcp-nodelay no # 设置backlog的大小,backlog是一个缓冲区,在slave端失连时存放要同步到slave的数据,因此当一个slave要重连时,经常是不需要完全同步的,执行局部同步就足够了。backlog设置的越大,slave可以失连的时间就越长。默认是1m,如果同步的数据超过1m,多余的数据就会丢失 repl-backlog-size 1mb # 如果一段时间后没有slave连接到master,则backlog size的内存将会被释放。如果值为0则表示永远不释放这部份内存。 repl-backlog-ttl 3600 # slave端的优先级设置,值是一个整数,数字越小表示优先级越高。当master故障时将会按照优先级来选择slave端进行恢复,如果值设置为0,则表示该slave永远不会被选择。 replica-priority 100 # 设置当一个master端的可用slave少于N个,延迟时间大于M秒时,不接收写操作。这个设置让他无限接近强一致性 min-replicas-to-write 3 min-replicas-max-lag 10
另外在注意一点: slave 最好设置
appendonly no
不然每次重启都会进行全量复制操作
Redis 复制如何处理 key 的过期
- slave 不会让 key 过期,而是等待 master 让 key 过期。当一个 master 让一个 key 到期(或由于 LRU 算法将之驱逐)时,它会合成一个 DEL 命令并传输到所有的 slave。
- 由于这是 master 驱动的 key 过期行为,master 无法及时提供 DEL 命令,所以有时候 slave 的内存中仍然可能存在在逻辑上已经过期的 key 。为了处理这个问题,slave 使用它的逻辑时钟以报告只有在不违反数据集的一致性的读取操作(从主机的新命令到达)中才存在 key。用这种方法,slave 避免报告逻辑过期的 key 仍然存在。在实际应用中,使用 slave 程序进行缩放的 HTML 碎片缓存,将避免返回已经比期望的时间更早的数据项。
- 在Lua脚本执行期间,不执行任何 key 过期操作。当一个Lua脚本运行时,从概念上讲,master 中的时间是被冻结的,这样脚本运行的时候,一个给定的键要么存在要么不存在。这可以防止 key 在脚本中间过期,保证将相同的脚本发送到 slave ,从而在二者的数据集中产生相同的效果。
- 一旦一个 slave 被提升为一个 master ,它将开始独立地过期 key,而不需要任何旧 master 的帮助。
主备
只讨论单一master情况下, 不讨论多master情况
主备方案需要解决这样的问题:
如何判读master是否正常?由于1台以上的standby server,所以由于网络问题出现把master误判成挂掉,这时候就会产生一个新的master,但老的master依然存在。
- 所有standby server都判断master挂掉,该种方案不可取,因为不能保证所有standby server跟master的通信都是不正常的
- 最多一半的数量standby server判断master挂掉, 这种情况下会产生分歧, 出现两个不同的判断。打个比方 9台standby server,4台判断master挂掉(简称集团A),4台判断master正常(简称集团B),集团A中就会选出一台作为新的master,这时候会会出现两个master。。
单一master场景下出现不同的master”这样的场景称为脑裂。
脑裂引起的问题:
1. 连接情况下,旧的客户端依然连接着旧的master, 新的客户端会去连接新的master,这样子数据会出现不一致,(所以这里再启用新的master以后, 应该挂掉旧的master,但还是会引起数据丢的问题, 但至少比数据不一致来的好)
2. 如果在短链接情况下,即使旧的master依然存在,但是所有的客户端会逐渐切换到新的master,这种现象还是脑裂, 但问题更像老的master停止服务,会引起数据丢失
- 超过一半(最少n/2 + 1)standby server判断master挂掉,是最合理的。 即使过半了, 如果在特殊的情况下, 过半投票都是错的, 那么还是有可能存在脑裂情况, 只是一般不存在这样的场景
PS:在考虑成本上问题,slave 还负责 standby server的任务
根据上面可以得出 CAP原则
一致性(C)在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
可用性(A)在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
分区容忍性(P)当出现分区以后,满足 一致性(C),必须停止服务,所以不能满足 可用性(A)。满足 可用性(A), 会同时存在多个分区,那么一致性(C)肯定会被破坏
如果永远是一个分区(隐含条件就是A永远可用), 那么CA是存在的,但这仅仅是理论。实际上P是必然存在的,因为可用性必然是集群,是多台服务器。当这个集群只存在2台服务器的时候, 就无法满足超过一半的条件,就出现脑裂
redis 主备方案(哨兵机制Sentinel):
原理:当主节点出现故障时,由Redis Sentinel自动完成故障发现和转移,并通知应用方,实现高可用性。
其实整个过程只需要一个哨兵节点来完成,首先使用Raft算法(选举算法)实现选举机制,选出一个哨兵节点来完成转移和通知
监控过程:
- 每个哨兵节点每10秒会向主节点和从节点发送info命令。
- 每个哨兵节点每隔2秒会向redis数据节点的指定频道上发送该哨兵节点对于主节点的判断以及当前哨兵节点的信息,同时每个哨兵节点也会订阅该频道,来了解其它哨兵节点的信息及对主节点的判断
- 每隔1秒每个哨兵会向主节点、从节点及其余哨兵节点发送一次ping命令做一次心跳检测,这个也是哨兵用来判断节点是否正常的重要依据
主观下线和客观下线
- 主观下线(Subjectively Down, 简称 SDOWN)指的是单个 Sentinel 实例对服务器做出的下线判断。 一个服务器必须在 master-down-after-milliseconds 毫秒内, 一直返回无效回复才会被 Sentinel 标记为主观下线。
- 客观下线(Objectively Down, 简称 ODOWN)指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断。 (一个 Sentinel 可以通过向另一个 Sentinel 发送 SENTINEL is-master-down-by-addr 命令来询问对方是否认为给定的服务器已下线。)