Consul 是一个支持多数据中心分布式高可用的服务发现和配置共享的服务软件,由 HashiCorp 公司用 Go 语言开发, 支持健康检查,并允许 HTTP 和 DNS 协议调用 API 存储键值对。
consul
Consul是一个服务发现和注册的工具,其具有分布式、高扩展性能特点,主要包含如下功能:
- 服务发现: 支持 http 和 dns 两种协议的服务注册和发现方式。
- 监控检查: 支持多种方式的健康检查。
- Key/Value存储: 支持通过HTTP API实现分布式KV数据存储。
- 多数据中心支持:支持任意数量数据中心。
Consul 的使用场景
- 实例的注册与配置共享
- 与 confd 服务集成,动态生成 nginx 和 haproxy 配置文件
优势
- 使用 Raft 算法来保证一致性, 比复杂的 Paxos 算法更直接. zookeeper 采用的是 Paxos, consul,etcd 使用的则是 Raft.
- 支持多数据中心,内外网的服务采用不同的端口进行监听。 多数据中心集群可以避免单数据中心的单点故障,而其部署则需要考虑网络延迟, 分片等情况等. zookeeper 和 etcd 均不提供多数据中心功能的支持.
- 支持健康检查. etcd 不提供此功能.
- 支持 http 和 dns 协议接口. zookeeper 的集成较为复杂, etcd 只支持 http 协议.
- 官方提供web管理界面, etcd 无此功能.
角色
- client: 客户端, 无状态, 将 HTTP 和 DNS 接口请求转发给局域网内的服务端集群.
- server: 服务端, 保存配置信息, 高可用集群, 在局域网内与本地客户端通讯, 通过广域网与其他数据中心通讯. 每个数据中心的 server 数量推荐为 3 个或是 5 个.
Consul安装
下载并解压
## 下载
wget https://releases.hashicorp.com/consul/1.0.0/consul_1.0.0_linux_amd64.zip?_ga=2.31706621.2141899075.1510636997-716462484.1510636997
## 解压
unzip consul_1.0.0_linux_amd64.zip
以UI形式后台启动:
./consul agent -server -ui -bootstrap-expect 1 -data-dir /tmp/consul &
可以使用脚本,正常使用的时候是需要完善参数的
nohup /opt/consul_1.0.2/consul agent -server -bootstrap-expect 1 -data-dir /opt/consul_1.0.2/data -ui -http-port=9996 -bind=10.47.178.81 -client 0.0.0.0 -config-dir /opt/consul_1.0.2/consul.d -enable-script-checks >/opt/consul_1.0.2/logs/start.log 2>&1 &
查看启动状态:
[root@iZ2ze74 home]# ./consul members
Node Address Status Type Build Protocol DC Segment
iZ2ze74 172.17.120.102:8301 alive server 1.0.0 2 dc1 <all>
说明:
- Address:节点地址
- Status:alive表示节点健康
- Type:server运行状态是server状态
- DC:dc1表示该节点属于DataCenter1
查看节点:
curl 127.0.0.1:8500/v1/catalog/nodes
使用
注册
consul注册注册service 的方式有多种
静态注册
创建文件夹consul.d
添加如下test.json:
{
"service":{
"id": "node",
"name": "prometheus-node",
"address": "127.0.0.1",
"port": 9100,
"tags": ["prometheus-target"],
"checks": [
{
"http": "http://127.0.0.1:9100/metrics",
"interval": "15s"
}
]
}
}
在consul启动命令中,指定配置路径
-config-dir=consul.d
启动后查看Prometheus 和consul 界面,可以看到target是否引入。
使用http Api 的方式
curl -X PUT -d '{"service":{"id":"node","name":"prometheus-node","address":"127.0.0.1","port":9100,"tags":["prometheus-target"],"checks":[{"http":"http://127.0.0.1:9100/metrics","interval":"15s"}]}}' http://127.0.0.1:8500/v1/agent/service/register
还可以使用各语言版本的sdk:https://www.consul.io/api/libraries-and-sdks.html
我这里使用JAVA 版本的
<dependency>
<groupId>com.orbitz.consul</groupId>
<artifactId>consul-client</artifactId>
<version>1.0.0</version>
</dependency>
使用如下:
public class ConsulTest {
Consul client;
/**
* 初始化.
*/
@Before
public void init() {
client = Consul.builder().withHostAndPort(HostAndPort.fromParts("xx.xx.xx.xx", 8500)).build();
// catalogClient = client.catalogClient();
}
@Test
public void queryAll() {
Map<String, Service> services = client.agentClient().getServices();
for (Map.Entry<String, Service> entry : services.entrySet()) {
System.out.println("key:" + entry.getKey());
System.out.println("value:" + entry.getValue().toString());
}
}
@Test
public void testDelete() {
client.agentClient().deregister("etcd");
}
@Test
public void testAdd1() {
String serviceName = "prometheus-etcd";
String serviceId = "etcd";
Registration.RegCheck single = Registration.RegCheck.http("http://127.0.0.1:2379/metrics", 20);
Registration reg = ImmutableRegistration.builder()
.check(single)
.addTags("prometheus-target")
.address("127.0.0.1")
.port(2379)
.name(serviceName)
.id(serviceId)
.build();
client.agentClient().register(reg);
}
}
发现
查询注册的服务
通过DNS api
dig @127.0.0.1 -p 8600 web.service.consul(dns域名)
通过http api
还有一个connect模块,直接连接,docker和k8s中使用的比较多。
健康检查
通过调用http api来获取监控状况
curl 'http://localhost:8500/v1/health/service/web?passing'
更新consul配置文件
1、可以通过更改配置文件并将SIGHUP代理文件发送到代理来更新服务定义。这使您可以在不停机或不可用于服务查询的情况下更新服务。现在还支持consul reload
2、HTTP API可用于动态添加,删除和修改服务。
常用命令
consul
- agent:运行一个consul agent
- join:将agent加入到consul cluster
- members:列出consul cluster集群中的members
常用选项option:
-data-dir
作用:指定agent储存状态的数据目录
这是所有agent都必须的
对于server尤其重要,因为他们必须持久化集群的状态
-config-dir
作用:指定service的配置文件和检查定义所在的位置
通常会指定为"某一个路径/consul.d"(通常情况下,.d表示一系列配置文件存放的目录)
-config-file
作用:指定一个要装载的配置文件
该选项可以配置多次,进而配置多个配置文件(后边的会合并前边的,相同的值覆盖)
-dev
作用:创建一个开发环境下的server节点
该参数配置下,不会有任何持久化操作,即不会有任何数据写入到磁盘
这种模式不能用于生产环境(因为第二条)
-bootstrap-expect
作用:该命令通知consul server我们现在准备加入的server节点个数,该参数是为了延迟日志复制的启动直到我们指定数量的server节点成功的加入后启动。
-node
作用:指定节点在集群中的名称
该名称在集群中必须是唯一的(默认采用机器的host)
推荐:直接采用机器的IP
-bind
作用:指明节点的IP地址
-server
作用:指定节点为server
每个数据中心(DC)的server数推荐为3或5(理想的是,最多不要超过5)
所有的server都采用raft一致性算法来确保事务的一致性和线性化,事务修改了集群的状态,且集群的状态保存在每一台server上保证可用性
server也是与其他DC交互的门面(gateway)
-client
作用:指定节点为client
若不指定为-server,其实就是-client
-join
作用:将节点加入到集群
实例
prometheus原生就支持consul的服务发现,可以直接获取consul上的配置,如下
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: 'prometheus'
# Override the global default and scrape targets from this job every 5 seconds.
scrape_interval: 5s
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ['localhost:9090']
- job_name: 'security'
# Override the global default and scrape targets from this job every 5 seconds.
scrape_interval: 5s
metrics_path: '/prometheus'
# scheme defaults to 'http'.
static_configs:
- targets: ['10.94.20.33:80']
- job_name: 'overwritten-default'
consul_sd_configs:
- server: '10.110.200.29:8500'
services: ['lookup', 'security', 'workflow']
relabel_configs:
- source_labels: ['__metrics_path__']
regex: '/metrics'
target_label: __metrics_path__
replacement: '/prometheus'
这里简单说明下上面的配置意义,在scrape_configs下,定义了3个job_name
- job_name: ‘prometheus’是监听prometheus服务本身;
- job_name: ‘security’是按固定IP:PORT的方式监听微服务 ;
- job_name: ‘overwritten-default’就是一个监听consul的任务,在consul_sd_configs下,server是consul服务器的访问地址,services是微服务名的数组,如果什么都不填,则默认取consul上注册的所有微服务。relabel_configs是修改默认配置的规则,这里由于使用了springboot和promethues整合,暴露的metrics是通过/promethues路径访问的,而promethues默认的metrics访问路径(即metrics_path配置项)是/metrics,需要修改。
consul-template
consul-template可以启动多个程序用于生成不同的模版json文件.
consul-template的两种使用方法:
- 直接启动作为进程使用,配置文件中间有一个时间设定,多长时间更新一次
- 使用crontab来定时拉去一次,使用启动参数-once
使用consul+consul-template可以构建一套基于文件服务发现的动态注册和配置生成的服务发现功能。
- 通过consul的api向consul上注册prometheus的采集信息,使用k/v的模式
- consul-template设置定时功能,命令行拉去consul上的配置,按着模版的形式生成json文件
- prometheus使用fd的服务发现模式读取json文件拉去采集信息
什么时候使用k/v模式?
使用consul的services注册job的服务信息,然后使用consul-template动态生成prometheus的配置文件。然后prometheus通过查询consul中注册的信息正则匹配来完成prometheus的采集操作,在规模请求很小的时候,service完全没有问题 但是这样当job量很大的时候,比如有20组job,一组job130的target的的时候,就会出现consul请求瓶颈。
所以在规模扩大的时候使用consul的k/v格式进行注册,直接通过IP:port作为key,对应的label作为vaule,然后使用consul-template动态生成discovery的json文件,然后prometheus使用file sd来发现这个json文件,相当于将对应的json的内容写到了prometheus的配置文件中去,这个时候五分钟consul-template动态生成一次,不会每次都去请求,这样consul的压力就几乎没有了,经过测试可以达到5000个target,prometheus的shard极限,对consul依旧没有什么压力,现在主要瓶颈在于json文件大小,filesd的压力,可以继续优化成多个文件。
原理
raft算法
Raft将系统中的角色分为领导者(Leader)、跟从者(Follower)和候选人(Candidate):
- Leader:接受客户端请求,并向Follower同步请求日志,当日志同步到大多数节点上后告诉Follower提交日志。
- Follower:接受并持久化Leader同步的日志,在Leader告之日志可以提交之后,提交日志。
- Candidate:Leader选举过程中的临时角色。
Raft实现了和Paxos相同的功能,它将一致性分解为多个子问题:Leader选举(Leader election)、日志同步(Log replication)、安全性(Safety)、日志压缩(Log compaction)、成员变更(Membership change)等,核心就是Leader选举,可以详细了解raft。
Raft 使用心跳(heartbeat)触发Leader选举。当服务器启动时,初始化为Follower。Leader向所有Followers周期性发送heartbeat。如果Follower在选举超时时间内没有收到Leader的heartbeat,就会等待一段随机的时间后发起一次Leader选举。
Follower将其当前term加一然后转换为Candidate。它首先给自己投票并且给集群中的其他服务器发送 RequestVote RPC 。结果有以下三种情况:
- 赢得了多数的选票,成功选举为Leader;
- 收到了Leader的消息,表示有其它服务器已经抢先当选了Leader;
- 没有服务器赢得多数的选票,Leader选举失败,等待选举时间超时后发起下一次选举。