防弹卡夫卡,以及亚马逊停运的故事

119 阅读8分钟

8月25日,我们的一个客户使用Supertubes在亚马逊的Kubernetes上操作Kafka集群,他们的Kubernetes集群开始出现服务中断的情况。

  • 他们之前配置的普罗米修斯警报通知了infra团队哪些服务受到了影响。
  • 结果发现,亚马逊在伦敦的一个AZ中出现了一些实例连接问题。
  • 由于正确配置了Kafka和Zookeeper集群,没有发生数据丢失,这两个集群都分布在多个区域。
  • 一旦集群有足够的资源,Supertubes就会无缝恢复。
  • 通过MirrorMaker 2.0启用复制,我们也可以从整个区域范围内的全面中断中恢复。

支持案例 🔗︎

8月初,我们的一个客户向我们提出了一个支持案例。他们收到的警报显示,由Supertubes管理的一个Kafka经纪商出现了错误。随后进行了简短的调查。结果发现,AWS伦敦地区的一个可用区出现了连接问题,因此位于该地区的节点上的pod受到了影响。他们的一个Supertubes管理的Kafka代理报告了错误。与今天的大多数公司一样,他们依靠亚马逊EC2实例来运行他们的工作负载。好吧,有时甚至亚马逊也会出现故障:他们报告了伦敦地区的一些实例连接问题,更具体地说,在其中一个可用区,euw2-az2 。(这是一个物理可用区ID,它映射到不同的区域名称,如eu-west-2a ,为每个AWS账户。你可以通过aws ec2 describe-availability-zones --region eu-west-2 来检查)。

outage

幸运的是,由于Kubernetes和Supertubes,没有发生数据丢失和中断。

Kubernetes最受欢迎的两个功能/概念 🔗︎

自我修复 🔗︎

我想你们中的大多数人已经知道,容器是捆绑应用程序的好方法。在生产环境中,你需要管理运行应用程序的容器,并确保没有停机时间。也就是说,如果一个容器宕机,另一个就需要启动。Pod是最小的可部署的计算单元,你可以在Kubernetes中创建和管理。一个Pod是由一个或多个容器组成的一组,具有共享的存储/网络资源,以及如何运行容器的规范。Kubernetes为Pod提供了自我修复功能,这意味着它可以重新启动失败的Pod,替换Pod,杀死不响应你的用户定义的健康检查的Pod,并在它们准备好服务之前不向客户公布。

此外,Kubernetes可以在支持动态配置节点的环境中,通过使用其Cluster Autoscaler动态地扩大(或缩小)集群规模。Cluster Autoscaler能够根据指标自动调整Kubernetes集群的规模。如果由于资源不足,集群中出现了无法运行的pod,它就会请求更多的资源。如果集群中的节点未被充分利用,它也可以触发降级。

操作员模式 🔗︎

操作员是Kubernetes的扩展,使用自定义资源来管理应用程序及其组件。Kubernetes中的资源是Kubernetes API中的一个端点,它存储着某种类型的Kubernetes对象(例如Pod实例本身)。自定义资源本质上是一种可以添加到Kubernetes的资源,以扩展其基本API。一旦安装了自定义资源,用户就可以用kubectl来管理这类对象,与管理Kubernetes内置资源(例如Pod)的方式一样。相应地,必须有一个自定义控制器,当事件发生在自定义资源上时(例如,通过kubectl诱导),对其做出反应,并执行处理事件所需的操作。总而言之,Kubernetes控制器让你在不修改Kubernetes本身代码的情况下扩展集群的行为。

最好的支持是不支持 🔗︎

Supertubes利用了我们一直在讨论的运营商模式。在Supertubes内部,有五个以上的操作者在尽力维持一个理想的状态。Banzai Cloud对如何操作Kafka、Kubernetes和Istio的深刻理解体现在这些操作者的实现上。依靠这些知识和操作者模式,这些组件是自力更生的。这就是我们所说的,最好的支持是不需要支持,客户不需要做任何事情就能解决问题的意思。这是基于我们的信念,没有人能够提供与一群Kubernetes操作员相同水平的支持,他们会在事件发生的确切时刻照顾你的工作负载,无论何时。

architecture

这个具体案例也不例外。Supertubes发现了问题并立即启动了行动。

在伦敦zone2的亚马逊EC2实例出现一些连接问题后,Supertubes配置的Prometheus警报通知infra团队,其中一个Kafka经纪人出现了故障。多亏了经纪人的配置,其中包括设置broker.rack ,才没有发生数据丢失。

broker.rack 是一个经纪人配置。当你设置了它,Kafka会尽量把副本放在尽可能多的不同机架上,这样,如果一个机架发生故障,分区可以继续运作。这也让Kafka集群的维护变得更容易,因为你可以一次性拆掉整个机架。在云供应商的情况下,机架通常被映射到可用性区域的概念。

Supertubes是这样设计的,无论如何都会保存绑定在经纪人身上的卷。因为其中一个经纪商倒下了,它立即在同一个可用区重新创建,所以卷可以被保存。不幸的是,那个区域仍然有一些问题,所以重新创建pod并没有立即治愈集群。

为了保持理想的状态,必须做两件事。

  • 用户必须创建一个新的代理,其亲和力指向一个未受影响的区域。
  • 而且,由于Supertubes可以优雅地处理经纪商的增加,这就触发了一个调和操作,这反过来又重新平衡了集群,使其再次完全运行。

另一个选择是配置一个普罗米修斯警报,自动触发升级。在升级过程中,一个新的经纪商被创建在不同的区域。这是必要的,因为绑定到故障吊舱的卷在受影响的区域是可用的,并且在该区域再次运行之前不能被移动。当代理变得可操作时,Supertubes启动了一个分区重新平衡以修复集群。一旦不可用的区域开始运行,就会启动降级,以删除利用率低的代理。

在这第二种方法中,这些步骤是自动执行的,不需要任何形式的人为互动。

我们想强调一个关键的设计决定,它使Supertubes能够执行我们刚才描述的步骤。Kafka是一个有状态的应用程序,但我们的解决方案并不依赖于Kubernetes StatefulSets。只是从K8s的文档中快速回顾一下。

StatefulSet管理一组Pod的部署和扩展,并提供关于它们的顺序和唯一性的保证。和部署一样,StatefulSet管理的Pod是基于相同的容器规格。与部署不同的是,StatefulSet为其每个Pod维护粘性身份。这些Pod是根据相同的规范创建的,但不能互换:每个Pod都有一个持久的标识符,在任何重新安排中都会被维护。

在这种情况下,使用StatefulSet将意味着Supertubes不能启动一个升级。StatefulSet控制器将无法创建一个新的实例,直到有一个实例处于失败状态。这意味着集群会一直处于不健康的状态,直到区域问题得到解决。

你可能知道,Kafka依赖于Zookeeper,而Supertubes使用了一个开源的Zookeeper Operator,并做了一些改进。在我们讨论的情况下,Zookeeper集群受到了影响,而且由于StatefulSet的原因,它不能干净地恢复。但由于配置的原因,这并没有影响到相关的Kafka集群的健康。Kafka对Zookeeper的依赖很快就会结束,希望是在3.0.0版本。

如果你对这个问题及其进展感兴趣,请关注KIP-500

进化,进化,进化 🔗︎

你可能会问,"如果这'只是'一个区域的中断,我们怎么知道这个系统能从影响整个区域或整个云供应商的中断中恢复过来?"那么,通过使用Mirror Maker 2,第二部分也是可行的。我们正在与客户密切合作,在他们的环境中启用Mirror Maker 2,以确保在整个集群受到区域中断影响的情况下不会出现数据丢失。

如果你对MirrorMaker 2以及Supertubes如何简化交互和配置感兴趣,请查看我们之前关于使用MirrorMaker2在Kubernetes上进行Kafka灾难恢复的博文。

Kafka被设计为包括一个顶级的弹性功能。Supertubes通过额外的增强功能完成了这一点。详见Supertubes的最新公告。它们一起允许在不同的云提供商之间维护Kafka基础设施,而没有任何开销。