Redis主从切换(单点故障)解决源码

1、使用过程:

发布创建channel1消息

redis-cli> PUBLISH channel1 "Hello, world!"

redis-cli> SUBSCRIBE channel1

        优点:

                1、采用Reactor事件单线程去驱动发布订阅事件的,实时性高

                2、从redis架构去思考,拓展哨兵、master、salve都相对简单容易, 扩展性高

        缺点:

                1、可靠性一般,redis只管发送消息,不会等待订阅该频道的实例响应。

                2、高频次访问发布消息,容易阻塞挤压,说白了还是Reactor单线程驱动缺点。

 2、实现过程:主从切换通过发布订阅模式实现的。

        2-1、实例化pubsub_channels(频道)哈希表,当前为空。

initServer函数
server.pubsub_channels = dictCreate(&keylistDictType,NULL);
server.pubsub_patterns = listCreate(); listSetFreeMethod(server.pubsub_patterns,freePubsubPattern); listSetMatchMethod(server.pubsub_patterns,listMatchPubsubPattern);

        2-2、发布命令

        初始化发布命令,往pubsub_channels添加channel和对应的订阅者列表。hash key存储了channel名称,value存储了订阅者列表。

initServerConfig函数
populateCommandTable函数加载redisCommandTable列表。
struct redisCommand redisCommandTable[] = {...{"publish",publishCommand,3,"pltr",0,NULL,0,0,0,0,0},{"pubsub",pubsubCommand,-2,"pltrR",0,NULL,0,0,0,0,0},...
}
publishCommand函数
void publishCommand(redisClient *c) {//发布命令,从pubsub_channels哈希表中查询到对应发布的消息。int receivers = pubsubPublishMessage(c->argv[1],c->argv[2]);if (server.cluster_enabled)//如果是cluster节点,则使用集群发布模式clusterPropagatePublish(c->argv[1],c->argv[2]);else//forceCommandPropagation(c,REDIS_PROPAGATE_REPL);//返回接收消息的订阅者数量addReplyLongLong(c,receivers);
}

       2-3、订阅消息

        从pubsub_channels适配channel对应的订阅者列表。

initServerConfig函数
populateCommandTable函数加载redisCommandTable列表。
批量订阅和退订指令加载
struct redisCommand redisCommandTable[] = {...{"subscribe",subscribeCommand,-2,"rpslt",0,NULL,0,0,0,0,0},{"unsubscribe",unsubscribeCommand,-1,"rpslt",0,NULL,0,0,0,0,0},{"psubscribe",psubscribeCommand,-2,"rpslt",0,NULL,0,0,0,0,0},{"punsubscribe",punsubscribeCommand,-1,"rpslt",0,NULL,0,0,0,0,0},...
}
void subscribeCommand(redisClient *c) {int j;for (j = 1; j < c->argc; j++)pubsubSubscribeChannel(c,c->argv[j]);
}void unsubscribeCommand(redisClient *c) {if (c->argc == 1) {pubsubUnsubscribeAllChannels(c,1);} else {int j;for (j = 1; j < c->argc; j++)pubsubUnsubscribeChannel(c,c->argv[j],1);}
}void psubscribeCommand(redisClient *c) {int j;for (j = 1; j < c->argc; j++)pubsubSubscribePattern(c,c->argv[j]);
}void punsubscribeCommand(redisClient *c) {if (c->argc == 1) {pubsubUnsubscribeAllPatterns(c,1);} else {int j;for (j = 1; j < c->argc; j++)pubsubUnsubscribePattern(c,c->argv[j],1);}
}
/* Subscribe a client to a channel. Returns 1 if the operation succeeded, or* 0 if the client was already subscribed to that channel. ** 设置客户端 c 订阅频道 channel 。** 订阅成功返回 1 ,如果客户端已经订阅了该频道,那么返回 0 。*/
int pubsubSubscribeChannel(redisClient *c, robj *channel) {dictEntry *de;list *clients = NULL;int retval = 0;/* Add the channel to the client -> channels hash table */// 将 channels 填接到 c->pubsub_channels 的集合中(值为 NULL 的字典视为集合)if (dictAdd(c->pubsub_channels,channel,NULL) == DICT_OK) {retval = 1;incrRefCount(channel);// 关联示意图// {//  频道名        订阅频道的客户端//  'channel-a' : [c1, c2, c3],//  'channel-b' : [c5, c2, c1],//  'channel-c' : [c10, c2, c1]// }/* Add the client to the channel -> list of clients hash table */// 从 pubsub_channels 字典中取出保存着所有订阅了 channel 的客户端的链表// 如果 channel 不存在于字典,那么添加进去de = dictFind(server.pubsub_channels,channel);if (de == NULL) {clients = listCreate();dictAdd(server.pubsub_channels,channel,clients);incrRefCount(channel);} else {clients = dictGetVal(de);}// before:// 'channel' : [c1, c2]// after:// 'channel' : [c1, c2, c3]// 将客户端添加到链表的末尾listAddNodeTail(clients,c);}/* Notify the client */// 回复客户端。// 示例:// redis 127.0.0.1:6379> SUBSCRIBE xxx// Reading messages... (press Ctrl-C to quit)// 1) "subscribe"// 2) "xxx"// 3) (integer) 1addReply(c,shared.mbulkhdr[3]);// "subscribe\n" 字符串addReply(c,shared.subscribebulk);// 被订阅的客户端addReplyBulk(c,channel);// 客户端订阅的频道和模式总数addReplyLongLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns));return retval;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/580604.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4.vue学习笔记(事件处理+事件参数+事件修饰符)

文章目录 1.事件处理1.1.内联事件处理器 2.事件参数2.1.传参过程中获取Event 3.事件修饰符3.1.阻止默认事件阻止事件冒泡 1.事件处理 我们可以使用v-on指令&#xff08;简写为&#xff09;来监听DOM事件&#xff0c;并在事件触发时执行对应的JavaScript。 用法&#xff1a;v-o…

ubuntu服务器上安装KVM虚拟化

今天想着在ubuntu上来安装一个windwos操作系统&#xff0c;原因是因为我们楼上有几台不错的服务器&#xff0c;但是都是linux系统的。 今天我想着要给同事们搭建一个chatgpt环境&#xff0c;用来开发程序&#xff0c;但是ubuntu上其实也可以安装我嫌麻烦&#xff0c;刚好想折腾…

VMware16 pro 安装openEuler-23.09-x86_64,详细操作流程+详图。

1.环境&#xff1a; win11, vmware16 pro, openEuler-23.09-x86_64-dvd.iso 社区版openEuler 23.09官方下载地址&#xff1a; openEuler下载 | 欧拉系统ISO镜像 | openEuler社区官网欧拉操作系统(openEuler, 简称“欧拉”)是面向数字基础设施的操作系统,支持服务器、云计算、…

【教学类-35-07】17号的字帖(二)班级字帖“大4”(A4竖版1份)

作品展示 背景需求&#xff1a; 大4班17号孩子练习数字书写&#xff0c;上一次是“17”号&#xff0c;这次是大“4”。 【教学类-35-05】17号的学号字帖&#xff08;A4竖版1份&#xff09;-CSDN博客文章浏览阅读440次&#xff0c;点赞6次&#xff0c;收藏7次。【教学类-35-05…

Vue2从源码角度来回答一些常见的问题

1.请说一下Vue2响应式数据的理解&#xff08;先知道基本的问题在哪里&#xff0c;源码的角度来回答&#xff0c;用的时候会有哪些问题&#xff09; 可以监控一个数据的修改和获取操作。针对对象格式会给每个对象的属性进行劫持 Object.defineProperty 源码层面 initData ->…

在香橙派5 Plus上搭建Gitlab

作为一个码农&#xff0c;一定知道Github这个最大的成人交友网站。但是Github在国内不稳定&#xff0c;经常拉不下来代码&#xff0c;也就无法推送代码。为了更方便的使用&#xff0c;顺便更好地了解Git工具&#xff0c;决定在香橙派5 Plus上搭建一个属于自己的代码仓库。 1、…

k8s的二进制部署: 源码包部署-----node节点部署

服务器IP软件包k8s--master0120.0.0.61kube-aplserver&#xff0c;kube-controer-manager&#xff0c;kube-scheduler&#xff0c;etcdk8s--master0220.0.0.62kube-controer-manager&#xff0c;kube-schedulernode节点0120.0.0.62kubelet&#xff0c;kube-proxy&#xff0c;et…

MongoDB 根据 _id 获取记录的创建时间并回填记录中

1、单条更新 MongoDB 集合 test1,有字段 _id&#xff0c;createTime&#xff0c;createTimeStr&#xff0c;name字段 &#xff0c; 查询createTime不为空的&#xff0c;根据 _id 生成该条记录的创建时间时间戳并填写到字段 createTime 字段中 &#xff0c;并打印时间戳…

IDEA快捷使用-快捷键模板

常用快捷模板 .方法的使用,例如输入 arr.null 回车 其他常规方法直接输入回车&#xff0c;不需要对象通过.来调用。 创建变量 psfi 创建公开int类型常量 public static final int prsf 创建 私有静态变量 private static final psf 创建公开静态变量 public static final创…

【问题系列】同时管理多版本node方案

目录 一、问题描述 二、解决方案 三、详细步骤 3.1 安装NVM&#xff1a; 3.2 运行NVM 3.3 安装Node.js 3.4 切换Node.js版本 3.5 验证安装&#xff1a; 四、拓展 4.1 设置默认 Node.js 版本 4.2 列出已安装的 Node.js 版本 4.3 其他命令介绍 一、问题描述 需要运行…

C#实现串口通讯

1、官网下载Launch Virtual Serial Port Driver Virtual Serial Port Driver - create and emulate virtual COM port&#xff0c;开个虚拟串口&#xff1a; Pair模式&#xff08;一对&#xff0c;成双成对的意思&#xff0c;就是COM1向COM2传或者COM2向COM1,好比两台机器的CO…

软件工程期末复习

● 用例&#xff1a;借书 ●参与者&#xff1a;管理员,借阅者 ●操作流&#xff1a; ① 管理员进入图书借阅界面&#xff0c;用例开始。 ② 系统要求输入借阅者的借书证编码。 ③系统检验借书证编码,如果正确,则显示借阅者的信息。 A1&#xff1a;借书证编码有错。 A2: 如果该借…

巨量引擎大众消费发布“十佳好课”榜单:涵盖五大行业 助力商家进阶

2023&#xff0c;中国消费市场出现温和复苏态势&#xff0c;在不确定市场环境下&#xff0c;大众消费商家如何用好科学营销手段&#xff0c;实现确定性增长?如何紧跟平台趋势&#xff0c;把握生意增长先机? 为了给商家持续提供前沿适配的营销方法、解决实际生意卡点&#xff…

MYSQL一一函数一一字符串函数

嘿嘿大家好我回来啦&#xff0c;今天我们要学习的是MYSQL中的函数&#xff0c;函数呢我们又分为字符串函数&#xff0c;数值函数&#xff0c;日期函数&#xff0c;流程函数来介绍&#xff0c;今天重点介绍字符串函数(从小题到案例方便你们更加深入的理解) 函数指的是一段可以直…

软件测试面试题合集,金三银四offer稳了。。。

前言 前面看到了一些面试题&#xff0c;总感觉会用得到&#xff0c;但是看一遍又记不住&#xff0c;所以我把面试题都整合在一起&#xff0c;都是来自各路大佬的分享&#xff0c;为了方便以后自己需要的时候刷一刷&#xff0c;不用再到处找题&#xff0c;今天把自己整理的这些…

操作系统期末复习题

进程同步(P、V操作) 桌上有一空盘&#xff0c;允许存放一只水果。爸爸可向盘中放苹果&#xff0c;也可向盘中放桔子&#xff0c;儿子专等吃盘中的桔子&#xff0c;女儿专等吃盘中的苹果。规定当盘空时一次只能放一只水果供吃者取用&#xff0c;请用P、V原语实现爸爸、儿子、女…

nginx源码分析-1

使用gdb查看函数上下文&#xff1a; gdb attach nginx的work线程 监听端口状态时&#xff1a; 断点打在ngx_http_process_request 并通过浏览器触发请求时&#xff1a;

剑指offer题解合集——Week2day2

文章目录 剑指offerWeek2周二&#xff1a;剪绳子AC代码思路&#xff1a; 剑指offerWeek2 周二&#xff1a;剪绳子 题目链接&#xff1a;剪绳子 给你一根长度为 n绳子&#xff0c;请把绳子剪成 m段&#xff08;m、n都是整数&#xff0c;2≤n≤58 并且 m≥2&#xff09;。每段…

Unity-序列化和反序列化

序列化是指把对象转换为字节序列的过程,而反序列化是指把字节序列恢复为对象的过程。序列化最主要的用途就是传递对象和保存对象。 在Unity中保存和加载、prefab、scene、Inspector窗口、实例化预制体等都使用了序列化与反序列化。 1 可序列化类型 1> 自定义的具有Serial…

简易考试系统第1关:简易考试系统之用户注册

任务描述 本关任务&#xff1a;实现简易考试系统中新用户注册的功能。 编程要求 仔细阅读右侧编辑区内给出的代码框架及注释&#xff0c;在 Begin-End 中实现简易考试系统中新用户注册的功能&#xff0c;具体要求如下&#xff1a; User.java 提供了用户的基本信息&#xff0…