Consul包含多个组件,但是作为一个整体,为你的基础设施提供服务发现和服务配置的工具。
它提供以下关键特性:
服务发现: Consul的客户端可用提供一个服务,比如 api 或者mysql ,另外一些客户端可用使用Consul去发现一个指定服务的提供者。通过DNS或者HTTP应用程序可用很容易的找到他所依赖的服务。
健康检查: Consul客户端可用提供任意数量的健康检查,指定一个服务(比如:webserver是否返回了200 OK 状态码)或者使用本地节点(比如:内存使用是否大于90%)。 这个信息可由operator用来监视集群的健康.被服务发现组件用来避免将流量发送到不健康的主机。
Key/Value存储: 应用程序可用根据自己的需要使用Consul的层级的Key/Value存储。比如动态配置,功能标记,协调,领袖选举等等,简单的HTTP API让他更易于使用.
多数据中心: Consul支持开箱即用的多数据中心,这意味着用户不需要担心需要建立额外的抽象层让业务扩展到多个区域.
Consul面向DevOps和应用开发者友好.是他适合现代的弹性的基础设施。
安装
应用consul到微服务集群中,首先要解决的是运维的问题。使用ansible能快速部署与管理consul。
在ansible的配置文件中,指定consul集群的所有机器名,server机器名与client机器名
[dev_all:children]
dev
lab
demo
[dev_server:children]
dev
lab
demo
[dev_client:children]
使用ansible部署consul的脚本
#定义配置目录
installPath="/usr/local/bin/"
configPath="/etc/consul.d"
dataPath="/tmp/consul"
runLogPath="/tmp/consulRun.log"
ansibleConfPath="/data/x/tools/pub/conf"
sudoCmd="-b --become-user=root --become-method=sudo --ask-become-pass -k"
#安装consul
cmd="src=$curDir/consul dest=$installPath owner=root group=root mode=0755"
ansible -i $ansibleConfPath/consul.hosts $hostList -m copy -a "$cmd" $sudoCmd
cmd="src=$curDir/consul-template dest=$installPath owner=root group=root mode=0755"
ansible -i $ansibleConfPath/consul.hosts $hostList -m copy -a "$cmd" $sudoCmd
#创建配置目录
cmd="mkdir -m 755 $configPath;mkdir -m 777 $dataPath"
ansible -i $ansibleConfPath/consul.hosts $hostList -m shell -a "$cmd" $sudoCmd
建立集群

图中的Server是服务端,Client是客户端。客户端不保存数据,将接收到的请求转发给响应的Server端。Server之间通过局域网或广域网通信实现数据一致性。每个Server或Client都是一个consul agent。Consul集群间使用了gossip协议通信和raft一致性算法。
Agent 是一直运行在Consul集群中每个成员上的守护进程。agent可以运行在client或者server模式。所有的agent都能运行DNS或者HTTP接口,并负责运行时检查和保持服务同步。
Client 是一个转发所有RPC到server的代理。client是相对无状态的。client唯一执行的后台活动是加入LAN gossip池。这有一个最低的资源开销并且仅消耗少量的网络带宽。
Server 是一个有一组扩展功能的代理,这些功能包括参与raft选举,维护集群状态,响应RPC查询,与其他数据中心交互和转发查询给leader或者远程数据中心。
DataCenter 是一个私有的,低延迟和高带宽的一个网络环境。
综合可用性和性能考虑,一个数据中心(dc)建议有3-5台server。如果server越多,达成共识越慢。但不限制client的数量,client可以扩展到数千或者数万台。下面是使用ansible启动consul集群的过程
#启动server
cmd="consul leave;nohup consul agent -server -data-dir $dataPath -ui -config-dir=$configPath -client 0.0.0.0 >$runLogPath 2>&1 &"
ansible -i $ansibleConfPath/consul.hosts $serverHostList -m shell -a "$cmd" $sudoCmd
#启动client
cmd="consul leave;nohup consul agent -data-dir $dataPath -config-dir=$configPath -client 0.0.0.0 >$runLogPath 2>&1 &"
ansible -i $ansibleConfPath/consul.hosts $clientHostList -m shell -a "$cmd" $sudoCmd
#构建集群
cmd="consul join 10.24.188.52"
ansible -i $ansibleConfPath/consul.hosts $allHostList -m shell -a "$cmd" $sudoCmd
服务的注册与发现
平台当前的微服务的架构,服务注册与发现是通过如下几个步骤实现的
- 每个服务项目在nginx中配置独立的域名,例如 api.xxx.xxx.cn
- 阿里云上新建一个私网slb,设置健康检查域名,并挂载该服务对应的后端服务器。
- 将该服务的域名api.xxx.xxx.com解析到slb的内网地址上。这样网关就可以通过内网域名访问到对应的服务。
如果使用consul实现服务发现,步骤如下
- 每个服务项目需要添加一个服务描述模板文件,如下图
{
"service":{
"id" : "MARKET",
"name" : "MARKET",
"address" : "api.market.{{key "domain/cn"}}",
"port" : 8086,
"tags" : ["{{key "env/name"}}"],
"checks": [
{
"http": "http://api.market.{{key "domain/cn"}}:8086/monitor",
"interval": "5s"
}
]
}
}
- 在项目发布后的重启脚本中,使用consul-template工具将服务描述模板文件生成服务描述文件。模板文件中dmoain/cn"与env/name保存在consul提供的kv存储中。
Consul Template能监控Consul实例的变化,并将模板中变化的数据通过后台程序渲染到文件。模板文件更新完成后可以运行任何命令
- 将服务描述文件软链到consul的config目录中后,执行consul reload 。
脚本如下,这里consul template使用-once指令,只渲染一次。
serviceName=$PRJNAME"_service.json"
consul-template -consul-addr=127.0.0.1:8500 -template "options/service.json:used/service.json:ln -fs $CONFDIR/used/service.json /etc/consul.d/$serviceName" -once
consul reload
通过以上几个步骤就完成了服务注册。服务发现则是在sdk中,调用consul的http接口查询服务实现
// 通过consul的8500端口查询服务信息
static function getConsulCaller()
{
$conf = new XHttpConf();
$conf->conf("127.0.0.1",$logger);
$conf->port = 8500;
$conf->timeout = 5;
$conf->caller = "sdk";
return new XHttpCaller($conf);
}
// 随机返回一个可用的Address地址
static function queryService()
{
$serviceName = static::confXPath();
$curl = static::getConsulCaller();
$resp = $curl->get("/v1/catalog/service".$serviceName."?passing");
$ret = \XRestResult::ok($resp);
$roundBin = rand(0,$nodeCount);
return $ret[$roundBin];
}
//查询服务信息
$data = static::queryService();
//通过查询到的信息生成httpCaller
$conf = self::conf($data['ServiceAddress'],$logger,$proxy,$data['ServicePort'],$data['Address']);4
示意图如下

从日志中可以看到最终到服务的请求过程

consul控制台界面如下,可以查看服务的运行情况

总结
consul的引入能够帮我们解决系统开发中的一些痛点问题,包括以下几点
- consul使服务注册与发现变得简单,不用再去配置slb。
- 使用consul的kv存储与consul-template工具管理项目配置信息,配置信息变更不用再发版。
还有些问题需要探讨
- 服务发现时在sdk中实现的,是否需要单独一台机器做请求转发
- 每个服务的内网域名是否还需要进行解析
以上只是简单的使用了consul,想在生产环境中使用起来还有很长的一段路要走。
网友评论