S3 存储
在流存储库 S3Stream 中,S3 存储是另一个核心组件。WAL 仅用于写入加速以及故障恢复,S3 才是数据真正存储的地方。海量的数据正在往云端聚集,对象存储已经成为了大数据和数据湖生态事实上的存储引擎,我们今天可以发现大量的数据密集型软件正在从文件 API 迁移到对象 API,以 Kafka 为代表的流式数据入湖也是大势所趋。
S3Stream 基于 Object API 提供流式数据高效的读取和摄入,然后 通过存算分离的架构将 Apache Kafka 的存储层对接至对象存储,充分获得了共享存储带来的技术和成本优势:
-
阿里云对象存储同城冗余的标准版存储单价为 0.12 元/GiB/月,相较于 ESSD PL1 的单价(1 元/1 GiB/月)便宜 8 倍以上。同时,对象存储天然具备多可用区的可用性和持久性,数据无需额外再做复制,使得相比较传统的基于云盘的 3 副本架构,成本能节省 25 倍。
-
共享存储架构相比较 Shared-Nothing 架构,是真正的存算分离,数据跟计算节点无绑定关系。因此,AutoMQ 在进行分区移动时无需复制数据,能够做到真正的秒级无损分区迁移。这也是支撑 AutoMQ 流量实时重平衡和秒级节点水平扩缩容的原子能力。
S3 存储架构

AutoMQ 所有的数据都通过 S3Stream 存储至对象存储,在对象存储中定义了两个 Object 类型:
-
Stream Set Object: WAL 数据上传的时候,大部分数据量较小的 Stream 会合并作为一个 Stream Set Object 上传。
-
Stream Object: Stream Object 里面只有单个 Stream 的数据,方便对不同生命周期的 Stream 做精细化的数据删除。
Kafka 一个分区的数据会映射到多个 Stream 之上,核心为两个:
-
Metadata Stream: 元数据流保存数据索引、Kafka LeaderEpoch 快照、Producer 快照等信息。
-
Data Stream: 数据流保存分区中完整的 Kafka 数据。
S3 上对象的元数据信息是保存在 KRaft 当中的,为了降低海量分区场景下元数据的规模,S3Stream 内部提供了两种 Compaction 机 制,用于合并小对象,从而降低元数据的规模。
StreamSet Object Compact
StreamSet Object Compact 会在 Broker 后台以 20min 的间隔定期执行。类似 RocksDB SST, StreamSet Object Compact 根据策略选取当前 Broker 合适的 StreamSet Object 列表,采用归并排序合并的方式进行合并:
-
对于合并后会超过 16MiB 的 Stream,会分裂出一个单独的 Stream Object 上传;
-
剩余的 Stream 归并排序写入到一个新的 StreamSet Object 中。
归并排序进行 StreamSet Object 的合并,在 500MiB 的内存占用、读写 Range 16MiB 大小下,可以完成至多 15TiB 的 StreamSet Object 的合并。
通过 StreamSet Object Compact,零散的小流量 Stream 数据段,被合并成更大的数据段,对于冷数据 Catch-up Read 的场景,极大的降低读取 API 调用和提升读取效率。
Stream Object Compact
Stream Object Compact 的核心目的是节省集群维护 Object 映射的元数据总量,并且提高 Stream Object 数据的聚合度以减少冷数据 Catch-up Read 的 API 调用费用。
参与到 Compact 的 Stream Object 通常已经是 16MB,满足对象存储的最小 Part 限制。Stream Object Compact 会使用对象存储的 MultiPartCopy API 来直接进行 Range Copy 上传,避免从对象存储读取再写入浪费网络带宽。
多 Bucket 架构
对象存储作为各个云厂商最重要的存储服务,提供了 12 个 9 的数据持久性和高达 4 个 9 的可用性。但软件的故障永远都无法被消除,对象存储依然可能出现重大的软件故障,从而导致 AutoMQ 服务不可用。
另一方面,在云端,多云、多地域、甚至混合云的架构形态逐渐萌芽,以满足企业更灵活的 IT 治理诉求。
鉴于此,AutoMQ 企业版创新性地通过多 Bucket 架构来进一步提高系统的可用性,以及满足企业更灵活的 IT 治理诉求。

AutoMQ 企业版支持配置 1 个或者多个 Bucket 用于数据存储,同时 S3Stream 支持 4 种写入策略以满足不同的业务场景。
轮询法(Round Robin)
多个 Bucket 被同等对待,以轮询地方式写入。一般用于突破云厂商对单个 Bucket 或者单个账户的带宽限制。比如一个 Bucket 如果仅支持 5GiB/s 的带宽,可以通过组合两个 Bucket 来达到 10GiB/s 的带宽,以支持超大流量规模的业务场景。
故障转移(Failover)
对象存储依然可能出现故障,甚至软件级故障可能比可用区级的故障更严重。对于那些对可用性要求极高的业务场景,可以通过故障转移地方式写入两个 Bucket。故障转移场景下的 Bucket 配置可能为:
-
其中一个作为主 Bucket,跟业务在同地域,数据尽可能写入主 Bucket。
-
在另外一个地域,甚至另外一朵云创建一个备用 Bucket。跟主地域通过专线或者公网的形式打通网络,当主地域的对象存储不可用时,新的数据提交到备用 Bucket。备用链路会付出较高的网络成本,但因为仅发生在主 Bucket 不可用期间,成本相对可控。
该写入策略能极大地丰富 AutoMQ 的容灾场景,可以让 AutoMQ 以低成本的形式构建多地域容灾、多云容灾甚至混合云容灾的架构。
复制(Replication)
故障转移形式的多 Bucket 架构,只能在故障期间对写流量进行转移,读需要延迟读取。如果业务不能容忍故障期间的读延迟,希望是一个读写多活的架构,那么可以将写入策略配置为复制形式,此时数据会同步写入多个 Bucket。
该方式成本非常高,仅适合非常关键的业务。
动态分流(Dynamic Sharding)
数据以一种动态的,可随时调节的比例写入多 Bucket,轮询是该策略的一种特殊场景。动态分流的写入方式往往适用于多云和混合云架构。在该架构中,配置不同云服务的 Bucket,或者组合公共云和私有云的对象存储,同时动态调节流量比例,可以让架构时刻具备多云迁移,甚至下云的灵活能力。