Please enable Javascript to view the contents

Etcd、Confd 、Nginx 服务发现

 ·  ☕ 5 分钟

本篇主要阐述了为什么需要服务发现功能,对几种服务发现工具进行了比较。同时,在 CentOS 上,对 Etcd、Confd 、Nginx 实现服务发现功能进行了实践。

1. 服务注册与发现

1.1 为什么需要注册和发现服务

随着微服务的兴起,大量接口服务化。当新的微服务加入或微服务的信息发生变更时,服务方如何通知周边系统、使用方如何知道这些变更呢?

这时就需要服务的注册配置和发现功能。

  • 服务注册配置——存储的信息至少包括正在运行的服务的主机和端口信息
  • 服务发现——允许其他用户可以发现在服务注册配置阶段存储的信息。

1.2 几种服务发现工具的比较

FeatureConsulZookeeperEtcdEuerka
服务健康检查服务状态,内存,硬盘等(弱)长连接,keepalive连接心跳可配支持
多数据中心支持
kv存储服务支持支持支持
一致性raftpaxosraft
capcacpcpap
使用接口(多语言能力)支持http和dns客户端http/grpchttp(sidecar)
watch支持全量/支持long polling支持支持 long polling支持 long polling/大部分增量
自身监控metricsmetricsmetrics
安全acl /httpsaclhttps支持(弱)
spring cloud集成已支持已支持已支持已支持
注:
- C,强一致性 (Consistency)
- A,可用性 (Availability)
- P,网络分区故障的容错性 (Partition Tolerance)

Consul 是使用 Go 语言开发的分布式协调系统,对业务发现的管理提供很好的支持,它的 HTTP API 也能很好的和不同的语言绑定,并支持跨数据中心的应用。缺点是相对较新,适合喜欢尝试新事物的用户。

ZooKeeper 功能全,社区活跃,用户群体很大,对所有典型的用例都有很好的封装,支持不同语言的绑定。缺点是,整个应用比较重,依赖于 Java,不支持跨数据中心。

Etcd 是一个更轻量级的分布式协调的应用,更适合一些轻量级的应用来使用,同时 Etcd 也提供 HTTP API 操作接口。值得注意的是,Kubernetes 采用了 Etcd 作为配置中心。

Eureka 是 Netflix 开源的一个 RESTful 服务,主要用于服务的注册发现。Eureka 由两个组件组成:Eureka 服务器和 Eureka 客户端。Eureka 服务器用作服务注册服务器。Eureka 客户端是一个 Java 客户端,用来简化与服务器的交互、作为轮询负载均衡器,并提供服务的故障切换支持。

2. Etcd

2.1 简介

Etcd 是一个分布式、使用 Raft 算法维护一致性的 key-value 存储系统,与其类似产品有 Zookeeper、Consul 等,Etcd 相对 Zookeeper,更加轻量、易运维。同时,Etcd 支持 TLS 通信,具备高性能的写入能力。

2.2 Raft 算法

很多的分布式系统都会采用 Paxos 协议,但是 Paxos 协议难以理解,并且在实际实现中差别比较大。所以 Etcd 选择了 Raft 作为它的一致性协议。Raft 是 Diego Ongaro 和 John Ousterhout 在 In Search of an Understandable Consensus Algorithm 中提出的。它在牺牲很少可用性,达到相似功能的情况下,对 Paxos 做了很大的优化,并且比 Paxos 简单易懂很多。

它主要集中在解决两个问题:

  • 领导者选举(Leader Election)
    Raft 先通过领导选举选出一个 Leader,后续的一致性维护都由 Leader 来完成,这就简化了一致性的问题。Raft 会保证一个时间下只会有一个 Leader,并且在超过一半节点投票的情况下才会被选为 Leader。当 Leader 挂掉的时候,新的 Leader 将会被选出来。

  • 日志复制 (Log Replication)
    为了维护状态,系统会记录下来所有的操作命令日志。Leader 在收到客户端操作命令后,会追加到日志的尾部。然后 Leader 会向集群里所有其它节点发送 AppendEntries RPC 请求,每个节点都通过两阶段提交来复制命令,这保证了大部分的节点都能完成。

3. Etcd + Confd + Nginx

在进行应用部署时,服务运行起来后,通过接口向 Etcd 注册相关 key-value 信息,Confd 检测到 Etcd 的 key-value 变化后,立即触发程序通过模板形成新的 Nginx 配置文件。

Nginx 先做离线语法测试,如果没问题就覆盖原配置,进而 reload,测试不通过就不覆盖原配置,整个过程安全可控。

3.1 Nginx 安装配置

  • 安装以 CentOS 为例
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 安装 nginx
yum install -y nginx
# 查看 nginx 安装位置
whereis nginx
nginx: /usr/sbin/nginx /usr/lib64/nginx /etc/nginx /usr/share/nginx /usr/share/man/man3/nginx.3pm.gz /usr/share/man/man8/nginx.8.gz
# 查看 nginx 配置文件位置
nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# 查看配置
cat /etc/nginx/nginx.conf
...
    include /etc/nginx/conf.d/*.conf;
...

include /etc/nginx/conf.d/*.conf; 这句配置会将 conf.d 目录下 .conf 后缀的文件配置载入 Nginx。

3.2 Confd 安装配置

直接从 github 下载 Confd 的 Linux 编译版本,然后将可执行文件移动到 /usr/sbin/ 目录即可。

1
2
3
4
5
6
# 下载 Confd 包
wget https://github.com/kelseyhightower/confd/releases/download/v0.15.0/confd-0.15.0-linux-amd64
# 复制可执行文件
mv confd-0.15.0-linux-amd64 /usr/sbin/confd
# 增加可执行权限
chmod +x /usr/sbin/confd

3.3 Etcd 安装配置

  • 安装以 CentOS 为例
1
yum -y install etcd
  • 配置文件目录,/etc/etcd/etcd.conf
1
2
3
4
5
# 默认配置,可以不修改
ETCD_NAME=default
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://0.0.0.0:2379"
  • 启动服务
1
service etcd start

3.4 Confd 安装配置

  • 创建配置目录
1
mkdir -p /etc/confd/{conf.d,templates}

在 conf.d 下创建 .toml 配置文件

/etc/confd/conf.d/app1.toml

1
2
3
4
5
6
7
8
[template]
prefix = "/app1"
src = "subdomain.conf.tmpl"
dest = "/tmp/app1-subdomain-confd-auto.conf"
keys = [
  "/subdomain",
  "/upstream",
]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[template]
prefix = "/app1"
src = "subdomain-nginx.conf.tmpl"
dest = "/etc/nginx/conf.d/app1-subdomain-confd-nginx-auto.conf"
keys = [
  "/subdomain",
  "/upstream",
]
check_cmd = "/usr/sbin/nginx -t"
reload_cmd = "/usr/sbin/nginx -s reload"

在 templates 下创建 .tmpl 模板文件

/etc/confd/templates/subdomain.conf.tmpl

1
2
3
[subdomain]
subdomain = {{getv "/subdomain"}}
upstream = {{getv "/upstream"}}

Nginx 模板配置

/etc/confd/templates/subdomain-nginx.conf.tmpl

upstream {{getv "/subdomain"}} {
{{range getvs "/upstream/*"}}
    server {{.}};
{{end}}
}

server {
    server_name  {{getv "/subdomain"}}.example.com;
    location / {
        proxy_pass        http://{{getv "/subdomain"}};
        proxy_redirect    off;
        proxy_set_header  Host             $host;
        proxy_set_header  X-Real-IP        $remote_addr;
        proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;
   }
}

监听 Etcd 的 key-value 值的变化

1
2
3
4
# 只处理一次
confd -onetime -backend etcd -node http://127.0.0.1:2379
# 按时间轮询
confd -interval=60 -backend etcd -node http://127.0.0.1:2379 &   

3.5 注册服务

可以通过 etcdctl 命令,也可以通过 Etcd 提供的 HTTP API,在 Etcd 插入 subdomain 和 upstream 数据。下面以 etcdctl 为例:

1
2
etcdctl set /app1/subdomain app1
etcdctl set /app1/upstream/instance1 "127.0.0.1:5601"

由于在本地 5601 端口,启动了 ELK 服务,通过访问 http://app1.example.com 打开 Kibana 。

如果需要 Nginx 进行负载均衡,可以在 upstream 上配置多个键值。同时,需要在 /etc/confd/conf.d 目录下新建两个文件 app2-nginx.toml 和 app2.toml,内容上只需要将 app1-nginx.toml 和 app1.toml 中的 app1 修改为 app2 即可。

1
2
3
etcdctl set /app2/subdomain app2
etcdctl set /app2/upstream/instance1 "127.0.0.2:80"
etcdctl set /app2/upstream/instance2 "127.0.0.1:80"

4. 参考


微信公众号
作者
微信公众号