延續上一篇的話題繼續,順便放上一篇的傳送門:點這裡。
叢集的必要性
consul本身就是管理叢集的,現在還需要給consul搞個叢集,這是為啥?因為consul單點也容易掛啊!萬一管理叢集的consul掛掉了,那麼相當於上下游應用都變成了瞎子,看不到也調不到。所以叢集的必要性不用我說了吧?
Server & Client
生產環境下,可以選擇上面兩種模式,下面我就簡稱S端、C端。說說它倆有啥不一樣:
S端:
1、數量不宜過多,一般推薦3、5個,要求是奇數。
2、持久化儲存節點資料。
3、多個S端之間是主從關係(Leader/Follower),Leader要額外負責監控各節點的健康並且同步給Follower。
C端:
1、數量沒限制。
2、不儲存節點資料。
相同點就是S端、C端都可以註冊、查詢。
Leader & Follower
這模式我簡稱主從好了,它只針對S端。Leader是根據Raft演算法自動選舉得出的,不用手動指定,所有的Follower接到資訊以後,都要提交給Leader,然後Leader同步給其他的Follower。並且Leader要一直髮心跳給所有的Follower證明“我還活著”,否則其他的Follower之間就要再選舉出一個新的Leader了。這就導致S端最好不要擴充套件太多,否則你會懷疑人生。至於為什麼要求S端數量是奇數,其實很好理解,偶數容易影響選舉結果導致效率變低,比如兩票對兩票,誰來當Leader?其實去了解一下Raft演算法就知道這裡的主從怎麼執行的,什麼原理。我上個神器:戳這裡,不用謝我。
S端
老規矩,還是用docker。先跑三個起來:
docker run -d --restart=always --name=server1 -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 server1 consul agent -server -bind=0.0.0.0 -bootstrap-expect=3 -node=server1 -data-dir=/tmp/data-dir -client 0.0.0.0 -ui
docker run -d --restart=always --name=server2 -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 server2 consul agent -server -bind=0.0.0.0 -join=你伺服器的IP -node=server2 -data-dir=/tmp/data-dir -client 0.0.0.0 -ui
docker run -d --restart=always --name=server3 -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 server3 consul agent -server -bind=0.0.0.0 -join=你伺服器的IP -node=server3 -data-dir=/tmp/data-dir -client 0.0.0.0 -ui
bootstrap-expect:叢集所需S端的最小數量,低於這個數量無法選舉出leader。
join:加入到哪個叢集,需要目標伺服器放通tcp8301埠,否則會出現這種情況
可以語句檢視主從關係:
docker exec -t server1 consul operator raft list-peers
也可以直接進入頁面檢視主從關係,結果一樣:
把現在的leader幹掉的話,會自動選舉一個新的leader出來:
server3成為了新的leader,而且只要它不掛,leader身份是不會轉移的。比如我把server1啟動以後,leader沒有轉移過去:
OK,現在S端已經是叢集了,而且它們之間的資料都是互通共存的。驗證一下:
server1新增鍵值,key=shenzhenma,value=hellow:
server2檢視:
server3修改value=hellow world以後,server1檢視:
C端
現在再來啟動客戶端:
docker run -d --restart=always --name=client1 -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt":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 client1 consul agent -bind=0.0.0.0 -retry-join=你伺服器的IP -node=client1 -data-dir=/tmp/data-dir -client 0.0.0.0 -ui
想要多個客戶端的話,改一下埠和名字就可以了,我這裡跑了3個,如圖:
和剛才的3個S端一起,這6個都是一體的,資料都會自動同步,任意節點註冊修改資料都會在其他節點看到。
入口統一
我把叢集弄好了,但是現在的叢集還沒有發揮作用。前幾篇文章有講服務註冊,consul註冊的時候需要一個固定的地址。叢集有很多節點,每一個IP埠都不一樣,如果下端只和其中一個節點產生聯絡,萬一這個節點掛了,下端就失去consul的支援了,叢集的作用也沒發揮出來。所以給下端一個統一的入口是必要的,這裡用Nginx的Upstream模式實現,修改下配置檔案就行了:
upstream myconsul {
server 42.XX.XX.64:8500;
server 42.XX.XX.64:9500;
server 42.XX.XX.64:10500;
server 42.XX.XX.64:11500;
server 42.XX.XX.64:12500;
server 42.XX.XX.64:13500;
}
server{
listen 88;
server_name localhost;
location / {
proxy_pass http://myconsul;
}
}
配置檔案修改好重啟一下,進去看看能不能訪問:
OK,下端註冊服務時,統一用這個地址就可以了。跑兩個試試(下端程式碼就不發了,前面幾篇文章有):
成功了!切換到其他consul節點看下能否正確展示:
很顯然是OK的。基於我之前為服務配置的健康檢查,最後來看下服務狀態變化會不會同步給其他節點,比如我停掉其中一個:
變更的狀態也很快同步到了其他節點。到這裡為止,consul的叢集就已經實現了,東西還是有點多的,如果實踐遇到麻煩,歡迎討論。