通过redis选主进程

详解Redis哨兵模式下,主节点掉线而重新选取主节点的流程 最核心的结论:所谓选举的过程不是直接选出新的主节点,而是先在哨兵节点中选出 leader ,再由 leader 负责后续主节点的指定。 阅读详情

选主进程的方式有很多,完善点的方案就是zookeeper来做。这里介绍的是一种基于redis选主的方案,快速开发,快速实现。

Springside4里有个MasterElector类,细读代码后整理出自己的总结如下。

1.      业务进程启动时生成hostId,hostId的规则是“主机名-随机数”,一台主机部署多个进程实例的情况,也可以改为“主机名-端口”。

2.      业务进程调用jedis.get(masterKey)获取masterFromRedis。

3.      如果masterFromRedis为空,调用setnx(masterKey, hostId)方法设值,方法返回值大于0当前进程选为主进程,并且expire(masterKey,expireSeconds)设置key的有效期。Setnx返回值小于等于0时不能选为主进程。

如果masterFromRedis等于hostId,当前进程选为主进程,并且expire(masterKey, expireSeconds)设置key的有效期。

4.      按时间间隔intervalSeconds定期执行第二步和第三步。

 

 

当get(masterKey)之后获取到的masterFromRdis为空,在setnx之前,有其他进程已经Set了masterKey的值,本进程再调用setnx返回0失败.reids api文档有详细介绍:

 

SETNX key value

将 key 的值设为 value ,当且仅当 key 不存在。

若给定的 key 已经存在,则 SETNX 不做任何动作。

SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。

可用版本:

>= 1.0.0

时间复杂度:

O(1)

返回值:

设置成功,返回 1 。

设置失败,返回 0 。

 

intervalSeconds定时时间间隔设置短些,可以减少异常情况下没有主的情况。

附上springside4的代码

 

 

public class MasterElector implementsRunnable {

 

                   publicstatic final String DEFAULT_MASTER_KEY = "master";

 

                   privatestatic Logger logger = LoggerFactory.getLogger(MasterElector.class);

 

                   privatestatic AtomicInteger poolNumber = new AtomicInteger(1);

                   privateScheduledExecutorService internalScheduledThreadPool;

                   privateScheduledFuture electorJob;

                   privateint intervalSeconds;

 

                   privateJedisTemplate jedisTemplate;

 

                   privateint expireSeconds;

                   privateString hostId;

                   privateAtomicBoolean master = new AtomicBoolean(false);

                   privateString masterKey = DEFAULT_MASTER_KEY;

 

                   publicMasterElector(JedisPool jedisPool, int intervalSeconds, int expireSeconds) {

                                      jedisTemplate= new JedisTemplate(jedisPool);

                                      this.expireSeconds= expireSeconds;

                                      this.intervalSeconds= intervalSeconds;

                   }

 

                   /**

                    * 发挥目前该实例是否master

                    */

                   publicboolean isMaster() {

                                      returnmaster.get();

                   }

 

                   /**

                    * 启动抢注线程, 自行创建scheduler线程池.

                    */

                   publicvoid start() {

                                      internalScheduledThreadPool= Executors.newScheduledThreadPool(1,

                                                                            Threads.buildJobFactory("Master-Elector-"+ poolNumber.getAndIncrement() + "-%d"));

                                      start(internalScheduledThreadPool);

                   }

 

                   /**

                    * 启动抢注线程, 使用传入的scheduler线程池.

                    */

                   publicvoid start(ScheduledExecutorService scheduledThreadPool) {

                                      if(intervalSeconds >= expireSeconds) {

                                                         thrownew IllegalArgumentException("periodSeconds must less than expireSeconds.periodSeconds is "

                                                                                               +intervalSeconds + " expireSeconds is " + expireSeconds);

                                      }

 

                                      hostId= generateHostId();

                                      electorJob= scheduledThreadPool.scheduleAtFixedRate(new WrapExceptionRunnable(this), 0,intervalSeconds,

                                                                            TimeUnit.SECONDS);

                                      logger.info("masterElectorstart, hostName:{}.", hostId);

                   }

 

                   /**

                    * 停止分发任务,如果是自行创建的threadPool则自行销毁。

                    */

                   publicvoid stop() {

                                      electorJob.cancel(false);

 

                                      if(internalScheduledThreadPool != null) {

                                                         Threads.normalShutdown(internalScheduledThreadPool,5, TimeUnit.SECONDS);

                                      }

                   }

 

                   /**

                    * 生成host id的方法哦,可在子类重载.

                    */

                   protectedString generateHostId() {

                                      Stringhost = "localhost";

                                      try{

                                                         host= InetAddress.getLocalHost().getHostName();

                                      }catch (UnknownHostException e) {

                                                         logger.warn("cannot get hostName", e);

                                      }

                                      host= host + "-" + new SecureRandom().nextInt(10000);

 

                                      returnhost;

                   }

 

                   @Override

                   publicvoid run() {

                                      jedisTemplate.execute(newJedisActionNoResult() {// NOSONAR

                                                                                               @Override

                                                                                               publicvoid action(Jedis jedis) {

                                                                                                                  StringmasterFromRedis = jedis.get(masterKey);

 

                                                                                                                  logger.debug("masteris {}", masterFromRedis);

 

                                                                                                                  //if master is null, the cluster just start or the master had crashed, try toregister myself

                                                                                                                  //as master

                                                                                                                  if(masterFromRedis == null) {

                                                                                                                                     //use setnx to make sure only one client can register as master.

                                                                                                                                     if(jedis.setnx(masterKey, hostId) > 0) {

                                                                                                                                                        jedis.expire(masterKey,expireSeconds);

                                                                                                                                                        master.set(true);

 

                                                                                                                                                        logger.info("masteris changed to {}.", hostId);

                                                                                                                                                        return;

                                                                                                                                     }else {

                                                                                                                                                        master.set(false);

                                                                                                                                                        return;

                                                                                                                                     }

                                                                                                                  }

 

                                                                                                                  //if master is myself, update the expire time.

                                                                                                                  if(hostId.equals(masterFromRedis)) {

                                                                                                                                     jedis.expire(masterKey,expireSeconds);

                                                                                                                                     master.set(true);

                                                                                                                                     return;

                                                                                                                  }

 

                                                                                                                  master.set(false);

                                                                                               }

                                                                            });

                   }

 

                   /**

                    * 如果应用中有多种master,设置唯一的mastername

                    */

                   publicvoid setMasterKey(String masterKey) {

                                      this.masterKey= masterKey;

                   }

 

                   //for test

                   publicvoid setHostId(String hostId) {

                                      this.hostId= hostId;

                   }

}

 

Redis哨兵模式原理剖析,监控、选主 为什么需要客观下线机制? 因为当前哨兵节点探测对方没有得到响应,很有可能这两个机器之间的网络发生了故障,而 Master 节点本身没有任何问题,此时就认为 Master 故障是不正确的。 为了解决上述问题,客观下线应运而生,Sentinel一般会集群部署,引入多个哨兵实例一起来判断,就可以避免单个哨兵因为自身网络状况不好,而误判主库下线的情况。 假设我们有N个哨兵实例,如果有N/2+1个实例判断主库“主观下线”,此时把节点标记为“客观下线”,此时就可以做主从切换了。 4.选举哨兵领导者? ========= 阅读详情

相关推荐

了解Redis集群概念,集群如何选举主节点

像上文的Redis集群的A、B、C三个节点,主从模型可以为这每一个主节点添加一个副本节点。Redis集群重新分片可以将任意数量已指派给某个节点的槽改为指派给另一个节点,而相关槽所属的键值对也会从源节点被移动到目标节点。Redis 集群将数据自动分片到多个 Redis 节点,Redis 集群还在分区期间提供一定程度的可用性,当某些节点发生故障或无法通信时,Redis集群能够继续运行。Redis集群的主从模型选举主节点和Redis哨兵选举出主节点非常相似,但大家不要搞混了,Redis集群中并没有哨兵的概念。

程序员-杨胡广的博客 1307

redis在集群模式下主节点的选举

无论采用哪种策略,主节点的选举是确保Redis集群高可用性的关键环节,应当得到特别关注和合适的配置。这些机制使用不同的选举策略来确保新的主节点的选举是可靠和高效的。这可以确保新的主节点具有更多的数据一致性,但也要求有足够多的节点参与选举。:当一个主节点被标记为失效时,Redis集群会从已有的从节点中选举一个新的主节点。:在Redis集群中,节点可以担任主节点或从节点的角色。这些协议确保在失效主节点的情况下,只有一个新的主节点被选举。:选举策略通常包括检测主节点的故障,以及检查潜在的主节点的健康状况。

weixin_42279822的博客 1517

redis-leader-by-lock:使用Redis Lock轻松实现集群领导者选举

Redis-leader-by-lock 使用Redis Lock轻松实现集群领导者选举 仅使用Spring-Boot和Redis 动机 几乎所有使用Spring Boot进行领导力选举的例子都转到Hazelcast(现在已弃用)和Zookeeper(在简单情况下过强)中的Spring Cloud Cluster,这有点奇怪,因为来创建几乎平凡的领导力选举。 这就是我这样做的原因。 要求 Java 8 玛文 雷迪斯 跑步 mvn全新安装 (在四个不同的终端中,因此您可以看到输出) java -jar target / redis-leader-by-lock-0.0.1-SNAPSHOT.jar --server.port = 8081 java -jar target / redis-leader-by-lock-0.0.1-SNAPSHOT.jar --server.port

redis cluster的raft算法选主流程

5. Redis Cluster 故障转移 上面已经介绍过单机模式的故障转移(主节点下线后,对应从节点升主并替代原主节点继续工作)过程,单机模式下故障转移需要 Sentinel 系统的辅助,与之不同,Redis 集群模式故障转移并不需要 Sentinel 系统辅助,而是通过集群内部主节点选举完成,是一个“自治”的系统。 Redis Cluster 的故障转移可划分为三大步骤:故障检测、从节点选举以及故障倒换,以下详细介绍。 5.1 故障检测 故障检测需要经历单节点视角检测、检测信息传播、下线判决三个

lzf的博客 2396

树莓派34/100 - Pico读取MPU6050加速度和陀螺仪传感器数据

树莓派Pico连接MPU-6050模块(三轴陀螺仪+三轴加速度),读取运动姿态数据。

申龙斌的程序人生 5092

基于奥比中光Orbbec Astra Pro与ROS实现实时3D环境建模:orb_slam2实战指南

本文提供了一份详细的实战指南,介绍如何使用奥比中光Orbbec Astra Pro深度摄像头与ROS系统,部署并运行ORB-SLAM2算法,实现实时3D环境建模与定位。内容涵盖从驱动安装、环境配置、算法编译到摄像头标定与性能调优的全流程,旨在帮助开发者快速搭建一套高性价比的视觉SLAM系统。

weixin_29054399的博客 337

redis哨兵模式——sentinel初尝试

redis哨兵模式——sentinel初尝试一.建立起主从体系二.shutdown掉主进程(模拟故障),观察结果 一.建立起主从体系 在一台centos7虚拟机上,分别以6379,6380,6381,6382启动4个redis进程,以6379为master,其它三个为slave。 首先要将原始的redis配置文件复制(原始配置文件位于redis解压的文件目录下),为每个redis进程准备一个配置文...

weixin_43954217的博客 227

PaddleOCR实战:DBnet++与DBnet模型训练全流程解析

本文详细解析了基于PaddleOCR框架的DBnet与DBnet++文字检测模型的完整训练流程。从环境配置、数据集准备、配置文件解读,到模型训练、评估调参及最终推理部署,提供了实战指南。重点对比了DBnet++与DBnet在精度、速度及适用场景上的差异,帮助开发者高效构建定制化的OCR检测模型。

weixin_29038155的博客 335

Redis 执行 RDB 快照期间,主进程可以正常处理命令吗?

所以 Redis 在使用 bgsave 快照过程中,如果主进程修改了内存数据,不管是否是共享的内存数据,RDB 快照都无法写入主进程刚修改的数据,因为此时主进程的内存数据和子进程的内存数据已经分离了,子进程写入到 RDB 文件的内存数据只能是原本的内存数据(快照的定义)。如果主进程执行写操作,则被修改的数据会复制一份副本,然后 bgsave 子进程会把它的副本数据写入 RDB 文件,在这个过程中,主进程仍然可以直接修改原来的数据。注意,只有在发生修改内存数据的情况时,物理内存才会被复制一份。

小楠的博客 1418

第二次 PX4仿真环境搭建过程全记录

参考链接 https://blog.youkuaiyun.com/yanwumuxi/article/details/80097294 https://www.ncnynl.com/archives/201709/2013.html 一、安装依赖项 我们使用Debian / Ubuntu LTS 作为Linux的标准支持版本,但是也支持Cent OS 和 Arch Linux的发行版本。 权限设置 警告:永远...

移步换景的博客 2263

手把手教你用 Docker 构建自己的 CentOS 基础镜像

目录一、准备CentOS基础镜像二、撰写Dockerfile三、构建Docker镜像四、生成Docker容器 相信码农们经常会听说:虚拟机将成为历史,Docker才是未来 !!! 事实如此,现在大部分公司都在用 Docker 技术,想拥有自己的 Docker 专属镜像,那么 Dockerfile 就是入门,现在让我们一起来看一下 ------ 构建 Docker 镜像的全过程。 好文章 记得收藏...

Nick.Peng's Blogs 1万+

Redis 重写 AOF 日志期间,主进程可以正常处理命令吗?

触发重写机制后,主进程就会创建重写 AOF 的子进程,此时父子进程共享物理内存,重写子进程只会对这个内存进行只读,重写 AOF 子进程会读取数据库里的所有数据,并逐一把内存数据的键值对转换成一条命令,再将命令记录到重写日志(新的 AOF 文件)。简单来说,两者的虚拟空间不同,但其对应的物理空间是同一个。那么问题来了,重写 AOF 日志过程中,如果主进程修改了已经存在的 key-value,就会触发「写时复制」,此时这个 key-value 数据在子进程的内存数据就和在主进程的内存数据不一致了。

小楠的博客 1117

STM32入门教程:智能储物柜控制

在这个例子中,我们将使用一个4x4的储物柜,共有16个储物格。我们了解了硬件准备、储物柜电路设计、STM32的基本配置、储物柜控制代码的编写以及测试和调试等方面的知识。根据我们的电路设计,我们需要将一些引脚配置为输出,并将其他引脚配置为输入。在本教程中,我们将使用STM32微控制器来实现一个基本的智能储物柜控制系统。在主函数中,我们将不断循环读取传感器数据,并根据数据的变化来控制储物柜的开关和显示相关信息。这个函数将读取人体感应传感器、温湿度传感器和光照传感器的数据,并将数据存储到相应的变量中。

m0_75244442的博客 663

AOF 重写期间如果 Redis 崩溃会怎样?

尽管 AOF 重写期间 Redis 崩溃可能会导致一些复杂的情况,但由于 Redis 对此进行了精心的设计,确保了即便在这种极端情况下也不会造成严重的数据丢失或一致性问题。子进程崩溃不影响现有 AOF 文件。主进程崩溃后,Redis 能够选择合适的 AOF 文件进行恢复。用户可以通过配置适当的策略进一步控制数据的安全级别。因此,在生产环境中合理设置 AOF 相关参数,并定期监控 Redis 的运行状态,可以帮助最大限度地减少潜在的风险。

wamp0001的博客 544

YOLOv11改进策略【独家融合改进】| MobileNetV4+BiFPN,轻松实现降参涨点,适用专栏内所有的骨干替换

可扩展的高效物体检测BiFPN(加权双向特征金字塔网络)

Limiiiing的博客 2362

SAP Fiori Launchpad Tile,UI5 应用,和 PFCG Role 的对应关系

问题:已经看到了SAP Fiori Launchpad上的某个tile,如何反推后台需要配置哪个PFCG Role才能看到该tile? 这个问题是今天一个朋友在微信上问我的。因为我最近忙着学习一个新的SAP产品,所以这个问题也没有时间展开来写,本文就只做概要介绍。 下图是一个Gateway系统上打开的SAP CRM Fiori Launchpad: 如何弄清楚后台用户配置了哪个PFCG Role之后,才能看到Sales Representative(CRM)这个Group下的tile? 既然当前我使用的用

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1521

从Redis主进程bgsave导致的应用超时说起

Redis进程阻塞 Redis RDB文件解析 rdb-tools工具查找Redis大key

lixia0417mul2的博客 854

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

docker 主进程 日志_[docker]从一个实例,一窥docker进程管理

在Docker中,进程管理的基础是Linux内核的PID命名空间技术。在不同的PID命名空间下,可以有相同的PID。Linux内核为所有的PID命名空间维护了一个树状的数据结构,最顶层是系统初始化时创建的root namespace(根命名空间), 父节点可以看到子节点中的进程,并可以通过信号等方式对子节点中的进程产生影响。反过来,子节点不能看到父节点名空间中的任何内容,也不可能通过kill或pt...

weixin_39859909的博客 355

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Redis_写时复制(cow)

RDB快照:bgsave 生成的是 fork 时刻的数据快照,不包含fork之后的新写入数据。写时复制:主进程在 fork 之后的新写入数据会存储在新的内存区域中。后续处理:下一次 bgsave 会包含最新的数据快照。AOF日志:如果启用AOF模式,所有写操作都会被记录在AOF文件中,确保数据的一致性和完整性。这种方式保证了RDB文件的一致性和高可用性,同时也提供了AOF模式作为补充,确保数据的完整性和一致性。欢迎关注:鲁班曰。

基础决定高度 1623

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Redis Save 与 BGSAVE 的区别

一,save保存数据到磁盘的方式: Redis Save 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘。 语法 redis Save 命令基本语法如下: redis 127.0.0.1:6379> SAVE 返回值 保存成功时返回 OK 。 二,BGSAVE保存数据到磁盘的方式: BGSAVE 命令执行之后立即返回 OK ,然后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续...

大JAVA解决方案 861

TBase vs Redis:不是选谁,是选谁干什么

TBase vs Redis 不是选择题,是分工题。需求用什么数据不能丢,查询要复杂TBase(或单机PG)读得要快,写得要快,丢了能恢复Redis两者都要TBase+Redis,Cache Aside模式只有一个,选谁选TBase(数据安全优先,缓存可以后补)最后一条建议很现实:如果你预算有限只能部署一套系统,先部署关系型数据库。缓存可以后加,数据丢了无法后补。Redis是锦上添花。TBase(或PostgreSQL)是雪中送炭。先解决"存得住",再解决"读得快"。

在渔村里看AI,偶尔捕点新鲜的。 203

Redis——BigKey

本文讲解Redis的BigKey问题。

qq_61350148的博客 918

Redis的AOF日志

如果 Redis 每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里,然后重启 Redis 的时候,先去读取这个文件里的命令,并且执行它,这不就相当于恢复了缓存数据了吗? 这种保存写操作命令到日志的持久化方式,就是 Redis 里的AOF(Append Only File)持久化功能,注意只会记录写操作命令,读操作命令是不会被记录的,因为没意义。 在 Redis 中 AOF 持久化功能默认是不开启的,需要我们修改redis.conf配置文件中的以下参数: AOF 日志文件其实...

小胡子 1239

持久化到底怎么选?Redis Persistence 技术实战

Redis提供RDB快照、AOF日志以及混合模式三种持久化方案。RDB以二进制快照形式保存数据,具有单文件易迁移、恢复快的优势,但存在分钟级数据丢失风险;AOF采用追加日志方式,可提供秒级持久化,7.0版本引入多段AOF架构优化性能;混合模式结合两者优势,适合对数据安全性要求高的场景。本文详细对比了各模式的优缺点,给出不同业务场景下的配置建议,包括备份策略、故障处理方案和平滑迁移方法,并附上最佳实践清单。核心结论是:关键业务推荐RDB+AOF组合,缓存场景可关闭持久化,定

hello.reader 1161

Redis两种持久化方式

Redis两种持久化方式

水w的博客 1976
上一篇: 基于springside4 的app token登录鉴权
下一篇: jvm堆外直接内存实现高性能接入层
ChainCode
ChainCode 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄11年 115粉丝 51原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值