读书笔记:redis开发与运维 集群篇

 集群: Redis Cluster是Redis分布式解决方案
   主要解决了单机内存、并发(OPS)、流量等瓶颈,采用Cluster架构方案达到负载均衡的目的,比如虽然redis官网说10万/s条命令,但是有些业务需要100万/每秒,机器内存16-256G但是业务需要500G,


   数据分布:
     分布式数据首先要解决把整个数据集按照分区规则映射到多个节点的问题

常见的分区规则有哈希分区和顺序分区两种

    

键值分布业务无关 像用户id;数据分散易倾斜:主要是用户可能存在之前注册的访问多

Redis 集群采用是哈希分区规则,常见的哈希分区有这几种:

     1>节点取余分区    客户端分片:哈希+取余

         使用特定的数据,如Redis的键或用户ID,再根据节点数量N使用公式:hash(key)%N计算出哈希值,用来决定数据映射在哪一个节点,其有点就是简单

         缺点:添加或者移除服务器时,几乎所有缓存都要重建,还要考虑雪崩式崩溃问题

         

          如果使用多倍扩容,可以使得迁移降到50%,这个迁移会存在一个问题,数据进行迁移后第一次是无法从缓存中获取到数据的,要在数据库中去取数据,然后进行回写,写到新的节点,大量的回写也会对系统性能带来问题

     2> 一致性哈希分区(在memcache使用比较广泛) 客户端分片:哈希+顺时针(优化取余)

          为系统中每一个节点分配一个token,范围一般在0-2的32次方,这些token构成一个哈希环。数据读写执行节点查找操作时,先根据key计算hash值,然后顺时针找到第一个大于等于该哈希值的token

  使得服务器的变动只能影响一个很小的范围,但是也没有解决雪崩问题,但是雪崩问题不只是算法能解决的问题了

  好处:在于加入和删除节点只影响哈希中相邻节点,对其他节点无影响,对于节点比较多的情况下,影响范围特别小。

   缺点:

       a>加减节点会造成哈希环中部分数据无法命中,比如添加了n5,将会在n5节点查找数据,但是数据不存在,就会去数据库获取数据,无法实现将n2数据迁移到n5,需要手动处理或者过略这部分数据,因此一致性哈希常用与缓存场景

       b>当使用少量节点,节点变化将大范围影响哈希环中数据映射,因此不适合数据节点的分布式方案

       c>普通的一致性哈希分区在增减节点时需要增加一倍或减去一半节点才能保证数据和负载的均衡,比如添加n5,但是没有改变n3和n4的流量

3>虚拟槽哈希分区: 服务端管理节点、槽、数据 

      虚拟槽分区巧妙使用了哈希空间,使用分散度良好的哈希函数把所有数据映射到一个固定范围的整数集合中,整数定义为槽(slot)。这个范围一般远远大于节点数,槽是集群内数据管理和迁移的基本单位。目的就是为了方便数据拆分和集群扩展。每个节点会负责一定数量的槽 

       键根据哈希函数映射到0-16383整数槽内,计算公式:slot=CRC16(key)&16383.每个节点负责维护一部分槽以及槽所映射的键值数据

       比如当前集群有5个节点,每个节点平均大约负责3276个槽。由于采用高质量的哈希算法,所以每个槽所映射的数据通常比较平均,将数据平均划分到5个节点进行数据分区。(比如redis 集群槽范围0-16383)

      如果算出这个值是100,发送给n1,n1返回数据,如果不在自己槽范围内,redis Cluster之间是一个共享消息模式,所以返回一个结果,让其在其他节点去取数据,不像之前一致性哈希在增加节点存在丢数据的问题,因为每个节点的范围时固定的,在添加节点时,需要节点把槽的范围和数据分配给新的节点

   集群功能限制:

       1)key批量操作和实务操作,只支持具有相同slot值的key执行批量操作。对于映射为不同slot值的key由于执行这些操作可能存在于多个节点因此不被支持

       2)key作为数据节点分区最小粒度,因此不能将一个大的键值对象如hash、list等映射到不同节点,不支持多数据库空间。(单机下redis支持16个),复制结构只能一层,从节点只能复制主节点,不支持嵌套树状复制结构

搭建集群:

   三步:准备节点、节点握手、分配槽

  一般为所有节点统一目录,一般划分三个目录:conf、data、log分别存放配置、数据和日志相关文件

  如果启动时存在集群配置文件,节点会使用配置文件初始化集群信息

集群模式的redis除了原有的配置文件外又添加了一份集群配置文件。当集群内节点信息发生变化,如添加节点、节点下线、故障转移等。节点会自动保存集群状态到配置文件中(注意:reids自动维护集群配置文件,不要手动修改,防止节点重启尝试集群信息错乱),文件内容记录了节点ID,是一个40位16进制字符串,用于唯一表示集群内一个节点,之后很多集群操作都要借助于节点ID来完成(不同于运行ID,节点ID集群初始化只创建一次,节点重启后只创建一次,节点重启时会加载集群配置文件进行重用,而Redis的运行ID每次重启都会变化)

节点握手:

    节点通过Gossip协议笔试通信,达到感知对方过程:cluster meet{ip}{port} 这里的ping、pong、meet消息都是Gossip协议通信的载体,作用是节点彼此交换数据信息 

节点6379创建6378节点信息对象,并发送meet信息,节点6380接受后,保存6379节点信息并回复pong消息,之后两节点定期通过ping/pong消息进行正常节点通信

cluster meet命令进行节点握手的过程

执行命令:redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7005  节点建立握手后集群还不能正常工作,这时处于下线状态,所以数据读写被禁止

通过cluster info 查看集群信息,被分配的槽(cluster_slots_assigned:0),由于目前所有的槽没有分配到槽,因此集群无法完成槽到及诶单的映射,只有当16384个槽全部分配节点,集群才进入在线状态

分配槽:

  redis集群把所有的数据映射到16384个槽中。每个key映射为一个固定的槽,只有当节点分配了槽,才能相应和这些槽关联的键命令 : redis-cli -h 127.0.0.1 -p 7000 cluster addslots {0..5461} 目前作为一个完整的集群,每个负责处理槽的节点应该具有从节点,首次启动的节点和被分配的槽的节点都是主节点,从节点负责复制主节点槽信息和相关数据。使用cluster replicate {nodeld}命令让一个节点变成从节点。命令执行必须要对应从节点执行。集群搭建完成

节点通信:

  1.通信流程:分布式部署需要提供维护节点元数据信息的机制(元数据是指:节点负责哪些数据,是否出现故障等状态信息。)

         常见的元数据维护方式:集中式和p2p方式。Redis集群采用P2P的Gossip(流言)协议

          Gossip协议工作原理就是节点彼此不断通信交换信息,一般时间后所有节点都会知道集群完整的信息

          通信过程:a>集群中的每个节点会单独开启一个TCP通道,用于节点之间彼此通信,通信端口都在基础端口加1万

                            b>每个节点在周期内选择几个节点发送ping消息,收到ping消息的节点通过pong消息作为响应

            有些节点可能知道全部也有可能知道部分节点,只要这些及诶单彼此可以正常通信,当节点出故障、新节点加入、主从角色变化、槽信息变更等事件发送通过不断ping/pong消息同喜,所有节点就知道集群全部节点的最新状态,达到集群状态同步

2.GOSSIP消息

     Gossip协议主要职责就是信息交换。常用的消息可分为ping、pong、meet消息、fail消息等

     meet:通知新节点加入,之后在集群中进行周期性的ping、pong消息交换

     fail消息:当节点预判集群内另一个节点下线时,会向集群内广播一个fail消息

         消息解析流程

节点选择:因为ping/pong消息会携带当前节点和部分其他节点的状态信息,势必加重带块和计算负担。redis集群节点通信采用固定频率。通信节点过多可以消息即使但是成本过高,如果过少降低交换频率影响故障判断

集群伸缩:

  伸缩原理:可以为集群添加节点或者扩容也可以下线部分节点进行缩容

          其中原理可抽象为槽和对应数据在不同节点之间灵活移动

  扩容集群:三步骤: 1>准备新节点   2>加入集群 3>迁移槽和数据

             2>cluster meet 127.0.0.01 port  在经过一段时间的ping/pong消息通信后,所有节点会发现新节点并将它们状态保存在本地  可以执行 cluster nodes 查看新节点信息,但是因为没有分配槽,所以不能任何读写操作

            redis-trib.rb add-node 127.0.0.1:7000 127.0.0.1:7001正常情况见识使用这个命令加入新节点,该命令内部会执行新节点状态检查,如果新节点已经加入其它集群或者包含信息,则放弃集群加入操作,如果手动执行cluster meet命令加入已经存在于其它集群的节点或造成被加入节点的集群合并到现在集群情况,从而造成数据丢失和错乱,后果非常严重

           3>槽的迁移过程中集群可以正常提供读写服务,迁移过程是集群扩容最核心的环节

(1)槽迁移计划
     槽是Redis集群管理数据的基本单位,迁移计划需要确保每个节点㺓相似数量的槽,从而保证节点的数据均匀,计划确定后开始逐个把槽内数据从源节点迁移到目标节点
(2)迁移数据
     数据迁移过程是逐个槽进行的,每个槽数据迁移流程如下
     流程说明:
     a)对目标节点发送 cluster setslot {slot} importing {source NodeId}命令,让目标节点准备导入槽的数据
     b)对源节点发送 cluster setlot{slot} migrating {targetNodeId}命令,让源节点准备迁出槽数据
     c)源节点循环执行cluster getkeysinslot{slot}{count}命令,获取count个属于槽{slot}的键
     d)在源节点执行migrate{targeIp}{targePort}""0{timeout}keys{keys...}命令,把获取的键通过流水线(pipeline)机制批量迁移到目标节点(批量迁移键将极大降低节点之间网络IO次数)
     e)重复c)d)步骤,直到槽下所有键值数据迁移到目标节点
     f)向集群内所有主节点发送cluster setslot {slot} node {targetNodeId}命令,通知槽分配给目标节点。为了保证槽节点映射变更及时传播,需要遍历发送给所有主节点更新被迁移的槽指向新节点。

 收缩集群:

      

猜你喜欢

转载自blog.csdn.net/ligupeng7929/article/details/88852897