当启动一个slave node的时候,它会发送一个PSYNC命令给master node
如果这是slave node重新连接master node,那么master node仅仅会复制给slave部分缺少的数据; 否则如果是slave node第一次连接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。
2、主从复制的断点续传 https://www.jianshu.com/p/532149db7650
从redis 2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份
master node会在内存中常见一个backlog,master和slave都会保存一个replica offset还有一个master id,offset就是保存在backlog中的。如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制
但是如果没有找到对应的offset,那么就会执行一次resynchronization
3、无磁盘化复制
master在内存中直接创建rdb,然后发送给slave,不会在自己本地落地磁盘了
repl-diskless-sync repl-diskless-sync-delay,等待一定时长再开始复制,因为要等更多slave重新连接过来
4、过期key处理
slave不会过期key,只会等待master过期key。如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave。
从之前学习到的知识我们知道,读写分离能提高读的吞吐量,提高高的QPS,但是却不能保证主节点的高可用。sentinal(哨兵)是redis集群中非常重要的组件,能保证集群的高可用。
哨兵作用: 1.集群检测,检查redis master和slave是否正常工作 2.消息通知,当检测到redis实例有故障,可以通过api通知管理员 3.故障转移,当发现master节点挂了,会提拔一个slave当作master。
哨兵本身也是分布式的,作为一个哨兵集群去运行; 一般来说至少需要3个哨兵实例,来保证自身的健壮性; 哨兵不能保证redis数据的0丢失,只能保证redis集群的高可用。
经典的哨兵集群(3个)
+----+
| M1 |
| S1 |
+----+
|
+----+ | +----+
| R2 |----+----| R3 |
| S2 | | S3 |
+----+ +----+
为什么哨兵需要部署两个节点以上? 要进行主从切换要满足下面两个条件 1.Configuration: quorum = 1
当master宕机的时候至少需要quorum个哨兵几点认为master宕机才可以进行主从切换
2.majority 需要majority,也就是大多数哨兵都是运行的,2个哨兵的majority就是2(2的majority=2,3的majority=2,5的majority=3,4的majority=2),2个哨兵都运行着,就可以允许执行故障转移
slave->master选举算法
https://www.cnblogs.com/codecheng99/p/12383589.html#slave-master-%E9%80%89%E4%B8%BE%E7%AE%97%E6%B3%95 如果一个master被认为odown了,而且majority哨兵都允许了主备切换,那么某个哨兵就会执行主备切换操作,此时首先要选举一个slave来
会考虑slave的一些信息
(1)跟master断开连接的时长 (2)slave优先级 (3)复制offset (4)run id
如果一个slave跟master断开连接已经超过了down-after-milliseconds的10倍,外加master宕机的时长,那么slave就被认为不适合选举为master
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
接下来会对slave进行排序
(1)按照slave优先级进行排序,slave priority越低,优先级就越高 (2)如果slave priority相同,那么看replica offset,哪个slave复制了越多的数据,offset越靠后,优先级就越高 (3)如果上面两个条件都相同,那么选择一个run id比较小的那个slave
数据丢失两种情况
(1)异步复制导致的数据丢失 因为redis 主从复制的异步的,所以当master宕机了,但是数据还没来得及复制到slave节点,哨兵当slave提拔为master这时候数据的丢失了。
(2)脑裂导致的数据丢失
当网络原因或者其他原因,master与slave和哨兵集群连接不上;这个时候哨兵会认为master宕机了,会提拔一个slave当作master,而实际上master没有宕机还在为客户端提供服务,某个slave被切换成了master,但是可能client还没来得及切换到新的master,还继续写向旧master的数据可能也丢失了
因此旧master再次恢复的时候,会被作为一个slave挂到新的master上去,自己的数据会清空,重新从新的master复制数据
解决异步复制和脑裂导致的数据丢失
min-slaves-to-write
min-slaves-max-lag 10
要求至少有1个slave,数据复制和同步的延迟不能超过10秒
如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了
上面两个配置可以减少异步复制和脑裂导致的数据丢失
(1)减少异步复制的数据丢失
有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内
(2)减少脑裂的数据丢失
如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求
这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失
上面的配置就确保了,如果跟任何一个slave丢了连接,在10秒后发现没有slave给自己ack,那么就拒绝新的写请求
因此在脑裂场景下,最多就丢失10秒的数据
读写分离的架构,对于每个master来说,写就写到master,然后读就从mater对应的slave去读,这个时候master能存多少数据就受到master节点物理机的限制,假设master的内存只有64G那么master就只能缓存64G的数据,当超过一定数量,redis会通过淘汰算法来删除即将过期的数据等。
所以这个时候我们就可以需要支持多个master来横向扩展,提高缓存能支撑的数据量。这种方式叫redis cluster
我们只要基于redis cluster去搭建redis集群即可,不需要手工去搭建replication复制+主从架构+读写分离+哨兵集群+高可用
redis cluster vs. replication + sentinal如何选择?
如果你的数据量很少,主要是承载高并发高性能的场景,比如你的缓存一般就几个G,单机足够了
replication,一个mater,多个slave,要几个slave跟你的要求的读吞吐量有关系,然后自己搭建一个sentinal集群,去保证redis主从架构的高可用性,就可以了
redis cluster,主要是针对海量数据+高并发+高可用的场景,海量数据,如果你的数据量很大,那么建议就用redis cluster
当redis要处理海量数据的时候,需要多个master来对redis集群进行扩容,从而支撑海量的数据,而这里主要介绍当多个master的时候数据存储在哪个master中。
hash算法 对存活的master求余数 假设master有3个节点 hash算法只要是指当一个key请求过来的时候,计算key的hash值,并对master的节点数(3个)求余, 从而将key请求到某一个节点。
当一个master宕机的时候,一个key请求过来,同样对key计算hash值,然后对master节点数求余数(2个),这时候发现求出来的余数跟之前对应不上,导致请求的节点没有数据需要到数据库去查询,这种算法只要有一个节点宕机就需要对缓存数据重新分布。
一致性hash算法 环形结构,将节点放在环上(可以搞几个虚拟节点,让其分散得均匀)。 将key计算hash放在环上,顺时针找到对应得节点,,这样如果有一台机器gg,,只是需要移动一小部分数据。。。
hash solt算法 槽slot 16384 redis cluster每个实例分一些slot(可以平分。。具体要自己计算) 将key计算映射到对应得slot中,当一个请求过来,到任意一个redis实例的时候, redis实例发现不是对应自己的slot将会返回 真实的redis实例,,客户端然后在去请求真实的服务器获取数据。
Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做哈希槽 (hash slot)的方式来分配的。redis cluster 默认分配了 16384 个slot,当我们set一个key 时,会用CRC16算法来取模得到所属的slot,然后将这个key 分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384。
gossip https://stor.51cto.com/art/201912/608491.htm
为什么redis是16384个slot? https://blog.csdn.net/fujiandiyi008/article/details/100147553