redis(十一):redis cluster[2]

1.集群的扩容

就是集群的节点的上线和下线,因为槽和数据一一对应,又新节点的加入必定导致槽的变化,故数据也会产生迁移。
在这里插入图片描述
(1)先启动两个新的节点 6385和6386,但这两个节点还没有加入集群
在这里插入图片描述
(2)meet
在这里插入图片描述
(3)redis-trib命令来新加入一个节点和meet操作
在这里插入图片描述
(4)迁移槽的命令
在这里插入图片描述
(5)迁移槽的流程图
在这里插入图片描述

2.集群的收缩

(1)下线槽
在这里插入图片描述
(2)忘记节点(60s内如果与节点A关联的某一个节点没有忘记节点A,那么节点A无法被忘记)
在这里插入图片描述
(3)最后就是关闭不需要使用的节点即可

3. move重定向

槽所对应的我们连接的节点不一致,如果通过槽去查找对应的节点失败,返回moved

如:连接8000节点,8000节点的槽是0-100,数据<hello,world>在槽120上,那么我们在8000节点上如果不是集群模式连接就会报moved异常,如果是集群模式连接8000节点就会重定向到其他节点帮我们去执行该命令。
在这里插入图片描述
槽不命中,moved异常
在这里插入图片描述

4.ask重定向

ask重定向发生在扩容和缩容中,当我们连接8000节点发送数据时,原本归8000节点管理的数据<key,value>转移到了8001节点上,就会出现ask重定向一场。

它与moved重定向之间的不同之处在它是发生在数据迁移过程过。而moved异常发生在槽早已经迁移了或者该数据本来就不属于该槽。
在这里插入图片描述

5.mget在cluster中的使用

原来的思路:key1扫描redis中所有的节点,每个节点执行一次get操作
在这里插入图片描述
优化:在client端,key1-keyN对节点数hash取余,然后计算出每个节点的所有的key的集合,集合存在subKeys中,然后subkeys与对应的node建立一个pipeline,一次性将所有的数据发给对应的节点。

如果是单线程,那么n个pipeline需要n次网络时间(串行IO)
如果是多线程,那么n个pipeline通过n个线程发送只需要一个网络时间(并行IO)
在这里插入图片描述
hash_tag操作:
将所有的key合并起来,一起发给同一个节点(可能产生数据倾斜)
在这里插入图片描述

6.故障发现

通过ping/pong实现故障发现:
(1)主观下线:节点1给节点2发送ping超时,节点1就认为节点2主观下线
在这里插入图片描述
(2)客观下线:当认为节点1主观下线的节点数超过一半时,认为节点1客观下线

每个节点都护维持一个节点信息的表,表中记录所有的节点的故障信息,如果上面表示有半数的节点都认为节点1主观下线,那么节点1客观下线。当确定节点1客观下线以后就通知所有节点该消息
在这里插入图片描述

7.故障恢复

(1)资格审查:审查主节点的所有slave与master的断线时间,短线时间超过阈值的取消资格。
(2)准备选举阶段:所有通过(1)的节点会检查offset,如果offset最大的节点就会延迟最短的时间后产于选举。如图,rank=0偏移量最大,延迟1秒后参加选举,rank=2的偏移量最小,延迟时间最长。这样是为保证保存数据最完整的节点选举成功。
在这里插入图片描述
(3)选举投票:使用ruft协议选举新的master,很明显,偏移量大的节点开始选举的时间更早,也更有优势,当选举成功超过半数,选举就成功了,slave就可以替换master的工作了。
在这里插入图片描述
(4)替换主节点:首先使用slaveof no one的命令,然后撤销主节点的槽,替换主节点的槽,最后向集群广播成功转移故障。

8.缺陷

发布/订阅模式下,所有的节点都会受到相应的消息,消息传递带宽很大,不建议在大型机群中使用。

集群模式下读写分离实现很复杂,slave节点只可以通过readonly命令取去读数据(不适用readonly你直接去slave中读数据会重定向到master中去取数据),不可以写数据,不建议使用redis读写分离,不如扩大集群规模方便维护。需要自己去实现客户端维护slave的槽。

9.单机使用sentinel和cluaster的区别

如果不是容量上的需要使用sentinel性能就已经足够好了。而且cluster更加难以维护。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个基于sw::redis::RedisCluster和libevent异步订阅消息的示例代码: ```cpp #include <iostream> #include <string> #include <sw/redis++/redis++.h> #include <event2/event.h> using namespace std; using namespace sw::redis; void eventCallback(evutil_socket_t fd, short what, void *arg) { RedisCluster *redis = (RedisCluster *)arg; redis->cluster_recv(); } int main() { const string redis_cluster_address = "tcp://127.0.0.1:7000"; const string channel_name = "test_channel"; // 创建 RedisCluster 实例 auto redis = RedisCluster::create(); redis->connect(redis_cluster_address); // 订阅频道 auto callback = [](const string &channel, const string &msg) { cout << "Received message from channel " << channel << ": " << msg << endl; }; auto sub = redis->subscribe(channel_name, callback); // 创建 libevent 实例 auto event_base = event_base_new(); auto event = event_new(event_base, sub->fd(), EV_READ | EV_PERSIST, eventCallback, redis.get()); // 添加事件监听 event_add(event, nullptr); // 进入事件循环 event_base_dispatch(event_base); return 0; } ``` 这个示例代码中,首先创建了一个 RedisCluster 实例,然后调用其 connect 方法连接 Redis 集群。接着,调用 subscribe 方法订阅指定的频道,并传入一个回调函数来处理接收到的消息。 然后,创建了一个 libevent 实例,并使用 event_new 函数创建一个事件对象,将其绑定到 RedisCluster 实例的 socket 描述符上,并传入一个回调函数。最后,调用 event_base_dispatch 进入事件循环。 在事件循环中,libevent 会监听 Redis 集群返回的消息,当有消息到达时,会触发事件回调函数 eventCallback,在回调函数中调用 RedisCluster 实例的 cluster_recv 方法来处理接收到的消息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值