Consul系列:让服务Running in anywhere

8 篇文章 1 订阅

引言

随着微服务概念深入人心,越来越多的解决方案选择使用微服务架构,这类架构的共同点是服务数量多,因此种类繁多的服务之间如何互相访问就变成了一个很现实的问 题。目前比较流行的分布式存储比如:Consul, etcd, ZooKeeper,如何结合当前的业务场景,利用这些工具实现更加自动化的运维化方案、简化我们的流程呢?本文主要 给大家介绍在服务发现和配置管理方面的consul工具,同时也会为大家带来一些应用场景案例参考。

关于服务发现及Consul

将应用部署到集群时,服务IP或端口是动态分配的,用户访问时不知道后端的IP及端口,在访问这些服务时,使用一定的机制动态发现服务的IP及端口就是服务发现(ServiceDiscovery)。

Consul是一个服务发现和配置管理的工具,是具有分布式、高可用、高度可扩展的服务。

Consul的特性

  • 服务发现:Consul客户端可以提供其他服务的服务发现功能,使用dns和http,服务发现问题很容易被解决。
  • 监控检查:使用Consul可以提供任意数量的健康检查功能,无论是服务状态(web服务器返回 http 200)还是本地节点的信息(内存利用率超过90%),这些信息都可以 由我们进行自定义设置,并由服务发现组件将服务流量从不健康的组件中移开。
  • key/value存储:Consul的kv存储功能,通过http api可以很容易完成动态配置管理、协调服务、主选举、功能标记等服务。
  • 跨中心部署:Consul支持多数据中心感知,可以支撑任意数量的区域无需复杂配置。

节点

  • 节点类型
    • server服务发现、健康检查、数据一致性存储,leader选举机制,所以奇数部署。每个数据中心至少有一个 agent 运行在 server 模式,推荐为 3 个或 5个server节点 。
    • agent:运行在 consul 集群所有节点上的核心服务,其可运行在 client 或 server 模式,通过 consul agent命令来启动。由于所有节点必须运行 agent,指定节点运行于 client 或者 server 模式是很简单地,除非有其它的 agent 实例。 所有的 agent 都能运行 DNS 或者 HTTP 接口,并负责运行时检查和保持服务 同步
    • client:一个 client 是一个 转发所有 RPC 到 server的 agent 。这个 client 是相对无状态的。client 唯一执行的后台活动是加入 LAN gossip 池。这有一个 最低的资源开销并且仅消耗少量的网络带宽。
  • Consul节点退出
    • 正常退出(至关重要):节点通过信号正常关闭,接到信号的Consul会通知其他节点,正常离开后上面的服务和健康检查将被移除
    • 异常退出:没有通过信号正常关闭的节点,其他节点会由于没有接到信号,认为这个节点还是正常的,也不会移除其服务和健康检查。

架构

Consul vs. Other Software

Consul部署

可以参考Consul系列:Consul Server部署及用法介绍.

集群运行

Consul可以运行client和server 两种节点模式,每个数据中心必须有一个server节点,但如果高可用,需要部署3个以上。其它Consul全部运行在client模式。客户端连接 会有一个非常轻的注册过程,运行健康检查并发给server节点。

  • Consul server模板片段
#supervisor管理consul服务启动

[program:consul]

command=/usr/local/bin/consul agent -config-dir /home/项目用户/consul/conf -data-dir /home/项目用户/consul/data process_name=%(program_name)s

user=项目用户

numprocs=1

autostart=true

autorestart=true

startsecs=2

startretries=3

redirect_stderr=true

stdout_logfile_backups=10

stdout_logfile_maxbytes=300MB stdout_logfile=/home/项目用户/var/log/supervisor/s_%(program_name)s.log

#默认加载的config.json配置 {

"acl_token":"你的acl token", "bootstrap_expect":1, "client_addr":"0.0.0.0", "datacenter":"dc名称,一个数据中心统一使用一个", "enable_debug":false, "enable_syslog":false,

"log_level":"INFO", "node_name":"这里定义consul节点名称,通常建议hostname比较容易区分",, "raft_protocol":3,

"rejoin_after_leave":true,

"retry_interval":"3s", "retry_join":["server节点地址1","server节点地址2","....."], "server":true,

"ui":true

}
  • Consul client模板片段
#supervisor管理consul服务启动

[program:consul]

command=/usr/local/bin/consul agent -config-dir /home/项目用户/consul/conf -data-dir /home/项目用户/consul/data process_name=%(program_name)s

user=项目用户

numprocs=1

autostart=true

autorestart=true

startsecs=2

startretries=3

redirect_stderr=true

stdout_logfile_backups=10

stdout_logfile_maxbytes=300MB

stdout_logfile=/home/项目用户/var/log/supervisor/s_%(program_name)s.log

#默认加载的config.json配置 {

"acl_token":"你的acl token", "bootstrap_expect":0, "client_addr":"0.0.0.0", "datacenter":"dc名称,一个数据中心统一使用一个", "enable_debug":false, "enable_syslog":false,

"log_level":"INFO", "node_name":"这里定义consul节点名称,通常建议hostname比较容易区分",, "raft_protocol":3,

"rejoin_after_leave":true,

"retry_interval":"3s", "retry_join":["server节点地址1","server节点地址2","....."], "server":false,

"ui":false

} 

注册服务健康检查到Consul

Consul服务定义

Consul中的服务一种是可以在启动前就定义 ,提前写好定义服务的配置文件放置到 Consul配置的-config-dir指定目录中, 如果这种方式需要更新,需要使用重载命令 consul reload。另外一种是Consul api的方式来注册服务。注册服务的信息主要包含id, name, port, address, check每个服务可以由多个ip或者可以有多个端口的服务组 成。需要注意的是:每个服务可以有多个check,check可以是端口检查、http检查、脚本检查。其中检查脚本通常是自由做任何事情,以确定检查的状态。唯一的限制 是,该退出代码都必须遵守此约定:

  • Exit code 0 - 检查结果是 passing
  • Exit code 1 - 检查结果是 warning
  • 其它 Exit code - 检查结果是 failing

注册服务通常是通过agent来注册,因为服务的健康检查与所在Consul agent是绑定的,如果 Consul agent所在宿主机挂掉,就认为这台主机上的服务也是挂的。

注册服务及健康检查

  • 注消(deregister)agent 服务:-X PUT http://$IPADDR:8500/v1/agent/service/deregister/:service_id
  • 注销(deregister)检查:-X PUT http://$IPADDR:8500/v1/agent/check/deregister/:check_id
  • 注册服务:json文件注册方式。
{

"service": {

"name": "test",

"tags": ["test service"],

"port": 31030,

"address": "10.10.169.72",

"id": "test",

"check": {

"id": "api",

"http": "http://10.10.169.72:31030",

"interval": "3s"

        }

    }

}
  • 注册健康检查:json文件注册方式。
# cat http.json 

{

"service": {

"name": "web",

"tags": ["test web site"],

"port": 8099,

"check": {

"id": "web",

"name": "web on port 8099",

"tcp": "localhost:8099",

"interval": "10s",

"timeout": "1s"

        }

    }

}

注意:

  • 同一个服务 每个实例的id唯一
  • 同一个服务 每个检查项的id唯一

服务发现

Consul启动后,并且服务集群状态正常,就可以对外提供DNS或者HTTP API来查询服务了。

http api

  • 查询所有节点的服务列表信息:-X GET http://$IPADDR:8500/v1/catalog/services
  • 查询本节点注册的服务信息:-X GET http://$IPADDR:8500/v1/agent/services
  • 通过agent查询异常服务:X GET http://$IPADDR:8500/v1/health/state/critical

Consul dns服务发现

Consul自带一套dns 服务,所以可以处理简单的服务发现。通过dig命令查询Consul dns中的服务解析, critical的服务不会解析。

  • 使用DNSmasq转发Consul dnsConsul默认的dns服务端口是8600,常用的dns服务默认的端口为53,所以如果使用8600,不太方便。就算可以修改Consul dns端口,但又可能会跟其它的 dns服务冲突。
    • 可以使用puppet模块管理的服务DNSmasq来转发Consul dns和其它dns服务在/etc/dnsmasq.conf中添加 Consul dns地址

  • 配置NetworkManager在resolv.conf中添加search service.Consul和默认的dns server指定到本机,例如:

  • 这样即可直接在该节点使用dns访问到Consul中的服务了,而且可以使用短域名访问,例如:

案例分享

haproxy配合Consul dns实现服务发现

haproxy做为PaaS平台服务的负载均衡服务,对外服务;配置backend服务时,配置的是Consul中的服务域名。

这里有个坑,原来使用haproxy 1.5版本, 后端服务使用域名时,启动后只解析一次(和nginx类似),这时如果解析到的服务挂掉,访问haproxy页面时会503。查询官网得知haproxy 1.6支持了动态dns 域名解析的配置,后升级为haproxy 1.6。

下面是动态DNS解析相关的配置内容:

resolvers consuldns

nameserver dns1 127.0.0.1:53

resolve_retries 200 

timeout retry 1s

hold valid 10s

frontend uq

balance leastconn

cookie JSESSIONID prefix

bind 0.0.0.0:10000 accept-proxy

capture request header Host len 128 

option httplog

log-format %si:%sp\ %ci\ %ft\ %hrl\%r\ %ST\ %B\ %Tt



  # 自定义ACL(路由)策略

acl host_uq-xyteam hdr_dom(host) -i test.x.example.com

use_backend test if host_test



#自定义转发的realserver地址

backend test

server test test.service.consul:10000 resolvers mydns maxconn 50000 check inter 2000 rise 2 fall 100 

用户访问haproxy就会动态解析访问后端Consul中的服务。

基于Consul dns,实现推送服务的高可用切换

推送的unipush服务最初是基于常见的haproxy来做高可用的及入口的统一。为了减轻架构复杂度和更加的自动化,实现自动的阔缩容,通过将推送服务注册到Consul来做健康检查,并且去掉haproxy使用consul dns作为轻量级的代理。配置如下:

# cat service.json

{

"service": {

"name": "test_recv",

"port": 30121,

"check": {

"id": "up",

"name": "up on port 30121",

"tcp": "42.186.52.150:30121",

"interval": "60s",

"timeout": "30s"

        }

    }

}

正常情况该域名会解析到所有的test服务地址,如果一旦发生个别服务异常、节点故障等情况,dns会立即将故障服务节点踢出解析。

root@localhost:~$ dig @127.0.0.1 -p 53 test_recv.service.consul

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> @127.0.0.1 -p 53 test_recv.service.consul ; (1 server found)

;; global options: +cmd

;; Got answer:

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16206

;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0



;; QUESTION SECTION:

;test_recv.service.consul. IN A



;; ANSWER SECTION:

test_recv.service.consul. 0 IN A 10.192.4.163

test_recv.service.consul. 0 IN A 10.192.4.150

test_recv.service.consul. 0 IN A 10.192.4.240



;; Query time: 3 msec

;; SERVER: 127.0.0.1#53(127.0.0.1) 

;; WHEN: Sat Nov 17 12:20:29 2018

;; MSG SIZE rcvd: 93

基于Consul template,实现服务配置文件动态渲染

日常运维中由于各种情况,我们少不了会对各类服务的配置文件进行变更。例如服务迁移、增加配置参数项等。利用consul,我们可以使用K/V、services等等集群内的数据信息渲染我们的配置文件内容。 实时监听unipush_recv这个service的变化,一旦出现变化,立即触发渲染,例如新增、故障等等。

实时监听unipush_recv这个service的变化,一旦出现变化,立即触发渲染,例如新增、故障等等。

{{range service "unipush_recv"}}   server {{.Node}} {{.Address}}:{{.Port}} maxconn 50000 check inter 2s addr {{.Address}} port {{.Port}}{{end}}

listen niepush_4

....

渲染后的内容,会将定义的变量用对应的service信息进行填充。

server test-up02 10.192.4.240:30121 maxconn 50000 check inter 2s addr 10.192.4.240 port 30121 

server test-up04 10.192.4.150:30121 maxconn 50000 check inter 2s addr 10.192.4.150 port 30121 

server test-up06 10.192.4.147:30121 maxconn 50000 check inter 2s addr 10.192.4.147 port 30121

......

最后在渲染后指定后续的处理逻辑:reload重载。

[program:consul-template]

command=/usr/local/bin/consul-template -consul-addr 127.0.0.1:8500 -template "/home/test/haproxy/conf/test_recv.ctmpl:/home/test/haproxy/conf/test_recv.conf:haproxy reload"

process_name=%(program_name)s

user=test

numprocs=1

autostart=true

autorestart=true

startsecs=2

startretries=3

redirect_stderr=true

stdout_logfile_backups=10

stdout_logfile_maxbytes=300MB

stdout_logfile=/home/test/var/log/supervisor/s_%(program_name)s.log stderr_logfile=/home/test/var/log/supervisor/s_%(program_name)s.log

同样不仅限于service,包括例如可以使用K/V的渲染,利用WEB UI界面可修改的K/V的特性,提供产品同学自助的文件变更&服务更新生效的功能。根据不同的场景、利用 consul的watch、template、check、service等功能组合出业务更加自动化的运维方案。

Consul监控

Consul开放了API可以直接获取Consul集群性能数据,可以脚本化拿到后进行渲染,效果如下:

Consul告警

Consul的服务相关问题都会有日志记录,所有重要的一点就是做日志监控,并且将日志中的error信息进行告警,效果如下:

访问安全控制

WEB UI

web ui一般采用apache+web ui的模式,从apache这里设置用户密码认证&ssl证书,再转发到一个web ui接口,这个web ui接口进行白名单限制。

API

采用防火墙限制端口(8300/8301/8302)处理.

Consul实践遇到的坑

调用deregistry接口删除Consul服务后,诡异的出现了

初期进行http api 调试测试时,注册了一些服务到Consul, 后来想删除就调用,ip:8500/v1/catalog/deregister 接口进行删除,调用该接口返回成功。但过一会儿去web ui查询, 发现刚才删除的服务还在,后来查询官方文档,原来server端catalog和 agent端都有deregister接口,我们的服务都是通过agent注册的,所以在catalog 删除不 生效,只能通过agent的 deregistry接口来删除。

总的来说目前已经尝试的有两种解决方案:

  • 在新的另外的节点注册一个相同的service,包括id相同进行覆盖。
  • 在注册该servive的agent上调用deregister删除。

清理Consul持久化数据异常

测试Consul server服务的高可用,先停止其中一台Consul server节点的容器,并清理Consul 的持久化数据,其它服务的Consul节点正常,达到预期结果,后来尝试恢复 这个Consul server,恢复后发现从Consul ui查发现 少了一些服务节点,查询过后,正好是清理数据的这台Consul server上的服务在 Consul 中消失了,因此又重新在这个 节点进行相应的服务注册才真正恢复正常。

健康检查状态码的坑

健康检查脚本中使用grep检查结果内容,如果匹配则正常,不匹配为异常,例如: echo result|grep ok,有一次,一个服务节点异常,grep也没有匹配,当时认为这样就不 会被解析了,后来发现这个服务ip还是会被解析,查询问题发现grep 不匹配的error code 为1 ,code 1 只是warning ,还是会被解析,所以修改检查脚本内容,如果不匹 配,手动返回error code 2,之后这个异常服务才不解析。

使用registrator自动注册的坑

推送服务这边通常注册时候,为了和cmdb信息统一,registrator 默认的注册规则是服务名注册为 Consul中的service id。service和check id如果是不同的端口服务,不 能一样,否则在Consul同一个节点上就有可能同一个服务被注册多次,实际上是同 个服务不同实例,影响例如服务未注册上,检查的是其它进程端口等。不同的节点上的 service id或check id可以相同,同一台节点上的service的id不能一样,统一check之间的id也不能一样。

同一个节点设置为相同的id:

同一个节点设置为不同的id:

Consul agent节点异常

部署客户环境时遇到一个诡异的问题,有两个节点总是异常,健康检查这两个节点时好时坏,大部分时间是坏的,少部分时间显示正常状态。

排查问题时,发现主机之间响应时间很快,Consul server 与Consul agnet 之间的Consul端口都是可以通的。查询Consul server日志,看到 server 日志中有error:

以为是有端口漏开放了,telnet 测试后,发现Consul server到agent都是通的,谷歌下这个错误,发现有可能是因为没有开通udp端口导致的,后来又使用nmap测试 Consul相关的udp端口是不是开放的,测试后发现udp 果然没有开通。于是就向客户申请开通相应的udp端口,开通后,再进行测试,发现问题还是存在。

这就不得不再想其它办法,后来又查询异常的Consul agent节点日志发现,发现Consul agent 也报类似的错误,乍一看跟server端的日志是一样的,但仔细研究发现关键问 题,异常节点的agent报了很多访问其它agent节点8301端口的 time out的日志:

才发现agent不仅访问server, 还需要访问同级的其它agent 8301端口进行健康检查,后来开放8301所有Consul节点的端口访问后才正常。

比起另外两个同样流行的分布式存储etcd和ZooKeeper, Consul从设计上就考虑到了很多服务发现的需求, 比如说健康检查, 服务注册, DNS等。所以基于Consul来实现服

务发现的功能还是有很多的想象空间的。更多思考

Q1:Consul, etcd, ZooKeeper能比较一下吗?为什么没有选用后两者呢?

A1:ZooKeeper 处理数据 不支持 resf api , 需要操作的时候比较繁琐,功能也比较单一,etcd 服务功能也相对单一,需要依赖其它 组件 配合使用Consul 本身自

Q2:就服务发现和zk相比,会有多大的延迟?

A2: 就服务发现来说,Consul 支持 api 和 dns 两个方式获取 服务, dns 解析基本无消耗。 api 操作的话,具体的数据我没有进行严格测试,但zk是java服务本身 需要的内存比较多,java gc 垃圾回收也会影响一些性能。Consul 是go 语言开发性能会有一些优势。

Q3: 这里问一个不是很相关的问题,怎么看待Docker和微服务更配这样的说法?

A3: 以前是所有功能集成到一个服务中,微服务本身需要拆分服务,需要部署、更新、维护的服务数量会几何增加,如果是传统的方式运维的话,操作起来就是个挑

战,Docker化之后,部署、迁移、交付都会变简单。Q4:Consul最大承受多大规模,有瓶颈吗?

A4: 我没有针对 Consul服务 做过压力测试,我们一般是会对服务进行压力测试,就现在我们部署的集群规模而言,支持几百来的Consul 节点是没有问题的。理论 上可以更多。

Q5:内部的web服务怎么注册?用后台脚本周期性地检测web服务正常后,再请求接口注册服务吗?失败取消

A5: 如果 使用了 registrator ,docker服务启动时,添加相应的环境变量,就会自动注册到Consul,也会自动删除,不过registrator偶尔异常情况会有不同步的现 象,我们在 registrator 启动时添加同步参数定时同步,如果没有使用 registrator ,就需要自己处理注册和删除的逻辑,例如我们使用marathon /mesos 做为调试 的核心基础组件,可以监听marathon 的事件获取 容器实例 启动在哪,删除了哪些,就可以相应对 Consul做操作Consul 也支持异常服务定时清理,在注册添加时 添加DeregisterCriticalServiceAfter 参数 就可以

Q6:“每个数据中心必须有一个server节点,但如果高可用,需要部署3个以上”为啥一定要三个以上

A6: Consul server 节点也分为 leader 和 follower 节点,leader 选举一般为基数选举,1个就不是高可用了,所以最少3个,遵循2N+1 原则,支持宕机 N 个节

点。Q7: Consul能够支撑多大的高并发系统?

A7: 这个问题跟上面的问题稍有些重合,其实高并发是指的业务,业务一般在 启动、停止、迁移 、或业务之间相互访问时 Consul 才会有些数据交互 ,Consul的健 康检查 和 访问都是分摊到每个宿主机上, Consul 的压力 对比业务来说可以忽略不计。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值