springcloud(十三):Eureka 2.X 中止開發,但註冊中心還有更多選擇:Consul 使用詳解

在上個月咱們知道 Eureka 2.X 遇到困難中止開發了,但其實對國內的用戶影響甚小,一方面國內大都使用的是 Eureka 1.X 系列,另外一方面 Spring Cloud 支持不少服務發現的軟件,Eureka 只是其中之一,下面是 Spring Cloud 支持的服務發現軟件以及特性對比:html

Feature euerka Consul zookeeper etcd
服務健康檢查 可配支持 服務狀態,內存,硬盤等 (弱)長鏈接,keepalive 鏈接心跳
多數據中心 支持
kv 存儲服務 支持 支持 支持
一致性 raft paxos raft
cap ap ca cp cp
使用接口(多語言能力) http(sidecar) 支持 http 和 dns 客戶端 http/grpc
watch 支持 支持 long polling/大部分增量 全量/支持long polling 支持 支持 long polling
自身監控 metrics metrics metrics
安全 acl /https acl https 支持(弱)
spring cloud 集成 已支持 已支持 已支持 已支持

在以上服務發現的軟件中,Euerka 和 Consul 使用最爲普遍。若是你們對註冊中心的概念和 Euerka 不太瞭解的話, 能夠參考我前期的文章:springcloud(二):註冊中心Eureka,本篇文章主要給你們介紹 Spring Cloud Consul 的使用。java

Consul 介紹

Consul 是 HashiCorp 公司推出的開源工具,用於實現分佈式系統的服務發現與配置。與其它分佈式服務註冊與發現的方案,Consul 的方案更「一站式」,內置了服務註冊與發現框 架、分佈一致性協議實現、健康檢查、Key/Value 存儲、多數據中心方案,再也不須要依賴其它工具(好比 ZooKeeper 等)。使用起來也較 爲簡單。Consul 使用 Go 語言編寫,所以具備自然可移植性(支持Linux、windows和Mac OS X);安裝包僅包含一個可執行文件,方便部署,與 Docker 等輕量級容器可無縫配合。ios

Consul 的優點:git

  • 使用 Raft 算法來保證一致性, 比複雜的 Paxos 算法更直接. 相比較而言, zookeeper 採用的是 Paxos, 而 etcd 使用的則是 Raft。
  • 支持多數據中心,內外網的服務採用不一樣的端口進行監聽。 多數據中心集羣能夠避免單數據中心的單點故障,而其部署則須要考慮網絡延遲, 分片等狀況等。 zookeeper 和 etcd 均不提供多數據中心功能的支持。
  • 支持健康檢查。 etcd 不提供此功能。
  • 支持 http 和 dns 協議接口。 zookeeper 的集成較爲複雜, etcd 只支持 http 協議。
  • 官方提供 web 管理界面, etcd 無此功能。
  • 綜合比較, Consul 做爲服務註冊和配置管理的新星, 比較值得關注和研究。

特性:github

  • 服務發現
  • 健康檢查
  • Key/Value 存儲
  • 多數據中心

Consul 角色web

  • client: 客戶端, 無狀態, 將 HTTP 和 DNS 接口請求轉發給局域網內的服務端集羣。
  • server: 服務端, 保存配置信息, 高可用集羣, 在局域網內與本地客戶端通信, 經過廣域網與其它數據中心通信。 每一個數據中心的 server 數量推薦爲 3 個或是 5 個。

Consul 客戶端、服務端還支持誇中心的使用,更加提升了它的高可用性。算法

Consul 工做原理:spring

  • 一、當 Producer 啓動的時候,會向 Consul 發送一個 post 請求,告訴 Consul 本身的 IP 和 Port
  • 二、Consul 接收到 Producer 的註冊後,每隔10s(默認)會向 Producer 發送一個健康檢查的請求,檢驗Producer是否健康
  • 三、當 Consumer 發送 GET 方式請求 /api/address 到 Producer 時,會先從 Consul 中拿到一個存儲服務 IP 和 Port 的臨時表,從表中拿到 Producer 的 IP 和 Port 後再發送 GET 方式請求 /api/address
  • 四、該臨時表每隔10s會更新,只包含有經過了健康檢查的 Producer

Spring Cloud Consul 項目是針對 Consul 的服務治理實現。Consul 是一個分佈式高可用的系統,它包含多個組件,可是做爲一個總體,在微服務架構中爲咱們的基礎設施提供服務發現和服務配置的工具。windows

Consul VS Eureka

Eureka 是一個服務發現工具。該體系結構主要是客戶端/服務器,每一個數據中心有一組 Eureka 服務器,一般每一個可用區域一個。一般 Eureka 的客戶使用嵌入式 SDK 來註冊和發現服務。對於非本地集成的客戶,官方提供的 Eureka 一些 REST 操做 API,其它語言可使用這些 API 來實現對 Eureka Server 的操做從而實現一個非 jvm 語言的 Eureka Client。api

Eureka 提供了一個弱一致的服務視圖,儘量的提供服務可用性。當客戶端向服務器註冊時,該服務器將嘗試複製到其它服務器,但不提供保證複製完成。服務註冊的生存時間(TTL)較短,要求客戶端對服務器心跳檢測。不健康的服務或節點中止心跳,致使它們超時並從註冊表中刪除。服務發現能夠路由到註冊的任何服務,因爲心跳檢測機制有時間間隔,可能會致使部分服務不可用。這個簡化的模型容許簡單的羣集管理和高可擴展性。

Consul 提供了一些列特性,包括更豐富的健康檢查,鍵值對存儲以及多數據中心。Consul 須要每一個數據中心都有一套服務,以及每一個客戶端的 agent,相似於使用像 Ribbon 這樣的服務。Consul agent 容許大多數應用程序成爲 Consul 不知情者,經過配置文件執行服務註冊並經過 DNS 或負載平衡器 sidecars 發現。

Consul 提供強大的一致性保證,由於服務器使用 Raft 協議複製狀態 。Consul 支持豐富的健康檢查,包括 TCP,HTTP,Nagios / Sensu 兼容腳本或基於 Eureka 的 TTL。客戶端節點參與基於 Gossip 協議的健康檢查,該檢查分發健康檢查工做,而不像集中式心跳檢測那樣成爲可擴展性挑戰。發現請求被路由到選舉出來的 leader,這使他們默認狀況下強一致性。容許客戶端過期讀取取使任何服務器處理他們的請求,從而實現像 Eureka 這樣的線性可伸縮性。

Consul 強烈的一致性意味着它能夠做爲領導選舉和集羣協調的鎖定服務。Eureka 不提供相似的保證,而且一般須要爲須要執行協調或具備更強一致性需求的服務運行 ZooKeeper。

Consul 提供了支持面向服務的體系結構所需的一系列功能。這包括服務發現,還包括豐富的運行情況檢查,鎖定,密鑰/值,多數據中心聯合,事件系統和 ACL。Consul 和 consul-template 和 envconsul 等工具生態系統都試圖儘可能減小集成所需的應用程序更改,以免須要經過 SDK 進行本地集成。Eureka 是一個更大的 Netflix OSS 套件的一部分,該套件預計應用程序相對均勻且緊密集成。所以 Eureka 只解決了一小部分問題,能夠和 ZooKeeper 等其它工具能夠一塊兒使用。

Consul 強一致性(C)帶來的是:

服務註冊相比 Eureka 會稍慢一些。由於 Consul 的 raft 協議要求必須過半數的節點都寫入成功才認爲註冊成功
Leader 掛掉時,從新選舉期間整個 Consul 不可用。保證了強一致性但犧牲了可用性。

Eureka 保證高可用(A)和最終一致性:

服務註冊相對要快,由於不須要等註冊信息 replicate 到其它節點,也不保證註冊信息是否 replicate 成功
當數據出現不一致時,雖然 A, B 上的註冊信息不徹底相同,但每一個 Eureka 節點依然可以正常對外提供服務,這會出現查詢服務信息時若是請求 A 查不到,但請求 B 就能查到。如此保證了可用性但犧牲了一致性。

其它方面,eureka 就是個 servlet 程序,跑在 servlet 容器中; Consul 則是 go 編寫而成。

Consul 安裝

Consul 不一樣於 Eureka 須要單獨安裝,訪問Consul 官網下載 Consul 的最新版本,我這裏是 consul_1.2.1。

根據不一樣的系統類型選擇不一樣的安裝包,從下圖也能夠看出 Consul 支持全部主流系統。

我這裏以 Windows 爲例,下載下來是一個 consul_1.2.1_windows_amd64.zip 的壓縮包,解壓是是一個 consul.exe 的執行文件。

cd 到對應的目錄下,使用 cmd 啓動 Consul

cd D:\Common Files\consul
#cmd啓動:
consul agent -dev        # -dev表示開發模式運行,另外還有-server表示服務模式運行

爲了方便期間,能夠在同級目錄下建立一個 run.bat 腳原本啓動,腳本內容以下:

consul agent -dev
pause

啓動結果以下:

啓動成功以後訪問:http://localhost:8500,能夠看到 Consul 的管理界面

這樣就意味着咱們的 Consul 服務啓動成功了。

Consul 服務端

接下來咱們開發 Consul 的服務端,咱們建立一個 spring-cloud-consul-producer 項目

添加依賴包

依賴包以下:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
  • spring-boot-starter-actuator 健康檢查依賴於此包。
  • spring-cloud-starter-consul-discovery Spring Cloud Consul 的支持。

Spring Boot 版本使用的是 2.0.3.RELEASE,Spring Cloud 最新版本是 Finchley.RELEASE 依賴於 Spring Boot 2.x.

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

完整的 pom.xml 文件你們能夠參考示例源碼。

配置文件

配置文件內容以下

spring.application.name=spring-cloud-consul-producer
server.port=8501
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
#註冊到consul的服務名稱
spring.cloud.consul.discovery.serviceName=service-producer

Consul 的地址和端口號默認是 localhost:8500 ,若是不是這個地址能夠自行配置。
spring.cloud.consul.discovery.serviceName 是指註冊到 Consul 的服務名稱,後期客戶端會根據這個名稱來進行服務調用。

啓動類

@SpringBootApplication
@EnableDiscoveryClient
public class ConsulProducerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsulProducerApplication.class, args);
    }
}

添加了 @EnableDiscoveryClient 註解表示支持服務發現。

提供服務

咱們在建立一個 Controller,推文提供 hello 的服務。

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello() {
        return "helle consul";
    }
}

爲了模擬註冊均衡負載複製一份上面的項目重命名爲 spring-cloud-consul-producer-2 ,修改對應的端口爲 8502,修改 hello 方法的返回值爲:"helle consul two",修改完成後依次啓動兩個項目。

這時候咱們再次在瀏覽器訪問地址:http://localhost:8500,顯示以下:

咱們發現頁面多了 service-producer 服務,點擊進去後頁面顯示有兩個服務提供者:

這樣服務提供者就準備好了。

Consul 消費端

咱們建立一個 spring-cloud-consul-consumer 項目,pom 文件和上面示例保持一致。

配置文件

配置文件內容以下

spring.application.name=spring-cloud-consul-consumer
server.port=8503
spring.cloud.consul.host=127.0.0.1
spring.cloud.consul.port=8500
#設置不須要註冊到 consul 中
spring.cloud.consul.discovery.register=false

客戶端能夠設置註冊到 Consul 中,也能夠不註冊到 Consul 註冊中心中,根據咱們的業務來選擇,只須要在使用服務時經過 Consul 對外提供的接口獲取服務信息便可。

啓動類

@SpringBootApplication
public class ConsulConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsulConsumerApplication.class, args);
    }
}

進行測試

咱們先來建立一個 ServiceController ,試試若是去獲取 Consul 中的服務。

@RestController
public class ServiceController {

    @Autowired
    private LoadBalancerClient loadBalancer;
    @Autowired
    private DiscoveryClient discoveryClient;

   /**
     * 獲取全部服務
     */
    @RequestMapping("/services")
    public Object services() {
        return discoveryClient.getInstances("service-producer");
    }

    /**
     * 從全部服務中選擇一個服務(輪詢)
     */
    @RequestMapping("/discover")
    public Object discover() {
        return loadBalancer.choose("service-producer").getUri().toString();
    }
}

Controller 中有倆個方法,一個是獲取全部服務名爲service-producer的服務信息並返回到頁面,一個是隨機從服務名爲service-producer的服務中獲取一個並返回到頁面。

添加完 ServiceController 以後咱們啓動項目,訪問地址:http://localhost:8503/services,返回:

[{"serviceId":"service-producer","host":"windows10.microdone.cn","port":8501,"secure":false,"metadata":{"secure":"false"},"uri":"http://windows10.microdone.cn:8501","scheme":null},{"serviceId":"service-producer","host":"windows10.microdone.cn","port":8502,"secure":false,"metadata":{"secure":"false"},"uri":"http://windows10.microdone.cn:8502","scheme":null}]

發現咱們剛纔建立的端口爲 8501 和 8502 的兩個服務端都存在。

屢次訪問地址:http://localhost:8503/discover,頁面會交替返回下面信息:

http://windows10.microdone.cn:8501
http://windows10.microdone.cn:8502
...

說明 8501 和 8501 的兩個服務會交替出現,從而實現了獲取服務端地址的均衡負載。

大多數狀況下咱們但願使用均衡負載的形式去獲取服務端提供的服務,所以使用第二種方法來模擬調用服務端提供的 hello 方法。

建立 CallHelloController :

@RestController
public class CallHelloController {

    @Autowired
    private LoadBalancerClient loadBalancer;

    @RequestMapping("/call")
    public String call() {
        ServiceInstance serviceInstance = loadBalancer.choose("service-producer");
        System.out.println("服務地址:" + serviceInstance.getUri());
        System.out.println("服務名稱:" + serviceInstance.getServiceId());

        String callServiceResult = new RestTemplate().getForObject(serviceInstance.getUri().toString() + "/hello", String.class);
        System.out.println(callServiceResult);
        return callServiceResult;
    }

}

使用 RestTemplate 進行遠程調用。添加完以後重啓 spring-cloud-consul-consumer 項目。在瀏覽器中訪問地址:http://localhost:8503/call,依次返回結果以下:

helle consul
helle consul two
...

說明咱們已經成功的調用了 Consul 服務端提供的服務,而且實現了服務端的均衡負載功能。經過今天的實踐咱們發現 Consul 提供的服務發現易用、強大。

示例代碼-github

示例代碼-碼雲

相關文章
相關標籤/搜索