NO IMAGE

什麼是服務發現

相關原始碼: spring cloud demo

微服務的框架體系中,服務發現是不能不提的一個模組。我相信瞭解或者熟悉微服務的童鞋應該都知道它的重要性。這裡我只是簡單的提一下,畢竟這不是我們的重點。我們看下面的一幅圖片:

Image.png

圖中,客戶端的一個介面,需要呼叫服務A-N。客戶端必須要知道所有服務的網路位置的,以往的做法是配置是配置檔案中,或者有些配置在資料庫中。這裡就帶出幾個問題:

  • 需要配置N個服務的網路位置,加大配置的複雜性
  • 服務的網路位置變化,都需要改變每個呼叫者的配置
  • 叢集的情況下,難以做負載(反向代理的方式除外)

總結起來一句話:服務多了,配置很麻煩,問題多多

既然有這些問題,那麼服務發現就是解決這些問題的。話說,怎麼解決呢?我們再看一張圖

Image.png

與之前一張不同的是,加了個服務發現模組。圖比較簡單,這邊文字描述下。服務A-N把當前自己的網路位置註冊到服務發現模組(這裡註冊的意思就是告訴),服務發現就以K-V的方式記錄下,K一般是服務名,V就是IP:PORT。服務發現模組定時的輪詢檢視這些服務能不能訪問的了(這就是健康檢查)。客戶端在呼叫服務A-N的時候,就跑去服務發現模組問下它們的網路位置,然後再呼叫它們的服務。這樣的方式是不是就可以解決上面的問題了呢?客戶端完全不需要記錄這些服務網路位置,客戶端和服務端完全解耦!

這個過程大體是這樣,當然服務發現模組沒這麼簡單。裡面包含的東西還很多。這樣表述只是方便理解。

圖中的服務發現模組基本上就是微服務架構中服務發現的作用了。

consul 簡介

做服務發現的框架常用的有

  • zookeeper
  • eureka
  • etcd
  • consul

這裡就不比較哪個好哪個差了,需要的童鞋自己谷歌百度。

那麼consul是啥?consul就是提供服務發現的工具。然後下面是簡單的介紹:

consul是分散式的、高可用、橫向擴充套件的。consul提供的一些關鍵特性:

  • service discovery:consul通過DNS或者HTTP介面使服務註冊和服務發現變的很容易,一些外部服務,例如saas提供的也可以一樣註冊。
  • health checking:健康檢測使consul可以快速的告警在叢集中的操作。和服務發現的整合,可以防止服務轉發到故障的服務上面。
  • key/value storage:一個用來儲存動態配置的系統。提供簡單的HTTP介面,可以在任何地方操作。
  • multi-datacenter:無需複雜的配置,即可支援任意數量的區域。

我們這裡會介紹服務發現,健康檢查,還有一些基本KV儲存。多資料中心有機會另一篇文章再說。

總結:只要知道它是解決我上一部分提出的問題就行,其它的東西慢慢理解

consul的幾個概念

Image.png

上圖是我從consul官方文件摳出來的。

我們只看資料中心1,可以看出consul的叢集是由N個SERVER,加上M個CLIENT組成的。而不管是SERVER還是CLIENT,都是consul的一個節點,所有的服務都可以註冊到這些節點上,正是通過這些節點實現服務註冊資訊的共享。除了這兩個,還有一些小細節,一一簡單介紹。

  • CLIENT

CLIENT表示consul的client模式,就是客戶端模式。是consul節點的一種模式,這種模式下,所有註冊到當前節點的服務會被轉發到SERVER,本身是不持久化這些資訊。

  • SERVER

SERVER表示consul的server模式,表明這個consul是個server,這種模式下,功能和CLIENT都一樣,唯一不同的是,它會把所有的資訊持久化的本地,這樣遇到故障,資訊是可以被保留的。

  • SERVER-LEADER

中間那個SERVER下面有LEADER的字眼,表明這個SERVER是它們的老大,它和其它SERVER不一樣的一點是,它需要負責同步註冊的資訊給其它的SERVER,同時也要負責各個節點的健康監測。

  • 其它資訊

其它資訊包括它們之間的通訊方式,還有一些協議資訊,演算法。它們是用於保證節點之間的資料同步,實時性要求等等一系列叢集問題的解決。這些有興趣的自己看看官方文件

consul 基本使用

自己就一臺機子,所以這裡就演示下docker下部署使用consul。容器與宿主機的埠對映忽略,正常生產環境每個宿主機一個consul,埠需要對映到宿主機

部署

拉取映象

    docker search consul

咱們用官方的映象玩玩

    docker pull consul

不指定tag就拉取last,當前版本是0.8.0

啟動consul

  • 啟動節點1(server模式)
    docker run -d -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' --name=node1 consul agent -server -bind=172.17.0.2  -bootstrap-expect=3 -node=node1
    

    -node:節點的名稱
    -bind:繫結的一個地址,用於節點之間通訊的地址,可以是內外網,必須是可以訪問到的地址
    -server:這個就是表示這個節點是個SERVER
    -bootstrap-expect:這個就是表示期望提供的SERVER節點數目,數目一達到,它就會被啟用,然後就是LEADER了

  • 啟動節點2-3(server模式)
    docker run -d -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' --name=node2 consul agent -server -bind=172.17.0.3  -join=172.17.0.2 -node-id=$(uuidgen | awk '{print tolower($0)}')  -node=node2
    docker run -d -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' --name=node3 consul agent -server -bind=172.17.0.4  -join=172.17.0.2 -node-id=$(uuidgen | awk '{print tolower($0)}')  -node=node3 -client=172.17.0.4
    

    -join:這個表示啟動的時候,要加入到哪個叢集內,這裡就是說要加入到節點1的叢集
    -node-id:這個貌似版本8才加入的,這裡用這個來指定唯一的節點ID,可以檢視這個issue
    -client:這個表示註冊或者查詢等一系列客戶端對它操作的IP,如果不指定這個IP,預設是127.0.0.1。

  • 啟動節點4(client模式)
    docker run -d -e 'CONSUL_LOCAL_CONFIG={"leave_on_terminate": true}' --name=node4 consul agent -bind=172.17.0.5 -retry-join=172.17.0.2 -node-id=$(uuidgen | awk '{print tolower($0)}')  -node=node4
    

    除了沒有-server,其它都是一樣的,沒有這個就說明這個節點是CLIENT

  • 檢視下叢集的狀態
    docker exec -t node1 consul members
    

    Image.png
    4個節點都列出來了。Status表示它們的狀態,都是alive。Type表示它們的型別,三個SERVER一個CLIENT,和我們之前啟動的一樣。DC表示資料中心,都是dc1。

  • 節點異常consul的處理

    • LEADER 掛了
      leader掛了,consul會重新選取出新的leader,只要超過一半的SERVER還活著,叢集是可以正常工作的。node1是leader,所以把這個容器停了。

      docker stop node1
      看看其他節點的日誌(node2):
      Image.png
      日誌列印,心跳檢查node1的ip超時,接著開始選舉。node2被選舉為新的leader。我們檢視下現在的leader:

      curl http://172.17.0.4:8500/v1/status/leader
      

      返回的內容:

        "172.17.0.3:8300"
      

      172.17.0.3 就是 node2節點的IP

使用

部署完了,那麼可以看看怎麼用這個東東了。

註冊個服務

使用HTTP API 註冊個服務,使用[介面API](https://www.consul.io/api/agent/service.html API)呼叫

呼叫 http://consul:8500/v1/agent/service/register PUT 註冊一個服務。request body:

{
"ID": "userServiceId", //服務id
"Name": "userService", //服務名
"Tags": [              //服務的tag,自定義,可以根據這個tag來區分同一個服務名的服務
"primary",
"v1"
],
"Address": "127.0.0.1",//服務註冊到consul的IP,服務發現,發現的就是這個IP
"Port": 8000,          //服務註冊consul的PORT,發現的就是這個PORT
"EnableTagOverride": false,
"Check": {             //健康檢查部分
"DeregisterCriticalServiceAfter": "90m",
"HTTP": "http://www.baidu.com", //指定健康檢查的URL,呼叫後只要返回20X,consul都認為是健康的
"Interval": "10s"   //健康檢查間隔時間,每隔10s,呼叫一次上面的URL
}
}

使用curl呼叫

curl http://172.17.0.4:8500/v1/agent/service/register -X PUT -i -H "Content-Type:application/json" -d '{
"ID": "userServiceId",  
"Name": "userService",
"Tags": [
"primary",
"v1"
],
"Address": "127.0.0.1",
"Port": 8000,
"EnableTagOverride": false,
"Check": {
"DeregisterCriticalServiceAfter": "90m",
"HTTP": "http://www.baidu.com",
"Interval": "10s"
}
}'

OK,註冊了一個服務

發現個服務

剛剛註冊了名為userService的服務,我們現在發現(查詢)下這個服務

curl http://172.17.0.4:8500/v1/catalog/service/userService

返回的響應:

[
{
"Address": "172.17.0.4",
"CreateIndex": 880,
"ID": "e6e9a8cb-c47e-4be9-b13e-a24a1582e825",
"ModifyIndex": 880,
"Node": "node3",
"NodeMeta": {},
"ServiceAddress": "127.0.0.1",
"ServiceEnableTagOverride": false,
"ServiceID": "userServiceId",
"ServiceName": "userService",
"ServicePort": 8000,
"ServiceTags": [
"primary",
"v1"
],
"TaggedAddresses": {
"lan": "172.17.0.4",
"wan": "172.17.0.4"
}
}
]

內容有了吧,這個就是我們剛剛註冊的服務的資訊,就可以獲取到

服務的名稱是“userService”
服務地址是“127.0.0.1”
服務的埠是“8000”

儲存個K/V

設定一個值到user/config/connections 內容為5

docker exec -t node1 consul kv put user/config/connections 5

獲取特定的值

docker exec -t node1 consul kv get -detailed user/config/connections

Image.png

值的內容為5,還有key等相關的值

總結

服務發現以及配置共享的簡單樣例展示了下,詳細的使用還是需要看官方文件,這裡只是列舉了一些樣例,用於理解和簡單的使用consul。

Spring Cloud 結合consul使用

如果是使用spring cloud來使用consul,可以檢視我的相關樣例:http://git.oschina.net/buxiaoxia/spring-demo

spring cloud 結合consul的使用,下一篇文章再進行描述吧

相關文件連線

CONSUL:https://www.consul.io/
CONSUL HTTP API:https://www.consul.io/api/index.html
CONSUL CLI:https://www.consul.io/docs/commands/info.html
CONSUL Health Checks:https://www.consul.io/docs/agent/checks.html