consul-and-nginx

使用 consul 实现 nginx 动态负载均衡

consul 简介

consul 是一个 service mesh 解决方案,主要提供服务发现、健康检查、KV 存储、数据中心等功能。

安装 consul

consul 使用 go 语言实现,只需要到官网 https://www.consul.io/downloads.html 下载对应平台的二进制文件即可。 linux 和 windows 平台均可以放在环境变量已有路径或者另外配置环境变量。

运行 agent

consul 完成安装后,需要运行 agent 。 agent 可以分为 server 和 client 模式,每个数据中心至少必须有一台 server ,建议一个集群里有 3 到 5 个 server ,部署单一的 server,在出现失败时会不可避免的造成数据丢失。

consul 架构

consul 官方架构图如图所示:
consul-arch

图中包含了 consul 多数据中心的设计,本次只讲上面单数据中心的情况。consul 推荐 3-5 台 server 做集群,其他节点和 server 通信通过 client 代理。

consul client 设计为 sidecar 模式。使用 client 代理的好处,所有操作都只用对本机 client 进程操作,读操作 (如服务发现、kv 读) 减轻 consul 集群压力,写操作 (如服务注册、kv 写等) 由 client 代理通过 rpc 转发到 consul 集群,解耦一些业务不相关的操作,如建康检查等。

consul 配合 nginx 使用实现动态负载均衡

只使用 nginx 做负载均衡

一般只使用 nginx 做负载均衡的设计如下图所示:
consul-arch

nginx 单独部署,然后将请求负载均衡到对应服务器上的具体业务服务。
这样做的好处是使用了 nginx 带来的好处,缺点是 nginx 负载均衡只支持静态配置文件,业务服务下线或者上线,需要手动修改配置文件重启 nginx 生效。

consul 配合 nginx 使用

使用 conusl 做为注册中心,可以将设计改为如下图所示:
consul-arch

所有微服务的服务注册和服务发现由 consul 集群管理,微服务只需要实现 / 调用服务注册,服务发现和建康检查 3 个 http 接口,在服务启动时将服务注册请求到本机 consul client 即可。

我们将 nginx 的 upstream 配置使用 consul-template 写出模板文件,然后启动 consul-template 进程监听。当有微服务下线或者上线新的微服务,consul-template 能根据模板文件更新 nginx 配置文件,并执行自定义命令(重启 nginx),这样就完成了微服务上下线 / 维护 / 扩容时,nginx 负载均衡做动态更新。

consul 集群的高可用需要部署 3-5 台 consul server,多了影响网络性能,小于 3 台则 consul server 不能出现单机故障。

nginx 所在机子的高可用可以使用 keepalived,主从配置,从机可同主机配置和启动方式一样,这样微服务在线状态更新时,从机的 nginx 配置也是最新的,如果主机故障了,从机可以顺利切换。

微服务的高可用理论上(单机能够满足业务 qps 的情况)只需相同的微服务部署大于 1 台机子即可,这样一台机子故障了,请求还能负载均衡到另一台上继续业务。

讲了使用 consul, consul-template,nginx 配合进行动态负载均衡的情况,也总结一下缺点:

1. 如果网络情况不好的情况,可能会出现具体业务微服务频繁上下线导致频繁更新 nginx 配置,nginx 频繁重启。这点可以考虑适当加大心跳时间来避免偶尔网络状况带来的心跳检测问题,或者将 consul-template 配置成定时同步(配置会更新不实时,但是如果大量上下线微服务可以只用更新一次配置,重启一次)。

2.nginx 重启多少会对性能带来一些影响,nginx reload 机制保证已经接收请求的进程在处理完请求再退出,但是不满足 http keepalive。
consul 支持 dns 查询,nginx 也支持配置 dns,可以考虑使用 nginx dns 查询代替 consul-template,这样不需要更新 nginx 配置和重启 nginx。但是原生 nginx 不支持 dns srv,所以如果出现一台机子上部署相同微服务使用不同端口,nginx dns 查询方式就不能正确支持并负载均衡了。

consul 集群部署

consul server 单节点启动命令示例

1
consul agent -bind=ip -server=true -bootstrap -client=0.0.0.0 -ui -data-dir=/path/to/data -config-dir=/path/to/config -datacenter=datacenter_name -node=node_name

-bind在多网卡时需要使用,多网卡时,consul 不清楚绑定哪个网卡,需要指定 ip,单网卡时可以不填。

-sever模式表示 consul agent 以 client 还是 server 模式启动,默认为 server 模式,以 client 模式启动需修改为 -server=false,

-bootstrap表示以 bootstrap 模式启动,单节点时必填,不然会因为没有 leader 无法正常启动,同命令 -bootstrap-expect 互斥,后续部署集群再继续讲。

-client 配置 ip 表示可以访问 consul http api 这个 server 监听的 ip,如果为 127.0.0.1 只能本机访问。

-ui表示启动 consul 默认 web 界面。-data-dir 为 consul 保存节点信息的路径,必填。

-config-dir为 consul 配置文件信息路径,可填可不填,在配置文件路径里的 json 文件。

-datacenter指定数据中心名称,不填默认 dc1, 同一数据中心下的名称要求一定相同。

-node表示节点名称,不填默认 pc 的名称,建议按照一定格式规范节点名

更多命令参数和解释可以参考官网:https://www.consul.io/docs/agent/options.html#command-line-options

consul 集群部署命令示例

consul 可以以两种方式启动集群,一种是指定 leader 启动,先启动一个 leader,再依次启动剩下节点,然后执行命令 consul join leader ip。leader 启动命令同上,带上-bootstrap 参数。

另一种启动方式为不指定 leader 启动三个节点,启动命令同上,-bootstrap替换为-bootstrap-expecp=3,三个节点都启动完后因为没有 leader 和不知道彼此,集群还不能使用,在三个节点依次执行命令consul join ip1 ip2 ip3 三台机子都执行完后,会进行选举,然后集群可以使用。

判断集群是否可以使用可以登录 consul 自带的 web 页面,若报错则表示未正常运行,web 页面默认是 8500 端口,如图所示为一个三节点集群,leader 为五角星标志的机子:cluster.jpg

consul client 启动

consul client 启动命令同 consul server 大致相同,区别 -server=false 必须为 false,不能使用 -bootstrap 或者 -bootstrap-expect 参数,其他同 server 启动命令一致。
consul client 加入器群节点也很简单,可以在启动时加入 -join=consul server 中其中一台的 ip,也可先启动,再执行命令consul join server ip

1
consul agent -bind=ip -server=false -client=0.0.0.0 -ui -data-dir=/path/to/data -config-dir=/path/to/config -datacenter=datacenter_name -node=node_name -join=ip

或者不带上-join,启动完后执行consul join ip

consul client 不可脱离 consul server 运行,至少要有一个 consul server 节点,且 client 要 join server 节点才可使用

consul-tempalte 使用

安装 conusl-template

到官网 https://releases.hashicorp.com/consul-template 下载对应平台的二进制文件即可,部署方式同 consul。

编写 consul-template 模板

undefined

示例为一个 upstream.tpl 文件,range service "web"end 类似 for 循环, web表示服务发现名称为 web 的服务,ip 和端口不做解释。

nginx.conf 里 include 这部分模板生成的对应文件, 如图所示:config

启动 consul-template

1
consul-template -consul-addr 127.0.0.1:8500 -template "./upstream.tpl:./conf/upstream.conf:nginx -s reload"

如上所示为一个 consul-template 监控集群微服务上下线状况后并更新相应 nginx 配置的启动命令。

-consul-addr指定 consul client/server 的 ip 和 http 端口,此处我们还是使用 consul 推荐的连本机 client 的方式,所以 ip 是 127.0.0.1,端口默认是 8500。consul 不限制 server 可以被使用,也可以将 ip 配置成 consul 集群的里其中一个 consul server 的 ip,推荐还是使用当前方式,即 consul 推荐的方式。

-template表示执行的模板命令,upstream.tpl 为之前编写的 consul-template 模板文件的具体路径,upstream.conf 为生成的配置文件,同上面截图 include upstream.conf 相对应,nginx -s reload生成完配置文件后重启 nignx,也可以自定义别的命令。
这样当有服务在线状态变化,upstream.conf 文件会自动生成,并重启 nginx 动态更新 nginx 的负载均衡。

更多命令和用法参考官网:https://github.com/hashicorp/consul-template#command-line-flags