暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

redis-cluster

老码农空杯修行记 2020-09-11
270

单点问题

单点问题,有两个层次:

服务单点:服务故障无其它节点顶替,导致服务不可用,此时单点故障;

访问单点:没有出故障,即便出现也有其它节点顶替提供服务,但是访问始终落在单个点上,单个点有瓶颈,这也是一种单点问题。

redis-cluster

redis 通过哨兵主从复制机制解决单点故障问题和读访问单点问题,但是存在写访问单点的问题,因此redis引入了集群

redis 集群是去中心化网状结构,集群中无论是否主从关系,都需要与集群中的其它节点建立连接,这个连接叫做TCP总线(内部连接端口是在对外提供请求的端口之上加10000,比如对外6379,则总线端口为16379)。建立连接之后集群内部都通过该总线进行交流(槽位节点映射表、配置信息等)。

集群收到用户请求时如何分库分表的?其实redis-cluster 引入了槽位的概念,但本质上就是类似 Mysql 等分库分表的机制(通过id或请求信息得到准确的存储位置)。redis-cluster 最大 16384,也就是说集群最大规模是 16384 个节点,这样足以满足实际需求,实际中不会太大,当节点收到请求时会根据 key 计算槽位(crc16(key) mod 16384),通过槽位找到对应的节点,然后向节点发起请求获得结果。

读写原理

  • 客户端连接任意一个节点
  • 客户端发送请求,比如:get name
  • 节点计算 name 的 HASH-SLOT: crc16(name) mod 16384= 5798
  • 节点查询本节点槽位节点映射表,发现是自己,则处理请求并返回
  • 节点查询本节点槽位节点表,发现是槽位归其它节点,则返回重定向MOVED 信息(MOVED 槽位 ip:port)
  • 客户端若得到错误响应,并且是重定向错误,则连接重定向的节点处理请求 

重定向发生的时机
  • 连接节点是 SLAVE, 并且不是只读请求,必定重定向,SLAVE 默认不处理任何请求,只是故障时替代其对应 MASTER的作用
  • 槽位不归本节点

客户端优化

到此知道一旦客户端无法连接到正确的节点将会重定向再次发生连接,这是两次tcp请求,代价比较大,所以应当优化客户端,客户端维护一份槽位节点映射表,客户端请求先计算HASH-SLOT,然后查寻本地槽位节点映射表,若有映射,则对目标机器发起请求,大部分情况下(槽位发生变化的可能很小,因为一般不会变动)一次 TCP 请求获取结果。

当然也有意外,比如服务端发生槽位迁移,此时则可以通过重定向更新,更新之后再刷新本地表

槽位节点映射表

集群中的各个节点如何知道其它节点槽位信息?

集群中的节点都有16384个槽位到节点的映射关系表,初始化为空,即各个槽位对应的节点为NULL,然后填充各自槽位信息,之后各个节点通过TCP 总线维持一个心跳,心跳里会包含归属自己的槽位信息,其它节点收到槽位信息表时会和本地的槽位信息比较更新,若本地槽位信息表中槽位对应节点为NULL,则直接更新,若不是NULL,则比较版本,比如原来是2,收到心跳里该槽位对应的节点版本为3,则刷新该槽位,否则不处理。
这样做的好处是,一旦集群新增节点或槽位发生迁移,则可以更新,最终得到准确的槽位节点分布信息。
故障转移

默认情况下,SLAVE 节点只是当做备份节点,一旦对应 Master 故障,SLAVE 被提升为 Master,其流程如下

  • 断开和主节点的链接

  • 提升自己的配置版本 epoch + 1(比如:3+1)

  • 向所有的 Master 节点发起 FAILOVER_AUTH_REQUEST 投票请求

  • 在 2 * NODE_TIMEOUT 周期内若大部分 Master 回复 FAILOVER_AUTH_ACK,则竞选成功

如何避免多个节点发起竞选请求?
一旦 Master 收到竞选,会和本地的版本lastEpoch比较,一旦比这个小,则拒绝投票,否则投票,投票后lastEpoch会在发起请求的epoch之上加1(对应上面:4+1),之后在 2 * NODE_TIMEOUT 周期内它不会再给别的 SLAVE 投票(这里在说的透一点,主节点正常工作时,所有该主节点的 SLAVE 节点都有相同的 Epoch 版本,Master 失败,其中一个首先竞选,提升了自己的版本,其它Master 收到后就会更新 lastEpoch,其它的 slave 再发就已经没意义了,发过去后由于版本低,会被否决,投票给一个slave后一段时间内不再投票)。
存储破局的几个方向

触类旁通,为什么能触类旁通?原因是学东西有没有学到本质的东西,直达本质才发现很多都是相似,从而如同轻车熟路。人说你不开窍,我想不开窍不是因为笨,而是没有到本质。

存储中,无论redis、mysql,可能实现不同,应对场景不同,但是破局瓶颈时几乎都是类似的,已mysql和redis为例,无非通过以下几种方式:

  • 高可用

主从结构,主宕机或故障,从节点提升为主

  • 读性能瓶颈

增加从节点,做读写分离,主写,从读
  • 写性能瓶颈
增加多个主从节点,前段增加分库分表策略,说白了就是数据路由,前段可以是客户端,也可以是集群前面加个代理




文章转载自老码农空杯修行记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论