confluent博客解读part1 confluent cloud serveless经验心得
背景
confluent博客解读是一个系列,主要是对confluent以下博客内容的一个阅读总结。
- Introduction: Design Considerations for Cloud-Native Data Systems
- Part 1: Making Apache Kafka Serverless: Lessons From Confluent Cloud
- Part 2: Speed, Scale, Storage: Our Journey from Apache Kafka to Performance in Confluent Cloud
- Part 3: From On-Prem to Cloud-Native: Multi-Tenancy in Confluent Cloud
- Part 4: Protecting Data Integrity in Confluent Cloud: Over 8 Trillion Messages Per Day
今天我们介绍的是第2篇,主要是关于confluent cloud是如何做serveless kafka的
前言
云上提供serveless能力是软件工程师的最爱,像S3。实现serveless kafka,用户使用起来感觉是没有ZK,没有broker,这里有很多有挑战的问题需要解决,包括:
- 在保证可用性的情况下,自动弹性扩缩kafka集群
- 在一个有状态的系统上保证数据存储的均衡性
这篇文章介绍confluent cloud的架构,并且说明confluent是如何通过k8s、confluent opeartor来达成kafka serveless的。
confluent的serveless经验会分成关键的四块来探讨:
- confluent cloud control plane
- confluent k8s operator
- self-balancing cluster
- infinite storage
confluent cloud总体架构
总体上采用了微服务化、event-driven的架构。这样可以保证:
- 敏捷开发:confluent的各个开发小组可以敏捷响应用户需求,开发新特性。有各自的发布节奏。
- 松耦合:服务间通过消息事件总线解耦,有更好的容错性
- 控制面数据面解耦:一个中心化的全局的控制面和很多运行在不同region上的数据面
- 运行在K8S上
该架构的好处是:
- 解耦故障点:数据面和控制面各自都可以独立工作,互不影响
- 可审计和可观测:因为都是事件流,可以做事件流回放,排查诊断一些消费慢的场景很有帮助
- 安全与治理:中心的事件流方便做安全控制,消息溯源
- 低延迟、消息追赶:数据面彻底解耦控制面后,控制面的一些long run操作可以异步执行,数据面重启恢复就更加快
笔者观点:
- 采用一个高可用的内置kafka集群来解耦,如果能把系统复杂性和额外带来的副作用控制好,用内置kafka完全解耦控制面和数据面还是非常有价值的,而且可以非常方便的做event driven的架构
- 虽然微服务化、event driven带来了不少非常不错的好处,例如敏捷开发、更好的event观测和追踪,不过也不要忽视其额外引入的架构复杂性,过早设计过于复杂的系统可能带来额外的负担
confluent cloud控制面
confluent控制面职责:
- 资源的供应、退役、弹性
- 访问控制
- 处理API请求,更新目标状态,例如一些生命周期相关的操作
- 同步API keys
- 执行替换策略,主要是处理一些弹性事件
- etc…
设计CKU
设计confluent unit for kafka(CKU): 避免客户自己去映射云资源和容量的关系。CKU通过设定各个维度资源的值,来表征整体kafka集群的容量。用户修改CKU会反应到一个自定义K8S资源 physical stateful cluster(PSC)。调整CKU的工作流程大致如下:
笔者解读:先落库持久化,然后PSC感知请求。文中没有提到细节,不过这里应该是做成了一个解耦的形态了,转成PSC的行为应该是watch了数据库的状态。
kafka cluster resize
resize流程如下
Infinite Storage(tiered storage)
完成分层存储的能力需要控制面提供一个工作流编排引擎。这个编排引擎接受一个spec,然后基于这个spec生成一个执行计划,确保spec关联的所有依赖按照依赖的逻辑顺序正确执行。
笔者解读:
- 控制面的编排引擎会负责资源准备
- bucket provisioner提供的BYOK对数据安全性是个不错的措施
控制面和数据面的交互
利用outbox patterm分发event
outbox pattern本质就是通过CDC来订阅控制面数据库的变更,然后来通知其他watcher,在confluent cloud上主要是各种service
通过mothership kafka的PSC topic分发PSC change event
k8s上PSC资源的更新是通过监听mothership kafka的PSC topic来达成的。watch PSC topic的数据,并且通过k8s api更新到K8S数据面。
控制面也通过mothership kafka监听数据面的操作
由于引入mothership kafka解耦控制面和数据面,数据面的一些信息,例如变更完成事件,也可以让控制面监听mothership kafka的topic来接受事件。
核心理念就是事件驱动,API KEY同步、资源的provisioning和deprovisioning都遵循围绕mothership kafka的事件驱动架构。
笔者解读:如果没有mothership kafka如何做相同的事情?可以引入其他提供watch能力的中间件,也可以自己做轮询。
Confluent Kubernetes Operator
confluent定义的operator主要就是围绕PSC来工作的,执行变更来meet PSC声明的最终状态。operator会和kafka做密切的交互来完成一系列操作。
operator扩容时的执行流程
例如在一个kafka cluster集群的扩容场景,operator会执行如下操作:
- 确保网络配置正确,新的pod在内部网络和外部网络都可以正常工作
- 为POD设置持久卷
- 确保新增的pod的DNS是可以被正常解析的,这样才可以后续将partition data均衡过来,否则会导致后续数据无法正常访问
- pod creation的时候会提供一个Init容器,提供pod az的布局图给kafka,方便kafka执行replace操作
psc声明
下图是PSC的部分spec内容,声明了kafka broker/pods在一个多AZ k8s集群上的replacement。
replacement的工作要点
- 检查前置条件:执行replacement时,operator会查询metric信息,确保kafka当前是healthy的,并且没有底层的一些分区平衡操作,才可以进行操作。
- 状态validation: operator更新完一个broker后会执行pre和post-roll validation,来确保当前broker重启是一个stable和healthy的状态。这些check确保kafka弹性的时候不丧失可用性。
- operator状态回显:SBC重平衡、K8S集群、持久卷的供应、POD的状态都需要回显给控制面(主要是编排引擎),下面是一个status状态案例:
1 | status: |
笔者解读:这里状态回显的关键是需要梳理好有哪些状态,不同状态表征的含义是什么
Self-Balancing Cluster(SBC’s)
当operator扩展了一个kafka broker以后,会有如下事件发生:
- kafka cluster controller感知新节点:kafka cluster controller会检测到当前broker所在机器没有任何数据,说明该节点是不均衡的
- 触发重新均衡:workload还没有发往新的broker节点,等SBC完成充平衡
- 新broker提供服务:重新均衡后,新的broker可以提供服务
confluent tips:
- 利用对象存储来做快速的重平衡
- 重平衡尽量挪动少量数据,快速达到平衡
- 重平衡需要考虑多个维度的细节,包括replica counts、leader counts、disk和networ用量等。还需要考虑用户剩余磁盘、网络容量充足
Elasticity with dual-tier architecture
一些观点和事实
- 无论重平衡算法多么好,如果移动大量数据的话是不可能有很好的弹性体验的:因为这会消耗大量的网络带宽、磁盘IOPS和CPU资源
- confluent依赖分层的对象存储加速重平衡:这样broker节点上的数据(EBS数据卷)只是总数据量的一个子集。通过挪动数据子集可以加速重平衡。(如果没有对象存储,对于一个大型集群来说重平衡会要1~2天,有对象存储则只需要20~40分钟)
confluent存储架构
- BROKER上存储可以独立工作:即使对象存储offline,broker仍然可以正常工作
- 使用磁盘扩容来支持更好的弹性
- **双层架构可以兼容低延迟、高吞吐两种workload: **如果低延迟,则主要读取broker local storage,否则则读取S3
未来
总体上就是提供无缝的serveless体验,会在以下领域继续深耕:
- 控制面将请求、集群调整通过mothership kafka分发给数据面
- 解耦的控制面和数据面
- Confluent Kubernetes Operator:提供云原生的核心能力,包括SBC、双层存储。结合K8S本身的能力通过和kafka cluster协调完成平滑的弹性体验
- 充分利用公有云提供的elastic resource