引言
对于一个 Apache Kafka 集群,其成本主要由两部分组成:计算成本与存储成本。前者主要包括用于运行 Kafka Broker 的服务器(例如 AWS EC2),后者主要包括用于保存数据的存储设备(例如 AWS EBS)。
针对计算和存储这两部分,AutoMQ Kafka 均进行了大幅优化。在相同流量下,可以将集群总成本降低为原本的 1/10。
在本报告中,我们将分别从存储和计算两方面介绍 AutoMQ Kafka 在成本上做出的优化,并计算出理论上节约的成本。最后,我们还参照线上的常见场景,运行了一个 AutoMQ Kafka 集群,并将其成本与 Apache Kafka (低于 3.6.0 版本,无分层存储) 进行对比。
如无特殊说明,下文中提到的相关云产品定价均为 2023 年 10 月 31 日,亚马逊云科技宁夏区域 (cn-northwest-1) 的定价。
存储:充分利用高可靠、低成本的云存储
在云的时代,各个云厂商均提供了具有超高可靠性的云存储;同时,在不同的场景下,云厂商提供了多种各有特点的云产品以供用户选择,例如 AWS EBS, AWS S3, AWS EFS 等。 为了充分利用云存储,AutoMQ Kafka 将绝大多数数据卸载到对象存储中,仅使用很小的块存储(数百 MB 至数 GB)作为缓冲区,在保证了性能和可靠性的前提下,大幅降低了数据存储成本。
单副本,高可靠
云盘作为云存储中应用最广泛的存储之一,当前已经提供了超高的存储可靠性;而基于云盘构建的多副本存储,对于可靠性的提升微乎其微,反而会使得存储成本成倍增加。
在 AutoMQ Kafka 中,小容量单副本的云盘被用作数据在上传到对象存储之前的缓冲区,无需进行额外的数据复制;同时 AutoMQ Kafka 通过一系列手段(参见单副本高可用▸)可以保障单副本云盘在各种场景下依然具有高可用性。
故 AutoMQ Kafka 使用单副本云盘即可达到与 Apache Kafka 3 副本相同的存储可靠性与可用性。
物美价廉的对象存储
对象存储作为云上最便宜的存储产品之一,其拥有极低的价格和近乎无限的容量。AutoMQ Kafka 通过将绝大多数数据卸载到对象存储中(参见Main Storage▸),大幅降低了存储成本。
以 AWS 为例, AWS S3 Standard Storage 的单价为 0.1755 CNY/(GiB*month), AWS EBS gp3 的单价为 0.5312 CNY/(GiB*month), 使用 S3 将节约 67.0% 的存储成本。
下面以使用 AWS EBS 与 S3 为例,对比计算一下 AutoMQ Kafka 与 Apache Kafka 的存储成本。
AutoMQ Kafka 使用 S3 Standard Storage 存储 10 TiB 数据每月的花费为:
10 TiB * 1024 GiB/TiB * 0.1755 CNY/(GiB*month) = 1797.12 CNY/month
而 3 副本 Apache Kafka 使用 EBS gp3 存储 10 TiB 数据每月的花费为(令磁盘水位为 80%):
10 TiB * 1024 GiB/TiB ÷ 80% * 3 * 0.5312 CNY/(GiB*month) = 20398.08 CNY/month
Apache Kafka 的存储成本是理论上是 AutoMQ Kafka 的 20398.08 / 1797.12 ~= 11.4 倍。
计算:充分利用按量计费、任意扩缩的云计算
在云的时代,云厂商们提供了极具弹性的云计算服务,用户可以随时根据需要购买或释放云服务器;同时这些云服务器按量计费,用户可以在服务器闲置时释放它们以节约成本。
AutoMQ Kafka 存算分离的架构,天然可以利用云计算的弹性能力:无论是分区迁移还是扩缩机器,AutoMQ Kafka 均可以在分钟级的时间内完成。
按量扩缩,没有闲置
AutoMQ Kafka 拥有秒级分区迁移▸和持续数据重平衡▸的能力,所以无论缩容还是扩容,均可以在分钟级的时间内完成(参见分钟级平滑扩缩容▸)。
这种快速扩缩容的能力使得 AutoMQ Kafka 可以根据集群流量实时变更集群容量,以避免计算资源的浪费;而 Apache Kafka 则需要根据预估最大流量部署,以避免流量峰值到来时来不及扩容导致的业务受损。这对于流量峰谷很明显的场景来说,可以节约大量成本。
假定某个集群流量峰谷比为 10:1, 每日峰值流量持续 4 小时,AutoMQ Kafka 与 3 副本 Apache Kafka 所需实例数的理论比例为:
(1 * (24 - 4) + 10 * 4) : (10 * 24 * 3) = **1 : 12**
竞价实例,灵活便宜
当前各个主流云厂商均提供了竞价实例(又称“抢占式实例”)的服务,其相较于按需付费的实例,其有如下特点:
- 价格便宜。例如,AWS 竞价实例最高可享受 90% 的折扣,阿里云抢占式实例最高可享受 90% 的折扣。
- 生命周期不可控。当出价低于市场价时,竞价实例会被强制释放。
竞价实例随时有可能被强制释放的特点,导致其比按需实例更加难以利用,但是 AutoMQ Kafka 则完全可以解决这个问题:
- 当收到实例即将释放的信号时,AutoMQ Kafka 可以将该 Broker 上的分区快速迁移到其他 Broker(参见秒级分区迁移▸),进而优雅下线。
- 在极端情况下,分区未被完全迁移走实例即被释放时,AutoMQ Kafka 仍可以从该实例的数据盘中恢复并上传数据(参见异常宕机▸),以避免数据丢失。
在一个 AutoMQ Kafka 集群中,所有 Broker 均可以是竞价实例,进而大幅节约成本。
以 AWS r6i.large 机型为例,按需售价为 0.88313 CNY/hour, 竞价售价为 0.2067 CNY/hour, 使用竞价实例可以节约 76.6% 的成本。
带宽用在刀刃上
各个云厂商对于不同机型的实例,均设置了网络带宽上限(出入流量分别计算),这个上限会限制单台 Broker 所能承载的流量。反之,如果能够节约 Broker 使用的网络带宽,则可以提升单机流量上限,进而节约成本。
下面我们对比 AutoMQ Kafka 与 Apache Kafka 的流量使用情况,在集群生产消费比为 1:1 的条件下:
- 对于 AutoMQ Kafka,Broker 收到 1 份流量的消息时,其出流量包括 1 份发送给消费者的流量,1 份上传至对象存储的流量。合计 2 份。
- 对于 3 副本的 Apache Kafka,Broker 收到 1 份流量的消息时,其出流量包括 1 份发送给消费者的流量,2 份进行副本间复制的流量。合计 3 份。
可以推算出,生产消费比为 1:1 时,AutoMQ Kafka Broker 承载流量上限是 Apache Kafka 的 1.5 倍。
线上场景实测
为了验证 AutoMQ Kafka 在成本方面的优势,我们在 AWS 搭建了一个 AutoMQ Kafka 集群,并在模拟了常见场景收发消息,最终通过 AWS CloudWatch 和 AWS Cost Explorer 获得集群容量变化曲线与成本曲线,并将 AutoMQ Kafka 的成本与 Apache Kafka 进行了对比。
测试方案
- 部署一套 AutoMQ Kafka 集群。
- 使用 OpenMessaging Benchmark Framework 对该集群收发消息,持续 24 小时。
- 使用 AWS CloudWatch 观察该集群中 Broker 数量,各 Broker 流量与集群总流量的变化关系。
- 使用 AWS Cost Explorer 获得该集群中各云产品小时级成本。
值得说明的是,为了模拟真实场景下的集群流量,我们对 OpenMessaging Benchmark Framework 做了一定改动,使其支持在指定时间段变化收发消息的流量。测试时使用的流量曲线为:
- 常时流量为 80 MiB/s。
- 从 00:00 到 01:00 流量上升至 800 MiB/s, 到 02:00 流量下降至 400 MiB/s, 到 03:00 流量回归至 80 MiB/s。
- 从 13:00 到 13:45 流量上升至 800 MiB/s, 到 14:30 流量回归至 80 MiB/s。
- 从 18:00 到 19:00 流量上升至 1200 MiB/s, 到 20:00 流量回归至 80 MiB/s。
其他配置详见附录一。
运行结果
在 AWS 宁夏区域 (cn-northwest-1) 运行上述负载 24 小时,获得以下结果。
动态扩缩容
通过 AWS CloudWatch 可以获得在对应时间内,broker 数量与集群总流量随时间的变化关系。如下图:

注:
- 图中蓝色曲线为集群中生产消息的总流量(即每秒生产的消息总大小),由于生产消费比为 1:1, 这同时也是消费消息的总流量。其单位为 byte/s, 左 Y 轴中标识的单位是以 10 为底数的指数,例如,1M = 1,000,000, 1G = 1,000,000,000.
- 由于开启了 AWS Auto Scaling group 的重平衡,以及竞价实例的释放,在集群流量维持稳定时,依然可能发生短时间内 Broker 数量的增减。
从图中可以看出:
- AutoMQ Kakfa 可以实时随流量的增减进行扩缩容,仅存在分钟级延迟,这将节约大量的计算成本。
- AutoMQ Kakfa 在扩缩容的过程中,仅会带来短时间、小幅度的流量波动,不会影响集群可用性。
成本组成
通过 AWS Cost Explorer 可以获得在对应时间内,集群总成本及其组成。见下表:
类型 | 成本 (CNY) | 占比 |
---|---|---|
EC2 - 按需实例 | 64.450 | 34.3% |
EC2 - 竞价实例 | 19.446 | 10.4% |
S3 - 标准存储费 | 93.715 | 49.9% |
S3 - API 调用费 | 7.692 | 4.1% |
EBS - gp3 | 2.431 | 1.3% |
合计 | 187.734 | 100.0% |
注:
- 表中列出的成本统计周期为 2023-11-01 00:00 至 2023-11-01 23:59, 总计 24 小时。
- 为保证集群稳定性,AutoMQ Kafka 会使用 3 台按需实例作为 Controller(同时,其也会作为 Broker 承担一小部分流量),其成本为 0.88313 CNY/hour * 3 * 24 hour = 63.59 CNY, 与表中“EC2 - 按需实例”项基本一致。
- 由于 AWS Cost Explorer 对于“S3 - 标准存储费”的统计存在延迟,故表中所列成本为估算值 0.1755 CNY/(GiB*month) * 16242 GiB / 730 hour/month * 24 hour = 93.715 CNY. 其中 16242 GiB 为前述流量在 24 小时中产生的数据量。
- “S3 - API 调用费”包括调用以下 API 产生的费用: GetObject, PutObject, InitiateMultipartUpload, UploadPart, CopyPart 和 CompleteMultipartUpload.
- 表中没有列出花费未超过 0.001 CNY 的费用,例如 CreateBucket, ListBucket, DeleteBucket 等 API 调用费。
从表中可以看出:
- 由于 AutoMQ Kafka 中所有 Broker 都使用了竞价实例,且实例按需扩缩,大幅降低了计算成本。
- AutoMQ Kafka 将绝大多数数据都保存在对象存储(S3)中,仅有少部分数据保存在作为缓冲区的块存储(EBS)中,大幅降低了存储成本。
综上,AutoMQ Kafka 分钟级平滑扩缩容▸和对于对象存储的利用(参见S3 Stream▸ )可以充分发挥云的优势,大幅降低了成本,真正做到了云原生。
与 Apache Kafka 对比
我们还估算了在同样场景下,Apache Kafka (低于 3.6.0 版本,无分层存储) 所需成本。
为该 Apache Kafka 集群做出以下预设:
- 根据集群流量峰值 (1200 MiB/s) 购买按需实例,使用同样的 r6i.large 机型(其按需售价为 0.88313 CNY/hour,竞价售价为 0.2067 CNY/hour,基准带宽为 100MiB/s),同时网络水位为 80%;此外,额外购买 3 台按需实例作为 Controller.
- 根据集群总存储量 (16242 GiB) 购买块存储,使用 gp3 (其售价为 0.5312 CNY 每 GiB 每月),使用 3 副本存储,同时存储水位为 80%.
估算如下:
单 broker 承载流量上限:100 MiB/s * 80% / (1 + 2) = 26.67 MiB/s
集群中 broker 的数量:1200 MiB/s ÷ 26.67 MiB/s = 45
所需实例数量:45 + 3 = 48
每日计算成本:48 * 24 hour * 0.88313 CNY/hour = 1017.366 CNY
所需存储大小:16242 GiB * 3 / 80% = 60907.5 GiB
每日存储成本:60907.5 GiB * 0.5312 CNY/(GiB*month) / 730 hour/month * 24 hour = 1063.695 CNY
总成本:1017.366 CNY + 1063.695 CNY = 2081.061 CNY
将其与 AutoMQ Kafka 对比:
成本类别 | Apache Kafka (CNY) | AutoMQ Kafka (CNY) | 倍率 |
---|---|---|---|
计算 | 1017.336 | 83.896 | 12.13 |
存储 | 1063.695 | 103.838 | 10.24 |
合计 | 2081.061 | 187.734 | 11.09 |
可以看到,AutoMQ Kafka 充分发挥了云的弹性能力,充分利用了对象存储,相较于 Apache Kafka 大幅降低了计算和存储的成本,最终节约了超过 10 倍的成本。
附录一:测试配置
AutoMQ for Kafka 安装器的配置文件 kos-config.yaml:
kos:
installID: xxxx
vpcID: vpc-xxxxxx
cidr: 10.0.1.0/24
zoneNameList: cn-northwest-1b
kafka:
controllerCount: 3
heapOpts: "-Xms6g -Xmx6g -XX:MetaspaceSize=96m -XX:MaxDirectMemorySize=6g"
controllerSettings:
- autobalancer.reporter.network.in.capacity=60000
- autobalancer.reporter.network.out.capacity=60000
brokerSettings:
- autobalancer.reporter.network.in.capacity=100000
- autobalancer.reporter.network.out.capacity=100000
commonSettings:
- metric.reporters=kafka.autobalancer.metricsreporter.AutoBalancerMetricsReporter,org.apache.kafka.server.metrics.s3stream.KafkaS3MetricsLoggerReporter
- s3.metrics.logger.interval.ms=60000
- autobalancer.topic.num.partitions=1
- autobalancer.controller.enable=true
- autobalancer.controller.anomaly.detect.interval.ms=60000
- autobalancer.controller.metrics.delay.ms=20000
- autobalancer.controller.network.in.distribution.detect.threshold=0.2
- autobalancer.controller.network.in.distribution.detect.avg.deviation=0.05
- autobalancer.controller.network.out.distribution.detect.threshold=0.2
- autobalancer.controller.network.out.distribution.detect.avg.deviation=0.05
- autobalancer.controller.network.in.utilization.threshold=0.8
- autobalancer.controller.network.out.utilization.threshold=0.8
- autobalancer.controller.execution.interval.ms=100
- autobalancer.controller.execution.steps=1024
- autobalancer.controller.load.aggregation=true
- autobalancer.controller.exclude.topics=__consumer_offsets
- autobalancer.reporter.metrics.reporting.interval.ms=5000
- s3.network.baseline.bandwidth=104824045
- s3.wal.capacity=4294967296
- s3.wal.cache.size=2147483648
- s3.wal.object.size=536870912
- s3.stream.object.split.size=8388608
- s3.object.block.size=16777216
- s3.object.part.size=33554432
- s3.block.cache.size=1073741824
- s3.object.compaction.cache.size=536870912
scaling:
cooldown: 10
alarmPeriod: 60
scalingAlarmEvaluationTimes: 1
fallbackAlarmEvaluationTimes: 2
scalingNetworkUpBoundRatio: 0.8
scalingNetworkLowerBoundRatio: 0.8
ec2:
instanceType: r6i.large
controllerSpotEnabled: false
keyPairName: kafka_on_s3_benchmark_key-xxxx
enablePublic: true
enableDetailedMonitor: true
accessKey: xxxxxx
secretKey: xxxxxx
一些说明:
- 机型统一使用 r6i.large, 其网络基准带宽为 0.781 Gbps, 故将 s3.network.baseline.bandwidth 设置为 104824045 (Byte)
- 为了模拟生产场景,将 controller 的数量配置为 3 个,同时 controller 使用的是按需实例
- 为了快速感知流量变化并及时扩缩容,开启了 AWS EC2 detailed monitoring, 同时将 kos.scaling.cooldown 设置为 10 (s), 将 kos.scaling.alarmPeriod 设置为 60 (s)
- 为了充分发挥 AutoMQ Kafka 的弹性优势,将 kos.scaling.scalingNetworkUpBoundRatio 和 kos.scaling.scalingNetworkLowerBoundRatio 均设置为 0.8
OpenMessaging Benchmark Framework 配置如下:
driver.yaml:
name: AutoMQ for Kafka
driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver
# Kafka client-specific configuration
replicationFactor: 3
reset: false
topicConfig: |
min.insync.replicas=2
commonConfig: |
bootstrap.servers=10.0.1.134:9092,10.0.1.132:9092,10.0.1.133:9092
producerConfig: |
acks=all
linger.ms=0
batch.size=131072
send.buffer.bytes=1048576
receive.buffer.bytes=1048576
consumerConfig: |
auto.offset.reset=earliest
enable.auto.commit=false
auto.commit.interval.ms=0
max.partition.fetch.bytes=131072
send.buffer.bytes=1048576
receive.buffer.bytes=1048576
workload.yaml:
name: 1-topic-128-partitions-4kb-4p4c-dynamic
topics: 1
partitionsPerTopic: 128
messageSize: 4096
payloadFile: "payload/payload-4Kb.data"
subscriptionsPerTopic: 1
consumerPerSubscription: 4
producersPerTopic: 4
producerRate: 19200
producerRateList:
- [16, 0, 20480]
- [17, 0, 204800]
- [18, 0, 102400]
- [19, 0, 20480]
- [ 5, 0, 20480]
- [ 5, 45, 204800]
- [ 6, 30, 20480]
- [10, 0, 20480]
- [11, 0, 307200]
- [12, 0, 20480]
consumerBacklogSizeGB: 0
warmupDurationMinutes: 0
testDurationMinutes: 2100
此外,使用两台 c6in.2xlarge 实例作为 worker, 其网络基准带宽为 12.5 Gbps(即 1600 MiB/s),可以满足峰值流量时收发消息的需求。