Spring Cloud Consul 之Greenwich版本全攻略

方誌朋發表於2019-02-14

什麼是Consul

Consul是HashiCorp公司推出的開源軟體,使用GO語言編寫,提供了分散式系統的服務註冊和發現、配置等功能,這些功能中的每一個都可以根據需要單獨使用,也可以一起使用以構建全方位的服務網格。Consul不僅具有服務治理的功能,而且使用分散式一致協議RAFT演算法實現,有多資料中心的高可用方案,並且很容易和Spring Cloud等微服務框架整合,使用起來非常的簡單,具有簡單、易用、可插排等特點。使用簡而言之,Consul提供了一種完整的服務網格解決方案 。

Consul具有以下的特點和功能

  • 服務發現:Consul的客戶端可以向Consul註冊服務,例如api服務或者mysql服務,其他客戶端可以使用Consul來發現服務的提供者。Consul支援使用DNS或HTTP來註冊和發現服務。
  • 執行時健康檢查:Consul客戶端可以提供任意數量的執行狀況檢查機制,這些檢查機制可以是給定服務(“是Web伺服器返回200 OK”)或本地節點(“記憶體利用率低於90%”)相關聯。這些資訊可以用來監控群集的執行狀況,服務發現元件可以使用這些監控資訊來路由流量,可以使流量遠離不健康的服務。
  • KV儲存:應用程式可以將Consul的鍵/值儲存用於任何需求,包括動態配置,功能標記,協調,領導者選舉等。它採用HTTP API使其易於使用。
  • 安全服務通訊:Consul可以為服務生成和分發TLS證照,以建立相互的TLS連線。
  • 多資料中心:Consul支援多個資料中心。這意味著Consul的使用者不必擔心構建額外的抽象層以擴充套件到多個區域。

Consul原理

每個提供服務的節點都執行了Consul的代理,執行代理不需要服務發現和獲取配置的KV鍵值對,代理只負責監控檢查。代理節點可以和一個或者多個Consul server通訊。 Consul伺服器是儲存和複製資料的地方。伺服器本身選出了領導者。雖然Consul可以在一臺伺服器上執行,但建議使用3到5,以避免導致資料丟失的故障情況。建議為每個資料中心使用一組Consul伺服器。 如果你的元件需要發現服務,可以查詢任何Consul Server或任何Consul客戶端,Consul客戶端會自動將查詢轉發給Consul Server。 需要發現其他服務或節點的基礎架構元件可以查詢任何Consul伺服器或任何Consul代理。代理會自動將查詢轉發給伺服器。每個資料中心都執行Consul伺服器叢集。發生跨資料中心服務發現或配置請求時,本地Consul伺服器會將請求轉發到遠端資料中心並返回結果。

術語

  • Agent agent是一直執行在Consul叢集中每個成員上的守護程式。通過執行 consul agent 來啟動。agent可以執行在client或者server模式。指定節點作為client或者server是非常簡單的,除非有其他agent例項。所有的agent都能執行DNS或者HTTP介面,並負責執行時檢查和保持服務同步。
  • Client 一個Client是一個轉發所有RPC到server的代理。這個client是相對無狀態的。client唯一執行的後臺活動是加入LAN gossip池。這有一個最低的資源開銷並且僅消耗少量的網路頻寬。
  • Server 一個server是一個有一組擴充套件功能的代理,這些功能包括參與Raft選舉,維護叢集狀態,響應RPC查詢,與其他資料中心互動WAN gossip和轉發查詢給leader或者遠端資料中心。
  • DataCenter 雖然資料中心的定義是顯而易見的,但是有一些細微的細節必須考慮。例如,在EC2中,多個可用區域被認為組成一個資料中心?我們定義資料中心為一個私有的,低延遲和高頻寬的一個網路環境。這不包括訪問公共網路,但是對於我們而言,同一個EC2中的多個可用區域可以被認為是一個資料中心的一部分。
  • Consensus 在我們的文件中,我們使用Consensus來表明就leader選舉和事務的順序達成一致。由於這些事務都被應用到有限狀態機上,Consensus暗示複製狀態機的一致性。
  • Gossip Consul建立在Serf的基礎之上,它提供了一個用於多播目的的完整的gossip協議。Serf提供成員關係,故障檢測和事件廣播。更多的資訊在gossip文件中描述。這足以知道gossip使用基於UDP的隨機的點到點通訊。
  • LAN Gossip 它包含所有位於同一個區域網或者資料中心的所有節點。
  • WAN Gossip 它只包含Server。這些server主要分佈在不同的資料中心並且通常通過因特網或者廣域網通訊。
  • RPC 遠端過程呼叫。這是一個允許client請求server的請求/響應機制。

image

讓我們分解這張圖並描述每個部分。首先,我們能看到有兩個資料中心,標記為“1”和“2”。Consul對多資料中心有一流的支援並且希望這是一個常見的情況。

在每個資料中心,client和server是混合的。一般建議有3-5臺server。這是基於有故障情況下的可用性和效能之間的權衡結果,因為越多的機器加入達成共識越慢。然而,並不限制client的數量,它們可以很容易的擴充套件到數千或者數萬臺。

同一個資料中心的所有節點都必須加入gossip協議。這意味著gossip協議包含一個給定資料中心的所有節點。這服務於幾個目的:第一,不需要在client上配置server地址。發現都是自動完成的。第二,檢測節點故障的工作不是放在server上,而是分散式的。這是的故障檢測相比心跳機制有更高的可擴充套件性。第三:它用來作為一個訊息層來通知事件,比如leader選舉發生時。

每個資料中心的server都是Raft節點集合的一部分。這意味著它們一起工作並選出一個leader,一個有額外工作的server。leader負責處理所有的查詢和事務。作為一致性協議的一部分,事務也必須被複制到所有其他的節點。因為這一要求,當一個非leader得server收到一個RPC請求時,它將請求轉發給叢集leader。

server節點也作為WAN gossip Pool的一部分。這個Pool不同於LAN Pool,因為它是為了優化網際網路更高的延遲,並且它只包含其他Consul server節點。這個Pool的目的是為了允許資料中心能夠以low-touch的方式發現彼此。這使得一個新的資料中心可以很容易的加入現存的WAN gossip。因為server都執行在這個pool中,它也支援跨資料中心請求。當一個server收到來自另一個資料中心的請求時,它隨即轉發給正確資料中想一個server。該server再轉發給本地leader。

這使得資料中心之間只有一個很低的耦合,但是由於故障檢測,連線快取和複用,跨資料中心的請求都是相對快速和可靠的。

Consul 服務註冊發現流程

Consul在業界最廣泛的用途就是作為服務註冊中心,同Eureka型別,consul作為服務註冊中心,它的註冊和發現過程如下圖:

31.png

在上面的流程圖上有三個角色,分別為服務註冊中心、服務提供者、服務消費者。

  • 服務提供者Provider啟動的時候,會向Consul傳送一個請求,將自己的host、ip、應用名、健康檢查等後設資料資訊傳送給Consul
  • Consul 接收到 Provider 的註冊後,定期向 Provider 傳送健康檢查的請求,檢驗Provider是否健康
  • 服務消費者Consumer會從註冊中心Consul中獲取服務註冊列表,當服務消費者消費服務時,根據應用名從服務註冊列表獲取到具體服務的例項(1個或者多個),從而完成服務的呼叫。

Consul VS Eureka

Eureka是一種服務發現工具。 該體系結構主要是客戶端/伺服器,每個資料中心有一組Eureka伺服器,通常每個可用區域一個。 通常,Eureka的客戶使用嵌入式SDK來註冊和發現服務。 對於非本地整合的客戶端,使用Ribbon等邊車通過Eureka透明地發現服務。

Eureka使用盡力而為的複製提供弱一致的服務檢視。 當客戶端向伺服器註冊時,該伺服器將嘗試複製到其他伺服器但不提供保證。 服務註冊的生存時間很短(TTL),要求客戶端對伺服器進行心跳檢測。 不健康的服務或節點將停止心跳,導致它們超時並從登錄檔中刪除。 發現請求可以路由到任何服務,由於盡力複製,這些服務可以提供過時或丟失的資料。 這種簡化的模型允許輕鬆的叢集管理和高可擴充套件性。

Consul提供了一系列超級功能,包括更豐富的執行狀況檢查,鍵/值儲存和多資料中心感知。 Consul需要每個資料中心中的一組伺服器,以及每個客戶端上的代理,類似於使用像Ribbon這樣的邊車。 Consul代理允許大多數應用程式不知道Consul,通過配置檔案執行服務註冊以及通過DNS或負載平衡器sidecars進行發現。

Consul提供強大的一致性保證,因為伺服器使用Raft協議複製狀態。 Consul支援豐富的執行狀況檢查,包括TCP,HTTP,Nagios / Sensu相容指令碼或基於的Eureka的TTL。 客戶端節點參與基於gossip的健康檢查,該檢查分發健康檢查的工作,而不像集中式心跳,這成為可擴充套件性挑戰。 發現請求被路由到當選的Consul領導者,這使他們預設情況下非常一致。 允許過時讀取的客戶端允許任何伺服器處理其請求,從而允許像Eureka一樣的線性可伸縮性。

Consul的強烈一致性意味著它可以用作領導者選舉和叢集協調的鎖定服務。 Eureka不提供類似的保證,並且通常需要為需要執行協調或具有更強一致性需求的服務執行ZooKeeper。

Consul提供了支援面向服務的體系結構所需的功能工具包。 這包括服務發現,還包括豐富的執行狀況檢查,鎖定,鍵/值,多資料中心聯合,事件系統和ACL。 Consul和consul-template和envconsul等工具生態系統都試圖最大限度地減少整合所需的應用程式更改,以避免需要通過SDK進行本機整合。 Eureka是更大的Netflix OSS套件的一部分,該套件期望應用程式相對同質且緊密整合。 因此,Eureka只解決了有限的一部分問題,期望其他工具如ZooKeeper可以同時使用。

Eureka Server端採用的是P2P的複製模式,但是它不保證複製操作一定能成功,因此它提供的是一個最終一致性的服務例項檢視;Client端在Server端的註冊資訊有一個帶期限的租約,一旦Server端在指定期間沒有收到Client端傳送的心跳,則Server端會認定為Client端註冊的服務是不健康的,定時任務將會將其從登錄檔中刪除。Consul與Eureka不同,Consul採用Raft演算法,可以提供強一致性的保證,Consul的agent相當於Netflix Ribbon + Netflix Eureka Client,而且對應用來說相對透明,同時相對於Eureka這種集中式的心跳檢測機制,Consul的agent可以參與到基於goosip協議的健康檢查,分散了server端的心跳檢測壓力。除此之外,Consul為多資料中心提供了開箱即用的原生支援等。

Consul下載和安裝

Consul採用Go語言編寫,支援Linux、Mac、Windows等各大作業系統,本文使用windows作業系統,下載地址:www.consul.io/downloads.h…

consul --version
複製程式碼

終端顯示如下:

Consul v1.4.2
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use p
rotocol >2 when speaking to compatible agents)
複製程式碼

證明consul下載成功了,並可執行。

consul的一些常見的執行命令如下:

命令 解釋 示例
agent 執行一個consul agent consul agent -dev
join 將agent加入到consul叢集 consul join IP
members 列出consul cluster叢集中的members consul members
leave 將節點移除所在叢集 consul leave

更多命令請檢視官方網站:www.consul.io/docs/comman…

開發模式啟動:

consul agent -dev 
複製程式碼

啟動成功,在瀏覽器上訪問:http://localhost:8500,顯示的介面如下:

21.png

spring cloud consul

該專案通過自動配置並繫結到Spring環境和其他Spring程式設計模型成語,為Spring Boot應用程式提供Consul整合。通過幾個簡單的註釋,您可以快速啟用和配置應用程式中的常見模式,並使用基於Consul的元件構建大型分散式系統。提供的模式包括服務發現,控制匯流排和配置。智慧路由(Zuul)和客戶端負載平衡(Ribbon),斷路器(Hystrix)通過與Spring Cloud Netflix的整合提供。

使用spring cloud consul來服務註冊與發現

本小節以案例的形式來講解如何使用Spring Cloud Consul來進行服務註冊和發現的,並且使用Feign來消費服務。再講解之前,已經啟動consul的agent,並且在瀏覽器上http://localhost:8500能夠顯示正確的頁面。本案例一共有2個工程,分別如下:

工程名 描述
consul-provider 8763 服務提供者
consul-consumer 8765 服務消費者

其中,服務提供者和服務消費者分別向consul註冊,註冊完成後,服務消費者通過FeignClient來消費服務提供者的服務。

服務提供者consul-provider

建立一個工程consul-provider,在工程的pom檔案引入以下依賴,包括consul-discovery的起步依賴,該依賴是spring cloud consul用來向consul 註冊和發現服務的依賴,採用REST API的方式進行通訊。另外加上web的起步依賴,用於對外提供REST API。程式碼如下:

 
<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>
 
複製程式碼

在工程的配置檔案application.yml做下以下配置:

server:
  port: 8763
spring:
  application:
    name: consul-provider
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        serviceName: consul-provider
複製程式碼

上面的配置,指定了程式的啟動埠為8763,應用名為consul-provider,consul註冊中心的地址為localhost:8500

在程式設計師的啟動類ConsulProviderApplication加上@EnableDiscoveryClient註解,開啟服務發現的功能。

@SpringBootApplication
@EnableDiscoveryClient
public class ConsulProviderApplication {

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

}
複製程式碼

寫一個RESTAPI,該API為一個GET請求,返回當前程式的啟動埠,程式碼如下。


@RestController
public class HiController {

    @Value("${server.port}")
    String port;
    @GetMapping("/hi")
    public String home(@RequestParam String name) {
        return "hi "+name+",i am from port:" +port;
    }

}

複製程式碼

啟動工程,在瀏覽器上訪問http://localhost:8500,頁面顯示如下:

微信截圖_20190131175501.png

從上圖可知,consul-provider服務已經成功註冊到consul上面去了。

服務消費者consul-provider

服務消費者的搭建過程同服務提供者,在pom檔案中引入的依賴同服務提供者,在配置檔案application.yml配置同服務提供者,不同的點在埠為8765,服務名為consul-consumer。

寫一個FeignClient,該FeignClient呼叫consul-provider的REST API,程式碼如下:


@FeignClient(value = "consul-provider")
public interface EurekaClientFeign {

 
    @GetMapping(value = "/hi")
    String sayHiFromClientEureka(@RequestParam(value = "name") String name);
}


複製程式碼

Service層程式碼如下:

@Service
public class HiService {

    @Autowired
    EurekaClientFeign eurekaClientFeign;
 
   
    public String sayHi(String name){
        return  eurekaClientFeign.sayHiFromClientEureka(name);
    }
}

複製程式碼

對外提供一個REST API,該API呼叫了consul-provider的服務,程式碼如下:

@RestController
public class HiController {
    @Autowired
    HiService hiService;

    @GetMapping("/hi")
    public String sayHi(@RequestParam( defaultValue = "forezp",required = false)String name){
        return hiService.sayHi(name);
    }
}

複製程式碼

在瀏覽器上訪問http://localhost:8765/hi,瀏覽器響應如下:

hi forezp,i am from port:8763

這說明consul-consumer已經成功呼叫了consul-provider的服務。這說明consul-provider的服務已經註冊到了consul的註冊中心上面去了。consul-consumer能夠獲取註冊中心的註冊列表來獲來消費服務。

使用Spring Cloud Consul Config來做服務配置中心

Consul不僅能用來服務註冊和發現,Consul而且支援Key/Value鍵值對的儲存,可以用來做配置中心。Spring Cloud 提供了Spring Cloud Consul Config依賴去和Consul相整合,用來做配置中心。 現在以案例的形式來講解如何使用Consul作為配置中心,本案例在上一個案例的consul-provider基礎上進行改造。首先在工程的pom檔案加上consul-config的起步依賴,程式碼如下:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
複製程式碼

然後在配置檔案application.yml加上以下的以下的配置,配置如下:

spring:
  profiles:
    active: dev 
複製程式碼

上面的配置指定了SpringBoot啟動時的讀取的profiles為dev。 然後再工程的啟動配置檔案bootstrap.yml檔案中配置以下的配置:

spring:
  application:
    name: consul-provider
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        serviceName: consul-provider
      config:
        enabled: true
        format: yaml           
        prefix: config     
        profile-separator: ':'    
        data-key: data           

複製程式碼

關於spring.cloud.consul.config的配置項描述如下:

  • enabled 設定config是否啟用,預設為true
  • format 設定配置的值的格式,可以yaml和properties
  • prefix 設定配的基本目錄,比如config
  • defaultContext 設定預設的配置,被所有的應用讀取,本例子沒用的
  • profileSeparator profiles配置分隔符,預設為‘,’
  • date-key為應用配置的key名字,值為整個應用配置的字串。

網頁上訪問consul的KV儲存的管理介面,即http://localhost:8500/ui/dc1/kv,建立一條記錄,

key值為:config/consul-provider:dev/data value值如下:

foo:
  bar: bar1
server:
  port: 8081

複製程式碼

51.png

在consul-provider工程新建一個API,該API返回從consul 配置中心讀取foo.bar的值,程式碼如下:

@RestController
public class FooBarController {
    
    @Value("${foo.bar}")
    String fooBar;

    @GetMapping("/foo")
    public String getFooBar() {
        return fooBar;
    }
}
複製程式碼

啟動工程,可以看到程式的啟動埠為8081,即是consul的配置中心配置的server.port埠。 工程啟動完成後,在瀏覽器上訪問http://localhost:8081/foo,頁面顯示bar1。由此可知,應用consul-provider已經成功從consul的配置中心讀取了配置foo.bar的配置。

動態重新整理配置

當使用spring cloud config作為配置中心的時候,可以使用spring cloud config bus支援動態重新整理配置。Spring Cloud Comsul Config預設就支援動態重新整理,只需要在需要動態重新整理的類上加上@RefreshScope註解即可,修改程式碼如下:

@RestController
@RefreshScope
public class FooBarController {

    @Value("${foo.bar}")
    String fooBar;

    @GetMapping("/foo")
    public String getFooBar() {
        return fooBar;
    }
}
複製程式碼

啟動consul-provider工程,在瀏覽器上訪問http://localhost:8081/foo,頁面顯示bar1。然後 在網頁上訪問consul的KV儲存的管理介面,即http://localhost:8500/ui/dc1/kv,修改config/consul-provider:dev/data的值,修改後的值如下:

foo:
  bar: bar2
server: 
  port: 8081

複製程式碼

此時不重新啟動consul-provider,在瀏覽器上訪問http://localhost:8081/foo,頁面顯示bar2。可見foo.bar的最新配置在應用不重啟的情況下已經生效。

注意事項

  • consul支援的KV儲存的Value值不能超過512KB
  • Consul的dev模式,所有資料都儲存在記憶體中,重啟Consul的時候會導致所有資料丟失,在正式的環境中,Consul的資料會持久化,資料不會丟失。

參考資料

www.consul.io/intro/index…

www.consul.io/docs/intern…

www.consul.io/intro/vs/eu…

www.ityouknow.com/springcloud…

springcloud.cc/spring-clou…

www.cnblogs.com/lsf90/p/602…

blog.csdn.net/longgeqiaoj…

Spring Cloud Consul 之Greenwich版本全攻略
掃碼關注有驚喜

(轉載本站文章請註明作者和出處 方誌朋的部落格

相關文章