随笔- 2039  评论- 180  文章- 4 

consul分布式集群搭建

环境准备

三台机器:

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.9110.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"
}

 

posted on 2019-03-20 13:55 duanxz 阅读(...) 评论(...) 编辑 收藏