Slack 机器人的零停机部署

Zero downtime deployment of Slack bot

我们使用 BotKit 开发机器人,现在我们尝试以最少的部署停机时间解决问题。

此服务器上有服务器和docker容器运行ning。内部容器 运行 与 RTM 服务器 (Slack) 连接的 bot-app 实例。 当我开始部署 bot-app 的新版本 (v2) 时,我希望获得零停机时间,用户不应该看到 "bot is offline".

使用新版本的 bot-app 部署脚本 运行 的第二个 docker 容器。并且 bot-app 也连接到 RTM-server。这样,只有几秒钟的时间,两个应用程序 运行 连接到 RTM 服务器并响应用户命令(用户将看到他的命令的两个答案)。

如果我们一方面希望获得零停机时间,另一方面又希望防止用户同时与两个实例交互,我可以获得什么最优决策?

决定 1: 为了减少发生冲突的可能性,当两个实例都将响应用户命令时。

决定 2: 放弃零停机部署。在这种情况下,部署脚本首先停止第一个 docker-container,然后启动另一个。该应用程序不会响应在停止当前版本的应用程序和完全启动新版本的应用程序之间发送的用户命令。

决定 3: 通过并行 运行 当前版本和新版本的应用程序或互斥锁进行交互。总示意图: 1) 当前应用版本为 运行ning 2)部署脚本启动新版本的应用程序 3) 当新版本的应用程序几乎 运行 并准备好连接到 RTM 服务器时,它会向当前版本的应用程序发送命令以关闭 RTM 连接。 4) 当前版本的应用程序关闭 RTM 连接 5) 新版APP开启RTM连接

我认为还有其他好的解决方案。

您将如何解决您应用程序中的这个问题?

我会考虑的一个想法是分成两个部分:

  1. 保持 WebSocket 连接到 Slack RTM API 的组件。该组件只是从 API 中读取消息并将它们放入队列中。 (我们称之为 "queuer.")
  2. 实际 "bot," 从队列中读取消息并根据需要进行响应。

根据您的机器人的行为方式,它可以直接使用 Web API 或者可能将自己的消息放在 "queuer" 可以通过 RTM API 发送的出站队列中.

此架构可能会解决您的问题...您现在可以在升级时暂时关闭机器人——响应将延迟到新版本 运行ning 之前——或者您可以 运行 机器人的两个版本同时依赖于队列的语义来防止两个版本响应相同的消息。

(抱歉,第二次回复;有其他想法。)

我之前描述的方法会对您现有的代码造成很大的破坏,因为您可能需要停止使用 botkit(或者至少不要使用它来进行 RTM API 通信)。一种破坏性较小的方法是使用某种外部方式来表示给定消息已被处理。

例如,使用 Redis,让机器人在收到消息时执行以下命令:

SET message:<message timestamp> 1 NX PX 30000

NX 选项意味着只有当密钥不存在时此命令才会成功。因此,设法执行此操作的机器人的第一个实例将成功,而另一个实例将失败。机器人应该只处理消息并在命令成功时响应。

PX 30000 设置了 30 秒的过期时间,因此 Redis 不会填满这些键。)

这应该让您通过重叠 运行 机器人实例进行零停机升级,而不必担心消息被处理两次。

请注意,如果机器人以非正常方式关闭,则在此方案中仍有可能完全丢弃一条消息。 (它可能会在调用 SET 命令之后但在实际处理消息之前死掉。)具有两阶段 "get/delete" 的真实队列会更好,但是你又回到了我的另一个回答。 :-)