基于Docker的Consul集群实现服务发现
服务发现
以典型的集群为例,对于集群来说,是有多个节点的,这些节点对应多个ip(或者同一个ip的不同端口号),集群中不同节点责任是不一样的。
比如说一个数据集群中,可以分为读节点或者写节点,写节点和读节点都是相对的,不是硬绑定的,某一个逻辑节点,随着故障转移及恢复,是可以变换身份的(写变读,读变写;主降从,从升主等等)
集群对外提供服务的时候,对于外界来说,集群中节点身份变换的时候需要对外透明,外界无需因为集群节点的身份变换而更改配置,这就需要一个解耦合的服务。
这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建完整的服务解耦。 即便是用了谷歌翻译的情况下,这段翻译纠结了半天,不知道怎么翻译合适。
如下是按照自己对consul做服务发现的理解,简单整理的逻辑结构图,其原理还是比较容易理解的。
consul客户端可以提供一些健康检查,这些健康检查可以关联到一个指定的服务(服务是否返回200 ok),也可以关联到本地节点(内存使用率是否在90%以下)。
应用可以使用consul提供的分层键值存储用于一些目的,包括动态配置、特征标记、协作、leader选举等等。通过一个简单的http api可以很容易的使用这个组件。
多数据中心:
consul对多数据中心有非常好的支持,这意味着consul用户不必担心由于创建更多抽象层而产生的多个区域。
其中consul的服务端是3节点的集群,客户点是6节点3主3从的redis服务器集群,consul实现redis集群中读写服务注册于发现。
尽管redis cluster有多ip方式驱动连接,这里仅仅为了测试“服务发现”的。
其实本来想测试mysql单主模式的mgr,实现读写分离的服务发现,但是mysql有点太重了,机器配置不够,所以做了redis的集群来测试服务发现
作为服务发现的载体,consul是可以使用单节点运行的,作为解析服务的载体,是一个非常重要的角色,集群化具有更强的抗灾性,因此更多的时候是以多节点集群的方式运行解析服务的这个载体。
这里使用三个节点作为consul的集群服务端来运行,三个consul的服务节点ip分别是:172.18.0.11 ,172.18.0.12,172.18.0.13,需要固定ip
如下是172.18.0.11节点的配置,不同节点仅需修改bind_addr为对应机器(容器)的ip
/usr/local/server.json { "datacenter": "dc1", "data_dir": "/usr/local/", "log_level": "info", "server": true, "bootstrap_expect": 3, "bind_addr": "172.18.0.11", "client_addr": "0.0.0.0", "start_join": ["172.18.0.11","172.18.0.12","172.18.0.13"], "ui":true }
./consul agent -server -config-dir=/usr/local > /usr/local/consul.log &
由于配置文件中制定了集群的ip列表,因此无需显式加入集群(cluster join),正常情况下,启动三个节点后,会自动组成一个集群,并且自动选举出来一个leader。
consul客户端安装配置
docker run -itd --name redis01 --net mynetwork --ip 172.18.0.21 -v /usr/local/docker_file/redis01/:/usr/local/ centos
docker run -itd --name redis02 --net mynetwork --ip 172.18.0.22 -v /usr/local/docker_file/redis02/:/usr/local/ centos
docker run -itd --name redis03 --net mynetwork --ip 172.18.0.23 -v /usr/local/docker_file/redis03/:/usr/local/ centos
docker run -itd --name redis04 --net mynetwork --ip 172.18.0.24 -v /usr/local/docker_file/redis04/:/usr/local/ centos
docker run -itd --name redis05 --net mynetwork --ip 172.18.0.25 -v /usr/local/docker_file/redis05/:/usr/local/ centos
docker run -itd --name redis06 --net mynetwork --ip 172.18.0.26 -v /usr/local/docker_file/redis06/:/usr/local/ centos
如下是172.18.0.21节点的配置,不同节点仅需修改bind_addr为对应机器(容器)的ip
client.json { "data_dir": "usr/local/consuldata", "enable_script_checks": true, "bind_addr": "172.18.0.21", "retry_join": ["172.18.0.11","172.18.0.12","172.18.0.13"], "retry_interval": "30s", "rejoin_after_leave": true, "start_join": ["172.18.0.11","172.18.0.12","172.18.0.13"] }
redis集群安装参考,还是非常方便的,在本地(容器节点)一键创建6个节点3主3从的集群。
其中主节点是172.18.0.21,172.18.0.22,172.18.0.23,从节点是172.18.0.24,172.18.0.25,172.18.0.26
172.18.0.21节点上的redis-master-8888.json(172.18.0.22,172.18.0.23,172.18.0.24,172.18.0.25,172.18.0.26 类同,仅需修改address)
{ "services": [ { "name": "w-master-redis-8888", "tags": [ "master" ], "address": "172.18.0.21", "port": 8888, "checks": [ { "args":["sh","-c","/usr/local/consuldata/check_redis_master.sh 172.18.0.21 8888 ******"], "shell":"/bin/bash", "interval": "15s" } ] } ] }
redis-slave-8888.json
{ "services": [ { "name": "r-slave-redis-8888", "tags": [ "master" ], "address": "172.18.0.21", "port": 8888, "checks": [ { "args":["sh","-c","/usr/local/consuldata/check_redis_slave.sh 172.18.0.21 8888 ******"], "shell":"/bin/bash", "interval": "15s" } ] } ] }
consul client节点的redis主节点(写节点)服务检查脚本check_redis_master.sh
以下脚本来源于,做了简单的修改,在节点的身份判断逻辑上需要加强。
#!/bin/bash host=$1 myport=$2 auth=$3 if [ ! -n "$auth" ] then auth='\"\"' fi comm="/usr/local/redis_instance/redis8888/bin/redis-cli -h $host -p $myport -a $auth " role=`echo 'info replication'|$comm |grep -ec 'role:master'` echo 'info replication'|$comm if [ $role -ne 1 ] then exit 2 fi
consul client节点的redis从节点服务检查脚本check_redis_slave.sh
#!/bin/bash host=$1 myport=$2 auth=$3 if [ ! -n "$auth" ] then auth='\"\"' fi comm="/usr/local/redis_instance/redis8888/bin/redis-cli -h $host -p $myport -a $auth " role=`echo 'info replication'|$comm |grep -ec 'role:slave'` echo $role echo 'info replication'|$comm if [ $role -ne 1 ] then exit 2 fi
consul服务发现
redis集群配置成功后,重新加载代理服务,consul reload,一切正常的话,consul服务端就可以解析配置的服务了。
如下注册了两个服务,分别是r-slave-redis-8888,w-master-redis-8888,分别代表redis集群的读写节点。
需要注意的是,这三个节点都是写节点,这里仅仅是为了实现服务发现(尽管redis 有多ip的驱动支持)
r-slave-redis-8888.service.consul服务的解析,指向了三个从节点,172.18.0.24,172.18.0.25,172.18.0.26
故障转移之后的服务发现:模拟主节点故障,对172.18.0.21节点手动故障转移,现在172.18.0.21与172.18.0.24角色交换
redis集群故障转以后的服务发现解析结果 对于w-master-redis-8888.service.consul这个服务,成功解析到172.18.0.24,172.18.0.22,172.18.0.23三个主节点
redis集群故障转以后的服务发现解析结果 对于w-master-redis-8888.service.consul这个服务,成功解析到172.18.0.24,172.18.0.22,172.18.0.23三个主节点
遇到的问题:
1,cosnul服务端集群的时候,clustercenter一开始自定义了一个名称myconsule_datacenter,导致client节点死活加不进来,按照默认的dc1就没有问题
目前还不理解这个datacenter的命名规则是什么?
2,容器节点中的shell脚本要授予可执行权限chmod +x check_xxx.sh
3,其他异常问题,一定要看日志,搜索一下基本上都有结果。
以下纯粹是redis集群的问题,与consul没有直接关系,仅作为本测试中遇到的问题。
4,容器节点的redis集群时,需要移除bind_ip的127.0.0.1节点,直接配置docker创建容器时候的ip,创建集群的时候会一致等待,waiting for the cluster to join
这一点redis-cli --cluster做的很扯淡,明明找不到节点,还要死等,不人为终止的话,他会一直waiting
5,redis集群时候,因为主从都是相对的,需要相互识别对方,主从节点都要指定“masterauth”和“requirepass”,且密码一致,否则执行cluster failover提示成功,但故障转移不成功
6,遇到一个灵异的问题(之前单机多实例的时候也遇到过),在启动容器上的redis服务的时候,如果使用绝对路径启动,在创建集群的时候会出现从节点无法添加到集群中去的情况,停止服务,以相对路径方式重启之后就没有这个问题
总的来说consul这个中间件使用起来还算是比较简单,配置也很清爽,不像某些中间件令人作呕的配置结构(mycat???)
这里没有配置多数据中心模式,仅配置了单数据中心模式,作为一款服务发现的中间件,是完全没有问题的,尤其是作为mysql集群不支持多ip连接驱动的数据库连接。
参考:
下一篇: 三国最窝囊的军阀,袁绍为什么失败?