Consul集群Server模式
架構示意圖
Consul在生產環境下運行模式分為兩種:Server模式和Client模式(dev模式屬於開發模式不在這里討論),我們先用Server模式搭建一個Consul集群,示意圖如下:
Consul Server A、B、C是啟動的三個Consul服務運行於Server模式下,其中Consul Server C 是“總指揮”,他們的Leader,Consul Server A和B是Follower當“替補”,他們都可以提供注冊和查詢微服務器的功能。Leader負責給其他Follower同步數據和監控各個節點的健康,Leader是由他們仨根據Raft一致性算法選舉出來的,Server模式運行的Consul服務不能太多,推薦3或5個,因為太多開會選舉性能不佳,並且個數要求是奇數(選舉算法要求)。
spring-cloud-provider是模擬的服務提供者程序,spring-cloud-provider-second也是模式的服務提供者程序只是返回內容上不太一樣(便於區分是哪個服務返回),他們都在Consul中注冊同一個服務名稱:service-provider,spring-cloud-consul-consumer是模擬服務消費者程序,負責使用service-provider服務。
搭建環境
為了測試方便我們使用docker進行部署,上述服務可以從以下地址下載:
bluersw/spring-cloud-consul-consumer 是服務消費者鏡像里面運行的程序項目叫spring-cloud-consul-client,因為名字的起的不講究導致了混亂,spring-cloud-consul-client不是Consul Client。
docker pull consul
docker pull bluersw/spring-cloud-consul-consumer:v1
docker pull bluersw/spring-cloud-provider:v1
docker pull bluersw/spring-cloud-provider-second:v1
啟動Consul腳本(Windows版本的Docker運行命令時參數的IP地址要用"ip地址",比如:-client="0.0.0.0"):
docker run -i -t -p 8500:8500 --name=ConsulServer-C consul agent -server -ui -node=Server-C -bootstrap-expect=3 -client=0.0.0.0
docker run -i -t -p 8501:8500 --name=ConsulServer-A consul agent -server -ui -node=Server-A -bootstrap-expect=3 -client=0.0.0.0 -join=172.17.0.2
docker run -i -t -p 8502:8500 --name=ConsulServer-B consul agent -server -ui -node=Server-B -bootstrap-expect=3 -client=0.0.0.0 -join=172.17.0.2
bootstrap-expect是指最少幾個Server模式下的Consul服務,整個集群才啟動。
join=172.17.0.2這個地址就是Server-C的IP地址,Server-C是Leader。
啟動后查看127.0.0.1:8500端口查看后台:
然后啟動消費者和生產者docker:
docker run -t -i --name=spring-cloud-provider -p 9001:9001 bluersw/spring-cloud-provider:v1
source /etc/profile
cd /opt
java -jar spring-cloud-provider-0.0.1-SNAPSHOT.jar
docker run -t -i --name=spring-cloud-provider-second -p 9002:9002 bluersw/spring-cloud-provider-second:v1
source /etc/profile
cd /opt
java -jar spring-cloud-provider-second-0.0.1-SNAPSHOT.jar
docker run -t -i --name=spring-cloud-consul-consumer -p 9003:9003 bluersw/spring-cloud-consul-consumer:v1
source /etc/profile
cd /opt
java -jar spring-cloud-consul-client-0.0.1-SNAPSHOT.jar
注冊服務示例:
spring.application.name=spring-cloud-provider-01
server.port=9001
#172.17.0.3是Server-A
spring.cloud.consul.host=172.17.0.3
spring.cloud.consul.port=8500
#注冊到consul的服務名稱
spring.cloud.consul.discovery.serviceName=service-provider
#以下兩項如果不配置健康檢查一定失敗
spring.cloud.consul.discovery.prefer-ip-address=true
spring.cloud.consul.discovery.health-check-path=/actuator/health
spring.application.name=spring-cloud-provider-02
server.port=9002
#172.17.0.4是Server-B
spring.cloud.consul.host=172.17.0.4
spring.cloud.consul.port=8500
#注冊到consul的服務名稱
spring.cloud.consul.discovery.serviceName=service-provider
#以下兩項如果不配置健康檢查一定失敗
spring.cloud.consul.discovery.prefer-ip-address=true
spring.cloud.consul.discovery.health-check-path=/actuator/health
啟動后Docker容器內容:
service-provider服務已經注冊完畢:
訪問127.0.0.1:9003/TestHello 測試部署結果:
模擬服務器故障
關閉Consul Server B
Consul Server B 已經不能訪問:
從Leader上看Server-B節點已經故障:
從Leader上看服務service-provider的注冊節點檢查已經出現紅叉:
因為Consul處理機制consul節點故障其中注冊的服務都視為不可用,所以spring-cloud-provider-second服務雖然沒有出問題,但已經不再被輪詢到,兩次訪問都是訪問的spring-cloud-provider服務。
恢復Consul Server B
重新啟動Consul Server B后,一切自動恢復:
關閉Consul Server C
因為關閉Consul Server C是Leader,所以Consul Server C被關閉之后,Leader被Consul Server B接管:
此時如果spring-cloud-consul-consumer程序不重新啟動,那么因為其保留着上次查詢服務的緩存所以還可以繼續顯示正常:
如果重新啟動因為找不到注冊服務的Consul Server C會在訪問時發生異常:
恢復Consul Server C
Consul Server C之后,Leader仍然是Consul Server B
相關服務恢復正常,由上面的測試可以知道Consul大致的故障處理策略:
源碼
Github倉庫:https://github.com/sunweisheng/spring-cloud-example