Spring-Cloud服务在Consul中的异常注册
[原创]个人理解,请批判接受,有误请指正。转载请注明出处: https://heyfl.gitee.io/Bug-Log-Optimization/bug_in_spring-cloud_instance_registered_with_consul.html
优雅停机脚本见: shell-系统优雅停机
背景
公司实现微服务化并原来使用的Dubbo+Zookeeper实现应用间的服务调用,考虑到Dubbo不在维护最近想要切换为Spring Cloud+Consul
环境
- Spring Cloud: Edgware.SR3
- Spring-boot: 1.5.13.RELEASE
1 | <parent> |
根据网上流传的博客我们使用的配置为:
1 | spring.cloud.consul.discovery.instance-id=${spring.application.name}-${server.port} |
也就是【服务名】+【端口】的形式来标识Consul上的一个服务
1. 第一个问题
已注册上Consul的服务被后启动的提供者覆盖(采用【服务名】+【端口】的形式)
在我们实际开发测试时候发现 无论服务起了多少个实例,最终展示到Consul都只有一个 :
怀疑是Consul以【服务名】+【端口】为实例的唯一标示,导致【后起来的服务】覆盖掉【原来已经注册到Consul上的服务】了 ,我们通过Feign调用时发现也确实是如此
1.1. Kill 第一个问题
上Spring官方文档轻松找到解决方案(有问题还是官方文档好)
1 | ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}} |
原理就是每次启动时注册的实例ID都为【服务名】+【随机数】:
通过这种形式,可以让每一个服务提供者(实例)都有效地注册到Consul上,并且Consul上的每一个Instance都能唯一映射到每一个提供者上2. 第二、第三个问题
2.1. 服务器通过Kill -9的重启脚本快速重启导致一个提供者在Consul上注册了多次(Consul注册的实例
数>实际提供者
数)
首先,我们要知道当系统执行
kill-9命令的时候会立马强制关闭该进程,程序很可能正在处理请求中,同时也占用了一些的资源,本来需要做一些善后才能正常、安全的结束,但是你一个
kill-9命令过来,程序就措手不及了。
结合上述情况,实际上程序非正常重启,已经注册在consul上的服务没有被反注册,服务重新启动之后又重新的注册了一个新的服务上去了(而且重启后以前的服务在Consul心跳机制下海认为是可用的),一个服务就在Consul注册了多次了
这种情况可以修改重启脚本解决:
通过Kill -15直接关闭提供者进程 可以参考这篇文章
2.2. 【服务名】+【随机数】的InstanceID不能提供足够信息帮助我们快速定位问题
上面的方案可以解决我们遇到的问题,但是有一点不足的是,Consul上看到的InstanceID都是【服务名】+【随机数】,随机数没有可读性可言,
我们压根不能根据这个InstanceID一眼看出的它的服务提供者是谁。不便于我们排查问题
进一步优化
其实最好就是使用【服务名】+【机器IP】+【端口】的形式,这样既能通过唯一标示服务提供者解决 Consul服务被覆盖的问题
也能方便我们运维开发时快速知道当前服务的提供者列表,快速定位问题
最终方案
1 | spring.cloud.consul.discovery.instance-id=${spring.application.name}:${spring.cloud.client.ipAddress}:${server.port} |
Spring-Cloud服务在Consul中的异常注册
https://heyfl.gitee.io/Bug-Log-Optimization/bug_in_spring-cloud_instance_registered_with_consul.html