推ter 的 Kafka 迁移历程

OPEN编辑 5年前
   <p>推ter 的实时性特点为 推ter 的工程团队带来了独特而具有挑战性的问题。我们需要快速发布突发新闻,向用户提供相关广告,并解决很多其他实时性问题。推ter 的 Pub/Sub 系统为 推ter 团队提供了处理这些工作负载的基础设施。</p>    <p>推ter 的 Messaging 团队过去几年一直在运行一个内部 Pub/Sub 系统,叫作 EventBus(建立在 Apache DistributedLog 之上),但我们最近决定转向 Apache Kafka,不仅针对已有的用例,还包括新增的用例。在这篇文章中,我们将介绍为什么我们选择采用 Kafka 作为 推ter 的 Pub/Sub 系统,以及我们在迁移过程中遇到的各种挑战。</p>    <h2>Kafka 是什么?</h2>    <p>Apache Kafka 是一个开源的分布式流式处理平台,可以高吞吐和低延迟地传输数据。Kafka 最初是在 LinkedIn 诞生,并于 2011 年开源,从那时起开始被社区广泛采用,包括很多其他公司在内,使其成为业界首选的事实上的实时消息系统。</p>    <p>Kafka 的核心就是一个基于分布式提交日志构建的 Pub/Sub 系统,提供了很多非常好的特性,例如水平可伸缩性和容错性。从那以后,Kafka 已经从消息系统发展成为一个成熟的流式处理平台。</p>    <h2>为什么要迁移?</h2>    <p>你可能想知道为什么 推ter 需要自己构建内部的消息传递系统。几年前,推ter 也曾经使用过 Kafka(0.7 版本),但我们发现在某些方面它无法满足我们的要求——主要是在读取期间进行的 I/O 操作数量,而且缺乏持久化特性和复制机制。然而,随着时间推移,硬件和 Kafka 都已经走过了漫长的道路,这些问题现在都已经得到了解决。硬件的改进已经使 SSD 的价格足够便宜,这解决了我们之前在 HDD 上看到的随机读取的 I/O 问题,而且服务器 NIC 具有更多的带宽,就没有那么必要分离服务和存储层(EventBus 会这么做)。此外,较新版本的 Kafka 现在支持数据复制,提供了我们想要的持久性保证。</p>    <p>将 推ter 的所有 Pub/Sub 用例迁移到一个全新的系统将是一个非常耗费成本的过程。所以,迁移到 Kafka 的决定绝对不是自然发生的,而是经过精心策划的,并且是由数据驱动的。迁移到 Kafka 的动机可归纳为两个方面:成本和社区。</p>    <h2>成本</h2>    <p>在向整个公司宣布迁移到 Kafka 之前,我们的团队花了几个月时间评估了 Kafka 在与 EventBus 类似的工作负载下的表现——持久写入、尾部读取、追赶读取和高扇出读取,以及一些灰色故障情况(例如减慢集群中的特定 Kafka 代理)。</p>    <p>在性能方面,我们看到 Kafka 的延迟显著降低,无论是根据消息创建时间戳来衡量吞吐量,还是根据消费者读取消息时间戳来衡量吞吐量。</p>    <p><img src="https://simg.open-open.com/show/6f9f8fd75c0a7f637236ac48867b9d1c.png"></p>    <p>不同吞吐量下 EventBus 和 Kafka 之间的 P99 延迟比较</p>    <p>这可以归因于几个因素,可能包括但不限于:</p>    <ul>     <li>在 EventBus 中,服务层和存储层是分离的,这引入了额外的跳转(网络时间和通过 JVM 代理层的时间),而在 Kafka 中只有一个进程处理存储和请求服务(参见下图)。</li>     <li>EventBus 在通过 fsync() 调用进行写入时会阻塞,而 Kafka 在后台依赖操作系统进行 fsync()。</li>     <li>Kafka 使用零拷贝。</li>    </ul>    <p><img src="https://simg.open-open.com/show/f7671cfb792a54429e14acc5614dac0c.png"></p>    <p>EventBus(左)和 Kafka(右)之间的架构比较</p>    <p>从成本的角度来看,EventBus 需要服务层(针对高网络吞吐量进行了优化)和存储层(针对磁盘进行了优化)的硬件,而 Kafka 使用单台主机就可以提供这两者。因此,EventBus 需要更多的机器来提供与 Kafka 相同的工作负载。对于单个消费者,我们节省了 68%的资源,对于拥有多个消费者的案例,我们节省了 75%的资源。但有一个问题是,对于严重依赖带宽的工作负载(非常高的扇出读取),EventBus 理论上可能更有效,因为我们可以独立地扩展服务层。但是,我们在实践中发现,我们的扇出没有那么极端,分离服务层是不值得的。</p>    <h2>社区</h2>    <p>如上所述,Kafka 已经得到了广泛采用。我们可以利用数百名开发人员为 Kafka 项目所做出的贡献,他们修复错误、改进和添加新功能,这比 EventBus/DistributedLog 的八名工程师所做的要好得多。此外,推ter 内部用户在 EventBus 中想要的很多功能已经在 Kafka 中提供了,例如流式处理库、至少一次 HDFS 管道,以及恰好一次性处理。</p>    <p>此外,当我们遇到客户端或服务器问题时,我们可以通过搜索网络轻松快速地找到解决方案,因为很可能其他人之前也遇到了同样的问题。另外,相比不太受欢迎的项目,受欢迎的项目的文档通常更加详尽。</p>    <p>采用 Kafka 等热门项目,并向这些项目回馈我们的贡献,这样做的另一个重要原因是为了招聘。一方面,通过向 Kafka 社区回馈贡献,可以让人们了解 推ter 的工程。另一方面,由于新工程师已经熟悉了这些技术,因此为团队招聘工程师要容易得多。</p>    <h2>挑战</h2>    <p>尽管迁移到 Kafka 看起来非常棒,但过程并不是一帆风顺的。我们在这个过程中遇到了很多技术挑战和适应性挑战。</p>    <p>从技术角度来看,我们遇到的一些挑战包括配置调优和 Kafka Streams 库。与很多分布式系统一样,为了支持 推ter 的实时性用例,需要对大量配置进行微调。在运行 Kafka Streams 时,我们发现 Kafka Streams 库中的元数据大小存在一些问题,这些问题是由于老版本的客户端在关闭后仍然保留元数据造成的。</p>    <p>另一方面,Kafka 与 EventBus 存在架构差异,我们不得不以不同的方式配置系统和调试问题。例如,如何在 EventBus(仲裁写入)和 Kafka(主从复制)中完成复制。写请求在 EventBus 中并行发送,而 Kafka 要求从节点仅在主节点收到写请求后才复制写请求。此外,两个系统之间的持久性模型是非常不同的—— EventBus 仅在数据持久化到磁盘时确认写入成功,而 Kafka 复制本身就具有持久性保证,并在将数据持久存储在磁盘上之前确认写入请求。我们不得不重新考虑我们对数据持久性的定义:数据的所有三个副本同时失败是不太可能的,因此没有必要在每个副本中同步数据来提供我们想要的持久性保证。</p>    <h2>前行</h2>    <p>在接下来的几个月里,我们计划将我们的用户从 EventBus 迁移到 Kafka,这将有助于降低运营 推ter Pub/Sub 系统的成本,并使我们的用户能够使用 Kafka 提供的其他功能。我们将持续关注生态系统中的不同消息传递和流式处理系统,并确保我们的团队为我们的用户和 推ter 做出正确的决策,即使这些决策很艰难。</p>    <p>英文原文:</p>    <p><a href="/misc/goto?guid=5048128438178129435" rel="nofollow,noindex">https://blog.推ter.com/engineering/en_us/topics/insights/2018/推ters-kafka-adoption-story.html</a></p>    <p>来自: <a class="cut cut70" href="https://www.infoq.cn/articles/UvIbB_gqAotdb3iOHqQX?utm_source=tuicool&utm_medium=referral" style="display:inline-block;">https://www.infoq.cn/articles/UvIbB_gqAotdb3iOHqQX</a></p>