本文主要是介绍【退役之重学Java】Redis 高并发与高可用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Redis 单机承载的并发量,一般来说不超过10 万
一、Redis 如何支撑超过 10万的并发
读写分离,主从复制,分布式
Redis master 负责写操作,并同步数据到其他 Redis
Redis slave 负责读操作,增加 Redis slaver 的数量,就可以增加读的并发承受能力
二、Redis replication 核心机制
- Redis 采用异步方式复制数据到 slave 节点,不过 Redis 2.0 开始,slave node 会周期性地确认自己每次复制的数据量
- 一个 master node 可以配置多个 slave node
- slave node 可以连接其他 slave node
- slave node 做复制的时候,不会阻塞 master node 工作
- slave node 做复制的时候,不会阻塞对自己的查询操作,会用旧的数据集提供服务;但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务
- slave node 主要用来进行横向扩容,做读写分离,扩容的slave node 可以提高读的吞吐量
三、master 持久化对于主从架构安全保障的意义
- 如果采用了主从架构,就必须要开启 master node 的持久化!
- 不建议用 slave node 作为 master node 的数据热备份,因为那样的话,如果关掉 master 的持久化,可能在 master 宕机重启时数据是空的,master 认为自己的数据时空的,然后可能经过复制,slave node 数据也丢失了
- master node 必须要使用持久化机制
- master node 采取备份方案
- 即使采用了后续讲解的高可用机制,slave node 可以自动接管 master node,但是也可能 sentinal 还没有检测到 master failure,master node 就自动重启了,还是可能导致上面的所有 slave node 数据清空故障
四、Redis 主从复制的原理
- 当启动一个 slave node 的时候,他会发送一个 PSYNC 命令给 master node
- 如果这是slave node 重新连接 master node,那么 master node 仅仅会复制缺少的数据;否则,如果slave是第一次连接 master node,那么会触发一次 full resynchronization
- 开始 full resynchronization 的时候,master 会启动一个后台线程,开始生活充能一份 RDB 快照文件,同时还会将从客户端收到的所有写命令缓存在内存中,RDB 文件生成完毕之后,master 会将这个RDB 发送给slave,slave 会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后master 会将内存中缓存的写命令发送给 slave,slave 也会同步这些数据。
- slave node 如果跟master node 有网络故障,会自动重连。master 如果发现有多个 slave node 都来重连,仅仅会启动一个 rdb save 操作,用一份数据服务所有 slave node
五、主从复制的断点续传
- 从 Redis 2.8 开始,就支持只从复制的断点续传。如果网络连接断掉了,再次连接的时候,可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份
- master node 会在内存中常建一个 backlog,master 和 slave 都会保存一个 replica offset 开始继续复制
- 三十如果没有找到对应的 offset,就会执行一次 resynchronization
六、无磁盘化复制
- master 在内存中直接创建 rdb,然后发送给 slave,不会在自己本地落地磁盘
- repl-diskless-sync
- repl-diskless-delay,等待一段时间再开始复制,因为要等更多 slave 重新连接过来
七、过期 key 处理
slave 不会过期 key,只会等待master 过期 key, 如果 master 过期了一个 key,或者通过 LRU 淘汰了一个 key,就会模拟一条 del 命令发送给 slave
八、完整的复制流程
- slave node 启动,仅仅保存master node 的信息,包括 master node 的 host 和 ip,但是复制流程还没开始
master host 和 ip,在 redis.conf 里的 slaveof 配置的 - slave node 内部邮费定时任务,每秒检查是否有新的 master node 要连接和复制,如果发现,就跟master node 建立 socket网络连接
- slave node 发送 ping 命令给 master node
- 口令认证,如果 master 设置了 requirepass ,那么slave node 必须发送 masterauth 的口令过去认证
- master node 第一次执行全量复制,将所有数据发给slave node
- master node 后续将持续写命令,异步复制给 slave node
九、数据同步的核心机制
- master 和 slave 都会维护一个 offset
- master 会在自身不断累加 offset,slave 也会在自身不断累加 offset
- slave 每秒都会上报自己的 offset 给 master,同时 master 也会保存每个 slave 的 offset
- master 和 slave 都要知道各自的 offset,才能知道互相之间数据不一致的情况
- backlog
- master node 有一个 backlog, 默认是 1MB 大小
- master node 给 slave node复制数据时,也会将数据在 backlog 中同步一份
- backlog 主要是用来做全量复制中断时候的增量复制的
- master run id
- info server,可以看到 master run id
- 如果根据 host + ip 定位 master node,是不靠谱的,如果master node 重启或者数据出现了变化,那么 slave node 应该根据不同的 run id 区分,run id 不同就做全量复制
- 如果需要不更改 run id 重启 redis, 可以使用redis-cli debug reload 命令
- psync
- 从节点使用 psync 从 master node 进行复制,psync runid offset
- master node 会根据自身的情况返回相应信息,可能是 FULLRESYNC runid offset 出发全量复制,可能是CONTINUE出发增量复制
十、99.99% 高可用
如果系统能够保证在全年 99.99% 的时间,都是处于可用的状态,那么就可以称之为高可用。
十一、Redis 高可用架构
- 主备切换。在 master node 故障时,自动检测(sentinel node哨兵),并且将某个 slave node 自动切换为 master node 的过程,叫做主备切换。
- 此过程实现了 Redis 主从架构下的高可用性
哨兵
一、介绍
- sentinel,哨兵。是 Redis 集群架构中非常重要的一个组件,主要功能如下
- 集群监控,负责监控 Redis master 和 slave 进程是否正常工作
- 消息通知,如果某个 Redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员
- 故障转移,如果 master node 挂掉了,会自动转移到 slave node 上
- 配置中心,如果故障转移发生了,通知client 客户端新的 master 地址
- 哨兵本身也是分布式的,作为一个哨兵集群去运行,互相协同工作
- 故障转移时,判断一个master node 是宕机了,需要大部分的哨兵同意才行,涉及到了分布式选举的问题
- 即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果作为一个高可用机制重要组成部分的故障转移系统本身是单点的,那就很坑爹了。
- 目前采用的是 sentinel 2 版本,sentinel 2 相对与 sentinel 1 ,重写了很多代码,主要是让故障转移的机制和算法变得更加健壮和简单。
二、核心知识
- 哨兵至少需要三个实例,来保证自己的健壮性
- 哨兵 + Redis 主从的部署架构,是不会保证数据零丢失的,只能保证 Redis 集群的高可用
- 对于哨兵 + Redis 主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练
三、为什么 Redis 哨兵集群只有两个节点,无法正常工作
- 哨兵集群必须部署两个以上的节点
- 如果哨兵集群仅仅部署了两个哨兵实例,quorum=1
- master 宕机,只要有一个哨兵认为 master 宕机可以切换,就会从两个哨兵中选举出一个哨兵来执行故障转移
- 同时,需要 majority,也就是大多数哨兵都是运行的,两个哨兵的 majority 就是2,两个哨兵都运行着,就可以允许执行故障转移
- 但是如果整个master 节点机器挂掉了,那么哨兵就只有1个了,此时就没有 majority 来允许执行故障转移,虽然另一台机器还有一个,但故障转移不会执行
四、经典的3节点哨兵集群
- quorum=2,majority=2
- 如果master 节点机器挂掉了,那么哨兵还剩下2个,s2 和s3 可以一致认为 master 宕机了,然后选举出一个来执行故障转移
- 同时3个哨兵的majority是2,所以还剩下的2个哨兵,可以允许执行故障转移
五、两种数据丢失的情况
- 异步复制导致的数据丢失
因为 master->slave 的复制是异步的,所以可能有部分数据还没有复制到 slave,master 就宕机了,此时这些部分数据就丢失了 - 脑裂导致的数据丢失
脑裂,就是说,某个 master所在的机器突然脱离了正常网络,跟其他slave 机器失去连接,但是实际上master 还运行着,此时哨兵可能认为 master 宕机了,然后开始选举,将其他 slave 切换成了master,这个时候集群里就有两个master,这就是所谓的脑裂。
此时虽然某个slave 被切换成了master,但是可能 client 还没来得及切换到新的 master,还继续 写向旧的 master 的数据可能会丢失。因为旧 master 再次恢复时,会被作为一个 slave 挂到新的 master 上去,自己的数据会清空,重新从新的master 复制数据
六、解决异步复制和脑裂导致的数据丢失
min-slaves-to-write 1
min-slaves-max-lag 10
要求至少有一个 slave,数据复制和同步的延迟不能超过10秒
如果说一旦所有的 slave,数据复制和同步的延迟都超过了10秒,那么这个时候,master就不会再接收任何请求了
上面两个配置可以减少异步复制和脑裂导致的数据丢失
- 减少异步复制的数据丢失
有了 min-slaves-max-lag 这个配置,可以确保说,一旦 slave 复制数据和 ack 延时太长,就认为可能master 宕机后损失的数据太多了,那么就拒绝写请求,这样就可以把 master 宕机时由于部分数据未同步到 slave 导致的数据丢失的可控范围内 - 减少脑裂的数据丢失
如果一个master 出现了脑裂,跟其他slave 丢失了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的 slave 发送数据,而且slave 超过10秒没有给自己 ack 消息,那么就直接拒绝客户端的写请求
这样脑裂后的旧master 就不会接受 client 的新数据,也就避免了数据丢失
上面的配置就确保了,如果跟任何一个 slave 丢失了连接,在10秒后没有 slave 没有给自己ack ,那么就拒绝新的写请求
因此在脑裂场景下,最多就丢失10秒的数据
Redis 哨兵的多个核心原理深入
-
sdown 和 odown 转换机制
- sdown 和 odown 是两种失败状态
- sdown 是主观宕机,就一个哨兵如果自己觉得一个master 宕机了,那么就是主观宕机
- odown 是客观宕机,如果 quorum 数量的哨兵觉得一个master 宕机了,那就是客观宕机
- sdown 达成的条件和简单,如果一个哨兵ping 一个 master ,超过了 is-master-down-after-milliseconds 指定的毫秒数之后,就主观认为 master 宕机
- sdown 到 odown 转换的条件很简单,如果一个哨兵在指定时间内,收到了 quorum 指定数量的其他哨兵也认为那个 master 是 odown 了,那么就认为是 odown,客官认为 master 宕机
-
哨兵和 slave 集群的自动发现机制
- 哨兵之间互相的发现,是通过 Redis 的pub/sub 系统实现的,每个哨兵都会往 sentinel:hello 这个channel 里面发送一条消息,这个时候所有其他哨兵都可以消费到这个消息,并感知到其他的哨兵存在
- 每隔两秒,每个哨兵就会往自己监控的某个 master-slaves 对应的 sentinel:hello channel 里发送一个消息,内容是自己的 host,ip和runid,还有对这个master 的监控配置
- 每个哨兵也回去监听自己的监控的每个 master + slaves 对应的 sentinel:hello channel,然后去感知到同样在监听这个 master + slaves 的其他哨兵的存在
- 每个哨兵还会跟其他哨兵交换对 master 的监控配置,互相进行监控配置的同步
-
slave 配置的自动纠正
- 哨兵会负责自动纠正 slave 的一些配置,比如 slave 如果要成为潜在的 master 候选人,哨兵会确保 slave 在复制现有的 master 的数据
- 如果slave 连接到了一个错误的 master 上,比如故障转移之后,那么哨兵会确保他们连接到正确的 master 上
-
slave --> master 选举算法
如果一个master 被认为 odown了,且 mojority 哨兵都允许了主备切换,那么某个哨兵就会执行主备切换,此时首先要选举出一个 slave 来考虑 slave 的一些信息- 跟 master 断开连接的时长
- slave 优先级
- 复制 offset
- run id
如果一个slave 跟 master 断开连接超过了 down-after-milliseconds 的10倍,外加 master 宕机的时长,那么 slave 就被认为不合适选举为 master (down-after-miliseconds * 10 )+ milliseconds_since_master_is_in_SDOWN_state
接下来会对 slave 进行排序
- 按照 slave 优先级进行排序,slave priority 越低,优先级就越高
- 如果 slave priority 相同,那么看 replica offset ,哪个 slave 复制了越多的数据,offset 越靠后,优先级就越高
- 如果上面两个条件都相同,那么选择一个 run id 比较小的那么 slave
-
quorum 和 majority
- 每次一个哨兵要做主备切换,首先需要quorum 数量的哨兵认为 odown, 然后选举出一个哨兵来做切换,这个哨兵还得得到 majority 哨兵的授权,才能正式执行切换
- 如果 quorum < majority ,比如5 哨兵,majority 就是3,quorum设置为2,那么 3 个哨兵授权就可以执行切换
- 但是如果quorum >= majority,那么必须 quorum 数量的哨兵都授权,比如 5 个哨兵,quorum 是5,那么必须5 哥哨兵都同意授权,才能切换
-
configuration epoch
- 执行切换的那个哨兵,会从要切换到的新master 那里得到一个 configuration epoch,这就是一个 version 号,每次切换的 version 号都必须是唯一的
- 如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待 failover-timeout 事件,然后接替继续执行切换,此时会和从新获取有一个新的 configuration epoch, 作为新的 version 号
-
configuration 传播
- 哨兵完成切换之后,会在自己本地更新生成最新的 master 配置,然后同步给其他的哨兵,就是通过之前收的pub/sub 消息机制
- 这里之前的 version 号就很重要了,因为各种消息都是通过一个channel 去发布和监听的,所以一个哨兵完成一次新的切换之后,新的 master 配置是根河新的 version号 的
- 其他的哨兵都是根据版本号的大小来更新自己的 master 配置的
此系列博客,为学习笔记,不做其他用途,如有侵权,请联系我删除
这篇关于【退役之重学Java】Redis 高并发与高可用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!