在Segment,我们每天处理数百亿个事件。虽然这从业务角度来看是积极的,但也意味着我们的云提供商的账单需要持续监控和管理。作为一项基础设施密集型SaaS业务,成本很容易失控,因此我们必须非常小心云成本对毛利率的影响。
在过去的几个月里,在线活动的增加意味着流量的大幅增加。连锁反应是,我们开始注意到我们的网络传输成本(即云提供商对进出实例的数据收取的费用)的增长速度明显高于流量负载本身。
在深入研究之后,我们意识到很大一部分增长与我们的Kafka集群有关,我们使用这些集群通过我们的核心管道传递事件。我们决定应对挑战,在尊重我们的可用性、SLO和SLI的同时,大幅降低我们的Kafka平台的成本。
这篇文章将解释为什么Kafka网络在云环境下会如此昂贵,以及我们做了什么来解决这个问题。
在详细介绍我们所做的更改之前,让我们先讨论一下将消息(大致相当于Segment后端中的单个事件)添加到Kafka主题中的分区时发生的网络扇出。
首先,消息从生产者发送到写入消息的分区领导者。该领导者将该消息复制到分区中的跟随者(在Segment,我们在大多数主题中使用复制因子3,这意味着有2个跟随者)。最后,消息从领导者传递到从分区读取的每个消费者。
假设有3个副本和3个消费者,这意味着每条消息在网络上传输6次。
问题是,如果传输跨越云环境中的可用区(AZ)边界,它就不是免费的。
以下是可能出现的最坏情况,其中主节点与所有其他节点位于不同的区域:
在AWS的情况下,我们的大部分Kafka基础设施都运行在这里,数据传输成本可能很难计算出来(请参阅本指南以获得良好的摘要)。
在我们的Kafka集群中,同一VPC内的EC2实例之间的跨AZ流量不涉及其他AWS服务,因此标价为0.02美元/GB。
这看起来不像是一大笔钱。但是,当你每天转账多个TBS时,就会增加。它也比原始消息数量增加得更快,所以你的会计团队开始注意到这只是个时间问题。
在分析了数据并评估了不同策略的权衡之后,我们开始了几项平行的努力,以减少我们跨区域的Kafka网络流量。
在此项目之前,我们几乎所有主题分区的副本都分布在三个可用区中。这是为了确保最佳的服务可靠性,并保护自己免受全区停机的影响。
但是,如前所述,这意味着生成的每个消息都被复制到所有三个区域,从而导致大量代价高昂的跨区域数据传输。
在考虑了我们的管线的故障模式之后,我们意识到如果需要,我们的许多主题中的数据都可以从上游检查点重新创建。我们可以从我们的许多主题中删除跨区域复制,而不会影响我们渠道的整体可靠性。
基于这种洞察力,我们首先在管道的最前面设置了一组健壮的摄取主题。这些产品具有跨区域复制和较长的保留窗口(长达48小时)。
然后,我们浏览了每个下游主题,并使用topicctl将其转换为使用机架内复制放置。此拓扑仍使用相同数量的副本(在分段情况下为3个),但这些副本位于同一区域的代理中,从而最大限度地减少了跨AZ流量。
对于我们最大的主题,迁移耗时长达6个小时(有大量数据要传输!),但在迁移过程中,我们没有注意到集群中有任何重大的性能问题,这很棒。
我们的大多数Kafka消费者都是用Golang编写的,并使用建立在Kafka-Go之上的通用阅读器库。
在进行副本迁移的同时,我们的团队仔细检查了主数据管道中的所有消费者,并将他们切换到使用Kafka-Go的RackAffinityGroupBalancer功能的新阅读器库中。后者匹配使用者和分区,以便尽可能多的对位于同一区域中。
在此之后,我们消除了每个主题每封邮件另外1-5次跨区域传输(根据从该主题阅读的消费者组数量的不同而有所不同)。
虽然可以按区域将生产者与分区领导者相匹配,但每个经纪人或每个分区的负载很容易变得不平衡(特别是当领导者四处移动时)。如果生产者本身变得区域不平衡(例如,由于部署),这也可能在没有仔细协调的情况下导致集群中的不平衡。
例外的是我们正在筹备的重复数据删除部分,在之前的一篇博客文章中讨论了这一点。这就是我们在生成器和分区之间使用静态1:1映射的语义分区的地方。在这里,因为生产者的基数和区域不变,我们可以安全地围绕每个分区的区域移动,以减少跨区域的生产流量。我们在topicctl中使用了最新的静态机架策略来实现这一点。
我们计划重新考虑这一方法,并将生产者优化添加到我们流水线的更多组件中。Kafka-Go的路线图包括一个区域亲和性生产者的计划,所以在实现之后,我们可以在我们的代码中使用它。
随着2.1.0版本的发布,Kafka引入了对新的压缩编解码器Tzstd的支持。我们在生产流量的影子版本上进行了一些测试,发现zstd比我们之前的默认版本snappy节省了40%的空间,而没有显著降低管道性能(即,由于潜在的更高的压缩和解压缩开销)。
不幸的是,我们的大多数主题都在运行较旧卡夫卡版本的集群中。但是,我们可以切换到zstd来获取管道最前面的";摄取";主题,因为这些主题托管在一个新的集群中。我们为这些主题保留了跨区域复制,因此通过使用zstd,我们能够显著降低与这些主题相关的网络成本。
未来,我们希望在将集群升级到更新的Kafka版本时,将更多的主题迁移到zstd。
通过上述努力,我们逐渐将一些关键主题的拓扑从如下内容过渡:
随着我们取得进展,我们开始看到我们每天的EC2数据传输成本下降。当我们完成所有大型主题的工作时,我们已经减少了超过10万美元/月的成本,或120万美元/年。考虑到所需的工作量(大约2名工程师需要2个月),这项工作非常划算!
除了为Segment节省了一大笔钱,这个项目还带来了新的工具(包括topicctl),为我们的Kafka集群带来了新的Runbook,并对我们的主题和集群进行了全面的清理。
如果您在云环境中运营,请重新查看您的账单的转账成本,并计算跨区域Kafka网络的百分比。如果这不是一笔微不足道的数目,你也许可以通过尝试上面描述的一些策略来节省一大笔钱。
装满了市场趋势、分析和洞察力,这些都是我们从与数千名客户的交谈中总结出来的。