当前位置: 首页 > 科技观察

SpringCloudFinchley版本Consul多实例注册问题的处理

时间:2023-03-12 17:01:22 科技观察

由于SpringCloud对Etcd的支持还没有从孵化器中放出来,所以目前大部分用户还在使用Eureka和Consul,因为之前Eureka2.0还没有开源新闻和一些抢眼的标题党媒体减少了Eureka的用户数。因此,我相信在选择SpringCloud的用户群体中,应该有很多用户会选择Consul来进行服务注册和发现。本文将谈谈我们在使用Finchley版SpringCloud***+Consul1.2.x时最严重的坑:多实例注册的问题。问题解读:开发阶段不一定会发现这个问题,但是在线部署多个实例时,会发现Consul中只有一个实例。原因:出现这个问题的主要原因是SpringCloudConsul的实例名(InstanceId)在注册时使用了“服务名-端口号”(即:{spring.application.name}-{server.port})的值,可以看到如果实例名没有改变端口号,那么实例名是一样的。如果熟悉SpringCloudConsul的读者可能会问,老版本也有这个规则,为什么没有这个问题呢?.主要原因是Consul判断实例唯一性的标准也变了。在旧版本的Consul中,实例名相同但服务地址不同的实例仍然会被认为是不同的实例。在Consul1.2.x中,服务实例名成为了集群中的唯一标识,因此,也导致了上述问题。解决方案既然知道了原因,那我们就可以有针对性的去解决了。下面给出两种具体的解决方案:方法一:通过配置属性指定新的规则。下面以直接通过spring.cloud.consul.discovery.instance-id参数配置实例命名规则为例。这里粗略地使用随机数将实例名称组织在一起。当然这种组织方式不好,因为随机数还是有冲突的可能,所以可以用更负责的规则来组织实例名。spring.cloud.consul.discovery.instance-id=${spring.application.name}-${random.int[10000,99999]}方法二:通过扩展ConsulServiceRegistry重置实例名。定义实例名称的能力是有限的,所以我们希望我们可以以更灵活的方式定义它们。Atthistime,wecanmodifyitbyrewritingtheregistermethodofConsulServiceRegistry.比如下面的实现:publicclassMyConsulServiceRegistryextendsConsulServiceRegistry{publicMyConsulServiceRegistry(ConsulClientclient,ConsulDiscoveryPropertiesproperties,TtlSchedulerttlScheduler,HeartbeatPropertiesheartbeatProperties){super(client,properties,ttlScheduler,heartbeatProperties);}@Overridepublicvoidregister(ConsulRegistrationreg){reg.getService().setId(reg.getService().getName()+"-"+reg.getService().getAddress()+"-"+reg.getService().getPort());super.register(reg);}}上面通过拼接“服务名”-“ip地址”-“端口号”的方法构造了一个绝对唯一的实例名,从而使每个服务实例都能正确注册到Consul。【本文为专栏作家“翟永超”原创稿件,转载请联系作者获得授权】点此查看该作者更多好文