希望长大对我而言,是可以做更多想做的事,而不是被迫做更多不想做的事...... 首页 Redis读写分离和分布式缓存算法原理 丁D 学无止境 2019-05-29 22:45 2599已阅读 Redis 哨兵 分布式缓存 摘要本文介绍Redis哨兵和分布式缓存的原理。 ###读写分离、主从复制 当启动一个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个) ```js +----+ | 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复制数据 **解决异步复制和脑裂导致的数据丢失** ```js min-slaves-to-write 1 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秒的数据 ###redis主从复制+高可用,横向扩展1T的数据 读写分离的架构,对于每个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数据分布算法 当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 很赞哦! (1) 上一篇:SkyDNS 下一篇:商品详情页架构和Redis安装及持久化 目录 点击排行 Elasticsearch6.3.2之x-pack redis哨兵 2019-07-09 22:05 Redis+Twemproxy+HAProxy+Keepalived 2019-07-12 17:20 GC优化策略和相关实践案例 2019-10-10 10:54 JVM垃圾回收器 2019-10-10 10:23 标签云 Java Spring MVC Mybatis Ansible Elasticsearch Redis Hive Docker Kubernetes RocketMQ Jenkins Nginx 友情链接 郑晓博客 佛布朗斯基 凉风有信 MarkHoo's Blog 冰洛博客 南实博客 Rui | 丁D Java研发工程师 生活可以用「没办法」三个字概括。但别人的没办法是「腿长,没办法」、「长得好看,没办法」、「有才华,没办法」。而你的没办法,是真的没办法。 请作者喝咖啡