Spring Cloud Finchley版中Consul多實(shí)例注冊(cè)的問(wèn)題處理
由于Spring Cloud對(duì)Etcd的支持一直沒(méi)能從孵化器中出來(lái),所以目前來(lái)說(shuō)大多用戶(hù)還在使用Eureka和Consul,之前又因?yàn)镋ureka 2.0不在開(kāi)源的消息,外加一些博眼球的標(biāo)題黨媒體使得Eureka的用戶(hù)有所減少,所以,相信在選擇Spring Cloud的用戶(hù)群體中,應(yīng)該有不少用戶(hù)會(huì)選擇Consul來(lái)做服務(wù)注冊(cè)與發(fā)現(xiàn)。
本文就來(lái)說(shuō)一下,當(dāng)我們使用Spring Cloud***的Finchley版 + Consul 1.2.x時(shí)候最嚴(yán)重的一個(gè)坑:多實(shí)例注冊(cè)的問(wèn)題。
問(wèn)題解讀
問(wèn)題:該問(wèn)題可能在開(kāi)發(fā)階段不一定會(huì)發(fā)現(xiàn),但是在線(xiàn)上部署多實(shí)例的時(shí)候,將會(huì)發(fā)現(xiàn)Consul中只有一個(gè)實(shí)例。
原因:造成該問(wèn)題的主要原因是Spring Cloud Consul在注冊(cè)的時(shí)候?qū)嵗↖nstanceId)采用了:“服務(wù)名-端口號(hào)”(即:{spring.application.name}-{server.port})的值,可以看到這個(gè)實(shí)例名如果不改變端口號(hào)的情況下,實(shí)例名都是相同的。如果熟悉Spring Cloud Consul的讀者,可能會(huì)問(wèn)老版本也是這個(gè)規(guī)則,怎么沒(méi)有這個(gè)問(wèn)題呢?。主要是由于Consul對(duì)實(shí)例唯一性的判斷標(biāo)準(zhǔn)也有改變,在老版本的Consul中,對(duì)于實(shí)例名相同,但是服務(wù)地址不同,依然會(huì)認(rèn)為是不同的實(shí)例。在Consul 1.2.x中,服務(wù)實(shí)例名成為了集群中的唯一標(biāo)識(shí),所以,也就導(dǎo)致了上述問(wèn)題。
解決方法
既然知道了原因,那么我們要解決它就可以有的放矢了。下面就來(lái)介紹兩個(gè)具體的解決方式:
方法一:通過(guò)配置屬性指定新的規(guī)則
下面舉個(gè)例子,通過(guò)spring.cloud.consul.discovery.instance-id參數(shù)直接來(lái)配置實(shí)例命名規(guī)則。這里比較粗暴的通過(guò)隨機(jī)數(shù)來(lái)一起組織實(shí)例名。當(dāng)然這樣的組織方式并不好,因?yàn)殡S機(jī)數(shù)依然有沖突的可能,所以您還可以用更負(fù)責(zé)的規(guī)則來(lái)進(jìn)行組織實(shí)例名。
- spring.cloud.consul.discovery.instance-id=${spring.application.name}-${random.int[10000,99999]}
方法二:通過(guò)擴(kuò)展ConsulServiceRegistry來(lái)重設(shè)實(shí)例名
由于通過(guò)配置屬性的方式對(duì)于定義實(shí)例名的能力有限,所以我們希望可以用更靈活的方式來(lái)定義。這時(shí)候我們就可以通過(guò)重寫(xiě)ConsulServiceRegistry的register方法來(lái)修改。比如下面的實(shí)現(xiàn):
- public class MyConsulServiceRegistry extends ConsulServiceRegistry {
- public MyConsulServiceRegistry(ConsulClient client, ConsulDiscoveryProperties properties, TtlScheduler ttlScheduler, HeartbeatProperties heartbeatProperties) {
- super(client, properties, ttlScheduler, heartbeatProperties);
- }
- @Override
- public void register(ConsulRegistration reg) {
- reg.getService().setId(reg.getService().getName() + “-” + reg.getService().getAddress() + “-” + reg.getService().getPort());
- super.register(reg);
- }
- }
上面通過(guò)拼接“服務(wù)名”-“ip地址”-“端口號(hào)”的方式,構(gòu)造了一個(gè)絕對(duì)唯一的實(shí)例名,這樣就可以讓每個(gè)服務(wù)實(shí)例都能正確的注冊(cè)到Consul上了。
【本文為51CTO專(zhuān)欄作者“翟永超”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過(guò)51CTO聯(lián)系作者獲取授權(quán)】