# HipChat 如何使用 ElasticSearch 和 Redis 存储和索引数十亿条消息

> 原文： [http://highscalability.com/blog/2014/1/6/how-hipchat-stores-and-indexes-billions-of-messages-using-el.html](http://highscalability.com/blog/2014/1/6/how-hipchat-stores-and-indexes-billions-of-messages-using-el.html)

![](img/1f990901f6dd64766ac61ad0b37e95a1.png)

*本文来自 [Zuhaib Siddique](http://www.linkedin.com/in/zuhaib) 的采访， [HipChat ]](https://www.hipchat.com/) ， 团队聊天和即时消息的制造商。*

HipChat 始于一个不寻常的领域，您可能认为它没有太大的希望，即企业组消息传递，但是随着我们了解到那里有金 [企业群 [](http://www.developereconomics.com/still-building-consumer-apps-enterprise-pays-4x/) 。 这就是为什么 Atlassian 是 JIRA 和 Confluence 之类的工具开发者，他们 [在 2012 年收购了 HipChat](http://blog.hipchat.com/2012/03/07/weve-been-acquired-by-atlassian/) 。

在一个不经常听到的故事中，大父母的资源和联系实际上帮助 HipChat 进入了 [指数增长周期](https://s3.amazonaws.com/uploads.hipchat.com/10804/368466/10joz8sztfw4dfc/HipChat1B.jpg) 。 他们已达到 12 亿条消息存储标记，现在正每隔几个月发送，存储和建立索引的消息数量就增加一倍。

这种增长给曾经足够的基础架构带来了巨大压力。 HipChat 展示了一种常见的缩放模式。 从简单开始，经历流量激增，然后思考我们现在该怎么办？ 通常，使用大型计算机是最佳的选择。 他们做到了。 这给了他们一些喘息的空间，以便弄清楚下一步该怎么做。 在 AWS 上，在某个拐点之后，您将开始使用 Cloud Native，即水平扩展。 这就是他们所做的。

但是故事有一个转折。 除了云/ SaaS 版本之外，安全方面的考虑还推动了本地版本的 HipChat 的开发。 我们将在本周晚些时候的[帖子](http://highscalability.com/blog/2014/1/8/under-snowdens-light-software-architecture-choices-become-mu.html)中详细讨论这一有趣的发展。

虽然 HipChat 并非 Google 规模，但可以从 HipChat 中学习很多有关它们如何及时索引和搜索数十亿条消息的知识，这是 IRC 和 HipChat 之类的主要区别。 在不丢失消息的情况下索引和存储负载下的消息是挑战。

这是 HipChat 走的路，您可以学到什么？ 让我们看看…

## 统计信息

*   每秒 60 条消息。

*   已存储 12 亿个文档

*   4TB EBS 突袭

*   AWS 上的 8 台 ElasticSearch 服务器

*   26 个前端代理服务。 在后端应用服务器中将其翻倍。

*   18 人

*   0.5 TB 的搜索数据。

## 平台

*   **托管**：带有 75 个实例的 AWS EC2 East 当前全部为 Ubuntu 12.04 LTS

*   **数据库**：当前用于聊天记录的 CouchDB，正在过渡到 ElasticSearch。 MySQL-RDS 的其他所有功能

*   **缓存**：Redis

*   **搜索**：ElasticSearch

*   **队列/工作服务器**：Gearman（队列）和 [Curler](https://github.com/powdahound/curler) ，（工作人员）

*   **语言**：Twisted Python（XMPP 服务器）和 PHP（Web 前端）

*   **系统配置**：开源 Chef + Fabric

*   **代码部署**：Capistrano

*   **监视**：Sensu 和 monit 泵送警报到 Pagerduty

*   **图表**：statsd + Graphite

## 产品

*   交通非常繁忙。 在周末和节假日，这里会很安静。 在高峰负载期间，每秒数百个请求。 聊天消息实际上并不占流量的大部分; 它是状态信息（离开，空闲，可用），人们在连接/断开连接等。因此，每秒 60 条消息可能看起来很低，但这只是一个平均值。

*   HipChat 希望成为您的通知中心，您可以在这里与团队合作，并从工具和其他系统获得所有信息。 帮助使每个人都处于循环中。 特别是在远程办公室。

*   之所以在 IRC 上使用 HipChat 的主要原因是，HipChat 可以存储和索引每个会话，以便以后可以搜索它们。 强调搜索，因此您可以留在 HipChat 中。 使用此功能对团队来说是个胜利，您可以随时返回并记住发生了什么以及您同意做什么。 它还会将消息路由到同一用户拥有的多个设备，并在发送消息时无法访问您的设备时进行临时消息缓存/重试。

*   增长来自更多的客户，但随着更多的客户在每个站点使用该产品，其参与度也随之提高。 他们的 API 集成也看到了增长。

*   消息的存储和搜索是其系统中的主要可伸缩性瓶颈。

*   HipChat 使用 XMPP，因此任何 XMPP 客户端都可以连接到系统，这对于采用是一个巨大的胜利。 他们建立了自己的本机客户端（Windows，Linux，Mac，iOS，Android），并具有扩展功能，例如 PDF 查看，自定义表情符号，自动用户注册等。

*   不久前，将 Wiki 之类的工具引入企业文化几乎是不可能的。 现在，企业级工具似乎已被接受。 为什么现在？

    *   基于文本的通信现在很普遍并且被接受。 我们拥有短信，IM 和 Skype，因此现在很自然地使用聊天工具。

    *   分散的工作团队的兴起。 团队越来越分散。 我们不能只是一起坐下来听讲座。 需要记录所有内容，这意味着组织交流被视为一项重要资产。

    *   增强功能。 内嵌图像，gif 动画等功能使它变得有趣，吸引了更广泛的人群。

*   HipChat 具有 [API](https://www.hipchat.com/docs/api) ，该 API 使得可以编写类似于 [IRC 机器人](http://en.wikipedia.org/wiki/Internet_Relay_Chat_bot)的工具。 示例用法用于 Bitbucket 提交。 在 10:08，开发人员 X 提交了一些代码来修复错误。 它通过 HipChat 发送，并直接链接到代码提交和提交日志。 全部自动化。 Bitbucket 提交击中了 Web 钩子，并使用其中一个插件发布信息。 插件可帮助您编写自己的机器人。 转到您的 Bitbucket 帐户。 假设我有我的 API 令牌，并且每次提交时都想发布到此 API。 对于 GitHub 类似地工作。

*   从客户端上的 Adobe Air 开始，它泄漏了内存并会关闭计算机。 因此移至本机应用程序。 痛苦，但很好。 他们在公司各个部门的所有平台上都有用户。 您需要成为用户所在的地方。 希望用户在所有操作系统上都拥有出色的体验。 用户是所有人，而不仅仅是技术专家。

## XMPP 服务器体系结构

*   HipChat 基于 XMPP，消息是 [XMPP 节](http://xmpp.org/rfcs/rfc3920.html) 内的任何内容，可以是一行文本或日志的较长部分 输出。 他们不想谈论他们的 XMPP 体系结构，因此没有很多细节。

*   他们没有使用第三方 XMPP 服务器，而是使用 Twisted Python 和 XMPP 库构建了自己的服务器。 这允许创建可扩展的后端，用户管理以及轻松添加功能，而无需与其他人的代码库抗衡。

*   AWS 上的 RDS 用于用户身份验证以及事务和 SQL 有用的其他区域。 这是一项稳定，可靠的技术。 对于本地产品，他们使用 MariaDB。

*   Redis 用于缓存。 诸如哪些用户位于哪个房间，状态信息，谁在线等信息，因此与连接到哪个 XMPP 服务器无关紧要，XMPP 服务器本身不是限制。

    *   痛点是 Re​​dis 尚未聚类（尚未）。 为了实现高可用性，使用了热/冷模型，因此从器件可以使用了。 从主节点到从节点的故障转移大约需要 7 分钟。 奴隶促销是手工完成的，不是自动化的。

*   增加的负载暴露了代理服务器以及它们可以处理多少个客户端的弱点。

    *   这是一个实际的问题，因为不丢失消息是一个高度优先事项。 客户表示不丢弃消息比低延迟更重要。 用户宁愿迟到也不愿迟到。

    *   使用 6 个 XMPP 服务器，系统运行良好。 随着连接数量的增加，他们开始看到不可接受的延迟。 连接不仅来自客户端，还包括支持其编程界面的机器人。

    *   作为第一步，他们将前端服务器和应用程序服务器分开。 代理处理连接，后端应用程序处理节。 前端服务器的数量由活动的侦听客户端的数量决定，而不是由发送的消息数决定。 在提供及时服务的同时保持如此多的连接打开是一个挑战。

    *   解决数据存储问题后，计划将研究如何优化连接管理。 Twisted 效果很好，但是它们之间有很多联系，因此必须弄清楚如何更好地处理它。

## 存储体系结构

*   在 HipChat 上增长的 10 亿条消息不断增长的同时，他们突破了 CouchDB 和 Lucene 解决方案存储和搜索消息的限制。

    *   认为 Redis 将是失败点。 以为 Couch / Lucene 就足够了。 没有进行适当的容量规划，也没有查看邮件的增长率。 增长速度超出了他们的想象，因此不应该过多地关注 Redis 而是关注数据存储。

    *   当时，他们相信通过增加更多的功能进行扩展，然后再升级到越来越大的 Amazon 实例。 他们认为，随着这种方法的发展，这种方法只能再使用 2 个月。 因此，他们必须做一些不同的事情。

    *   Couch / Lucene 一年未更新，因此无法进行修改。 另一个原因的另一个原因。

*   在亚马逊上大约有十亿条消息是一个转折点。 有了专用服务器和 200 Gig 的 RAM，它们以前的体系结构可能仍然有效，但在资源有限的云中却无法实现。

*   他们想留在亚马逊上。

    *   喜欢它的灵活性。 只需旋转一个新实例并进行调整即可。

    *   亚马逊的脆弱让您发展得更好。 不要将所有鸡蛋都放在一个篮子里，如果某个节点出现故障，您已经处理好了，否则某些用户的流量将会丢失。

    *   使用动态模型。 可以快速丢失实例并启动新实例。 云原生类型的东西。 随时杀死一个节点。 杀死 Redis 大师。 5 分钟后恢复。 目前已划分为所有四个美国东部可用区，但尚未跨多个区域。

    *   EBS 仅使您拥有 1TB 的数据。 他们碰到这个限制时还不知道这个限制。 使用 Couch，他们遇到了 EBS 磁盘大小限制的问题。 HipChat 的数据为 0.5 TB。 要进行压缩，Couch 必须将数据复制到压缩文件中，从而使空间增加了一倍。 在周末进行压缩时，在 2 TB RAID 上达到极限。 不需要 RAID 解决方案。

*   无法选择 Amazon DynamoDB，因为他们正在启动 HipChat 服务器，这是防火墙后面的托管服务。

    *   HipChat Server 推动技术堆栈上的决策。 私有版本是您自己的解决方案的主机。 某些客户无法使用云/ SaaS 解决方案，例如银行和金融机构。 NSA 吓坏了国际客户。 雇用了两名工程师来创建产品的可安装版本。

    *   Redis Cluster 可以是自托管的，并且可以像 ElasticSearch 一样在 AWS 上运行。 他们使用本地版本的 MariaDB 代替 RDS。

    *   无法考虑完整的 SaaS 解决方案，因为这将是一个锁定。

*   现在过渡到 ElasticSearch。

    *   已移至 ElasticSearch 作为其存储和搜索后端，因为它可以吃掉他们可以提供的所有数据，它具有很高的可用性，只需添加更多节点即可透明地进行扩展，它是多租户的，可以通过分片和透明方式进行透明 复制处理节点丢失，它建立在 Lucene 之上。

    *   确实不需要 MapReduce 功能。 研究了 BigCouch 和 Riak Search（看起来效果不佳）。 但是 GET 上的 ES 性能相当不错。 喜欢删除组件的想法，少了一件麻烦的事。 ES HA 使他们对系统的可靠性感到非常有信心。

    *   与 Lucene 兼容是一个巨大的胜利，因为他们所有的查询都已经与 Lucene 兼容，因此这是自然的迁移途径。

    *   客户数据千差万别，从聊天记录到图像，因此响应类型无处不在。 他们需要能够快速引导来自超过 12 亿个文档的查询数据。

    *   在一个越来越普遍的举动中，HipChat 也将 ElasticSearch 用作其键值存储，从而减少了所需的数据库系统数量，从而降低了整体复杂性。 性能和响应时间是如此之好，他们以为为什么不使用它呢？ 响应时间在 10 毫秒至 100 毫秒之间。 它在某些区域击败了 Couch，而前面没有任何缓存。 为什么要使用多种工具？

    *   使用 ES 时，节点可能会宕机而没有人注意，您将在重新平衡时收到有关 CPU 使用率过高的警报，但它一直在困扰。

    *   有 8 个 ES 节点来处理流量的增长。

    *   与所有基于 Java 的产品一样，JVM 调整可能很棘手。

        *   要使用 ES，必须对您要使用的堆空间进行容量规划

        *   测试缓存。 ES 可以缓存过滤器结果，速度非常快，但是您需要大量的堆空间。 在 8 个盒子上有 22 个堆的内存时，打开了缓存后，内存耗尽。 因此，除非有计划，否则请关闭缓存。

        *   缓存出现问题，因为它会遇到内存不足错误，然后失败。 群集在几分钟内自我修复。 只有少数用户注意到了问题。

*   由于网络不可靠，Amazon 上的自动故障转移是有问题的。 在集群中，这可能会导致选举错误地发生。

    *   用 ElasticSearch 解决这个问题。 最初有 6 个 ES 节点作为主节点运行。 节点将耗尽内存或遇到 GC 暂停，最重要的是网络丢失。 然后其他人将不再能看到主人，也无法举行选举并宣布自己为主人。 他们的选举架构存在缺陷，即他们不需要法定人数。 因此，出现了脑裂。 两位大师。 造成了很多问题。

    *   解决方案是在专用节点上运行 ElasticSearch 主服务器。 他们要做的就是成为主人。 从那以后一直没有问题。 母版负责处理分片的分配方式（主要是谁），并映射副本分片的位置。 由于主机可以以出色的性能处理所有重新平衡，因此使重新平衡更加容易。 可以从任何节点查询，并将自己做内部路由。

*   使用月份索引。 每个月都是一个单独的索引。 每个主索引都有 8 个分片，然后在其上有两个副本。 如果一个节点丢失，系统仍然可以运行。

*   没有将 RDS 移入 ES。 他们需要 SQL 的东西留在 RDS / MariaDB 中，通常是用户管理数据。

*   在主/从设置中，Redis 中有大量缓存，直到发布 Redis Cluster。 有一个 Redis stat 服务器，它在一个房间里，并且离线。 Redis 历史记录会缓存最后 75 条消息，以防止在首次加载会话时不断访问数据库。 内部状态或快速数据的状态，例如登录的人数。

## 常规

*   Gearman 用于异步工作，例如 iOS 推送和传递电子邮件。

*   AWS West 用于灾难恢复。 一切都会复制到 AWS West。

*   Chef 用于所有配置。 ElasticSearch 为厨师提供了不错的食谱。 易于上手。 与 Chef 一样，因为您可以开始编写 Ruby 代码，而不使用 Puppet 风格的 DSL。 它还有一个不错的活跃社区。

*   采集经验。 他们现在可以使用公司的核心资产和人才，但是 Atlassian 不会弄乱什么可行，我们出于某种原因向您购买了。 可以在内部询问，例如，如何扩展 ElasticSearch 以及 Atlassian 中的其他人何时需要帮助才能介入。总体而言，良好的经验。

*   团队结构扁平。 还是一个小团队。 目前约有 18 人。 两个人在发展。 平台，iOS，Android，服务器端的一些开发人员以及 Web 开发工程师（法国）。

*   Capistrano 用于部署到所有盒子。

*   Sensu 用于监视应用程序。 忘记监视 ElasticSearch 节点的堆空间，然后遇到 OOM 问题，而没有任何通知。 当前占堆的 75％，这是他们想要的最佳位置。

*   Bamboo 用于连续集成。

*   客户端尚未正式发布，由开发人员驱动。 有一个测试的暂存区。

*   组标志。 可以控制哪些组获得功能以测试功能，以缓慢释放功能并控制包装盒上的负载。

*   功能标志。 例如，非常适合在 ElasticSearch 推出期间提供保护。 如果他们发现错误，则可以关闭功能并回滚到 Couch。 用户不会注意到差异。 在 Couch 和 ElasticSearch 之间的过渡阶段，他们将应用程序复制到两个商店。

*   新的 API 版本将使用 Oauth，因此开发人员可以使用 HipChat API 在自己的服务器上进行部署。 让客户使用自己的服务器是一种更具可扩展性的模型。

## 未来

*   将在几个月内达到 20 亿条消息，并且估计 ElasticSearch 可以处理大约 20 亿条消息。 不确定如何处理预期的负载增加。 期望去 Amazon West 以获得更多的数据中心可用性，并可能使更多的用户进入不同的数据中心。

*   希望使用 AWS 的自动扩展功能。

*   进入语音，私人 1-1 视频，音频聊天，基本会议。

*   将来可能会使用 RabbitMQ 进行消息传递。

*   与 Confluence（Wiki）进一步集成。 使用 HipChat 交谈，然后使用 Confluence 页面捕获详细信息。

## 课程

*   **企业应用程序**中有很多钱。 向企业推销可能会遭受酷刑。 较长的销售周期意味着可能会遇到麻烦。 但是如果你成功了，那将是一个有利可图的关系。 因此，您可能要考虑企业市场。 时代在变。 企业的发展可能仍然缓慢而缓慢，但是他们也正在采用新的工具和做事方式，那里有机会。

*   **隐私变得越来越重要，并且在出售给企业**时会影响您的堆栈选择。 HipChat 正在制作其产品的内部版本，以满足不信任公共网络或云数据的客户的需求。 对于程序员来说，云作为平台是非常有意义的。 对于企业而言，云可能是邪恶的。 这意味着您必须做出灵活的技术堆栈选择。 如果您 100％依赖 AWS 上的服务，则几乎不可能将系统移至另一个数据中心。 对于 Netflix 而言，这可能并不重要，但是如果您想向企业市场销售产品，那就很重要。

*   **放大以获得一些呼吸空间**。 在等待弄清楚体系结构的下一步工作时，只需很少的钱，您就可以扩大规模，并给自己提供几个月的呼吸空间。

*   **选择不能失败的内容**。 HipChat 将永不丢失用户聊天历史记录作为优先级，因此其体系结构将此优先级反映到将聊天记录保存到磁盘，然后在宕机的系统恢复后重新加载。

*   **转到本地** 。 您的客户在许多不同的平台上，本机应用程序将提供最佳体验。 对于拥有大量资源的创业公司来说，太多了​​。 因此，在某个时候，将产品出售给拥有更多资源的公司是有意义的，以便您可以开发出更好的产品。

*   **功能和组标志是更好的发行实践** 。 如果您可以选择要查看功能的组，并且可以在生产和测试中关闭功能，那么您不必担心发布新版本。

*   **选择您真正对** 充满信心的技术。 ElasticSearch 横向扩展以应对增长的能力使 HipChat 对他们的解决方案充满信心。 那个用户会很高兴的。 感觉很好。

*   **成为过程流的一部分，您变得更有价值，并且很难删除** 。 HipChat 作为人与工具之间的自然交汇点，也是编写实现各种有用的工作流程 hack 的机器人的自然点。 这使 HipChat 成为企业中的平台。 它启用了原本无法构建的功能。 而且，如果您能够做到这一点，那么就很难摆脱它。

*   **AWS 需要单独的节点存在总线** 。 荒谬的是，在云本身本身就是一件事，就是无法从客观的第三方来源获得机器状态信息。 如果您查看机架，它将经常有一条单独的状态总线，因此插槽可以知道其他插槽是否可用。 这样，您不必猜测。 在云中，软件使用基于 TCP 的原始连接技术和心跳来猜测另一个节点何时关闭，这可能导致脑裂问题和故障转移时的数据丢失。 现在是时候发展，并朝着可靠性迈出重大一步。

*   **产品决策驱动器堆栈决策** 。 HipChat 服务器在技术堆栈上驱动决策。 Redis Cluster 可以是自托管的。 不能选择 Amazon DynamoDB，因为他们正在防火墙后启动托管服务。

*   **在问题上投入很多精力只会使您到目前为止**。 您甚至需要在云中制定容量计划。 除非您的架构从一开始就完全是 Cloud Native，否则任何架构都将具有负载拐点，在这些拐点处其架构将不再能够处理负载。 看增长率。 投影出来。 什么会坏？ 您将如何处理？ 而且不要再犯同样的错误。 HipChat 将如何处理 40 亿条消息？ 不清楚。

*   **知道系统的限制** 。 EBS 的存储限制为 1 TB，这很多，但是如果您的存储量接近该限制，则需要制定计划。 同样，如果您的数据库（如 Couch）在压缩阶段使用两倍的磁盘空间，这将影响您的限制。

*   **世界会让您感到惊讶**。 六个月前，HipChat 认为 Redis 将是最弱的一环，但它仍将保持强劲，而 Couch 和 EBS 是最弱的一环。

## 相关文章

*   [在 Reddit 上](http://www.reddit.com/r/programming/comments/1ujzel/scaling_hipchat_with_elasticsearch_and_redis/) / [在黑客新闻](https://news.ycombinator.com/item?id=7015179)上
*   [为什么您仍在构建消费者应用程序？ 企业支付的费用是原来的 4 倍！](http://www.developereconomics.com/still-building-consumer-apps-enterprise-pays-4x/)
*   [HipChat 如何扩展到 10 亿条消息](http://blog.hipchat.com/2013/10/16/how-hipchat-scales-to-1-billion-messages/)
*   Reddit on [HipChat 如何扩展到 10 亿条消息-HipChat 的工程师 Zuhaib Siddique 解释了其如何使用 CouchDB，ElasticSearch 和 Redis 来处理站点的负载](http://www.reddit.com/r/programming/comments/1svjjo/how_hipchat_scales_to_1_billion_messages_zuhaib) 。
*   [HipChat 搜索现在由 Elasticsearch 支持](http://blog.hipchat.com/2013/08/12/hipchat-search-now-powered-by-elasticsearch/)
*   [HipChat ElasticSearch 聚会视频+幻灯片](http://zuhaiblog.com/2013/12/04/hipchat-elasticsearch-meetup-video-slides/)
*   [SF ElasticSearch Meetup-HipChat 如何扩展为 1B 消息](http://www.youtube.com/watch?v=K2P7l98Uj9c)

26 台前端服务器，每秒 60 条消息，似乎很重。

不错的诚实写作，谢谢。 非常丰富。

是的 每秒 60 条消息是不够的。 这是错字吗？

嗯 RTFA。

60 是平均，而不是一周中的全部 604800 秒。 有山峰。

我确定大多数前端服务器都用于与客户端的连接。 每个开放的客户端都需要维护与服务器的连接才能获取聊天消息。 每秒那 60 条消息是进来，而不是出去。 我猜如果所有的客户都在投票的话将会高出一吨。

这是最好的文章，我已经读过很长时间
Mirza Tarkash

我不知道从持久性的角度来看，它们如何处理 Redis 固有的 50％故障率。 或者也许对他们是否看到类似的表现发表评论...

从 http://www.infoq.com/articles/jepsen

在 2000 次写入中，Redis 声称其中 1998 年已成功完成。 但是，最终集中只有 872 个这些整数。 Redis 放弃了声称成功的 56％的写入。

Alex，绝对没有“ Redis 固有的 50％失败率” ...我不确定您是否正确地理解了这一点。 特别是在（希望！）罕见的“裂脑”问题中，这是一个关于他们使用它的目的（并且希望每个人都将它用于轻量级工作队列）的完全可以接受的问题。 我很高兴将 Redis 用于 API 服务器上的作业队列以及从 Logstash 进行提取，其失败率为 0。

此外，本文还特别提到海拔是手动的，这种情况不会发生。 更进一步，没关系，除了后端的负载。 这些是缓存服务器，而不是关键任务数据。 这确实是您完全不用担心 ACID 合规性或幻像写操作的情况。

很棒的文章。 肯定有帮助。

我确实要指出，尽管最后一段存在一些拼写和语法问题：

> 这个世界会让您感到惊讶。 六个月前，HipChat 虽然 Redis 可能是最薄弱的一环，但它的表现仍然很强劲，而 Couch 和 EBS 是最薄弱的一环。

非常好的文章，但与许多服务器相比，数字 60 很小。 可能在“高峰时段”运送 600 或 6000

是否曾经考虑过将 Cloudant 作为扩展 CouchDB 的选择？ 它适用于 Hothead Games。