近年微服務架構在互聯網應用領域中越來越火,引入微服務主要解決了單體應用多個模塊的緊耦合、沒法擴展和運維困難等問題。微服務架構就是按照功能粒度將業務模塊進行垂直拆分,對單體應用自己進行服務化和組件化,每一個組件單獨部署爲小應用(從DB
到UI
)。微服務與微服務之間經過Service API
進行交互,同時爲了支持水平擴展、性能提高和服務可用性,單個服務容許同時部署一個或者多個服務實例。在運行時,每一個實例一般是一個雲虛擬機或者Docker
容器。node
微服務系統內部多個服務的實例之間如何通訊?如何感知到彼此的存在和銷燬?生產者服務如何知道消費者服務的地址?如何實現服務與註冊中心的解耦?這就須要一個第三方的服務註冊中心,提供對生產者服務節點的註冊管理和消費者服務節點的發現管理。linux
docker
容器化方式部署(實現服務端口的動態生成),能夠經過 docker-compose
的方式來管理。經過 Registrator
檢測到 docker
進程信息以完成服務的自動註冊。一個較爲完整的服務註冊與發現流程以下:算法
一個服務發現系統主要由三部分組成:docker
對於第三方的服務註冊與發現的實現,現有的工具主要有如下三種:編程
簡單對比:json
與Zookeeper和etcd不同,Consul內嵌實現了服務發現系統,不須要構建本身的系統或使用第三方系統,客戶只須要註冊服務,並經過DNS或HTTP接口執行服務發現。bootstrap
Consul是什麼ubuntu
Consul
是一種分佈式的、高可用、支持水平擴展的的服務註冊與發現工具。它大體包括如下特性:後端
Consul
經過 DNS
或者 HTTP
接口使服務註冊和服務發現變的很容易。一些外部服務,例如 saas
提供的也能夠同樣註冊;consul
能夠快速的告警在集羣中的操做。和服務發現的集成,能夠防止服務轉發到故障的服務上面;HTTP
接口,能夠在任何地方操做;zookeeper
和etcd
均不提供多數據中心功能的支持;Raft
一致性協議算法,比Paxos
算法好用。 使用 GOSSIP
協議管理成員和廣播消息, 而且支持 ACL
訪問控制;Web UI
的服務註冊於健康狀態監控的管理頁面。Consul的幾個概念緩存
下圖是Consul
官方文檔提供的架構設計圖:
圖中包含兩個Consul
數據中心,每一個數據中心都是一個consul
的集羣。在數據中心1中,能夠看出consul
的集羣是由N
個SERVER
,加上M
個CLIENT
組成的。而不論是SERVER
仍是CLIENT
,都是consul
集羣的一個節點。全部的服務均可以註冊到這些節點上,正是經過這些節點實現服務註冊信息的共享。除了這兩個,還有一些小細節 一一 簡單介紹。
CLIENT
表示consul
的client
模式,就是客戶端模式。是consul
節點的一種模式,這種模式下,全部註冊到當前節點的服務會被轉發到SERVER
節點,自己是不持久化這些信息。
SERVER
表示consul
的server
模式,代表這個consul
是個server
節點。這種模式下,功能和CLIENT
都同樣,惟一不一樣的是,它會把全部的信息持久化的本地。這樣遇到故障,信息是能夠被保留的。
中間那個SERVER
下面有LEADER
的描述,代表這個SERVER
節點是它們的老大。和其它SERVER
不同的一點是,它須要負責同步註冊信息給其它的SERVER
,同時也要負責各個節點的健康監測。
其它信息包括各個節點之間的通訊方式,還有一些協議信息、算法。它們是用於保證節點之間的數據同步、實時性要求等等一系列集羣問題的解決。這些有興趣的本身看看官方文檔。
什麼是Registrator Registrator
是一個獨立於服務註冊表的自動服務註冊/註銷組件,通常以Docker container
的方式進行部署。Registrator
會自動偵測它所在的宿主機上的全部Docker
容器狀態(啓用/銷燬),並根據容器狀態到對應的服務註冊列表註冊/註銷服務。
事實上,Registrator
經過讀取同一臺宿主機的其餘容器Container
的環境變量進行服務註冊、健康檢查定義等操做。
Registrator
支持可插拔式的服務註冊表配置,目前支持包括Consul
, etcd
和SkyDNS 2
三種註冊工具。
我本地的使用的是Ubuntu16.04
的虛擬機:
容器名稱 | 容器IP地址 | 映射端口號 | 宿主機IP地址 | 服務運行模式 |
---|---|---|---|---|
node1 | 172.17.0.2 | 8500 -> 8500 | 192.168.127.128 | Server Master |
node2 | 172.17.0.3 | 9500 -> 8500 | 192.168.127.128 | Server |
node3 | 172.17.0.4 | 10500 -> 8500 | 192.168.127.128 | Server |
node4 | 172.17.0.5 | 11500 -> 8500 | 192.168.127.128 | Client |
Consul
的配置參數信息說明:
參數列表 | 參數的含義和使用場景說明 |
---|---|
advertise | 通知展示地址用來改變咱們給集羣中的其餘節點展示的地址,通常狀況下-bind地址就是展示地址 |
bootstrap | 用來控制一個server是否在bootstrap模式,在一個datacenter中只能有一個server處於bootstrap模式,當一個server處於bootstrap模式時,能夠本身選舉爲raft leader |
bootstrap-expect | 在一個datacenter中指望提供的server節點數目,當該值提供的時候,consul一直等到達到指定sever數目的時候纔會引導整個集羣,該標記不能和bootstrap共用 |
bind | 該地址用來在集羣內部的通信IP地址,集羣內的全部節點到地址都必須是可達的,默認是0.0.0.0 |
client | consul綁定在哪一個client地址上,這個地址提供HTTP、DNS、RPC等服務,默認是127.0.0.1 |
config-file | 明確的指定要加載哪一個配置文件 |
config-dir | 配置文件目錄,裏面全部以.json結尾的文件都會被加載 |
data-dir | 提供一個目錄用來存放agent的狀態,全部的agent容許都須要該目錄,該目錄必須是穩定的,系統重啓後都繼續存在 |
dc | 該標記控制agent容許的datacenter的名稱,默認是dc1 |
encrypt | 指定secret key,使consul在通信時進行加密,key能夠經過consul keygen生成,同一個集羣中的節點必須使用相同的key |
join | 加入一個已經啓動的agent的ip地址,能夠屢次指定多個agent的地址。若是consul不能加入任何指定的地址中,則agent會啓動失敗,默認agent啓動時不會加入任何節點 |
retry-interval | 兩次join之間的時間間隔,默認是30s |
retry-max | 嘗試重複join的次數,默認是0,也就是無限次嘗試 |
log-level | consul agent啓動後顯示的日誌信息級別。默認是info,可選:trace、debug、info、warn、err |
node | 節點在集羣中的名稱,在一個集羣中必須是惟一的,默認是該節點的主機名 |
protocol | consul使用的協議版本 |
rejoin | 使consul忽略先前的離開,在再次啓動後仍舊嘗試加入集羣中 |
server | 定義agent運行在server模式,每一個集羣至少有一個server,建議每一個集羣的server不要超過5個 |
syslog | 開啓系統日誌功能,只在linux/osx上生效 |
pid-file | 提供一個路徑來存放pid文件,可使用該文件進行SIGINT/SIGHUP(關閉/更新)agent |
madison@ubuntu:~$ docker pull consul:latest
複製代碼
運行consul
鏡像,啓動Server Master
節點node1
:
node1:
madison@ubuntu:~$ docker run -d --name=node1 --restart=always \
-e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' \
-p 8300:8300 \
-p 8301:8301 \
-p 8301:8301/udp \
-p 8302:8302/udp \
-p 8302:8302 \
-p 8400:8400 \
-p 8500:8500 \
-p 8600:8600 \
-h node1 \
consul agent -server -bind=172.17.0.2 -bootstrap-expect=3 -node=node1 \
-data-dir=/tmp/data-dir -client 0.0.0.0 -ui
複製代碼
查看node1
的日誌,追蹤運行狀況:
如今集羣中尚未選舉leader
節點,繼續啓動其他兩臺Server
節點node2
和node3
:
node2:
madison@ubuntu:~$ docker run -d --name=node2 --restart=always \
-e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' \
-p 9300:8300 \
-p 9301:8301 \
-p 9301:8301/udp \
-p 9302:8302/udp \
-p 9302:8302 \
-p 9400:8400 \
-p 9500:8500 \
-p 9600:8600 \
-h node2 \
consul agent -server -bind=172.17.0.3 \
-join=192.168.127.128 -node-id=$(uuidgen | awk '{print tolower($0)}') \
-node=node2 \
-data-dir=/tmp/data-dir -client 0.0.0.0 -ui
複製代碼
查看node2
節點的進程啓動日誌:
node3:
madison@ubuntu:~$ docker run -d --name=node3 --restart=always \
-e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' \
-p 10300:8300 \
-p 10301:8301 \
-p 10301:8301/udp \
-p 10302:8302/udp \
-p 10302:8302 \
-p 10400:8400 \
-p 10500:8500 \
-p 10600:8600 \
-h node2 \
consul agent -server -bind=172.17.0.4 \
-join=192.168.127.128 -node-id=$(uuidgen | awk '{print tolower($0)}') \
-node=node3 \
-data-dir=/tmp/data-dir -client 0.0.0.0 -ui
複製代碼
查看node3
節點的進程啓動日誌:
當3個Server
節點都啓動並正常運行時,觀察node2
和node3
的進程日誌,能夠發現node1
被選舉爲leader
節點,也就是這個數據中心的Server Master
。
再次查看node1
節點的進程啓動日誌:
觀察日誌發現,node2
和node3
都成功join到了node1
所在的數據中心dc1
。當集羣中有3臺Consul Server
啓動時,node1
被選舉爲dc1
中的主節點。而後,node1
會經過心跳檢查的方式,不斷地對node2
和node3
進行健康檢查。
node4:
madison@ubuntu:~$ docker run -d --name=node4 --restart=always \
-e 'CONSUL_LOCAL_CONFIG={"leave_on_terminate": true}' \
-p 11300:8300 \
-p 11301:8301 \
-p 11301:8301/udp \
-p 11302:8302/udp \
-p 11302:8302 \
-p 11400:8400 \
-p 11500:8500 \
-p 11600:8600 \
-h node4 \
consul agent -bind=172.17.0.5 -retry-join=192.168.127.128 \
-node-id=$(uuidgen | awk '{print tolower($0)}') \
-node=node4 -client 0.0.0.0 -ui
複製代碼
查看node4
節點的進程啓動日誌:
能夠發現:node4
是以Client
模式啓動運行的。啓動後完成後,把dc1
數據中心中的以Server
模式啓動的節點node1
、node2
和node3
都添加到本地緩存列表中。當客戶端向node4
發起服務發現的請求後,node4
會經過RPC
將請求轉發給Server
節點中的其中一臺作處理。
madison@ubuntu:~$ docker exec -t node1 consul members
複製代碼
dc1
數據中心中的4個節點node1
, node2
, node3
和node4
分別成功啓動,Status
表示他們的狀態,都爲alive
。node1
, node2
, node3
以Server
模式啓動,而node4
以Client
模式啓動。
madison@ubuntu:~$ docker pull gliderlabs/registrator:latest
複製代碼
madison@ubuntu:~$ docker run -d --name=registrator \
-v /var/run/docker.sock:/tmp/docker.sock \
--net=host \
gliderlabs/registrator -ip="192.168.127.128" consul://192.168.127.128:8500
複製代碼
--net指定爲host代表使用主機模式。 -ip用於指定宿主機的IP地址,用於健康檢查的通訊地址。 consul://192.168.127.128:8500: 使用Consul做爲服務註冊表,指定具體的Consul通訊地址進行服務註冊和註銷(注意:8500是Consul對外暴露的HTTP通訊端口)。
查看Registrator
的容器進程啓動日誌:
Registrator
在啓動過程完成了如下幾步操做:
Consul
提供了一個Web UI
來可視化服務註冊列表、通訊節點、數據中心和鍵/值存儲等,直接訪問宿主機的8500
端口。
服務註冊列表:
NODES
節點下掛載着dc1
數據中心中的全部的Consul
節點,包括Consul Server
和Client
。
通訊節點列表:
啓動Registrator
之後,宿主機中的全部容器把服務都註冊到Consul
的SERVICES
上,測試完成!
單數據中心的Consul
集羣的搭建就完成了!!!後續章節我會介紹如何使用Registrator
進行服務註冊的標籤化。而後經過docker
部署多實例的Web
容器來實現基於HTTP
的RESTful Service
和基於TCP
的RPC Service
的服務註冊和健康檢查定義,並演示如何以標籤標識一個服務的多個實例。
歡迎關注技術公衆號: 零壹技術棧
本賬號將持續分享後端技術乾貨,包括虛擬機基礎,多線程編程,高性能框架,異步、緩存和消息中間件,分佈式和微服務,架構學習和進階等學習資料和文章。