- 服務注冊到節點后,其他節點為什么沒有同步?
- Client是干什么的?(Client有什么作用?)
- 能不能直接注冊到Server?(是否只有Server節點就夠了?)
- 服務信息是保存在哪里的?
- 如果節點掛了健康檢查能不能轉移到別的節點?
關於服務注冊和發現還沒有概念,consul與zookeeper,etcd有不同之處
一 什么是注冊中心、服務注冊、服務發現
所謂服務注冊中心就是一個保存可用服務實例的數據庫
服務注冊與服務發現是在分布式服務架構中常常會涉及到的東西,業界常用的服務注冊與服務發現工具有 ZooKeeper、etcd、Consul 和 Eureka。Consul 的主要功能有服務發現、健康檢查、KV存儲、安全服務溝通和多數據中心。Consul 與其他幾個工具的區別可以在這里查看 Consul vs. Other Software。
二 為什么需要有服務注冊與服務發現?
假設在分布式系統中有兩個服務 Service-A (下文以“S-A”代稱)和 Service-B(下文以“S-B”代稱),當 S-A 想調用 S-B 時,我們首先想到的時直接在 S-A 中請求 S-B 所在服務器的 IP 地址和監聽的端口,這在服務規模很小的情況下是沒有任何問題的,但是在服務規模很大每個服務不止部署一個實例的情況下是存在一些問題的,比如 S-B 部署了三個實例 S-B-1、S-B-2 和 S-B-3,這時候 S-A 想調用 S-B 該請求哪一個服務實例的 IP 呢?還是將3個服務實例的 IP 都寫在 S-A 的代碼里,每次調用 S-B 時選擇其中一個 IP?這樣做顯得很不靈活,這時我們想到了 Nginx
剛好就能很好的解決這個問題,引入 Nginx
后現在的架構變成了如下圖這樣:
引入 Nginx 后就解決了 S-B 部署多個實例的問題,還做了 S-B 實例間的負載均衡。但現在的架構又面臨了新的問題,分布式系統往往要保證高可用以及能做到動態伸縮,在引入 Nginx 的架構中,假如當 S-B-1 服務實例不可用時,Nginx 仍然會向 S-B-1 分配請求,這樣服務就不可用,我們想要的是 S-B-1 掛掉后 Nginx 就不再向其分配請求,以及當我們新部署了 S-B-4 和 S-B-5 后,Nginx 也能將請求分配到 S-B-4 和 S-B-5,Nginx 要做到這樣就要在每次有服務實例變動時去更新配置文件再重啟 Nginx。這樣看似乎用了 Nginx 也很不舒服以及還需要人工去觀察哪些服務有沒有掛掉,Nginx 要是有對服務的健康檢查以及能夠動態變更服務配置就是我們想要的工具,這就是服務注冊與服務發現工具的用處。下面是引入服務注冊與服務發現工具后的架構圖:
在這個架構中:
- 首先 S-B 的實例啟動后將自身的服務信息(主要是服務所在的 IP 地址和端口號)注冊到注冊工具中。不同注冊工具服務的注冊方式各不相同,后文會講 Consul 的具體注冊方式。
- 服務將服務信息注冊到注冊工具后,注冊工具就可以對服務做健康檢查,以此來確定哪些服務實例可用哪些不可用。
- S-A 啟動后就可以通過服務注冊和服務發現工具獲取到所有健康的 S-B 實例的 IP 和端口,並將這些信息放入自己的內存中,S-A 就可用通過這些信息來調用 S-B。
- S-A 可以通過監聽(Watch)注冊工具來更新存入內存中的 S-B 的服務信息。比如 S-B-1 掛了,健康檢查機制就會將其標為不可用,這樣的信息變動就被 S-A 監聽到了,S-A 就更新自己內存中 S-B-1 的服務信息。
所以務注冊與服務發現工具除了服務本身的服務注冊和發現功能外至少還需要有健康檢查和狀態變更通知的功能,服務注冊與發現可以防止硬編碼、容災、水平擴縮容、提高運維效率等等
因為使用微服務架構。傳統的單體架構不夠靈活不能很好的適應變化,從而向微服務架構進行轉換,而伴隨着大量服務的出現,管理運維十分不便,於是開始搞一些自動化的策略,服務發現應運而生。所以如果需要使用服務發現,你應該有一些對服務治理的痛點。
但是引入服務發現就可能引入一些技術棧,增加系統總體的復雜度,如果你只有很少的幾個服務,比如10個以下,並且業務不怎么變化,吞吐量預計也很穩定,可能就沒有必要使用服務發現。
Consul
Consul 作為一種分布式服務工具,為了避免單點故障常常以集群的方式進行部署,在 Consul 集群的節點中分為 Server 和 Client 兩種節點(所有的節點也被稱為Agent),Server 節點保存數據,Client 節點負責健康檢查及轉發數據請求到 Server;Server 節點有一個 Leader 節點和多個 Follower 節點,Leader 節點會將數據同步到 Follower 節點,在 Leader 節點掛掉的時候會啟動選舉機制產生一個新的 Leader。
Client 節點很輕量且無狀態,它以 RPC 的方式向 Server 節點做讀寫請求的轉發,此外也可以直接向 Server 節點發送讀寫請求。下面是 Consul 的架構圖:
Consul 作為一種分布式服務工具,為了避免單點故障常常以集群的方式進行部署,在 Consul 集群的節點中分為 Server 和 Client 兩種節點(所有的節點也被稱為Agent),Server 節點保存數據,Client 節點負責健康檢查及轉發數據請求到 Server;Server 節點有一個 Leader 節點和多個 Follower 節點,Leader 節點會將數據同步到 Follower 節點,在 Leader 節點掛掉的時候會啟動選舉機制產生一個新的 Leader。
Client 節點很輕量且無狀態,它以 RPC 的方式向 Server 節點做讀寫請求的轉發,此外也可以直接向 Server 節點發送讀寫請求。下面是 Consul 的架構圖:
下面這張圖來源於Consul官網,很好的解釋了Consul的工作原理,先大致看一下。
首先Consul支持多數據中心,在上圖中有兩個DataCenter,他們通過Internet互聯,同時請注意為了提高通信效率,只有Server節點才加入跨數據中心的通信。
在單個數據中心中,Consul分為Client和Server兩種節點(所有的節點也被稱為Agent),Server節點保存數據,Client負責健康檢查及轉發數據請求到Server;Server節點有一個Leader和多個Follower,Leader節點會將數據同步到Follower,Server的數量推薦是3個或者5個,在Leader掛掉的時候會啟動選舉機制產生一個新的Leader。
集群內的Consul節點通過gossip協議(流言協議)維護成員關系,也就是說某個節點了解集群內現在還有哪些節點,這些節點是Client還是Server。單個數據中心的流言協議同時使用TCP和UDP通信,並且都使用8301端口。跨數據中心的流言協議也同時使用TCP和UDP通信,端口使用8302。
集群內數據的讀寫請求既可以直接發到Server,也可以通過Client使用RPC轉發到Server,請求最終會到達Leader節點,在允許數據輕微陳舊的情況下,讀請求也可以在普通的Server節點完成,集群內數據的讀寫和復制都是通過TCP的8300端口完成。
Consul服務發現原理
下面這張圖是自己畫的,基本描述了服務發現的完整流程,先大致看一下。
首先需要有一個正常的Consul集群,有Server,有Leader。這里在服務器Server1、Server2、Server3上分別部署了Consul Server,假設他們選舉了Server2上的Consul Server節點為Leader。這些服務器上最好只部署Consul程序,以盡量維護Consul Server的穩定。
然后在服務器Server4和Server5上通過Consul Client分別注冊Service A、B、C,這里每個Service分別部署在了兩個服務器上,這樣可以避免Service的單點問題。服務注冊到Consul可以通過HTTP API(8500端口)的方式,也可以通過Consul配置文件的方式。Consul Client可以認為是無狀態的,它將注冊信息通過RPC轉發到Consul Server,服務信息保存在Server的各個節點中,並且通過Raft實現了強一致性。
最后在服務器Server6中Program D需要訪問Service B,這時候Program D首先訪問本機Consul Client提供的HTTP API,本機Client會將請求轉發到Consul Server,Consul Server查詢到Service B當前的信息返回,最終Program D拿到了Service B的所有部署的IP和端口,然后就可以選擇Service B的其中一個部署並向其發起請求了。如果服務發現采用的是DNS方式,則Program D中直接使用Service B的服務發現域名,域名解析請求首先到達本機DNS代理,然后轉發到本機Consul Client,本機Client會將請求轉發到Consul Server,Consul Server查詢到Service B當前的信息返回,最終Program D拿到了Service B的某個部署的IP和端口。
圖中描述的部署架構筆者認為是最普適最簡單的方案,從某些默認配置或設計上看也是官方希望使用者采用的方案,比如8500端口默認監聽127.0.0.1,當然有些同學不贊同,后邊會提到其他方案。
Consul實際使用
為了更快的熟悉Consul的原理及其使用方式,最好還是自己實際測試下。
Consul安裝十分簡單,但是在一台機器上不方便搭建集群進行測試,使用虛擬機比較重,所以這里選擇了docker。這里用了Windows 10,需要是專業版,因為Windows上的Docker依賴Hyper-V,而這個需要專業版才能支持。這里對於Docker的使用不會做過多的描述,如果遇到相關問題請搜索一下。
安裝Docker
通過這個地址下載安裝:
https://store.docker.com/editions/community/docker-ce-desktop-windows
安裝完成后打開 Windows PowerShell,輸入docker –version,如果正常輸出docker版本就可以了。
啟動Consul集群
在 Windows PowerShell中執行命令拉取最新版本的Consul鏡像:
docker pull consul |
然后就可以啟動集群了,這里啟動4個Consul Agent,3個Server(會選舉出一個leader),1個Client。
#啟動第1個Server節點,集群要求要有3個Server,將容器8500端口映射到主機8900端口,同時開啟管理界面 |
第1個啟動容器的IP一般是172.17.0.2,后邊啟動的幾個容器IP會排着來:172.17.0.3、172.17.0.4、172.17.0.5。
這些Consul節點在Docker的容器內是互通的,他們通過橋接的模式通信。但是如果主機要訪問容器內的網絡,需要做端口映射。在啟動第一個容器時,將Consul的8500端口映射到了主機的8900端口,這樣就可以方便的通過主機的瀏覽器查看集群信息。
進入容器consul1:
docker exec -it consul1 /bin/sh |
輸入exit可以跳出容器。
服務注冊
自己寫一個web服務,用最熟悉的開發語言就好了,不過需要在容器中能夠跑起來,可能需要安裝運行環境,比如python、java、.net core等的sdk及web服務器,需要注意的是Consul的docker鏡像基於alpine系統,具體運行環境的安裝請搜索一下。
這里寫了一個hello服務,通過配置文件的方式注冊到Consul,服務的相關信息:
- name:hello,服務名稱,需要能夠區分不同的業務服務,可以部署多份並使用相同的name注冊。
- id:hello1,服務id,在每個節點上需要唯一,如果有重復會被覆蓋。
- address:172.17.0.5,服務所在機器的地址。
- port:5000,服務的端口。
- 健康檢查地址:http://localhost:5000/,如果返回HTTP狀態碼為200就代表服務健康,每10秒Consul請求一次,請求超時時間為1秒。
請將下面的內容保存成文件services.json,並上傳到容器的/consul/config目錄中。
{ |
復制到consul config目錄:
docker cp {這里請替換成services.json的本地路徑} consul4:/consul/config |
重新加載consul配置:
consul reload |
然后這個服務就注冊成功了。可以將這個服務部署到多個節點,比如部署到consul1和consul4,並同時運行。
服務發現
服務注冊成功以后,調用方獲取相應服務地址的過程就是服務發現。Consul提供了多種方式。
HTTP API方式:
curl http://127.0.0.1:8500/v1/health/service/hello?passing=false |
返回的信息包括注冊的Consul節點信息、服務信息及服務的健康檢查信息。這里用了一個參數passing=false,會自動過濾掉不健康的服務,包括本身不健康的服務和不健康的Consul節點上的服務,從這個設計上可以看出Consul將服務的狀態綁定到了節點的狀態。
如果服務有多個部署,會返回服務的多條信息,調用方需要決定使用哪個部署,常見的可以隨機或者輪詢。為了提高服務吞吐量,以及減輕Consul的壓力,還可以緩存獲取到的服務節點信息,不過要做好容錯的方案,因為緩存服務部署可能會變得不可用。具體是否緩存需要結合自己的訪問量及容錯規則來確定。
上邊的參數passing默認為false,也就是說不健康的節點也會返回,結合獲取節點全部服務的方法,這里可以做到獲取全部服務的實時健康狀態,並對不健康的服務進行報警處理。
DNS方式:
hello服務的域名是:hello.service.dc1.consul,后邊的service代表服務,固定;dc1是數據中心的名字,可以配置;最后的consul也可以配置。
官方在介紹DNS方式時經常使用dig命令進行測試,但是alpine系統中沒有dig命令,也沒有相關的包可以安裝,但是有人實現了,下載下來解壓到bin目錄就可以了。
curl -L https://github.com/sequenceiq/docker-alpine-dig/releases/download/v9.10.2/dig.tgz\|tar -xzv -C /usr/local/bin |
然后執行dig命令:
dig @127.0.0.1 -p 8600 hello.service.dc1.consul. ANY |
如果報錯:parse of /etc/resolv.conf failed ,請將resolv.conf中的search那行刪掉。
正常的話可以看到返回了服務部署的IP信息,如果有多個部署會看到多個,如果某個部署不健康了會自動剔除(包括部署所在節點不健康的情況)。需要注意這種方式不會返回服務的端口信息。
使用DNS的方式可以在程序中集成一個DNS解析庫,也可以自定義本地的DNS Server。自定義本地DNS Server是指將.consul域的請求全部轉發到Consul Agent,Windows上有DNS Agent,Linux上有Dnsmasq;對於非Consul提供的服務則繼續請求原DNS;使用DNS Server時Consul會隨機返回具體服務的多個部署中的一個,僅能提供簡單的負載均衡。
DNS緩存問題:DNS緩存一般存在於應用程序的網絡庫、本地DNS客戶端或者代理,Consul Sever本身可以認為是沒有緩存的(為了提高集群DNS吞吐量,可以設置使用普通Server上的陳舊數據,但影響一般不大),DNS緩存可以減輕Consul Server的訪問壓力,但是也會導致訪問到不可用的服務。使用時需要根據實際訪問量和容錯能力確定DNS緩存方案。
Consul Template
Consul Template是Consul官方提供的一個工具,嚴格的來說不是標准的服務發現方式。這個工具會通過Consul監聽數據變化然后替換模板中使用的標簽,並發布替換后的文件到指定的目錄。在nginx等web服務器做反向代理和負載均衡時特別有用。
Consul的docker鏡像中沒有集成這個工具,需要自己安裝,比較簡單:
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 |
然后創建一個文件:in.tpl,內容為:
{{ range service "hello" }} |
這個標簽會遍歷hello服務的所有部署,並按照指定的格式輸出。在此文件目錄下執行:
nohup consul-template -template "in.tpl:out.txt" & |
現在你可以cat out.txt查看根據模板生產的內容,新增或者關閉服務,文件內容會自動更新。
此工具我沒有用在生產環境,詳細使用請訪問:https://github.com/hashicorp/consul-template
節點和服務注銷
節點和服務的注銷可以使用HTTP API:
- 注銷任意節點和服務:/catalog/deregister
- 注銷當前節點的服務:/agent/service/deregister/:service_id
注意:
如果注銷的服務還在運行,則會再次同步到catalog中,因此應該只在agent不可用時才使用catalog的注銷API。
節點在宕機時狀態會變為failed,默認情況下72小時后會被從集群移除。
如果某個節點不繼續使用了,也可以在本機使用consul leave命令,或者在其它節點使用consul force-leave 節點Id,則節點上的服務和健康檢查全部注銷。
Consul的健康檢查
Consul做服務發現是專業的,健康檢查是其中一項必不可少的功能,其提供Script/TCP/HTTP+Interval,以及TTL等多種方式。服務的健康檢查由服務注冊到的Agent來處理,這個Agent既可以是Client也可以是Server。
很多同學都使用ZooKeeper或者etcd做服務發現,使用Consul時發現節點掛掉后服務的狀態變為不可用了,所以有同學問服務為什么不在各個節點之間同步?這個根本原因是服務發現的實現原理不同。
Consul與ZooKeeper、etcd的區別
后邊這兩個工具是通過鍵值存儲來實現服務的注冊與發現。
- ZooKeeper利用臨時節點的機制,業務服務啟動時創建臨時節點,節點在服務就在,節點不存在服務就不存在。
- etcd利用TTL機制,業務服務啟動時創建鍵值對,定時更新ttl,ttl過期則服務不可用。
ZooKeeper和etcd的鍵值存儲都是強一致性的,也就是說鍵值對會自動同步到多個節點,只要在某個節點上存在就可以認為對應的業務服務是可用的。
Consul的數據同步也是強一致性的,服務的注冊信息會在Server節點之間同步,相比ZK、etcd,服務的信息還是持久化保存的,即使服務部署不可用了,仍舊可以查詢到這個服務部署。但是業務服務的可用狀態是由注冊到的Agent來維護的,Agent如果不能正常工作了,則無法確定服務的真實狀態,並且Consul是相當穩定了,Agent掛掉的情況下大概率服務器的狀態也可能是不好的,此時屏蔽掉此節點上的服務是合理的。Consul也確實是這樣設計的,DNS接口會自動屏蔽掛掉節點上的服務,HTTP API也認為掛掉節點上的服務不是passing的。
鑒於Consul健康檢查的這種機制,同時避免單點故障,所有的業務服務應該部署多份,並注冊到不同的Consul節點。部署多份可能會給你的設計帶來一些挑戰,因為調用方同時訪問多個服務實例可能會由於會話不共享導致狀態不一致,這個有許多成熟的解決方案,可以去查詢,這里不做說明。
健康檢查能不能支持故障轉移?
上邊提到健康檢查是由服務注冊到的Agent來處理的,那么如果這個Agent掛掉了,會不會有別的Agent來接管健康檢查呢?答案是否定的。
從問題產生的原因來看,在應用於生產環境之前,肯定需要對各種場景進行測試,沒有問題才會上線,所以顯而易見的問題可以屏蔽掉;如果是新版本Consul的BUG導致的,此時需要降級;如果這個BUG是偶發的,那么只需要將Consul重新拉起來就可以了,這樣比較簡單;如果是硬件、網絡或者操作系統故障,那么節點上服務的可用性也很難保障,不需要別的Agent接管健康檢查。
從實現上看,選擇哪個節點是個問題,這需要實時或准實時同步各個節點的負載狀態,而且由於業務服務運行狀態多變,即使當時選擇出了負載比較輕松的節點,無法保證某個時段任務又變得繁重,可能造成新的更大范圍的崩潰。如果原來的節點還要啟動起來,那么接管的健康檢查是否還要撤銷,如果要,需要記錄服務們最初注冊的節點,然后有一個監聽機制來觸發,如果不要,通過服務發現就會獲取到很多冗余的信息,並且隨着時間推移,這種數據會越來越多,系統變的無序。
從實際應用看,節點上的服務可能既要被發現,又要發現別的服務,如果節點掛掉了,僅提供被發現的功能實際上服務還是不可用的。當然發現別的服務也可以不使用本機節點,可以通過訪問一個Nginx實現的若干Consul節點的負載均衡來實現,這無疑又引入了新的技術棧。
如果不是上邊提到的問題,或者你可以通過一些方式解決這些問題,健康檢查接管的實現也必然是比較復雜的,因為分布式系統的狀態同步是比較復雜的。同時不要忘了服務部署了多份,掛掉一個不應該影響系統的快速恢復,所以沒必要去做這個接管。
Consul的其它部署架構
如果你實在不想在每個主機部署Consul Client,還有一個多路注冊的方案可供選擇,這是交流群中獲得的思路。
如圖所示,在專門的服務器上部署Consul Client,然后每個服務都注冊到多個Client,這里為了避免服務單點問題還是每個服務部署多份,需要服務發現時,程序向一個提供負載均衡的程序發起請求,該程序將請求轉發到某個Consul Client。這種方案需要注意將Consul的8500端口綁定到私網IP上,默認只有127.0.0.1。
這個架構的優勢:
- Consul節點服務器與應用服務器隔離,互相干擾少;
- 不用每台主機都部署Consul,方便Consul的集中管理;
- 某個Consul Client掛掉的情況下,注冊到其上的服務仍有機會被訪問到;
但也需要注意其缺點:
- 引入更多技術棧:負載均衡的實現,不僅要考慮Consul Client的負載均衡,還要考慮負載均衡本身的單點問題。
- Client的節點數量:單個Client如果注冊的服務太多,負載較重,需要有個算法(比如hash一致)合理分配每個Client上的服務數量,以及確定Client的總體數量。
- 服務發現要過濾掉重復的注冊,因為注冊到了多個節點會認為是多個部署(DNS接口不會有這個問題)。
這個方案其實還可以優化,服務發現使用的負載均衡可以直接代理Server節點,因為相關請求還是會轉發到Server節點,不如直接就發到Server。
是否可以只有Server?
這個問題的答案還是有關服務數量的問題,首先Server的節點數量不是越多越好,3個或者5個是推薦的數量,數量越多數據同步的處理越慢(強一致性);然后每個節點可以注冊的服務數量是有上限的,這個受限於軟硬件的處理能力。所以如果你的服務只有10個左右,只有Server問題是不大的,但是這時候有沒有必要使用Consul呢?因此正常使用Consul的時候還是要有Client才好,這也符合Consul的反熵設計。
大家可以將這個部署架構與前文提到的普適架構對比下,看看哪個更適合自己,或者你有更好的方案歡迎分享出來。
轉載:
https://segmentfault.com/a/1190000018731395
https://blog.didispace.com/consul-service-discovery-exp/
部署:
https://blog.csdn.net/a624575745856085/article/details/101618374
https://www.cnblogs.com/duanxz/p/10564502.html
異地中心配置:
https://blog.csdn.net/weixin_42215229/article/details/100561522
生產環境配置
https://blog.51cto.com/shmilyjinian/2512077
3個server一個client
https://blog.csdn.net/u014635374/article/details/106313858