2

使用开源组件构建自动运维Kafka集群 - Slack

 1 year ago
source link: https://www.jdon.com/60932
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

使用开源组件构建自动运维Kafka集群 - Slack
Slack团队使用 Cruise Control、Kafka Manager、Chef 和 Terraform 等开源组件大规模运行自我修复的 Kafka 集群。此外,使用标准 SRE 原则和适当的工具(如 Kafka Manager 和 Kafka offset exporter),可以使 Kafka 变得可靠、自助服务和自动驾驶。

在过去的几年里,Slack 一直在成功运行这种架构。展望未来,Kafka 将在 Slack 中扮演更重要的角色,因为它是新的变更数据捕获 (CDC) 项目的一部分。新的 CDC 功能将支持 Slack 权限服务的缓存需求,该服务用于授权 Slack 中的操作,还将实现对我们的数据仓库的近实时更新。为此,我们在 Slack 组建了一个新的数据流团队来处理所有当前和未来的 Kafka 用例。新的数据流团队将维护和支持 Slack 的所有 Kafka 集群。该团队还将负责构建与 Kafka 相关的标准化库和工具,并将致力于进一步改进当前的 Kafka 操作和效率。

什么是自驱动 Kafka 集群?
Kafka 是一款出色的软件,可在 Slack 的数百个节点上运行。但是,如果您曾经尝试过部署或管理 Kafka,您就会知道这并非易事。经常遭遇缓慢问题,有时是宕机的代理或容量管理问题。

自动化 Kafka 操作的目标是消除日常管理 Kafka 的运维开销。

为此,我们为 Kafka 集群确定了一些常见的运维操作任务,包括:

  • 例行的 Kafka 管理操作,例如创建主题、更改分区计数和将分区重新分配给代理
  • 容量规划操作,例如向集群添加/删除代理
  • 更换代理或部署新版本软件等运营问题
  • 诊断 Kafka 集群中问题的随叫随到的负担
  • 客户支持解释 Kafka 消费者是否跟上

因此,当我们迁移到新版本的 Kafka 集群时,我们决定将其操作方面自动化,或者使其成为自助服务。

Kafka 2项目
我们通过使用2.0.1版本的Kafka,统一了我们的努力,使Kafka更加自动化。我们的Kafka设置由以下部分组成:

构建、发布、配置和部署、Chef和Terraform

我们使用Chef来管理基础操作系统,在主机上部署和配置Kafka软件。我们的每个Kafka集群都在不同的角色下运行,有其自定义的配置,但它们都共享相同的底层配方。我们有一个Terraform模块,为AWS中的这个Chef角色创建一个ASG。ASG会自动管理节点的配置和删除。

旧的Kafka部署主要是通过部署Debian Kafka包来管理。然而,我们发现部署预先建立的软件包是很痛苦的,因为供应并不总是可靠的。此外,由于我们无论如何都要覆盖默认配置,所以我们的Chef配方很复杂。为了解决这些问题,我们创建了一个Kafka repo的内部分叉,并设置了我们的CI/CD管道来构建和发布静态二进制文件到S3。然后,我们的Chef配方将从S3中提取二进制文件进行部署,这使得供应非常可重复。

传统上,Apache Zookeeper 3.4集群是手动配置的,因为我们没有一个自动化的方法来确保每个Zookeeper节点都有唯一的ID,而且如果没有集群范围内的重新启动,就无法分配新的ID。手动配置Zookeeper节点不仅繁琐(我们被呼唤常规节点故障),而且容易出错,因为我们会意外地在同一AWS可用区启动多个Zookeeper节点,增加我们的爆炸半径。为了减少繁琐和错误,我们通过升级到Zookeeper 3.6来自动化这一过程,在更换经纪商时不需要在整个集群范围内重新启动。然后,在Zookeeper节点加入集群之前,我们通过Consul KV将唯一的ID分配给Zookeeper节点的过程自动化。有了这两个变化,我们就能通过ASG使用Terraform配置我们的Zookeeper集群了。

调整Kafka集群的稳定性
虽然这种设置有助于自动解决配置主机的痛点,但我们仍然需要管理集群操作,比如将分区迁移到新的broker上,并重新平衡broker的负载。此外,这样的集群管理操作对我们的客户造成了干扰,导致他们被呼唤或错过他们的SLO。

经过一些分析,我们发现Kafka集群中的热点导致了不稳定。而这些热点是由几个不同的问题造成的。

我们有几百个Kafka主题,它们被分配到我们的集群中。我们注意到,每个主题都有一个基于负载的不同分区数。在常规操作的过程中,一些经纪商会比其他经纪商运行得更热。这些热点又会在集群管理操作中加剧,比如添加和删除broker经纪人,从而导致我们的Kafka消费者在消费时出现延迟。

为了解决热点问题,我们希望均匀地利用集群中的所有broker经纪人。首先,为了抹平写的热点,我们把所有分区的数量改为经纪人数量的倍数。我们还通过在所有节点上挑选消费者数量来平滑读取热点。这一起平滑了集群上的读写率。 只要所有这些分区都均匀地分布在集群周围,我们就能在整个集群中获得可靠的利用率。此外,当我们扩大经纪人或消费者的规模时,我们将更新主题的分区数量,使分区数量仍然是经纪人数量的倍数,以确保均匀的利用率。

Kafka集群出现热点的另一个原因是在分区重新平衡事件中消耗的复制带宽。我们发现,大部分的资源被复制带宽饥饿的生产者或消费者所消耗,尤其是在高峰期。因此,我们限制了集群所能使用的复制带宽。然而,限制复制带宽导致我们的集群管理操作变得相当缓慢。我们还修改了我们的操作,每次只移动少量的分区。这使得我们可以持续地进行大量的小改动。

尽管做了这些努力,Kafka集群还是会因为部分故障而出现不平衡的情况。为了使这些变化自动化,我们使用了LinkedIn构建的优秀的Cruise Control自动化套件,使集群的再平衡操作自动化,并确保集群中所有节点的平均利用率。总的来说,这些调整导致了集群的稳定运行。

混乱工程 
由于从现有的集群切入是一个很大的变化,我们在prod中使用暗流量测试这个新集群时,进行了一些混沌实验。

我们的测试涉及到集群中各种资源在负载下的饱和。此外,我们能够在受控条件下终止经纪人,这有助于我们更好地了解我们经纪人的失败模式及其对生产者和消费者的影响。

在这些测试中,我们发现,我们的集群恢复操作主要受限于主机每秒发送的数据包数量。为了支持更快的恢复,我们在这些主机上启用了巨量帧。我们的Kafka实例在Slack的基础设施舰队中拥有一些最高的每秒包数利用率。

此外,这也帮助我们在使用Go Sarama库的消费者中发现了一些边缘案例的错误。在某些情况下,我们将这些消费者迁移到Confluent Go消费者,这也帮助我们在不同的语言中实现客户端配置的标准化。在无法升级消费者的情况下,我们添加了适当的变通方法和警报来监控这些用例。

在这些测试中,我们还意识到,Zookeeper的问题很快就会演变成更大的Kafka问题。因此,尽管成本略高,我们还是为每个Kafka集群使用了一个单独的Zookeeper集群,以减少Zookeeper故障的爆炸半径。

混沌测试也帮助我们了解在真正的故障中会出现的操作问题,并帮助我们对集群进行更多的调整。

自我服务的Kafka集群 
有很多情况下,我们的消费者团队会主动联系我们,询问或要求增加或删除集群的容量。其中一组问题是关于常规的运营问题,如容量规划,另一组问题是了解他们管道的健康状况。

此外,使用CLI工具来了解Kafka的情况也很乏味。因此,我们部署了kafka管理器,让每个人都能看到Kafka集群的元数据,如经纪人和主题列表。Kafka管理器还帮助我们简化了常规操作,如创建新主题和增加主题的分区数量。

为了提供对Kafka消费者健康状况的操作可见性,我们部署了一个kafka偏移量导出器的分叉,将消费者偏移量信息导出为Prometheus指标。在这些数据的基础上,我们建立了一个仪表盘,向消费者实时提供每个主题、每个消费者和汇总的消费指标。

为了减少知识的孤岛,我们将各种运行簿标准化为一个单一的单页运行簿。这有助于将所有的Kafka知识汇总到一个地方。此外,我们还将多个Kafka仪表盘整合为一个单一的全球仪表盘,用于我们所有的Kafka集群。

这些自助工具一起帮助我们的客户更好地了解数据,同时减少了团队的运营开销。这些工具还帮助我们改善了安全状况,最大限度地减少了SSH进入Kafka经纪商的需要。

升级Kafka集群
为了升级Kafka集群,我们决定不做原地集群升级,原因有几个。我们没有信心确保在升级窗口期间的零停机时间,尤其是在同时升级几个版本的时候。 此外,我们没有办法验证新的集群是否有问题,特别是在改变底层硬件类型时。

为了解决这些问题,我们制定了一个新的升级政策,在这个政策下,我们会切换到新的集群。切换过程如下。

  • 启动一个新的集群
  • 在新集群上使用暗流量运行任何验证测试
  • 停止向旧集群提供数据
  • 开始向新集群生产数据
  • 在保留窗口到期后关闭旧集群

虽然这个策略有协调切割消费者的缺点,但它是一个标准的操作程序,也适用于其他场景,如跨集群移动主题和测试新的EC2实例类型。

拆分主Kafka集群
在我们投入时间让Kafka自我维持和可靠之后,我们为自己赢得了宝贵的时间来开发其他具有高度影响力的功能,比如追踪。然而,即使我们投入了这么多的工作,还是会有一个时间点,那就是一个系统已经达到了需要重新审视假设和能力的程度。

我们在2021年初接近了这个点。我们由90个经纪人broker组成的单一集群在网络吞吐量上达到了临界点,上限为40,000 pps。网络饱和导致下游管道落后,因为Kafka在正常工作负荷下很难跟上消费者,更不用说处理巨大的流量高峰了。我们依赖日志管道来调试问题的开发人员每天都会受到Kafka网络饱和的影响。

为了减轻主Kafka集群的负载,我们利用我们的工具和自动化,将大型主题拆分到他们自己的更小、更高性能的集群中(从旧的d2实例升级到现代的nitro-en实例)。比较两个集群之间的类似工作负载,较新的集群能够在20个经纪人上实现类似的性能(每1,000 pps),从而使效率大约提高2.5倍。

在将三个最大的主题移出主集群后,我们看到集群上的情况立即得到缓解。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK