環境准備
三台機器:
vm-a 10.200.110.90 centos7
vm-b 10.200.110.91 centos7
vm-c 10.200.110.93 centos7
Consul官網(https://www.consul.io/downloads.html)下載相應系統的consul可執行文件並放系統PATH環境變量目錄內。
我下載的是consul_1.4.3_linux_amd64.zip,在上面的每台機器上解壓,並拷貝到/usr/local/bin目錄下。
unzip consul_1.4.3_linux_amd64.zip mv cosul /usr/local/bin
集群啟動
10.200.110.90啟動consul consul agent -server -bootstrap-expect=3 -data-dir=/tmp/consul -node=10.200.110.90 -bind=10.200.110.90 -client=0.0.0.0 -datacenter=shenzhen -ui 10.200.110.91啟動consul consul agent -server -bootstrap-expect 3 -data-dir /tmp/consul -node 10.200.110.91 -bind=10.200.110.91 -client=0.0.0.0 -datacenter shenzhen -ui 10.200.110.93啟動consul consul agent -server -bootstrap-expect 3 -data-dir /tmp/consul -node 10.200.110.93 -bind=10.200.110.93 -client=0.0.0.0 -datacenter shenzhen -ui
參數說明:
- server: 以server身份啟動。默認是client
- bootstrap-expect:集群要求的最少server數量,當低於這個數量,集群即失效。
- data-dir:data存放的目錄,更多信息請參閱consul數據同步機制
- node:節點id,集群中的每個node必須有一個唯一的名稱。默認情況下,Consul使用機器的hostname
- bind:監聽的ip地址。默認綁定0.0.0.0,可以不指定。表示Consul監聽的地址,而且它必須能夠被集群中的其他節點訪問。Consul默認會監聽第一個private IP,但最好還是提供一個。生產設備上的服務器通常有好幾個網卡,所以指定一個不會出錯
- client: 客戶端的ip地址,0.0.0.0是指誰都可以訪問(不加這個,下面的ui :8500無法訪問)
- ui: 可以訪問UI界面
- -config-dir指定配置文件夾,Consul會加載其中的所有文件
- -datacenter 指定數據中心名稱,默認是dc1
此時三台機器都會打印:
2019/03/20 10:57:36 [INFO] agent: Started HTTP server on 127.0.0.1:8500 (tcp) 2019/03/20 10:57:36 [INFO] agent: started state syncer 2019/03/20 10:57:44 [ERR] agent: failed to sync remote state: No cluster leader
此時三台機器還未join,不能算是一個集群,三台機器上的consul均不能正常工作,因為leader未選出。
三台機器組成consul集群
consul集群:當一個consul agent啟動后,它不知道任何其他節點,要學習到集群中的其他節點,agent必須加入一個已經存在的集群(cluster)。要加入這樣的集群,它只需要知道這個集群中的一個節點即可。它加入后,將會和這個member gossip(交談)並迅速發現集群中的其他節點。一個consul agent可以加入任何類型的其他agent,而不只是那些運行於server mode的agent。
分別登錄第2台和第3台虛擬機上執行如下命令,讓consul加入集群:
10.200.110.91加入10.200.110.90
[root@localhost consul-cluster]# consul join 10.200.110.90 Successfully joined cluster by contacting 1 nodes. [root@localhost consul-cluster]#
10.200.110.93加入10.200.110.90
[root@localhost consul-cluster]# consul join 10.200.110.90
Successfully joined cluster by contacting 1 nodes. [root@localhost consul-cluster]#
很快三台機器都會打印:
2019/03/20 10:59:12 [INFO] raft: Added peer d89335fd-cfb8-1fc0-3902-b847e125fa2c, starting replication 2019/03/20 10:59:12 [INFO] consul: cluster leadership acquired 2019/03/20 10:59:12 [INFO] consul: New leader elected: 10.200.110.90
證明此時leader已經選出,集群可以正常工作。訪問:http://10.200.110.90:8500/
上圖中的下拉框是datacenter的選項。
集群狀態查看
[root@localhost ~]# consul operator raft list-peers Node ID Address State Voter RaftProtocol 10.200.110.90 239bfd6a-28d0-094a-4d93-09bf81414528 10.200.110.90:8300 leader true 3 10.200.110.91 d1b05900-4f8f-b956-5ba6-5a3c798d93d3 10.200.110.91:8300 follower true 3 10.200.110.93 d89335fd-cfb8-1fc0-3902-b847e125fa2c 10.200.110.93:8300 follower true 3 [root@localhost ~]#
查看members狀態:
[root@localhost ~]# consul members Node Address Status Type Build Protocol DC Segment 10.200.110.90 10.200.110.90:8301 alive server 1.4.3 2 shenzhen <all> 10.200.110.91 10.200.110.91:8301 alive server 1.4.3 2 shenzhen <all> 10.200.110.93 10.200.110.93:8301 alive server 1.4.3 2 shenzhen <all> [root@localhost ~]#
集群參數get/set測試
10.200.110.93的set操作:
[root@localhost ~]# consul kv put addr nanshan Success! Data written to: addr [root@localhost ~]#
10.200.110.91的get操作:
[root@localhost consul-cluster]# consul kv get addr
nanshan
[root@localhost consul-cluster]#
在10.200.110.90可以正常設置key的值為value,並能正常查回來。三台機器獲取key的值均為value,如此可知key的值已經在集群中同步。
集群單機故障處理
單機consul進程故障發生
殺死三台機器中任意一台機器上的consul進程,這里殺死leader 192.168.1.235
在10.200.110.90機器上執行:
[root@localhost ~]# ps -ef | grep consul root 24811 7330 6 10:57 pts/0 00:12:44 consul agent -server -bootstrap-expect=3 -data-dir=/tmp/consul -node=10.200.110.90 -bind=10.200.110.90 -datacenter=shenzhen -ui root 24957 24939 0 13:59 pts/1 00:00:00 grep --color=auto consul [root@localhost ~]# kill -9 24811 [root@localhost ~]#
此時看此台機器上的consul的log:
2019/03/20 11:03:36 [INFO] serf: EventMemberUpdate: 10.200.110.93.shenzhen 2019/03/20 11:03:37 [WARN] raft: Failed to contact d89335fd-cfb8-1fc0-3902-b847e125fa2c in 2.500740308s 2019/03/20 11:03:37 [INFO] raft: pipelining replication to peer {Voter d89335fd-cfb8-1fc0-3902-b847e125fa2c 10.200.110.93:8300} 已殺死 [root@localhost consul-cluster]#
Consul進程已經在這台機器上退出。
此時都會10.200.110.91和10.200.110.93都會打印
[ERR] agent: failed to sync remote state:No cluster leader
[WARN] raft: Heartbeat timeout from"10.200.110.90:8300" reached, starting election
Leader丟失,剩下的兩台機重新進行leader選舉
[root@localhost ~]# consul operator raft list-peers Node ID Address State Voter RaftProtocol 10.200.110.93 d89335fd-cfb8-1fc0-3902-b847e125fa2c 10.200.110.93:8300 leader true 3 10.200.110.91 d1b05900-4f8f-b956-5ba6-5a3c798d93d3 10.200.110.91:8300 follower true 3 10.200.110.90 239bfd6a-28d0-094a-4d93-09bf81414528 10.200.110.90:8300 follower true 3 [root@localhost ~]#
此時再對10.200.110.91和10.200.110.93進行key的get/set操作:
[root@localhost ~]# consul kv get addr
nanshan
[root@localhost ~]#
均能正常get到key的值為nanshan。
Consul 多數據中心配置 MULTIPLE DATACENTERS
在consul集群中,多數據中心可以進行配置:
LAN gossip pool包含了同一局域網內所有節點,包括server與client。這基本上是位於同一個數據中心DC。
WAN gossip pool一般僅包含server,將跨越多個DC數據中心,通過互聯網或廣域網進行通信。
我們之前講過的啟動集群命令使用的是-bootstrap 來作為服務的啟動:
10.200.110.95啟動consul
consul agent -server -bootstrap-expect 3 -data-dir /tmp/consul -node 10.200.110.95 -bind=10.200.110.93 -datacenter guangzhou -ui
查詢當前集群下擁有的datacenter信息:
consul members -wan
我這里有兩個數據中心shenzhen和guangzhou,使用下面的命令將數據中心互相可見:
[root@localhost ~]# consul join -wan 10.200.110.91
Successfully joined cluster by contacting 1 nodes.
[root@localhost ~]#
多數據中心就配好了,在之前的UI中也可以看到了:
查詢當前集群下擁有的datacenter信息:
[root@localhost ~]# consul members -wan Node Address Status Type Build Protocol DC Segment 10.200.110.91.shenzhen 10.200.110.91:8302 alive server 1.4.3 2 shenzhen <all> 10.200.110.93.shenzhen 10.200.110.93:8302 alive server 1.4.3 2 shenzhen <all> 10.200.110.95.guangzhou 10.200.110.95:8302 alive server 1.4.3 2 guangzhou <all> [root@localhost ~]#
參照consul部署,部署兩個數據中dc1和dc2。數據中心的名字對consul而言是不透明的,它們只是用於管理員與consul交互使用。
通過consulmembers –wan命令可以查詢WAN中的節點:
$ consul members-wan
...
輸出結果是WAN gossip pool中的節點列表,只包含server節點。 client節點只會想本地數據中的server節點發送請求,不會加入WAN Gossip Pool。Client請求會通過本地數據中的Server節點轉發到目標數據中心。
下一步是保證所有的Server節點均加入到WAN gossip Pool。
$ consul join -wan<server 1> <server 2> ...
...
join命令加上-wan參數,是講Server加入到WAN gossip pool。而LAN gossip pool,只需要加入到現有的某個Server節點即可,和通過gossip協議與其他成員交換信息即可知道所有的成員節點。然而,對於啟動的consul的Server,只知道自己的信息,必須添加到群集中。
一旦加入完成,基於WAN通過gossip協議就可以使用members命令查詢所有的Server節點。
我們也可以通過HTTP API來查詢所有的數據中心:
$ curlhttp://localhost:8500/v1/catalog/datacenters
["dc1", "dc2"]
做一個簡單的測試,查詢某個數據中心的所有節點:
$ curlhttp://localhost:8500/v1/catalog/nodes?dc=dc1
...
$ curlhttp://localhost:8500/v1/catalog/nodes?dc=dc2
...
構建多數據中心,網絡需要滿足如下要求:1.所有的Server節點都是互通,否則,基於gossip協議的RPC轉發將無法工作。如果服務發現是可以跨數據中心,網絡必須能夠跨區域之間的路由的IP地址以及。2.如果使用服務發現,那么所有的數據中心都是互通的,或者基於VPN或其他隧道機制是互通的。Consul不能處理VPN、address rewritting,或者NAT traversal。
SpringCloud在consul集群示例
環境:
ip | 10.200.110.90 | 10.200.110.91 | 10.200.110.93 | 10.200.110.89 | 10.200.110.95 |
consul agent | consul agent server | consul agent server | consul agent server | ||
app | service-consumer | service-consumer | |||
app | service-producter | ||||
app |
應用注冊consul為:
應用啟動時注冊到consul集群的命令行:
java -jar -Dspring.cloud.consul.host=10.200.110.91 -Dserver.port=8091 -Dspring.cloud.consul.discovery.hostname=10.200.110.90 service-consumer-201903201556.jar
現在測試consul集群的高可用性,將10.200.110.90的consul agent server停掉。
service-consumer:
service-producter:
再觸發一次service-consumer調用service-producter的測試,訪問10.200.110.90:8091,調用到了10.200.110.95:8081的應用上。
http://10.200.110.90:8091/swagger-ui.html#!/book-consumer/getbook5UsingGET
consul的服務注冊的兩種方式:
和《Consul之:服務注冊與發現》有些重復。
方式1:通過配置文件方式
通過在consul的服務器的工作目錄中增加consul的配置文件的方式進行服務注冊,
例如,我在consul的機器上的/home/consul-cluster/config增加如下配置文件:
{ "service": { "name": "service-front", "tags": ["jar"], "address": "10.200.110.97", "port": 8001, "checks": [ { "http": "http://10.200.110.97:8001/health", "interval": "10s" }] } }
如果有多個服務時,
{ "services": [{ "id":"front1", "name": "service-front", "tags": ["local-dev"], "address": "10.200.110.100", "port": 8001, "checks": [{ "http": "http://10.200.110.100:8001/health", "interval": "10s" }] }, { "id":"front2", "name": "service-front", "tags": ["jar"], "address": "10.200.110.97", "port": 8001, "checks": [{ "http": "http://10.200.110.97:8001/health", "interval": "10s" }] }] }
在consul的控制台上,可見服務注冊成功。如下:
或者通過命令行查看驗證服務是否注冊成功:
[root@localhost consul-template]# curl http://10.200.110.90:8500/v1/catalog/service/service-front [{"ID":"d1b05900-4f8f-b956-5ba6-5a3c798d93d3","Node":"10.200.110.91","Address":"10.200.110.91","Datacenter":"shenzhen","TaggedAddresses":{"lan":"10.200.110.91","wan":"10.200.110.91"},"NodeMeta":{"consul-network-segment":""},"ServiceKind":"","ServiceID":"service-front-10-200-110-100-8001","ServiceName":"service-front","ServiceTags":["front-dev,這是個前置應用,網關層","duan"],"ServiceAddress":"10.200.110.100","ServiceWeights":{"Passing":1,"Warning":1},"ServiceMeta":{},"ServicePort":8001,"ServiceEnableTagOverride":false,"ServiceProxyDestination":"","ServiceProxy":{},"ServiceConnect":{},"CreateIndex":11382,"ModifyIndex":11382},{"ID":"382f88c2-4482-e1f7-1453-28f94ff65108","Node":"10.200.110.97","Address":"10.200.110.97","Datacenter":"shenzhen","TaggedAddresses":{"lan":"10.200.110.97","wan":"10.200.110.97"},"NodeMeta":{"consul-network-segment":""},"ServiceKind":"","ServiceID":"front1","ServiceName":"service-front","ServiceTags":["local-dev"],"ServiceAddress":"","ServiceWeights":{"Passing":1,"Warning":1},"ServiceMeta":{},"ServicePort":8001,"ServiceEnableTagOverride":false,"ServiceProxyDestination":"","ServiceProxy":{},"ServiceConnect":{},"CreateIndex":11976,"ModifyIndex":11976}][root@localhost consul-template]#
方式2:通過consul api方式
spring.cloud.consul.discovery.enabled: true spring.cloud.consul.discovery.healthCheckInterval: 10s spring.cloud.consul.discovery.instanceId: ${spring.application.name}:${spring.cloud.consul.discovery.hostname}:${server.port} spring.cloud.consul.enabled: true spring.cloud.consul.host: 10.200.110.100 spring.cloud.consul.port: 8500 spring.zipkin.base-url: http://10.200.110.4:9411 management.security.enabled: false server: port: 8001 spring: application: name: service-front author: duanxz description: service-front cloud: consul: discovery: hostname: 127.0.0.1 tags: - front-dev,這是個前置應用,網關層 - duan
待解決的問題
我組成的2個服務:
[root@localhost config]# cat apps.json { "services": [{ "id":"front1", "name": "service-front", "tags": ["local-dev"], "port": 8001, "checks": [{ "http": "http://10.200.110.97:8001/health", "interval": "10s" }] }, { "id":"demo", "name": "service-demo", "tags": ["jar"], "address": "10.200.110.97", "port": 8071, "checks": [{ "http": "http://10.200.110.97:8071/health", "interval": "10s" }] }] } [root@localhost config]#
通過json配置文件的方式,注冊到consul上的服務間無法通過Feign調用,
我的demo里,是service-front調用service-demo,打開swagger調用出現如下錯誤:
{ "timestamp": 1553161721543, "status": 500, "error": "Internal Server Error", "exception": "java.lang.RuntimeException", "message": "Request processing failed; nested exception is java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: service-demo", "path": "/book/show6/1" }