前言
近年微服務架構在互聯網應用領域中愈來愈火,引入微服務主要解決了單體應用
多個模塊的緊耦合、無法擴展和運維困難等問題。微服務架構就是按照功能粒度將業務模塊進行垂直拆分,對單體應用本身進行服務化和組件化,每個組件單獨部署為小應用(從DB到UI)。微服務與微服務之間通過Service API進行交互,同時為了支持水平擴展、性能提升和服務可用性,單個服務允許同時部署一個或者多個服務實例。在運行時,每個實例通常是一個雲虛擬機或者Docker容器。微服務系統內部多個服務的實例之間如何通信?如何感知到彼此的存在和銷燬?生產者服務如何知道消費者服務的地址?如何實現服務與註冊中心的解耦?這就需要一個第三方的服務註冊中心,提供對生產者服務節點的註冊管理和消費者服務節點的發現管理。
正文
1. 服務發現與註冊
1.1. 具體流程
- 服務註冊中心:作為整個架構中的核心,要支持分佈式、持久化存儲,註冊信息變動實時通知消費者。
- 服務提供者:服務以 docker 容器化方式部署(實現服務端口的動態生成),可以通過 docker-compose 的方式來管理。通過 Registrator 檢測到 docker 進程信息以完成服務的自動註冊。
- 服務消費者:要使用服務提供者提供的服務,和服務提供者往往是動態相互轉位置的。
一個較為完整的服務註冊與發現流程如下:
- 註冊服務:服務提供者到註冊中心註冊;
- 訂閱服務:服務消費者到註冊中心訂閱服務信息,對其進行監聽;
- 緩存服務列表:本地緩存服務列表,減少與註冊中心的網絡通信;
- 調用服務:先查找本地緩存,找不到再去註冊中心拉取服務地址,然後發送服務請求;
- 變更通知:服務節點變動時 (新增、刪除 等),註冊中心將通知監聽節點,更新服務信息。
1.2. 相關組件
一個服務發現系統主要由三部分組成:
- 註冊器(registrator):根據服務運行狀態,註冊/註銷服務。主要要解決的問題是,何時發起註冊/註銷動作。
- 註冊表(registry):存儲服務信息。常見的解決方案有zookeeper、etcd、cousul等。
- 發現機制(discovery):從註冊表讀取服務信息,給用戶封裝訪問接口。
1.3. 第三方實現
對於第三方的服務註冊與發現的實現,現有的工具主要有以下三種:
- zookeeper:一個高性能、分佈式應用程序協調服務,用於名稱服務、分佈式鎖定、共享資源同步和分佈式配置管理。
- Etcd:一個採用HTTP協議的健/值對存儲系統,主要用於共享配置和服務發現,提供的功能相對Zookeeper和Consul相對簡單。
- Consul:一個分佈式高可用的服務發現和配置共享的軟件,支持服務發現與註冊、多數據中心、健康檢查和分佈式鍵/值存儲。
簡單對比:
與Zookeeper和etcd不一樣,Consul內嵌實現了服務發現系統,不需要構建自己的系統或使用第三方系統,客戶只需要註冊服務,並通過DNS或HTTP接口執行服務發現。2. Consul和Registrator
2.1. Consul簡介
Consul是什麼
Consul 是一種分佈式的、高可用、支持水平擴展的的服務註冊與發現工具。它大致包括以下特性:
- 服務發現: Consul 通過 DNS 或者 HTTP 接口使服務註冊和服務發現變的很容易。一些外部服務,例如 saas 提供的也可以一樣註冊;
- 健康檢查:健康檢測使 consul 可以快速的告警在集群中的操作。和服務發現的集成,可以防止服務轉發到故障的服務上面;
- 鍵/值存儲:一個用來存儲動態配置的系統。提供簡單的 HTTP 接口,可以在任何地方操作;
- 多數據中心:支持多數據中心以避免單點故障,內外網的服務採用不同的端口進行監聽。而其部署則需要考慮網絡延遲, 分片等情況等。zookeeper和etcd均不提供多數據中心功能的支持;
- 一致性算法:採用 Raft 一致性協議算法,比Paxos算法好用。 使用 GOSSIP 協議管理成員和廣播消息, 並且支持 ACL 訪問控制;
- 服務管理Dashboard:提供一個 Web UI 的服務註冊於健康狀態監控的管理頁面。
Consul的幾個概念
下圖是Consul官方文檔提供的架構設計圖:
圖中包含兩個Consul數據中心,每個數據中心都是一個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,同時也要負責各個節點的健康監測。
- 其它信息
其它信息包括各個節點之間的通信方式,還有一些協議信息、算法。它們是用於保證節點之間的數據同步、實時性要求等等一系列集群問題的解決。這些有興趣的自己看看官方文檔。
2.2. Registrator簡介
什麼是Registrator
Registrator是一個獨立於服務註冊表的自動服務註冊/註銷組件,一般以Docker container的方式進行部署。Registrator會自動偵測它所在的宿主機上的所有Docker容器狀態(啟用/銷燬),並根據容器狀態到對應的服務註冊列表註冊/註銷服務。
事實上,Registrator通過讀取同一臺宿主機的其他容器Container的環境變量進行服務註冊、健康檢查定義等操作。
Registrator支持可插拔式的服務註冊表配置,目前支持包括Consul, etcd和SkyDNS 2三種註冊工具。
2.3. Docker安裝Consul集群
2.3.1. 集群節點規劃
我本地的使用的是Ubuntu16.04的虛擬機:
Consul的配置參數信息說明:
2.4. Docker安裝Consul集群
2.4.1. 拉取consul官方鏡像
madison@ubuntu:~$ docker pull consul:latest
2.4.2. 啟動Server節點
運行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進行健康檢查。
2.4.4. 啟動Client節點
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節點中的其中一臺做處理。
2.4.5. 查看集群狀態
madison@ubuntu:~$ docker exec -t node1 consul members
dc1數據中心中的4個節點node1, node2, node3和node4分別成功啟動,Status表示他們的狀態,都為alive。node1, node2, node3以Server模式啟動,而node4以Client模式啟動。
2.5. Docker安裝Registrator
2.5.1. 拉取Registrator的鏡像
madison@ubuntu:~$ docker pull gliderlabs/registrator:latest
2.5.2. 啟動Registrator節點
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數據中心的leader節點,作為服務註冊表;
- 同步當前宿主機的啟用容器,以及所有的服務端口;
- 分別將各個容器發佈的服務地址/端口註冊到Consul的服務註冊列表。
2.5.3. 查看Consul的註冊狀態
Consul提供了一個Web UI來可視化服務註冊列表、通信節點、數據中心和鍵/值存儲等,直接訪問宿主機的8500端口。
服務註冊列表:
NODES節點下掛載著dc1數據中心中的所有的Consul節點,包括Consul Server和Client。
通信節點列表:
啟動Registrator以後,宿主機中的所有容器把服務都註冊到Consul的SERVICES上,測試完成!
總結
單數據中心的Consul集群的搭建就完成了!!!後續章節我會介紹如何使用Registrator進行服務註冊的
標籤化。然後通過docker部署多實例的Web容器來實現基於HTTP的RESTful Service和基於TCP的RPC Service的服務註冊和健康檢查定義,並演示如何以標籤標識一個服務的多個實例。閱讀更多 程序猿的內心獨白 的文章