AutoMQ云上十倍成本节约的奥秘之SPOT实例

背景

近年来,无论是海外还是国内,虽然受疫情影响,公有云的市场规模增速有所放缓,但是云的市场总规模仍然是持续增长的。公有云作为一个各个国家重点布局的战略方向和其本身万亿级市场的定位[1],我们学习用好云是非常有必要的。

AutoMQ Kafka 充分认识到“云优先”的重要性,围绕公有云具备规模化效益和技术红利的云基础设施重新设计了 Kafka。在保证 100% 兼容 Apache Kafka 的基础上带来了极致的云成本优势和弹性能力,云上综合有 10 倍以上的成本节约[3]。今天就和大家分享下 AutoMQ Kafka 云上成本节约的利器之一,Spot实例。

Spot 实例与实例购买类型

Spot实例本质上是一种实例购买类型。Spot实例是云计算实例规模化成本红利的产物,通过机器的分时复用来提升利用率,从而推出更加廉价的实力购买类型。这本身也是云厂商相比私有IDC自建机房带来的巨大优势。不同云厂商提供的计算实例购买类型会有一些细微的差异,但是总体上都可以由以下几种类型构成:

  • 预留实例(reserved instance): 像阿里云称之为包年包月。这种计算实例不会中断,有SLA保证,属于预付费(pre-paid),所以价格上会比按需便宜很多,预付费的时间如果足够长,价格上甚至可以接近Spot实例。
  • **按需实例(on-demand instance):**用多少付多少,即支持pay-as-you-go,很多云的计费粒度都是按秒计费。实例有和预留实例相同的SLA保证,但是价格上非常昂贵。按需实例相比预留实例的价格可以相贵数倍。
  • **Spot实例:**与按需实例一样是用多少付多少。优点和缺点均十分突出。优点主要是价格及其便宜,在一些地域和可用区的计算实例的价格可以达到相同实例规格按需实例价格的十分之一。以 AutoMQ Kafka 使用的 AWS中国为例,r6i.large的平均成本节约相比按需实例达到80%左右。缺点主要是这种实例本身是没有SLA保证的,随时有中断的风险。

image.png

注意:在一些概念的名称定义上,文中会优先考虑采用AWS的定义。因为 AWS 作为公有云的开创者和很多理念的先行者,具有行业标杆意义。

在不可靠的Spot实例上提供可靠的服务

AutoMQ Kafka 通过大量应用 Spot 实例来降低总体计算成本[3]。如何在没有SLA、不可靠的 Spot 实例上提供可靠的 Kafka 服务是 AutoMQ Kafka 面临的主要挑战。在经过诸多实践后,我们得出一些在 Spot 实例上提供可靠 Kafka 服务的方法。

Broker无状态化

由于Spot本身随时会中断的特性, 云厂商的Spot实例最佳实践基本[4]都会强调Spot实例适用于无状态的应用。因此一个软件系统“无状态”完成得越彻底, 则Spot实例则会被利用的更彻底。

有状态引用最大的问题在于其状态数据的迁移、恢复。以 Apache Kafka 为例,即使在 3.6.0 版本以后支持了分级存储(非GA)的特性[5],其broker仍然是有状态的设计,对于每个broker上的分区数据要求最后一个logsegment必须在一级存储上。当这个logsegment非常大时,占用的一级存储空间将会非常大,当其关联的broker下线时,这些状态数据迁移是非常耗时的。如果不采用分级存储,这种迁移花费数小时甚至数天[6]都是很常见的。

AutoMQ Kafka 虽然在架构上除了依赖对象存储以外还依赖 EBS 块存储,但是其本质上是采用了一个无状态的架构,一级存储是松耦合的,充当一个缓冲区的角色。下图可以揭示 Apache Kafka 的多级存储和 AutoMQ 存储架构的区别。AutoMQ Kafka 使用的 EBS写入缓冲区默认值为固定的 3GB,在扩缩容场景可以完成秒级甚至毫秒级下线(取决于具体采用的机型)。

image.png
大量应用Spot实例,会存在集群中计算实例的频繁上下线,如果采用 Apache Kafka,不仅需要人为介入处理 Spot 实例的替换,同时这种频繁的上下线、分区数据移动将会造成系统明显抖动,对数据的生产、消费产明显的影响。而 AutoMQ Kafka 由于其无状态的设计,很好的规避了这种问题,即使使用大量的Spot实例,也可以将这种实例替换带来的系统抖动降低到最小,以业务无感的方式完成Spot实例的替换。

极速的弹性与Serverless

AutoMQ Kafka 是天然支持serverless的。系统本身的弹性速度和质量决定过了其所能提供的 Serverless服务质量。Spot实例的大量应用,由于不可预期的回收行为,会导致整个系统使用的计算实例经常性地被置换。在这个过程中,AutoMQ Kafka 所在计算实例接受实例终止信号到新的Spot实例被替换后启动 AutoMQ Kafka 并且重新接受流量整个冷启动过程的耗时长短决定着 AutoMQ Kafka 弹性的效率。

以 Apache Kafka 为例,如果使用 Spot 实例并且产生了实例的置换,其整个冷启动的过程如下。从图上我们可以非常清晰的看到,当数据规模较大时(TB级)或者存在分区热点时,Apache Kafka 整个冷启动时间中执行手动完成分区迁移、数据拷贝、流量重新均衡的过程耗时十分长,可达小时甚至是天级别[6],而采用 AutoMQ Kafka 由于其采用可靠性和可用性分离的设计,单副本即高可靠,整个分区移动过程无任何数据拷贝[7]。下图可以清晰看到,如果采用 Apche Kafka 在数据规模较大的场景下是完全没法应用 Spot 实例和提供serverless能力的,因为在冷启动的整个时间轴上,Apache Kafka 在分区移动和流量重平衡两个过程的耗时占据着总耗时绝对的比重。不将这两块耗时降低到与其他冷启动阶段相同数量级下,spot实例的应用和serverless也无从谈起。

与之相反的是,AutoMQ Kafka 凭借其秒级分区迁移[9]和持续流量重平衡[8]等杀手锏特性,不仅将高危的、重运维的分区移动和重平衡的耗时降低到秒级,同时整个过程还是自动化的,相比 Apache Kafka而言,有了跨时代的进步。当软件系统本身有较短的冷启动时间以后,围绕冷启动的其他阶段进行优化才有意义。在AutoMQ内核不再成为冷启动瓶颈的情况下,AutoMQ也将不断探索利用容器技术、GraalVM AOT编译等手段提升整个端到端冷启动的效率,给大家带来更快、更好的弹性能力。
image.png

充分利用云Spot实例的终止信号

Spot 实例回收的一般流程遵循如下流程,先发送终止信号,然后等待若干秒后再强制终止机器。不同云厂商的 Spot 实例的终止流程基本是如下流程的变种,核心路径基本相同。AutoMQ Kafka 的架构上使用了一块非常小(默认 3GB)的云盘SSD (AWS上即EBS,下文皆以EBS表示云盘SSD)来充当缓冲区的角色,以保证 AutoMQ Kafka 追尾读的低延迟。得益于 AutoMQ Kafka 无状态的 Broker 设计,EBS上只会残留约几百MB左右的少量缓存数据,只要保证Spot实例在接收到终止信号的等待期间将这部分数据刷到对象存储上,即可完成优雅停机。

AutoMQ 充分利用了这个实例终止信号,通过感知这个实例终止信号,然后在实例接收到终止信号的这段等待时间内提前执行刷出EBS缓存数据的操作来完成优雅停机。不同云厂商开放给用户去感知这个终止信号的方式会有差异,但是基本都会预留至少10秒以上的等待时间来让应用执行优雅下线,而这预留的时间对于 AutoMQ 来说是完全足够的。
image.png

Spot实例友好的容灾机制

前面小节提到了 AutoMQ Kafka 利用Spot实例终止信号后的一小段等待时间来完成优雅停机,这时候一定会有聪明的小伙伴提出质疑:我们应该考虑面向失败的设计,最坏情况下例如网络异常、系统负载异常卡顿导致 AutoMQ 来不及将数据在终止信号后的这段等待时间及时刷出怎么办呢? 其实,这种情况 AutoMQ 已经考虑到了,因此专门设计了 Spot 实例友好的容灾机制[10]。下图是整个容灾机制的简单示意图,总体上概括起来就是:

  1. AutoMQ 通过探测及时发现由于Spot实例回收而遗留的游离数据卷,将其挂载到一台合适的新的计算实例上
  2. 将游离数据卷残留的少量数据刷出到对象存储
  3. 删除已经为空的数据卷

通过这种容灾机制,及时在最坏情况下,AutoMQ Kafka 仍然可以完成自动化的容灾,整个过程业务无感。
image.png

按需实例与Spot实例混部

AutoMQ Kafka 虽然大量应用了Spot实例来降低成本,但是仍然在两个纬度上保留了少量按需实例的使用,从而确保 AutoMQ 可以给用户提供绝对可靠的 Kafka 服务。

  • KRaft节点使用on-demand实例: AutoMQ的核心能力依赖的重要元数据依靠KRaft,为了保证元数据的可靠性,参与Raft选举和保障元数据一致性的节点仍然使用的是on-demand实例,确保他们保持稳定。
  • Broker集群支持on-demand和Spot实例混布:以 AWS Spot实例的实际使用情况来看,一个30台机器的 AutoMQ Kafka 集群,一天内会有若干次实例置换,这种零碎时刻的实例置换,在AutoMQ这种无状态和极致弹性的设计下对业务基本是无感的。Spot实例的置换仅仅会导致部分分区数据的读写有秒级的RT抖动,这可以满足绝大部分Kafka的应用场景。即使如此,AutoMQ 也充分考虑到一部分对成本不敏感,但是对RT抖动要求非常苛刻的用户的诉求,允许用户调节Broker集群中on-demand实例的比例,权衡成本与延迟抖动频率。

image.png

回退按需实例

Spot实例除了存在会中断的问题,还存在容易库存不足的问题。对于云厂商而言,按需实例是有SLA的并且要最高优先级保障库存余量充足。如果一个地域某个可用区下的计算实例库存不足,则会优先用于满足按需实例的供给。在这种规则下,一些冷门地域或者可用区的Spot实例库存容量容易产生不足,当需要发生实例替换时,会存在无法购买到竞价实例的情况。
image.png的能力。Fallback本质就是探测并识别Spot实例库存不足的情况,然后在这种情况下重新购买按需实例来补充容量。并且fallback支持当Spot实例可以重新购买时,自动将集群中的按需实例重新替换成按需实例。该功能的总体实现主要是利用了弹性伸缩组本身容量管理的特性来达到的,因篇幅原因,后续会专门出一篇文章来介绍fallback能力的实现。

稳定性与成本之间的权衡

Spot 实例本身不可预期的中断、库存问题使得很多系统设计与开发者对其应用望而却步,持有过度的偏见。其实这种疑虑本质上源于不了解。正如世间没有绝对的安全一样,也不存在绝对的稳定性。稳定性的定义因应用场景而异,因为不同场景对于“稳定”的性能标准各不相同。在软件系统设计中,关键在于做出恰当的权衡。

以 AutoMQ 提供的 Kafka 为例,如果你可以容忍因Spot实例替换带来的某些时刻部分分区上秒级的RT抖动,那么你可以放心的使用较大比例的Spot实例从而获取巨大的成本收益;但是如果你是一个对RT抖动极度敏感的用户,那你也仍然可以全部采用按需实例,仅仅享受 AutoMQ 带来的极致弹性能力。简单而言,适合自己的才是最好的,也欢迎大家真正来体验 AutoMQ ,看看我们到底几斤几两。

参考资料

[1] 中国通信院 云计算白皮书 2023
[2] AutoMQ Kafka 云原生重塑 Kafka 架构
[3] AutoMQ Kafka 成本分析报告
[4] EC2 Spot 的最佳实践
[5] Kafka Tiered Storage Early Access Release Notes
[6] Making Apache Kafka Serverless: Lessons From Confluent Cloud
[7] AutoMQ 单副本高可用
[8] AutoMQ 持续重平衡
[9] AutoMQ 秒级分区迁移
[10] AutoMQ Kafka issue 447