cluster-computing - 在 CoreOS 上使用 etcd 进行服务发现时如何处理陈旧数据?

标签 cluster-computing docker service-discovery coreos

我目前正在研究 CoreOS 并基于它创建一个集群。到目前为止,在单主机上使用 CoreOS 的体验还是相当流畅的。但是当涉及到服务发现时,事情变得有点模糊。不知何故,我不明白总体思路,因此我现在在这里寻求帮助。

我想要做的是让两个 Docker 容器运行,第一个依赖于第二个。如果我们谈论的是纯 Docker,我可以使用 linked containers 解决这个问题.到目前为止,还不错。

但是这种方法不能跨机器边界工作,因为Docker不能跨多个主机链接容器。所以我想知道如何做到这一点。

到目前为止,我所了解的是 CoreOS 的处理方法是使用其 etcd 服务,它基本上是一个分布式键值存储,可在每个主机上访问在本地通过端口 4001,因此您不必(作为 etcd 的消费者)处理任何网络细节:只需访问 localhost:4001你很好。

所以,在我看来,我现在的想法是,当提供服务的 Docker 启动时,它会在本地 etcd 中注册自己(即它的 IP 地址和端口) > 和 etcd 负责在网络上分发信息。这样,例如你得到键值对,例如:

RedisService => 192.168.3.132:49236

现在,当另一个 Docker 容器需要访问一个 RedisService 时,它会从他们自己的本地 etcd 获取 IP 地址和端口,至少一旦信息被分布在整个网络中。到目前为止,还不错。

但现在我有一个我无法回答的问题,这已经困扰了我几天:当服务出现故障时会发生什么?谁清理etcd里面的数据?如果未清理,所有客户端都会尝试访问不再存在的服务。

目前我能想到的唯一(可靠)解决方案是利用 etcd 的数据 TTL 功能,但这涉及一个权衡:要么你有相当高的网络流量,因为您需要每隔几秒发送一次心跳,否则您将不得不忍受陈旧的数据。两者都不好。

我能想到的另一种“解决方案”是让服务在出现故障时自行注销,但这仅适用于计划关闭,不适用于崩溃、停电......

那么,你是如何解决这个问题的?

最佳答案

有几种不同的方法可以解决这个问题:sidekick 方法,使用 ExecStopPost 并在失败时删除。我假设三个 CoreOS , etcdsystemd ,但这些概念也可以应用于其他地方。

Sidekick 方法

这涉及在您的主应用程序旁边运行一个单独的进程,该进程向 etcd 发送心跳。简单来说,这只是一个永远运行的 for 循环。您可以使用 systemd 的 BindsTo 来确保当您的主单元停止时,该服务注册单元也会停止。在 ExecStop 中,您可以明确删除您正在设置的 key 。我们还设置了 60 秒的 TTL 来处理任何不正常的停止。

[Unit]
Description=Announce nginx1.service
# Binds this unit and nginx1 together. When nginx1 is stopped, this unit will be stopped too.
BindsTo=nginx1.service

[Service]
ExecStart=/bin/sh -c "while true; do etcdctl set /services/website/nginx1 '{ \"host\": \"10.10.10.2\", \"port\": 8080, \"version\": \"52c7248a14\" }' --ttl 60;sleep 45;done"
ExecStop=/usr/bin/etcdctl delete /services/website/nginx1

[Install]
WantedBy=local.target

在复杂的方面,这可能是一个启动并命中 /health 端点的容器,您的应用程序提供该端点以在将数据发送到 etcd 之前运行运行状况检查.

ExecStopPost

如果您不想在主应用程序旁边运行某些东西,您可以在主单元中使用 etcdctl 命令在启动和停止时运行。请注意,正如您提到的,这不会捕获所有失败。

[Unit]
Description=MyWebApp
After=docker.service
Require=docker.service
After=etcd.service
Require=etcd.service

[Service]
ExecStart=/usr/bin/docker run -rm -name myapp1 -p 8084:80 username/myapp command
ExecStop=/usr/bin/etcdctl set /services/myapp/%H:8084 '{ \"host\": \"%H\", \"port\": 8084, \"version\": \"52c7248a14\" }'
ExecStopPost=/usr/bin/etcdctl rm /services/myapp/%H:8084

[Install]
WantedBy=local.target

%H 是一个 systemd 变量,用于替代机器的主机名。如果您对更多变量用法感兴趣,请查看 CoreOS Getting Started with systemd指导。

失败时删除

在客户端,您可以删除连接失败次数超过 X 次的任何实例。如果您从 /services/myapp/instance1 获得 500 或超时,您可以运行并继续增加失败计数,然后尝试连接到 /services/myapp/< 中的其他主机 目录。

etcdctl set /services/myapp/instance1 '{ \"host\": \"%H\", \"port\": 8084, \"version\": \"52c7248a14\", \"failures\": 1 }'

当您达到所需的阈值时,使用 etcdctl 删除 key 。

关于心跳会导致的网络流量——在大多数情况下,您应该通过您的提供商运行的本地专用网络发送此流量,因此它应该是免费且非常快速的。 etcd 无论如何都在不断地与其同行进行心跳,所以这只是流量的一点点增加。

如果您有任何其他问题,请访问 Freenode 上的#coreos!

关于cluster-computing - 在 CoreOS 上使用 etcd 进行服务发现时如何处理陈旧数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21597039/

相关文章:

redis - 集群故障转移

python - 使用docker时无法打开共享对象文件

docker - 使用 Go docker SDK 的二进制 TLS 配置失败

mysql - 如何使用 MYSQL Docker 容器编辑 secure_file_priv

mysql - Galera DB wsrep 连接失败

cluster-computing - 提交Condor作业期间的代码更新

apache-zookeeper - ZooKeeper 在 CAP 定理方面总是一致的吗?

docker - 如何使用 consul 和 gliderlabs/registrator 防止僵尸服务?

python - 在 hadoop 集群上运行时出现 MRJob 错误

load-balancing - 服务发现工具和检查节点运行状况的负载均衡器在概念上有什么区别?