天天看點

Spring Cloud Finchley版中Consul多執行個體注冊的問題處理

由于Spring Cloud對Etcd的支援一直沒能從孵化器中出來,是以目前來說大多使用者還在使用Eureka和Consul,之前又因為Eureka 2.0不在開源的消息,外加一些博眼球的标題黨媒體使得Eureka的使用者有所減少,是以,相信在選擇Spring Cloud的使用者群體中,應該有不少使用者會選擇Consul來做服務注冊與發現。

本文就來說一下,當我們使用Spring Cloud最新的Finchley版 + Consul 1.2.x時候最嚴重的一個坑:多執行個體注冊的問題。

https://blog.didispace.com/Spring-Cloud-Finchley-Consul-InstanceId/#%E9%97%AE%E9%A2%98%E8%A7%A3%E8%AF%BB 問題解讀

問題:該問題可能在開發階段不一定會發現,但是線上上部署多執行個體的時候,将會發現Consul中隻有一個執行個體。

原因:造成該問題的主要原因是Spring Cloud Consul在注冊的時候執行個體名(InstanceId)采用了:“服務名-端口号”(即:

{spring.application.name}-{server.port}

)的值,可以看到這個執行個體名如果不改變端口号的情況下,執行個體名都是相同的。如果熟悉Spring Cloud Consul的讀者,可能會問老版本也是這個規則,怎麼沒有這個問題呢?。主要是由于Consul對執行個體唯一性的判斷标準也有改變,在老版本的Consul中,對于執行個體名相同,但是服務位址不同,依然會認為是不同的執行個體。在Consul 1.2.x中,服務執行個體名成為了叢集中的唯一辨別,是以,也就導緻了上述問題。

https://blog.didispace.com/Spring-Cloud-Finchley-Consul-InstanceId/#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95 解決方法

既然知道了原因,那麼我們要解決它就可以有的放矢了。下面就來介紹兩個具體的解決方式:

方法一:通過配置屬性指定新的規則

下面舉個例子,通過

spring.cloud.consul.discovery.instance-id

參數直接來配置執行個體命名規則。這裡比較粗暴的通過随機數來一起組織執行個體名。當然這樣的組織方式并不好,因為随機數依然有沖突的可能,是以您還可以用更負責的規則來進行組織執行個體名。

spring.cloud.consul.discovery.instance-id=${spring.application.name}-${random.int[10000,99999]}      

方法二:通過擴充

ConsulServiceRegistry

來重設執行個體名

由于通過配置屬性的方式對于定義執行個體名的能力有限,是以我們希望可以用更靈活的方式來定義。這時候我們就可以通過重寫

ConsulServiceRegistry

register

方法來修改。比如下面的實作:

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);
    }

}      

上面通過拼接“服務名”-“ip位址”-“端口号”的方式,構造了一個絕對唯一的執行個體名,這樣就可以讓每個服務執行個體都能正确的注冊到Consul上了。