consul重启导致服务必须跟着重启解决方案

2023-11-06

问题:consul作为注册中心和eureka的机制不同。

当微服务启动后首先向注册中心发注册请求,这点两者一致。之后consul在维护可用服务列表时,采用的是主动向微服务发健康检查的接口(也可以配置成微服务主动向consul发心跳,但是我看完官网和各类文章都没说清楚具体怎么搞)。如果微服务正常返回,那么就认为服务正常。eureka是等待微服务主动向eureka发心跳,eureka收到心跳后,就给这个服务续约,认为服务是正常的。

正是因为这点差异就产生了大问题!

场景一:consul和微服务间的网络不稳定,断开了几分钟。

在此情况下,consul向微服务发的健康检查请求发不通,认为微服务挂了,就从服务列表里剔除他。

当网络恢复后,注意,已经剔除的服务,consul是不会主动再发健康检查的。那么服务列表里没有他,

也就不正常了。网关的转发都是需要获取可用服务列表,才能做转发的!

这时候,你想让微服务注册上consul就只能重启微服务了。这在生产环境意味着什么就不用多说了吧。

是不是很坑?

 

场景二:consul因为某种情况需要重启。(可能是consul也需要投产,或者其他原因,总之就是需要重启consul)

这个场景和上面的类似。当consul重启后,之前已经注册上来的,状态正常的服务,consul忘记了。

因为他重启了,他不记得前世的服务列表。

所以这种情况下,也需要重启我们的微服务,才能使状态正常。

 

综上,因为consul的健康检查机制是consul主动发,跟eureka不同才导致这种问题。

问题很清楚了,要怎么解决呢?

我查了很多资料,除了consul可以用ttl的方式,让微服务主动发心跳来续约外,好像没有想成的方案。

但是这个ttl的方案,官网没仔细说,网上的文章也是一大抄,没人说的明白。

我经过研究后,发现consul提供了好多rest接口。可以通过接口注册,注销,查询等。

那么我们就可以仿照eureka的方式,主动查consul的服务列表,类似心跳。

如果没查到,或者发不通(consul挂了)那么久开始发注册的接口,把自己注册上去。

不停的发,直至成功。

 

我用2个服务来模拟,一个是springcloudgateway网关gate,一个是微服务one

在应用启动后起一个定时任务:

package com.example.one.init;


import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
//CommandLineRunner ApplicationRunner


@Component
public class InitRunner implements ApplicationRunner {
        private static final Logger logger = LoggerFactory.getLogger(InitRunner.class);

        
        @Value("${spring.cloud.consul.host}")
    	private String consulip;
        
        @Value("${spring.cloud.consul.port}")
    	private String consulport;
        
    	@Value("${spring.cloud.client.ip-address}")
    	private String ip;
    
    	@Value("${spring.application.name}")
    	private String servername;
    
    	@Value("${server.port}")
    	private String port;
    	
    	@Value("${my.consul.check.register:false}")
    	private String registerFlag;//检查服务在consul列表不存在,或者consul访问不通,就不停的注册自己。保证consul因为网络不稳定或者重启,服务不正常。(微服务只有在启动是会注册自己,这样做是为了不重启服务)
        
    	@Value("${my.consul.check.interval:10}")
    	private String interval;//检查服务在consul中是否正常的频率,每interval秒检查一次
    	
    	private long intervalNum=10;//interval转成long类型
    	
        public long getIntervalNum() {
        	if(interval!=null) {
        		try {
        			intervalNum = Long.valueOf(interval.trim());
				} catch (NumberFormatException e) {
					intervalNum=10;
					e.printStackTrace();
				}
        	}
			return intervalNum;
		}
		public void setIntervalNum(long intervalNum) {
			this.intervalNum = intervalNum;
		}
		
		public String getRegisterFlag() {
        	//保证只有2个值
        	if(registerFlag!=null && registerFlag.trim().equals("true")) {
        		return "true";
        	}
			return "false";
		}


		public void setRegisterFlag(String registerFlag) {
			this.registerFlag = registerFlag;
		}


		@Autowired
    	private RestTemplate restTemplate;
//        @Autowired
//        private DbRouteDefinitionRepository dbRouteDefinitionRepository;

        public RestTemplate getRestTemplate() {
			return restTemplate;
		}


		public void setRestTemplate(RestTemplate restTemplate) {
			this.restTemplate = restTemplate;
		}


        @Override
        public void run(ApplicationArguments args) throws Exception {
        	DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        	String dateStr=LocalDateTime.now().format(df);
        	String serverInfo="["+servername+":"+ip+":"+port+"]";
        	
        	System.out.println(serverInfo+",InitRunner初始化逻辑。。。");
        	
        	/
        	
//          LocalDateTime startTime = LocalDateTime.now();
    		String message=serverInfo;
    		
    		//gate-192-168-124-17-8888
    		String defalutConsulId=servername+"-"+ip.replace(".", "-")+"-"+port;
    		
//    		long interVal=10;
        	ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
        	scheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
        	    @Override
        	    public void run() {
        	    	if(getRegisterFlag().equals("false")) {
        	    		logger.info("InitRunner consul检查纠正服务开关未开启,不执行检查纠错服务。。。。。");
        	    		return;
        	    	}
        	    	try {
        	    		logger.info("InitRunner 执行consul检查纠正服务"+serverInfo+"。。。delay "+getIntervalNum()+" seconds...");
            	    	
            	    	//查询consul的已经注册的服务列表
            	    	String consulQueryUrl="http://"+consulip+":"+consulport+"/v1/agent/services";
            	    	String consulRegisterUrl="http://"+consulip+":"+consulport+"/v1/agent/service/register";
            	    	
//            	    	getRestTemplate().getForObject(url, responseType, uriVariables)
            	        HttpHeaders headers = new HttpHeaders();
            	        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
            	        HttpEntity<String> entity = new HttpEntity<String>(headers);
//            	        String strbody=restTemplate.exchange(consulUrl, HttpMethod.GET, entity,String.class).getBody();
//            	        Map responseData=restTemplate.exchange(consulUrl, HttpMethod.GET, entity,Map.class).getBody();
            	        
            	        ResponseEntity<Map> responseEntity=restTemplate.exchange(consulQueryUrl, HttpMethod.GET, entity,Map.class);
            	        Map responseData = responseEntity.getBody();
            	        
            	        boolean isExistSelf=false;//是否能从consul查到自己的信息。查不到说明自己没注册上或者被注销了,需要主动注册。
            	        if(responseData!=null) {
            	        	logger.info("InitRunner 执行consul检查纠正服务。。。返回 :\r\n"+responseData.toString());
            	        	
            	        	Iterator it= responseData.keySet().iterator();
            	        	while(it.hasNext()) {
            	        		String key= (String) it.next();
            	        		Map instance = (Map) responseData.get(key);
            	        		if(instance!=null) {
                	        		String Service =(String) instance.get("Service");
                	        		String Address =(String) instance.get("Address");
                	        		String Port =null;
                	        		if(instance.get("Port")!=null) {
                	        			Port =""+ instance.get("Port");
                	        		}
                	        		String ID =(String) instance.get("ID");
                	        		
                	        		if(Service.equalsIgnoreCase(servername) && Address.equals(ip) && Port.equals(port)) {
                	        			logger.info("InitRunner 执行consul检查纠正服务,找到本实例的ID==="+
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

consul重启导致服务必须跟着重启解决方案 的相关文章

随机推荐

  • MinGW和 MinGW-W64的区别

    部分参照备忘录原文 bitbucket org FrankHB yslib src 50c3e6344a5a24b2382ce3398065f2197c2bd57e doc Workflow Annual2014 txt at master
  • 使用R语言进行柱状图可视化特征的种类和个数

    使用R语言进行柱状图可视化特征的种类和个数 柱状图是一种常用的数据可视化工具 用于展示变量 特征 的种类及其数量 通过柱状图 我们可以更直观地了解数据的分布情况和特征之间的差异 在R语言中 我们可以使用多种方法来创建柱状图 并对特征种类和个
  • 使用Excel实现数据驱动测试

    文章目录 1 概述 2 xlrd 3 openpyxl 4 pandas 5 如何在excel表格中描述多个用例 5 1 制定解析规则 5 2 创建测试用例 1 概述 测试类型 本质 数据类型 接口测试 数据流动和验证 csvyamljso
  • RTX2080ti配置tensorflow gpu版

    tensorflow gpu配置 昨晚搞到1点 终于把tensorflow gpu给配置成功了 之前是交给一位朋友搞的 我也懒得弄 结果还是没搞定 秉着万事靠自己的态度 终于 一边下军旗 一边配置成功了 首先 讲讲我个人的电脑配置 E3 1
  • 有关‘全局唯一id‘

    UUID和Snowflake的对比 当需保证全局唯一的id 可以选用UUID或Snowflake 及其变种 其中UUID 不依赖于任何第三方系统 性能和可用性上较好 Snowflake生成的id具有单调递增性 可以拿到生成时的时间戳信息 能
  • MySQL高级增删改查

    新增数据 基本语法 insert into 表名 字段列表 values 值列表 主键冲突 更新和替换 主键冲突 更新操作 insert into 表名 字段列表 包含主键 values 值列表 on duplicate key updat
  • SqlServer数据库版本不一致使用DROP TABLE IF EXISTS语法报错

    SqlServer数据库版本不一致使用DROP TABLE IF EXISTS语法报错 在SqlServer2016版本及更高版本 建表前判断表是否存在 可以使用 DROP TABLE IF EXISTS sysuser 低版本的SqlSe
  • linux启动停留时间,Ubuntu 16.04 启动长时间停留在紫屏状态

    Ubuntu 16 04 启动长时间停留在紫屏状态 1 Ubuntu 16 04 启动长时间停留在紫屏状态 2 Advanced options for Ubuntu 3 Ubuntu with Linux 4 10 0 28 generi
  • Framework工具——EA画图

    EA 是一个著名的企业架构 Enterprise Architecture 工具 用于绘制和管理企业的架构图和过程模型 该工具提供了多种功能 包括建立业务流程图 数据流图 组织结构图 应用架构图等 EA工具可帮助企业进行战略规划 业务流程改
  • Redis过期监听—订单超时-取消

    最近在做电商项目 涉及支付超时处理的几种方式 记录哈使用redis监听处理 提交订单的时候 支付 超过了有效时间则支付状态自动更新为已取消 redis过期监听的实现 1 修改redis windows conf配置文件中notify key
  • OpenBSD cvsup更新

    安装了 OpenBSD 后你会发现它很小个 只有500多M 当然里面只有ssh sendmail功能 dev wd0a 130M 38 8M 84 7M 31 dev wd0h 95 5G 16 0K 90 8G 0 home dev wd
  • vue2.0解决el-table无限滚动解决数据量大前端界面渲染耗时或卡顿问题

    vue相关依赖版本 name vue demo version 0 1 0 private true scripts serve vue cli service serve build vue cli service build lint
  • input元素的事件的触发顺序及change事件触发条件

    1 input元素的事件触发顺序
  • Ubuntu学习笔记:配置账户密码使用期限

    Ubuntu学习笔记 配置账户密码使用期限 配置账户密码最短使用期限为 10天 最长使用期限为 90 天 查看的方式还可以是 sudo passwd S liu
  • SpringBoot使用ShedLock调度任务

    前言 在分布式的场景下 SpringBoot程序以集群的方式部署 这些程序中运行着相同的代码 如果其中有定时任务的话 所有的程序都会运行该任务 这样就会导致任务的重复执行 由于所有的定时任务在集群的不同节点值中 所以需要一个专属的数据存储空
  • GCC编译选项参数

    linux系统下头文件 库文件搜索路径总结 文章目录 一 头文件 1 1 gcc或g 找头文件有三种策略 二 库文件 2 1 编译时查找库文件路径 2 2 运行时查找动态库文件路径 2 3 动态库的搜索路径搜索的先后顺序 一 头文件 1 1
  • java类静态实例成员_java中 静态成员、实例成员、构造方法在子类和父类中的执行顺序...

    java中的成员分为 静态成员 静态成员变量 静态代码块 静态成员方法 实例成员 实例成员变量 实例代码块 实例成员方法 构造方法 析构方法 下面做的实验 主要是验证 当new 一个子类时 子类和它的父类中 静态成员变量 静态代码块 实例成
  • jar还原源码

    上周接到个新任务 一个遗留的接口工程需要改造 然而根据前任开发留下的文档看 这个工程没有代码 只有生产环境的jar包供使用 边吐 咒 槽 骂 边在SVN服务器上四处翻找 想找到这个工程的源码 毕竟没源码怎么跑起来这个工程 不能跑起来怎么改造
  • 导致服务器CPU跑满的原因有哪些

    一 硬件原因 服务器CPU自身出现问题 比如机房散热不足 温度过热或者驱动故障 导致CPU性能下降 很容易造成CPU跑满的情况 二 网站代码错误 排查硬件原因后 我们进入网站后台查看是哪些程序占用了大量CPU 检测这些代码自身是否有问题 如
  • consul重启导致服务必须跟着重启解决方案

    问题 consul作为注册中心和eureka的机制不同 当微服务启动后首先向注册中心发注册请求 这点两者一致 之后consul在维护可用服务列表时 采用的是主动向微服务发健康检查的接口 也可以配置成微服务主动向consul发心跳 但是我看完