一篇文章了解Consul服務(wù)發(fā)現(xiàn)實(shí)現(xiàn)原理
從 2016 年起就開(kāi)始接觸 Consul,使用的主要目的就是做服務(wù)發(fā)現(xiàn),后來(lái)逐步應(yīng)用于生產(chǎn)環(huán)境,并總結(jié)了少許使用經(jīng)驗(yàn)。
最開(kāi)始使用 Consul 的人不多,這兩年微服務(wù)越來(lái)越火,使用 Consul 的人也越來(lái)越多。
經(jīng)常有人會(huì)問(wèn)一些問(wèn)題,比如:
- 服務(wù)注冊(cè)到節(jié)點(diǎn)后,其他節(jié)點(diǎn)為什么沒(méi)有同步?
- Client 是干什么的?(Client 有什么作用?)
- 能不能直接注冊(cè)到 Server?(是否只有 Server 節(jié)點(diǎn)就夠了?)
- 服務(wù)信息是保存在哪里的?
- 如果節(jié)點(diǎn)掛了,健康檢查能不能轉(zhuǎn)移到別的節(jié)點(diǎn)?
有些人可能對(duì)服務(wù)注冊(cè)和發(fā)現(xiàn)還沒(méi)有概念,有些人可能使用過(guò)其他服務(wù)發(fā)現(xiàn)的工具,比如 ZooKeeper,etcd,會(huì)有一些先入為主的經(jīng)驗(yàn)。
這篇文章將結(jié)合 Consul 的官方文檔和自己的實(shí)際經(jīng)驗(yàn),談一下 Consul 做服務(wù)發(fā)現(xiàn)的方式,文中盡量不依賴(lài)具體的框架和開(kāi)發(fā)語(yǔ)言,從原理上進(jìn)行說(shuō)明,希望能夠講清楚上邊的幾個(gè)問(wèn)題。
為什么使用服務(wù)發(fā)現(xiàn)
防止硬編碼、容災(zāi)、水平擴(kuò)縮容、提高運(yùn)維效率等等,只要你想使用服務(wù)發(fā)現(xiàn)總能找到合適的理由。
一般的說(shuō)法是因?yàn)槭褂梦⒎?wù)架構(gòu)。傳統(tǒng)的單體架構(gòu)不夠靈活不能很好的適應(yīng)變化,從而向微服務(wù)架構(gòu)進(jìn)行轉(zhuǎn)換。
而伴隨著大量服務(wù)的出現(xiàn),管理運(yùn)維十分不便,于是開(kāi)始搞一些自動(dòng)化的策略,服務(wù)發(fā)現(xiàn)應(yīng)運(yùn)而生。所以如果需要使用服務(wù)發(fā)現(xiàn),你應(yīng)該有一些對(duì)服務(wù)治理的痛點(diǎn)。
但是引入服務(wù)發(fā)現(xiàn)就可能引入一些技術(shù)棧,增加系統(tǒng)總體的復(fù)雜度,如果你只有很少的幾個(gè)服務(wù),比如 10 個(gè)以下,并且業(yè)務(wù)不怎么變化,吞吐量預(yù)計(jì)也很穩(wěn)定,可能就沒(méi)有必要使用服務(wù)發(fā)現(xiàn)。
Consul 內(nèi)部原理
下面這張圖來(lái)源于 Consul 官網(wǎng),很好的解釋了 Consul 的工作原理,先大致看一下:
首先 Consul 支持多數(shù)據(jù)中心,在上圖中有兩個(gè) DataCenter,他們通過(guò) Internet 互聯(lián),同時(shí)請(qǐng)注意為了提高通信效率,只有 Server 節(jié)點(diǎn)才加入跨數(shù)據(jù)中心的通信。
在單個(gè)數(shù)據(jù)中心中,Consul 分為 Client 和 Server 兩種節(jié)點(diǎn)(所有的節(jié)點(diǎn)也被稱(chēng)為 Agent),Server 節(jié)點(diǎn)保存數(shù)據(jù),Client 負(fù)責(zé)健康檢查及轉(zhuǎn)發(fā)數(shù)據(jù)請(qǐng)求到 Server。
Server 節(jié)點(diǎn)有一個(gè) Leader 和多個(gè) Follower,Leader 節(jié)點(diǎn)會(huì)將數(shù)據(jù)同步到 Follower,Server 的數(shù)量推薦是 3 個(gè)或者 5 個(gè),在 Leader 掛掉的時(shí)候會(huì)啟動(dòng)選舉機(jī)制產(chǎn)生一個(gè)新的 Leader。
集群內(nèi)的 Consul 節(jié)點(diǎn)通過(guò) gossip 協(xié)議(流言協(xié)議)維護(hù)成員關(guān)系,也就是說(shuō)某個(gè)節(jié)點(diǎn)了解集群內(nèi)現(xiàn)在還有哪些節(jié)點(diǎn),這些節(jié)點(diǎn)是 Client 還是 Server。
單個(gè)數(shù)據(jù)中心的流言協(xié)議同時(shí)使用 TCP 和 UDP 通信,并且都使用 8301 端口。跨數(shù)據(jù)中心的流言協(xié)議也同時(shí)使用 TCP 和 UDP 通信,端口使用 8302。
集群內(nèi)數(shù)據(jù)的讀寫(xiě)請(qǐng)求既可以直接發(fā)到 Server,也可以通過(guò) Client 使用 RPC 轉(zhuǎn)發(fā)到 Server,請(qǐng)求最終會(huì)到達(dá) Leader 節(jié)點(diǎn)。
在允許數(shù)據(jù)輕微陳舊的情況下,讀請(qǐng)求也可以在普通的 Server 節(jié)點(diǎn)完成,集群內(nèi)數(shù)據(jù)的讀寫(xiě)和復(fù)制都是通過(guò) TCP 的 8300 端口完成。
Consul 服務(wù)發(fā)現(xiàn)原理
下面這張圖是自己畫(huà)的,基本描述了服務(wù)發(fā)現(xiàn)的完整流程,先大致看一下:
首先需要有一個(gè)正常的 Consul 集群,有 Server,有 Leader。這里在服務(wù)器 Server1、Server2、Server3 上分別部署了 Consul Server。
假設(shè)他們選舉了 Server2 上的 Consul Server 節(jié)點(diǎn)為 Leader。這些服務(wù)器上最好只部署 Consul 程序,以盡量維護(hù) Consul Server 的穩(wěn)定。
然后在服務(wù)器 Server4 和 Server5 上通過(guò) Consul Client 分別注冊(cè) Service A、B、C,這里每個(gè) Service 分別部署在了兩個(gè)服務(wù)器上,這樣可以避免 Service 的單點(diǎn)問(wèn)題。
服務(wù)注冊(cè)到 Consul 可以通過(guò) HTTP API(8500 端口)的方式,也可以通過(guò) Consul 配置文件的方式。
Consul Client 可以認(rèn)為是無(wú)狀態(tài)的,它將注冊(cè)信息通過(guò) RPC 轉(zhuǎn)發(fā)到 Consul Server,服務(wù)信息保存在 Server 的各個(gè)節(jié)點(diǎn)中,并且通過(guò) Raft 實(shí)現(xiàn)了強(qiáng)一致性。
最后在服務(wù)器 Server6 中 Program D 需要訪問(wèn) Service B,這時(shí)候 Program D 首先訪問(wèn)本機(jī) Consul Client 提供的 HTTP API,本機(jī) Client 會(huì)將請(qǐng)求轉(zhuǎn)發(fā)到 Consul Server。
Consul Server 查詢(xún)到 Service B 當(dāng)前的信息返回,最終 Program D 拿到了 Service B 的所有部署的 IP 和端口,然后就可以選擇 Service B 的其中一個(gè)部署并向其發(fā)起請(qǐng)求了。
如果服務(wù)發(fā)現(xiàn)采用的是 DNS 方式,則 Program D 中直接使用 Service B 的服務(wù)發(fā)現(xiàn)域名,域名解析請(qǐng)求首先到達(dá)本機(jī) DNS 代理,然后轉(zhuǎn)發(fā)到本機(jī) Consul Client,本機(jī) Client 會(huì)將請(qǐng)求轉(zhuǎn)發(fā)到 Consul Server。
Consul Server 查詢(xún)到 Service B 當(dāng)前的信息返回,最終 Program D 拿到了 Service B 的某個(gè)部署的 IP 和端口。
圖中描述的部署架構(gòu)筆者認(rèn)為是最普適最簡(jiǎn)單的方案,從某些默認(rèn)配置或設(shè)計(jì)上看也是官方希望使用者采用的方案,比如 8500 端口默認(rèn)監(jiān)聽(tīng) 127.0.0.1,當(dāng)然有些同學(xué)不贊同,后邊會(huì)提到其他方案。
Consul 實(shí)際使用
為了更快的熟悉 Consul 的原理及其使用方式,最好還是自己實(shí)際測(cè)試下。
Consul 安裝十分簡(jiǎn)單,但是在一臺(tái)機(jī)器上不方便搭建集群進(jìn)行測(cè)試,使用虛擬機(jī)比較重,所以這里選擇了 Docker。
這里用了 Windows 10,需要是專(zhuān)業(yè)版,因?yàn)?Windows 上的 Docker 依賴(lài) Hyper-V,而這個(gè)需要專(zhuān)業(yè)版才能支持。
這里對(duì)于 Docker 的使用不會(huì)做過(guò)多的描述,如果遇到相關(guān)問(wèn)題請(qǐng)搜索一下。
安裝 Docker
通過(guò)這個(gè)地址下載安裝:
- https://store.docker.com/editions/community/docker-ce-desktop-windows
安裝完成后打開(kāi) Windows PowerShell,輸入 docker –version,如果正常輸出 Docker 版本就可以了。
啟動(dòng) Consul 集群
在 Windows PowerShell 中執(zhí)行命令拉取最新版本的 Consul 鏡像:
- docker pull consul
然后就可以啟動(dòng)集群了,這里啟動(dòng) 4 個(gè) Consul Agent,3 個(gè) Server(會(huì)選舉出一個(gè) Leader),1 個(gè) Client。
- #啟動(dòng)第1個(gè)Server節(jié)點(diǎn),集群要求要有3個(gè)Server,將容器8500端口映射到主機(jī)8900端口,同時(shí)開(kāi)啟管理界面
- docker run -d --name=consul1 -p 8900:8500 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --bootstrap-expect=3 --client=0.0.0.0 -ui
- #啟動(dòng)第2個(gè)Server節(jié)點(diǎn),并加入集群
- docker run -d --name=consul2 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.2
- #啟動(dòng)第3個(gè)Server節(jié)點(diǎn),并加入集群
- docker run -d --name=consul3 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.2
- #啟動(dòng)第4個(gè)Client節(jié)點(diǎn),并加入集群
- docker run -d --name=consul4 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=false --client=0.0.0.0 --join 172.17.0.2
第 1 個(gè)啟動(dòng)容器的 IP 一般是 172.17.0.2,后邊啟動(dòng)的幾個(gè)容器 IP 會(huì)排著來(lái):172.17.0.3、172.17.0.4、172.17.0.5。
這些 Consul 節(jié)點(diǎn)在 Docker 的容器內(nèi)是互通的,他們通過(guò)橋接的模式通信。但是如果主機(jī)要訪問(wèn)容器內(nèi)的網(wǎng)絡(luò),需要做端口映射。
在啟動(dòng)第一個(gè)容器時(shí),將 Consul 的 8500 端口映射到了主機(jī)的 8900 端口,這樣就可以方便的通過(guò)主機(jī)的瀏覽器查看集群信息。
進(jìn)入容器 consul1:
- docker exec -it consul1 /bin/sh
- #執(zhí)行l(wèi)s后可以看到consul就在根目錄
- ls
輸入 exit 可以跳出容器。服務(wù)注冊(cè)自己寫(xiě)一個(gè) Web 服務(wù),用最熟悉的開(kāi)發(fā)語(yǔ)言就好了,不過(guò)需要在容器中能夠跑起來(lái),可能需要安裝運(yùn)行環(huán)境。
比如 Python、Java、.net core等的 sdk 及 Web 服務(wù)器,需要注意的是 Consul 的 Docker 鏡像基于 alpine 系統(tǒng),具體運(yùn)行環(huán)境的安裝請(qǐng)搜索一下。
這里寫(xiě)了一個(gè) hello 服務(wù),通過(guò)配置文件的方式注冊(cè)到 Consul,服務(wù)的相關(guān)信息如下:
- name:hello,服務(wù)名稱(chēng),需要能夠區(qū)分不同的業(yè)務(wù)服務(wù),可以部署多份并使用相同的 name 注冊(cè)。
- id:hello1,服務(wù) id,在每個(gè)節(jié)點(diǎn)上需要唯一,如果有重復(fù)會(huì)被覆蓋。
- address:172.17.0.5,服務(wù)所在機(jī)器的地址。
- port:5000,服務(wù)的端口。
- 健康檢查地址:http://localhost:5000/,如果返回 HTTP 狀態(tài)碼為 200 就代表服務(wù)健康,每 10 秒 Consul 請(qǐng)求一次,請(qǐng)求超時(shí)時(shí)間為 1 秒。
請(qǐng)將下面的內(nèi)容保存成文件 services.json,并上傳到容器的 /consul/config 目錄中:
- {
- "services": [
- {
- "id": "hello1",
- "name": "hello",
- "tags": [
- "primary"
- ],
- "address": "172.17.0.5",
- "port": 5000,
- "checks": [
- {
- "http": "http://localhost:5000/",
- "tls_skip_verify": false,
- "method": "Get",
- "interval": "10s",
- "timeout": "1s"
- }
- ]
- }
- ]
- }
復(fù)制到 consul config 目錄:
- docker cp {這里請(qǐng)?zhí)鎿Q成services.json的本地路徑} consul4:/consul/config
重新加載 consul 配置:
- consul reload
然后這個(gè)服務(wù)就注冊(cè)成功了??梢詫⑦@個(gè)服務(wù)部署到多個(gè)節(jié)點(diǎn),比如部署到 consul1 和 consul4,并同時(shí)運(yùn)行。
服務(wù)發(fā)現(xiàn)
服務(wù)注冊(cè)成功以后,調(diào)用方獲取相應(yīng)服務(wù)地址的過(guò)程就是服務(wù)發(fā)現(xiàn)。Consul 提供了多種方式。
HTTP API 方式
- curl http://127.0.0.1:8500/v1/health/service/hello?passing=true
返回的信息包括注冊(cè)的 Consul 節(jié)點(diǎn)信息、服務(wù)信息及服務(wù)的健康檢查信息。
這里用了一個(gè)參數(shù) passing=false,會(huì)自動(dòng)過(guò)濾掉不健康的服務(wù),包括本身不健康的服務(wù)和不健康的 Consul 節(jié)點(diǎn)上的服務(wù),從這個(gè)設(shè)計(jì)上可以看出 Consul 將服務(wù)的狀態(tài)綁定到了節(jié)點(diǎn)的狀態(tài)。
如果服務(wù)有多個(gè)部署,會(huì)返回服務(wù)的多條信息,調(diào)用方需要決定使用哪個(gè)部署,常見(jiàn)的可以隨機(jī)或者輪詢(xún)。
為了提高服務(wù)吞吐量,以及減輕 Consul 的壓力,還可以緩存獲取到的服務(wù)節(jié)點(diǎn)信息,不過(guò)要做好容錯(cuò)的方案,因?yàn)榫彺娣?wù)部署可能會(huì)變得不可用。具體是否緩存需要結(jié)合自己的訪問(wèn)量及容錯(cuò)規(guī)則來(lái)確定。
上邊的參數(shù) passing 默認(rèn)為 false,也就是說(shuō)不健康的節(jié)點(diǎn)也會(huì)返回,結(jié)合獲取節(jié)點(diǎn)全部服務(wù)的方法,這里可以做到獲取全部服務(wù)的實(shí)時(shí)健康狀態(tài),并對(duì)不健康的服務(wù)進(jìn)行報(bào)警處理。
DNS 方式
hello 服務(wù)的域名是:hello.service.dc1.consul,后邊的 service 代表服務(wù),固定;dc1 是數(shù)據(jù)中心的名字,可以配置;最后的 consul 也可以配置。
官方在介紹 DNS 方式時(shí)經(jīng)常使用 dig 命令進(jìn)行測(cè)試,但是 alpine 系統(tǒng)中沒(méi)有 dig 命令,也沒(méi)有相關(guān)的包可以安裝,但是有人實(shí)現(xiàn)了,下載下來(lái)解壓到 bin 目錄就可以了。
- curl -L https://github.com/sequenceiq/docker-alpine-dig/releases/download/v9.10.2/dig.tgz|tar -xzv -C /usr/local/bin
然后執(zhí)行 dig 命令:
- dig @127.0.0.1 -p 8600 hello.service.dc1.consul. ANY
如果報(bào)錯(cuò):parse of /etc/resolv.conf failed ,請(qǐng)將 resolv.conf 中的 search 那行刪掉。
正常的話(huà)可以看到返回了服務(wù)部署的 IP 信息,如果有多個(gè)部署會(huì)看到多個(gè),如果某個(gè)部署不健康了會(huì)自動(dòng)剔除(包括部署所在節(jié)點(diǎn)不健康的情況)。需要注意這種方式不會(huì)返回服務(wù)的端口信息。
使用 DNS 的方式可以在程序中集成一個(gè) DNS 解析庫(kù),也可以自定義本地的 DNS Server。
自定義本地 DNS Server 是指將 .consul 域的請(qǐng)求全部轉(zhuǎn)發(fā)到 Consul Agent,Windows 上有 DNS Agent,Linux 上有 Dnsmasq。
對(duì)于非 Consul 提供的服務(wù)則繼續(xù)請(qǐng)求原 DNS;使用 DNS Server 時(shí) Consul 會(huì)隨機(jī)返回具體服務(wù)的多個(gè)部署中的一個(gè),僅能提供簡(jiǎn)單的負(fù)載均衡。
DNS 緩存問(wèn)題:DNS 緩存一般存在于應(yīng)用程序的網(wǎng)絡(luò)庫(kù)、本地 DNS 客戶(hù)端或者代理,Consul Sever 本身可以認(rèn)為是沒(méi)有緩存的(為了提高集群 DNS 吞吐量,可以設(shè)置使用普通 Server 上的陳舊數(shù)據(jù),但影響一般不大)。
DNS 緩存可以減輕 Consul Server 的訪問(wèn)壓力,但是也會(huì)導(dǎo)致訪問(wèn)到不可用的服務(wù)。使用時(shí)需要根據(jù)實(shí)際訪問(wèn)量和容錯(cuò)能力確定 DNS 緩存方案。
Consul Template
Consul Template 是 Consul 官方提供的一個(gè)工具,嚴(yán)格的來(lái)說(shuō)不是標(biāo)準(zhǔn)的服務(wù)發(fā)現(xiàn)方式。
這個(gè)工具會(huì)通過(guò) Consul 監(jiān)聽(tīng)數(shù)據(jù)變化然后替換模板中使用的標(biāo)簽,并發(fā)布替換后的文件到指定的目錄。在 Nginx 等 Web 服務(wù)器做反向代理和負(fù)載均衡時(shí)特別有用。
Consul 的 Docker 鏡像中沒(méi)有集成這個(gè)工具,需要自己安裝,比較簡(jiǎn)單:
- curl -L https://releases.hashicorp.com/consul-template/0.19.5/consul-template_0.19.5_linux_amd64.tgz|tar -xzv -C /usr/local/bin
然后創(chuàng)建一個(gè)文件 in.tpl,內(nèi)容為:
- {{ range service "hello" }}
- server {{ .Name }}{{ .Address }}:{{ .Port }}{{ end }}
這個(gè)標(biāo)簽會(huì)遍歷 hello 服務(wù)的所有部署,并按照指定的格式輸出。在此文件目錄下執(zhí)行:
- nohup consul-template -template "in.tpl:out.txt" &
現(xiàn)在你可以 cat out.txt 查看根據(jù)模板生產(chǎn)的內(nèi)容,新增或者關(guān)閉服務(wù),文件內(nèi)容會(huì)自動(dòng)更新。
此工具我沒(méi)有用在生產(chǎn)環(huán)境,詳細(xì)使用請(qǐng)?jiān)L問(wèn):
- https://github.com/hashicorp/consul-template
節(jié)點(diǎn)和服務(wù)注銷(xiāo)
節(jié)點(diǎn)和服務(wù)的注銷(xiāo)可以使用 HTTP API:
注銷(xiāo)任意節(jié)點(diǎn)和服務(wù):/catalog/deregister
注銷(xiāo)當(dāng)前節(jié)點(diǎn)的服務(wù):/agent/service/deregister/:service_id
注意:如果注銷(xiāo)的服務(wù)還在運(yùn)行,則會(huì)再次同步到 catalog 中,因此應(yīng)該只在 Agent 不可用時(shí)才使用 catalog 的注銷(xiāo) API。
節(jié)點(diǎn)在宕機(jī)時(shí)狀態(tài)會(huì)變?yōu)?failed,默認(rèn)情況下 72 小時(shí)后會(huì)被從集群移除。
如果某個(gè)節(jié)點(diǎn)不繼續(xù)使用了,也可以在本機(jī)使用 consul leave 命令,或者在其他節(jié)點(diǎn)使用 consul force-leave 節(jié)點(diǎn) id,則節(jié)點(diǎn)上的服務(wù)和健康檢查全部注銷(xiāo)。
Consul 的健康檢查
Consul 做服務(wù)發(fā)現(xiàn)是專(zhuān)業(yè)的,健康檢查是其中一項(xiàng)必不可少的功能,其提供 Script/TCP/HTTP+Interval,以及 TTL 等多種方式。
服務(wù)的健康檢查由服務(wù)注冊(cè)到的 Agent 來(lái)處理,這個(gè) Agent 既可以是 Client 也可以是 Server。
很多同學(xué)都使用 ZooKeeper 或者 etcd 做服務(wù)發(fā)現(xiàn),使用 Consul 時(shí)發(fā)現(xiàn)節(jié)點(diǎn)掛掉后服務(wù)的狀態(tài)變?yōu)椴豢捎昧耍杂型瑢W(xué)問(wèn)服務(wù)為什么不在各個(gè)節(jié)點(diǎn)之間同步?這個(gè)根本原因是服務(wù)發(fā)現(xiàn)的實(shí)現(xiàn)原理不同。
Consul 與 ZooKeeper、etcd 的區(qū)別
后邊這兩個(gè)工具是通過(guò)鍵值存儲(chǔ)來(lái)實(shí)現(xiàn)服務(wù)的注冊(cè)與發(fā)現(xiàn):
ZooKeeper 利用臨時(shí)節(jié)點(diǎn)的機(jī)制,業(yè)務(wù)服務(wù)啟動(dòng)時(shí)創(chuàng)建臨時(shí)節(jié)點(diǎn),節(jié)點(diǎn)在服務(wù)就在,節(jié)點(diǎn)不存在服務(wù)就不存在。
etcd 利用 TTL 機(jī)制,業(yè)務(wù)服務(wù)啟動(dòng)時(shí)創(chuàng)建鍵值對(duì),定時(shí)更新 TTL,TTL 過(guò)期則服務(wù)不可用。
ZooKeeper 和 etcd 的鍵值存儲(chǔ)都是強(qiáng)一致性的,也就是說(shuō)鍵值對(duì)會(huì)自動(dòng)同步到多個(gè)節(jié)點(diǎn),只要在某個(gè)節(jié)點(diǎn)上存在就可以認(rèn)為對(duì)應(yīng)的業(yè)務(wù)服務(wù)是可用的。
Consul 的數(shù)據(jù)同步也是強(qiáng)一致性的,服務(wù)的注冊(cè)信息會(huì)在 Server 節(jié)點(diǎn)之間同步,相比 ZK、etcd,服務(wù)的信息還是持久化保存的,即使服務(wù)部署不可用了,仍舊可以查詢(xún)到這個(gè)服務(wù)部署。
但是業(yè)務(wù)服務(wù)的可用狀態(tài)是由注冊(cè)到的 Agent 來(lái)維護(hù)的,Agent 如果不能正常工作了,則無(wú)法確定服務(wù)的真實(shí)狀態(tài)。
并且 Consul 是相當(dāng)穩(wěn)定了,Agent 掛掉的情況下大概率服務(wù)器的狀態(tài)也可能是不好的,此時(shí)屏蔽掉此節(jié)點(diǎn)上的服務(wù)是合理的。
Consul 也確實(shí)是這樣設(shè)計(jì)的,DNS 接口會(huì)自動(dòng)屏蔽掛掉節(jié)點(diǎn)上的服務(wù),HTTP API 也認(rèn)為掛掉節(jié)點(diǎn)上的服務(wù)不是 passing 的。
鑒于 Consul 健康檢查的這種機(jī)制,同時(shí)避免單點(diǎn)故障,所有的業(yè)務(wù)服務(wù)應(yīng)該部署多份,并注冊(cè)到不同的 Consul 節(jié)點(diǎn)。
部署多份可能會(huì)給你的設(shè)計(jì)帶來(lái)一些挑戰(zhàn),因?yàn)檎{(diào)用方同時(shí)訪問(wèn)多個(gè)服務(wù)實(shí)例可能會(huì)由于會(huì)話(huà)不共享導(dǎo)致?tīng)顟B(tài)不一致,這個(gè)有許多成熟的解決方案,可以去查詢(xún),這里不做說(shuō)明。
健康檢查能不能支持故障轉(zhuǎn)移?
上邊提到健康檢查是由服務(wù)注冊(cè)到的 Agent 來(lái)處理的,那么如果這個(gè) Agent 掛掉了,會(huì)不會(huì)有別的 Agent 來(lái)接管健康檢查呢?答案是否定的。
從問(wèn)題產(chǎn)生的原因來(lái)看,在應(yīng)用于生產(chǎn)環(huán)境之前,肯定需要對(duì)各種場(chǎng)景進(jìn)行測(cè)試,沒(méi)有問(wèn)題才會(huì)上線(xiàn),所以顯而易見(jiàn)的問(wèn)題可以屏蔽掉。
如果是新版本 Consul 的 Bug 導(dǎo)致的,此時(shí)需要降級(jí);如果這個(gè) Bug 是偶發(fā)的,那么只需要將 Consul 重新拉起來(lái)就可以了,這樣比較簡(jiǎn)單。
如果是硬件、網(wǎng)絡(luò)或者操作系統(tǒng)故障,那么節(jié)點(diǎn)上服務(wù)的可用性也很難保障,不需要?jiǎng)e的 Agent 接管健康檢查。
從實(shí)現(xiàn)上看,選擇哪個(gè)節(jié)點(diǎn)是個(gè)問(wèn)題,這需要實(shí)時(shí)或準(zhǔn)實(shí)時(shí)同步各個(gè)節(jié)點(diǎn)的負(fù)載狀態(tài)。
而且由于業(yè)務(wù)服務(wù)運(yùn)行狀態(tài)多變,即使當(dāng)時(shí)選擇出了負(fù)載比較輕松的節(jié)點(diǎn),無(wú)法保證某個(gè)時(shí)段任務(wù)又變得繁重,可能造成新的更大范圍的崩潰。
如果原來(lái)的節(jié)點(diǎn)還要啟動(dòng)起來(lái),那么接管的健康檢查是否還要撤銷(xiāo),如果要,需要記錄服務(wù)們最初注冊(cè)的節(jié)點(diǎn),然后有一個(gè)監(jiān)聽(tīng)機(jī)制來(lái)觸發(fā)。
如果不要,通過(guò)服務(wù)發(fā)現(xiàn)就會(huì)獲取到很多冗余的信息,并且隨著時(shí)間推移,這種數(shù)據(jù)會(huì)越來(lái)越多,系統(tǒng)變的無(wú)序。
從實(shí)際應(yīng)用看,節(jié)點(diǎn)上的服務(wù)可能既要被發(fā)現(xiàn),又要發(fā)現(xiàn)別的服務(wù),如果節(jié)點(diǎn)掛掉了,僅提供被發(fā)現(xiàn)的功能實(shí)際上服務(wù)還是不可用的。
當(dāng)然發(fā)現(xiàn)別的服務(wù)也可以不使用本機(jī)節(jié)點(diǎn),可以通過(guò)訪問(wèn)一個(gè) Nginx 實(shí)現(xiàn)的若干 Consul 節(jié)點(diǎn)的負(fù)載均衡來(lái)實(shí)現(xiàn),這無(wú)疑又引入了新的技術(shù)棧。
如果不是上邊提到的問(wèn)題,或者你可以通過(guò)一些方式解決這些問(wèn)題,健康檢查接管的實(shí)現(xiàn)也必然是比較復(fù)雜的,因?yàn)榉植际较到y(tǒng)的狀態(tài)同步是比較復(fù)雜的。
同時(shí)不要忘了服務(wù)部署了多份,掛掉一個(gè)不應(yīng)該影響系統(tǒng)的快速恢復(fù),所以沒(méi)必要去做這個(gè)接管。
Consul 的其他部署架構(gòu)
如果你實(shí)在不想在每個(gè)主機(jī)部署 Consul Client,還有一個(gè)多路注冊(cè)的方案可供選擇,這是交流群中獲得的思路。
如圖所示,在專(zhuān)門(mén)的服務(wù)器上部署 Consul Client,然后每個(gè)服務(wù)都注冊(cè)到多個(gè) Client。
這里為了避免服務(wù)單點(diǎn)問(wèn)題還是每個(gè)服務(wù)部署多份,需要服務(wù)發(fā)現(xiàn)時(shí),程序向一個(gè)提供負(fù)載均衡的程序發(fā)起請(qǐng)求,該程序?qū)⒄?qǐng)求轉(zhuǎn)發(fā)到某個(gè) Consul Client。
這種方案需要注意將 Consul 的 8500 端口綁定到私網(wǎng) IP 上,默認(rèn)只有 127.0.0.1。
這個(gè)架構(gòu)的優(yōu)勢(shì):
Consul 節(jié)點(diǎn)服務(wù)器與應(yīng)用服務(wù)器隔離,互相干擾少。
不用每臺(tái)主機(jī)都部署 Consul,方便 Consul 的集中管理。
某個(gè) Consul Client 掛掉的情況下,注冊(cè)到其上的服務(wù)仍有機(jī)會(huì)被訪問(wèn)到。
但也需要注意其缺點(diǎn):
引入更多技術(shù)棧:負(fù)載均衡的實(shí)現(xiàn),不僅要考慮 Consul Client 的負(fù)載均衡,還要考慮負(fù)載均衡本身的單點(diǎn)問(wèn)題。
Client 的節(jié)點(diǎn)數(shù)量:?jiǎn)蝹€(gè) Client 如果注冊(cè)的服務(wù)太多,負(fù)載較重,需要有個(gè)算法(比如 hash 一致)合理分配每個(gè) Client 上的服務(wù)數(shù)量,以及確定 Client 的總體數(shù)量。
服務(wù)發(fā)現(xiàn)要過(guò)濾掉重復(fù)的注冊(cè):因?yàn)樽?cè)到了多個(gè)節(jié)點(diǎn)會(huì)認(rèn)為是多個(gè)部署(DNS 接口不會(huì)有這個(gè)問(wèn)題)。
這個(gè)方案其實(shí)還可以?xún)?yōu)化,服務(wù)發(fā)現(xiàn)使用的負(fù)載均衡可以直接代理 Server 節(jié)點(diǎn),因?yàn)橄嚓P(guān)請(qǐng)求還是會(huì)轉(zhuǎn)發(fā)到 Server 節(jié)點(diǎn),不如直接就發(fā)到 Server。
是否可以只有 Server?
這個(gè)問(wèn)題的答案還是有關(guān)服務(wù)數(shù)量的問(wèn)題,首先 Server 的節(jié)點(diǎn)數(shù)量不是越多越好,3 個(gè)或者 5 個(gè)是推薦的數(shù)量,數(shù)量越多數(shù)據(jù)同步的處理越慢(強(qiáng)一致性)。
然后每個(gè)節(jié)點(diǎn)可以注冊(cè)的服務(wù)數(shù)量是有上限的,這個(gè)受限于軟硬件的處理能力。
所以如果你的服務(wù)只有 10 個(gè)左右,只有 Server 問(wèn)題是不大的,但是這時(shí)候有沒(méi)有必要使用 Consul 呢?
因此正常使用 Consul 的時(shí)候還是要有 Client 才好,這也符合 Consul 的反熵設(shè)計(jì)。
大家可以將這個(gè)部署架構(gòu)與前文提到的普世架構(gòu)對(duì)比下,看看哪個(gè)更適合自己,或者你有更好的方案歡迎分享出來(lái)。































