您当前的位置:首页 > 电脑百科 > 数据库 > Redis

面试问Redis集群,被虐的不行了

时间:2020-06-17 14:10:41  来源:  作者:

【51CTO.com原创稿件】 上一篇我们讲解了 redis 哨兵的工作原理,哨兵主要针对单节点故障无法自动恢复的解决方案,集群主要针对单节点容量、并发问题、线性可扩展性的解决方案。

面试问Redis集群,被虐的不行了......

图片来自 Pexels

本篇我将讲解 Redis 集群的工作原理,文末有你们想要的设置 SSH 背景哦!

本文主要围绕如下几个方面介绍集群:

  • 集群简介
  • 集群作用
  • 配置集群
  • 手动、自动故障转移
  • 故障转移原理

本文实现环境:

  • centos 7.3
  • Redis 4.0
  • Redis 工作目录 /usr/local/redis
  • 所有操作均虚拟机模拟进行

集群简介

集群是为了解决主从复制中单机内存上限和并发问题,假如你现在的云服务内存为 256GB,当达到这个内存时 Redis 就没办法再提供服务。

同时数据量能达到这个地步写数据量也会很大,容易造成缓冲区溢出,造成从节点无限的进行全量复制导致主从无法正常工作。

面试问Redis集群,被虐的不行了......

 

那么我们就需要把单机的主从改为多对多的方式,并且所有的主节点都会连接在一起互相通信。

这样的方式既可以分担单机内存,也可以分发请求,提高系统的可用性。

如下图:当有大量请求写入时,不再会单一的向一个主节点发送指令,而会把指令进行分流到各个主节点,达到分担内存、避免大量请求的作用。

面试问Redis集群,被虐的不行了......

 

那么指令是如何进行分流存储的呢?我们就需要到集群存储结构中一探究竟。

集群作用

集群的作用有如下几个:

  • 分散单机的存储能力,同时也可以很方便的实现扩展。
  • 分流单机的访问请求。
  • 提高系统的可用性。

如何理解提高系统的可用性这句话,我们看下图,当 master1 宕机后对系统的影响不会那么大,仍然可以提供正常的服务。

面试问Redis集群,被虐的不行了......

 

这个时候就会有人问了,当 master1 宕机后,集群这个时候怎么工作呀?这个问题会在下文的故障转移来给你解答,并且在原理篇会对这个问题进行详解。

集群存储结构

存储结构

单机的存储是当用户发起请求后直接把 key 存储到自己的内存即可。

面试问Redis集群,被虐的不行了......

 

集群的存储结构就没有那么简单了,首先当用户发起一个 key 指令后需要做的事情如下:

  • 通过 CRC16(key) 会计算出来一个值。
  • 用这个值取模 16384,会得到一个值,我们就先认为是 28。
  • 这个值 28 就是 key 保存的空间位置。

那么现在问题来了,这个 key 到底应该存储在哪个 Redis 存储空间里边呢?

面试问Redis集群,被虐的不行了......

 

其实 Redis 在集群启动后就已经把存储空间划分了 16384 份,每台主机保存一部分。

这里需要注意的是我给每个 Redis 存储空间里边的编号就相当于一个小的存储空间(专业术语“哈希槽”)。

你可以理解为一栋楼里边的编号,一栋楼就是 Redis 的整个存储空间,每个房子的编号就相当于一个存储空间,这个存储空间会有一定的区域来保存对应的 key,并非上图取模后的位置。

箭头指向的 28 是指的 28 会存储在这个区域里,这个房子有可能会存储 29、30、31 等。

面试问Redis集群,被虐的不行了......

 

此时问题来了,如果新增、减少一台机器后怎么办呢?看图说话,能用图说明尽量不去用文字。

在新增一台机器后,会从其他三个存储空间中拿出一定的槽分配给新的机器。这里可以自己设置想给新的机器放多少个槽。

同样减少一台机器后会把去掉的槽在重新分配给其它现有的机器跟新增节点一样,可以指定节点接收槽。

所谓的增节点或去节点就是改变槽所存储的位置不同。

面试问Redis集群,被虐的不行了......

 

了解了集群的存储结构后,我们就需要在对另一个问题进行说明了,集群是如何设计内部通讯呢?

来了一个值,获取一个 key,去哪拿数据?跟着这个问题我们看下文。

通讯设计

集群中的每个节点会在一定的时期给其它节点发送 ping 消息,其他节点返回 pong 作为响应。

经过一段时间后所有节点都会知道集群全部节点的槽信息。如下图有三个节点,那么就会把 16384 个哈希槽分成三份。

分别为:

  • 0-5500
  • 5501-11000
  • 11001-16384
面试问Redis集群,被虐的不行了......

 

当用户发起了一个 key 的请求,集群是如何处理请求的呢?上图的黑框代表这集群所有节点的槽信息,里边还有很多其它信息。

如图所示,用户发起请求 key,Redis 接收后计算 key 的槽位置,在根据槽位置找出对应的节点。

如果访问的槽就在节点本身,那么就会直接返回 key 对应数据。否则会回复 moved 重定向错误,并且给客户端返回正确的节点。

然后重发 key 指令,如下图:

面试问Redis集群,被虐的不行了......

 

配置集群

①修改配置文件

如下图:

面试问Redis集群,被虐的不行了......

 

只需要注意圈中的配置信息即可:

  • cluster-enabled yes:开启集群模式。
  • cluster-config-file nodes-6379.conf:集群配置文件。
  • clustre-node-timeout 10000:节点超时时间,这里为了方便测试设置为 10s。
面试问Redis集群,被虐的不行了......

 

②构建 6 个节点的配置文件并全启动

给大家提供一个命令可以很方便的替换文件:

sed 's/6379/6380/g' 6379-redis.conf > 6380-redis.conf 

按照这样的方式创建出来 6 个不同端口的配置文件:

面试问Redis集群,被虐的不行了......

 

随便打开一个配置文件查看,检测是否替换成功:

面试问Redis集群,被虐的不行了......

 

为了查看日志信息方便,全部使用前台启动。并且查看服务是否都正常启动,执行命令:

ps -ef | grep redis 

可以看到启动后多了个 cluster 标识,代表着都是集群的一个节点。

面试问Redis集群,被虐的不行了......

 

所有节点启动完成,集群启动的指令需要基于 Ruby(本人使用 Redis 版本为 4.0),接下来一起安装。

③安装 Ruby

执行命令:

wget https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.1.tar.gz 

解压(根据自己下载的版本来解压):

tar -xvzf ruby-2.7.1.tar.gz 

安装:

./configure | make | make install 

这三个指令一气呵成,查看 ruby 和 gem 版本:ruby -v。

面试问Redis集群,被虐的不行了......

 

④启动集群

集群的执行命令在 /usr/local/redis/src/redis-trib.rb,注意如果需要直接使用 redis-trib.rb 命令,需要 ln 到 bin 目录下,否则就必须使用 ./redis-trib.rb 的方式。

如果按照步骤走,这里会出现一个错误,如下图:

面试问Redis集群,被虐的不行了......

 

执行 gem install redis,很不幸的是在这里也会出现错误:

面试问Redis集群,被虐的不行了......

 

随后需要安装 yum install zlib-devel 和 yum install openssl-devel。

安装完成后,在 /ruby-2.7.1/ext/openssl 和 /ruby-2.7.1/ext/zlib 分别执行 ruby extconf.rb,并且执行 make | make install。

然后再执行 gem install redis 就 OK:

面试问Redis集群,被虐的不行了......

 

这时再回头来执行:

./redis-trib.rb create --replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 
面试问Redis集群,被虐的不行了......

 

信息解读:创建集群,并且给 6 个节点分配哈希槽,后三个节点配置为前三个节点的从节点。

面试问Redis集群,被虐的不行了......

 

显示每个节点的哈希槽信息和节点 ID,最后一步需要输入 yes:

面试问Redis集群,被虐的不行了......

 

来到 data 目录下查看配置文件的变化。配置文件主要信息是每个主节点分的槽:

面试问Redis集群,被虐的不行了......

 


面试问Redis集群,被虐的不行了......

 

查看主机点的运行日志:这里给的主要信息 cluster status changed:ok 集群状态正常。

面试问Redis集群,被虐的不行了......

 

⑤集群设置与获取数据

当直接设置数据会报错,并且把 name 这个 key 进行转化后的槽位置为 5798 并且给出了 ip 地址和端口号。

面试问Redis集群,被虐的不行了......

 

需要使用命令 redis-cli -c,在进行设置值的时候提示说重定向到 5798 的这个槽。

面试问Redis集群,被虐的不行了......

 

接下来进行获取数据,会自动的切换节点:

面试问Redis集群,被虐的不行了......

 

故障转移

①集群从节点下线

根据上文集群启动信息知道端口 6383 是 6379 的从节点。接下来就是让 6383 下线查看 6379 的日志信息。

6379 会报出连接 6383 丢失,并且给上标记 fail,表示不可用。这个时候集群还是正常工作的。

总结:从节点下线对集群没有影响。

面试问Redis集群,被虐的不行了......

 

当端口 6383 上线后,所有的节点会把 fail 的标记清除,如下图:

面试问Redis集群,被虐的不行了......

 

②集群主节点下线

手动下线主节点 6379,查看从节点 6383 日志信息,此时的 6383 节点会持续连接 6379 共计 10 次,那为什么是 10 次呢?

是根据我们配置的参数 cluster-node-timeout 10 来决定的,这里给我们一个信息就是一秒连接一次。

直到时间到期后,开始故障转移。这时 6383 在故障转移选举中胜任,翻身奴隶把歌唱,成为了主节点。

面试问Redis集群,被虐的不行了......

 

此时在查看一下集群的节点信息,命令 cluster nodes。会发现这里竟然存在四个主节点,但是其中一个主节点时下线状态:

面试问Redis集群,被虐的不行了......

 

6379 原主节点上线:6379 上线后,同样所有的节点也会清除 fail 信息。并且节点信息也会改变,此时的 6379 改变为 6383 的从节点。

面试问Redis集群,被虐的不行了......

 

③新增主节点

再新增俩个端口 6385 和 6386:

面试问Redis集群,被虐的不行了......

 

执行新增命令 ./redis-trib.rb add-node 127.0.0.1:6385 127.0.0.1:6379,这里发送的就是 meet 消息。

执行 add-node 命令,第一个参数为新节点的 ip+端口,第二个参数为已存在集群中的节点。根据下图我们就可以看到新增的节点已经存在集群中了。

注意:虽说 6385 已经成为集群中的节点了,但是跟其它节点有区别。它没有数据,也就是没有哈希槽。

面试问Redis集群,被虐的不行了......

 

接下来我们就需要把集群中的某些哈希槽分配到这个新节点上,分配结束后这个节点才会成为真正意义上的主节点。

执行命令 ./redis-trib.rb reshard 127.0.0.1:6385,会提示转移多少个哈希槽并填写接收节点的 id。

最后一步询问是否从所有节点中转移:我使用的是 all。使用指令:cluster nodes 查看,6385 的这个节点就已经拥有三个范围的哈希槽了。

面试问Redis集群,被虐的不行了......

 

主节点已经新增好了,接下来就需要给 6385 这个主节点配置一个从节点 6386,命令如下:

./redis-trib.rb add-node --slave --master-id dcc0ec4d0c932ac5c35ae76af4f9c5d27a422d9f 127.0.0.1:6386 127.0.0.1:6385

master-id 是 6385 的 id,第一个参数为新节点的 ip+端口,第二个为指定的主节点 ip+端口。

面试问Redis集群,被虐的不行了......

 

④手动故障迁移

当想对集群中的主节点进行升级的话可以手动执行故障转移到从节点,避免集群可用性受影响。

在从节点执行命令:cluster failover。

执行过程:查看节点信息就可以看到 6386 这个节点已经成为了主机点。

当给从节点发送 cluster failover 指令后,从节点会给主节点发送 CLUSTERMSG_TYPE_MFSTART 包。从节点请求主节点停止访问,从而对比两者的数据偏移量达到一致。

这时客户端不会连接我们淘汰的主节点,同时主节点向从节点发送复制偏移量,从节点得到复制偏移量后故障转移开始,接着通知主节点进行配置切换。

当客户端在旧的 master 上解锁后,重新连接到新的主节点上。

面试问Redis集群,被虐的不行了......

 

故障转移原理篇

上文中我们测试了故障转移,主节点下线后从节点变为主节点,接下来剖析这个过程。

①故障发现到确认

集群中的每个节点会定期的给其它节点发送 ping 消息,接收方用 pong 作为回复。

如果在 cluster-node-timeout 的时间内 ping 消息一直失败,则会把接收方的节点标记为 pfail 状态也就是主观下线。

这个下线状态是不是很熟悉?没错,这个跟哨兵判断主节点是否异常有点相似。

当一个哨兵发现主节点有问题时也会标记主节点客观下线(s_down)。突然发现跑题了,尴尬......

面试问Redis集群,被虐的不行了......

 

再提一下哨兵,当一个哨兵认为主节点异常后标记主观下线,但是其他哨兵怎么能会同意,不能你说什么就是什么。

都会去尝试连接异常的主节点,当半数以上的哨兵都认为主节点异常后会直接让其主节点客观下线。

同样集群也不会因为一个节点判断其状态为下线就行的,节点直接通过 Gossip 消息传播,集群中节点会不断收集故障节点的下线反馈并且存储到本地的故障节点下线报告中。

当有半数以上的集群主节点都标记为主观下线后改变状态为客观下线。最后向集群广播一条 fail 消息,通知所有节点将故障节点标记为客观下线。

例如:节点 A 发送 ping 到节点 B 通信异常后标记节点 B 为 pfail,之后节点 A 会继续给节点 C 发送 ping,并且携带节点 B 的 pfail 信息,然后节点 C 将节点 B 的故障保存到下线报告中。

当下线报告数量大于有哈希槽主节点的一半数量以上后就会尝试客观下线。

②故障恢复(从节点从此翻身奴隶把歌唱)

当故障节点被定义为客观下线后,故障节点的所有从节点承担故障恢复的责任。

故障恢复是从节点通过定时任务发现自己的主机点客观下线后就会执行故障恢复流程。

资格检查:所有的从节点都会进行检查与主节点最后的连接时间,断线时间大于 cluster-node-time*cluster-slave-validity-factor 时不具备故障转移的资格。

准备选举时间:先说说为什么这里会有一个准备选举时间。资格检查过后存在多个从节点,那么就需要使用不同的延迟选举时间来支持优先级。

这里的优先级就是以复制偏移量为基准,偏移量越大与故障主节点的延迟越小,那么就更有机会拥有替换主节点的机会。主要的作用就是确保数据一致性最好的节点优先发起选举。

选举投票:Redis 集群的投票机制没有采用从节点进行领导选举,这点切记不要跟哨兵搞混了。集群的投票机制都是持有槽的主机点进行投票的。

故障节点的从节点会广播一个 FAILOVER_AUTH_REQUEST 数据包给所有的持有槽的主节点请求投票。

当主节点回复 FAILOVER_AUTH_ACK 投票后在 NODE_TIMEOUT * 2 的这段时间不能给其他的从节点投票。从节点获取到半数以上的投票后就会进行故障恢复阶段。

故障转移:选举成功的从节点取消复制变为主节点,删除故障节点的槽,并且将故障节点的槽委托到自己身上,向集群广播自己的 pong 消息,通知主机点的改变和接管了故障节点的槽信息。

福利:你们想要的 SSH 的背景

上一篇利用两个夜晚才弄完的 Redis 哨兵文章,结果你们的关注点却不在文章本身,啊!小编心很痛......

为了满足大家的要求,我忍痛说一下如何设置亮瞎的背景,我使用的工具是xsheel。

面试问Redis集群,被虐的不行了......

 

打开工具选择选项 :

面试问Redis集群,被虐的不行了......

 

接着到查看有个窗口透明就可以设置 xsheel 透明了。

面试问Redis集群,被虐的不行了......

 

对喽!你想的没错,这就是桌面背景,是不是准备开始设置去了?最后,欢迎各路大神给予技术点补充和辨错。

作者:咔咔

简介:从业三年,从搬砖一样的生活方式换成了现在有“单”而居的日子。当然这个单不是单身的单!虽然极尽苛刻的技术学习但也远不及客户千奇百怪的要求。进入了朝九晚六,虽然躲过了风吹日晒,但是仍然很享受那些熬得只剩下黑眼圈的日子。坚持学习、坚持写博、坚持分享是咔咔从业以来一直所秉持的信念。希望在诺大互联网中咔咔的文章能带给你一丝丝帮助。

编辑:陶家龙

【51CTO原创稿件,合作站点转载请注明原文作者和出处为51CTO.com】



Tags:Redis集群   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
本文主要针对 Redis 常见的几种使用方式及其优缺点展开分析。一、常见使用方式Redis 的几种常见使用方式包括: Redis 单副本 Redis 多副本(主从) Redis Sentinel(哨兵) Redis...【详细内容】
2021-03-19  Tags: Redis集群  点击:(202)  评论:(0)  加入收藏
Redis集群详解Redis有三种集群模式,分别是:* 主从模式 * Sentinel模式 * Cluster模式三种集群模式各有特点,关于Redis介绍可以参考这里:NoSQL(二)——RedisRedis官网:ht...【详细内容】
2020-10-17  Tags: Redis集群  点击:(127)  评论:(0)  加入收藏
./redis-trib.rb create --replicas 1 172.20.10.8:7001 172.20.10.8:7002 172.20.10.8:7003 172.20.10.8:7004 172.20.10.8:7005 172.20.10.8:70061.安装ruby环境redis集群...【详细内容】
2020-08-11  Tags: Redis集群  点击:(75)  评论:(0)  加入收藏
这里的Redis集群指的是Redis Cluster,它是Redis在3.0版本正式推出的专用集群方案,有效地解决了Redis分布式方面的需求。当单机内存、并发、流量等遇到瓶颈的时候,可以采用这种...【详细内容】
2020-07-16  Tags: Redis集群  点击:(62)  评论:(0)  加入收藏
【51CTO.com原创稿件】 上一篇我们讲解了 Redis 哨兵的工作原理,哨兵主要针对单节点故障无法自动恢复的解决方案,集群主要针对单节点容量、并发问题、线性可扩展性的解决方案...【详细内容】
2020-06-17  Tags: Redis集群  点击:(55)  评论:(0)  加入收藏
redis集群简述哨兵模式中如果主从中 master宕机了,是通过哨兵来选举出新的master,在这个选举切换主从的过程,整个redis服务是不可用的。而且哨兵模式中只有一个主节点对外提供...【详细内容】
2020-03-18  Tags: Redis集群  点击:(67)  评论:(0)  加入收藏
参考 《Redis并发与运维》串行命令由于n个key是比较均匀的分布在Redis Cluster的各个节点上,因此无法使用mget命令一次性获取,所以通常来讲要获取n个key的值,最简单的方法就是...【详细内容】
2020-01-13  Tags: Redis集群  点击:(266)  评论:(0)  加入收藏
前面我们介绍了国人自己开发的Redis集群方案——Codis,Codis友好的管理界面以及强大的自动平衡槽位的功能深受广大开发者的喜爱。今天我们一起来聊一聊Redis作者自...【详细内容】
2019-09-23  Tags: Redis集群  点击:(126)  评论:(0)  加入收藏
▌简易百科推荐
来源: my.oschina.net/xiaomu0082/blog/2990388首先说下问题现象:内网sandbox环境API持续1周出现应用卡死,所有api无响应现象刚开始当测试抱怨环境响应慢的时候 ,我们重启一下应...【详细内容】
2021-12-08  Java识堂    Tags:Redis   点击:(18)  评论:(0)  加入收藏
我不知道为什么你会选择对特定数量的“错误”(或警告)如此具体。听起来您正在寻找将要发布到 Yahoo! 的某些文章的内容。 Insider (N Foos to Blah for the BlahBlah)。那说:...【详细内容】
2021-12-07  富集云科技有限公司    Tags:Redis   点击:(14)  评论:(0)  加入收藏
目录 一、背景 二、步骤 0.理论支持 1、获取数据 2、结果 3、分析数据并评估大小 三、关于repl-backlog-size 一、背景 repl-backlog-size控制这个环形缓冲区. ​ 主从断...【详细内容】
2021-11-05  弈秋的美好生活    Tags:redis   点击:(41)  评论:(0)  加入收藏
Redis 性能测试是通过同时执行多个命令实现的。1,Redis-benchmarkRedis性能命令:redis性能命令格式: redis-benchmark [option] [option value] redis 性能测试工具可选参数如...【详细内容】
2021-11-02  川石信息    Tags:Redis   点击:(41)  评论:(0)  加入收藏
1 概述数据结构和内部编码 无传统关系型数据库的 Table 模型schema 所对应的db仅以编号区分。同一 db 内,key 作为顶层模型,它的值是扁平化的。即 db 就是key的命名空间。 key...【详细内容】
2021-11-01  JavaEdge    Tags:Redis   点击:(28)  评论:(0)  加入收藏
普通java中使用引用Java redis 驱动,即可连接:import redis.clients.jedis.Jedis; public class RedisTestJava { public static void main(String[] args) { //连...【详细内容】
2021-10-13  faesuite    Tags:Redis   点击:(34)  评论:(0)  加入收藏
Redis常用的数据结构有 string list set zset hashstringstring 是 Redis 的基本的数据类型,一个 key 对应一个 value。string 类型是二进制安全的,Redis的string可以包含任...【详细内容】
2021-10-12  语霖    Tags:Redis   点击:(36)  评论:(0)  加入收藏
列表类型可以存储一组按插入顺序排序的字符串,它非常灵活,支持在两端插入、弹出数据,可以充当栈和队列的角色。> LPUSH fruit apple(integer) 1> RPUSH fruit banana(integer)...【详细内容】
2021-09-17  深夜敲代码    Tags:Redis   点击:(54)  评论:(0)  加入收藏
Redis持久化意义 是做灾难恢复,数据恢复,也可以归类到高可用的一个环节里面去,比如你的redis整个挂了,然后redis就不可用了,你要做的事情是让redis变得可用,尽快变得可用 大量的请...【详细内容】
2021-08-12  小李说IT    Tags:Redis   点击:(77)  评论:(0)  加入收藏
当查询Redis中没有的数据时,该查询会下沉到数据库层,同时数据库层也没有该数据,当这种情况大量出现或被恶意攻击时,接口的访问全部透过Redis访问数据库,而数据库中也没有这些数据...【详细内容】
2021-07-30  随便t    Tags:缓存穿透   点击:(91)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条