Skip to content

StreamNative Ursa:重新定义数据流引擎

最近经常在思考 RobustMQ 的核心竞争力到底在哪里。技术方向的选择不能闭门造车,需要知道业界都在做什么、往哪个方向走。所以会不定时发一些和 RobustMQ 没有直接关系,但与消息队列领域相关的技术调研文章。

StreamNative Ursa 是一个 Kafka 兼容的数据流引擎,于 2024 年 5 月首次发布,2025 年 3 月在 AWS 上正式 GA。Ursa 不是对现有流处理系统的渐进式改进,而是从架构层面重新设计的下一代流引擎。它的核心理念是将流数据直接写入数据湖仓(Lakehouse)的开放表格式,而不是传统的磁盘副本。

Ursa 基于 Apache Pulsar 构建,但重新设计了关键组件。它用 Oxia 替代了 ZooKeeper 作为元数据存储,用对象存储(S3/GCS/Azure Blob)替代了 BookKeeper 作为数据持久化层。最重要的是,Ursa 采用了无领导者(Leaderless)、无状态(Stateless)的 broker 架构,这与 Kafka 和传统 Pulsar 的基于领导者的架构有本质区别。

StreamNative 声称 Ursa 可以将基础设施成本降低到传统流引擎的 5%,也就是降低 95%。这个数字来自消除跨可用区复制、本地磁盘存储和领导者选举等开销。Ursa 的论文"Ursa: A Lakehouse-Native Data Streaming Engine for Kafka"获得了 VLDB 2025 最佳工业论文奖,这在一定程度上验证了其技术创新的价值。

核心架构

Ursa 的架构可以概括为三个关键特征:无领导者、湖仓原生、计算存储分离。

传统的 Kafka 和 Pulsar 都使用基于领导者的架构。每个分区有一个领导者 broker 负责写入,其他副本 broker 从领导者同步数据。这种设计的问题是领导者故障时需要重新选举,而且跨可用区的副本同步会产生大量的网络流量。在云环境中,跨 AZ 的网络流量是昂贵的,可能占到总成本的 80%。

Ursa 采用无领导者设计。任何 broker 都可以处理任何分区的读写请求,没有固定的领导者。为了保持性能,Ursa 使用一致性哈希将同一可用区内的生产者和消费者路由到同一个 broker,这样尾部读取可以从 broker 的本地写缓冲区提供服务,避免访问对象存储。但在全局层面,系统是无领导者的,任何 broker 都可以接管任何分区。

无领导者设计的好处是消除了领导者选举的停机时间和跨数据中心的复制流量。当 broker 故障时,客户端可以立即切换到另一个 broker,不需要等待选举完成。而且由于 broker 是无状态的,新 broker 可以快速启动,不需要加载本地状态。

Ursa 的数据持久化直接写入对象存储(S3)的开放表格式,而不是本地磁盘。写入流程是:broker 接收数据后先写入 WAL(Write-Ahead Log)对象到 S3,然后异步地由后台的压缩服务(Compaction Service)将 WAL 对象转换成 Parquet 格式的文件,并提交到数据湖仓表(Iceberg 或 Delta Lake)。

这种设计的关键是流表二元性(Stream-Table Duality)。同一份数据既是流(可以被 Kafka 客户端消费),又是表(可以被 SQL 引擎查询)。不需要单独的 ETL 管道将流数据导入数据湖仓,数据写入后立即可以通过 Spark、Trino、Databricks 等分析工具查询。

Ursa 的存储层使用 Parquet 格式,这带来了额外的好处。Parquet 的压缩效率很高,通常可以将数据大小减少 2-3 倍。而且 Parquet 是列式存储,非常适合分析查询。Ursa 论文中的测试显示,200GB 的原始数据经过 Parquet 压缩后只有 55GB。

计算和存储完全分离。Broker 层负责计算(接收数据、路由、缓存),对象存储负责持久化。两者可以独立扩展。需要更高吞吐量时增加 broker,需要更多存储时只是增加 S3 容量(几乎无限)。这消除了传统系统中计算和存储耦合导致的资源浪费。

元数据管理

Ursa 用 Oxia 替代了 ZooKeeper 作为元数据存储。ZooKeeper 是 Kafka 和经典 Pulsar 的核心依赖,但它的可扩展性有限,而且运维复杂。Oxia 是 StreamNative 开发的新一代元数据存储,水平可扩展,高可用,更适合云原生环境。

Ursa 的元数据包括分区的 offset 索引、压缩进度、topic 配置等。每个 topic-partition 维护一个 offset 索引,将逻辑 offset 映射到物理存储位置(WAL 对象或 Parquet 文件)。这个索引存储在 Oxia 中,broker 通过查询索引来定位数据。

压缩服务是后台运行的独立组件,负责将 WAL 对象转换成 Parquet 文件。它持续监控 Oxia 中的压缩进度,选择未压缩的 WAL 对象,读取数据,写入 Parquet,然后更新 offset 索引。压缩完成后,WAL 对象可以被删除,只保留 Parquet 文件。

Kafka 兼容性

Ursa 完全兼容 Kafka API。生产者和消费者可以使用标准的 Kafka 客户端连接到 Ursa,无需修改代码。Kafka 的工具生态(Kafka Connect、Schema Registry、监控工具)也可以直接使用。

这种兼容性不是简单的协议转换,而是在架构层面实现了 Kafka 的语义。虽然底层是无领导者 + 对象存储,但对外提供的仍然是 Kafka 的分区、offset、消费组等概念。用户迁移时不需要重写应用,只需要改变连接地址。

目前 Ursa 只支持 Kafka 协议,Pulsar 和 MQTT 协议的支持在路线图中。这是因为 Ursa 首先瞄准的是 Kafka 用户,希望他们能够平滑迁移。对于需要 Pulsar 原生协议的用户,可以继续使用经典 Pulsar 引擎。

StreamNative 还提供了 UniLink 迁移工具,可以将 Kafka topic 和元数据无缝复制到 Ursa,实现零停机迁移。UniLink 还可以将 Kafka topic 直接转换成 Iceberg 或 Delta 表,方便用户同时完成数据湖仓的迁移。

成本模型

Ursa 的成本优势来自几个方面。首先是消除跨 AZ 复制。传统的 Kafka 需要在多个 AZ 部署副本以保证高可用,这会产生大量的跨 AZ 网络流量。Ursa 通过对象存储的内置复制机制实现高可用,不需要跨 AZ 的 broker 间复制。

其次是消除本地磁盘存储。Kafka 需要为每个 broker 配置大容量的本地磁盘(通常是 SSD)来存储数据,而且为了保证高可用需要保留多份副本。Ursa 的 broker 是无状态的,不需要本地磁盘。数据直接写入对象存储,存储成本降低到磁盘的几分之一。

第三是计算资源的优化。由于计算存储分离,broker 只需要处理请求和缓存热数据,不需要管理大量的磁盘 I/O。这意味着可以用更小的实例类型,降低计算成本。

StreamNative 的基准测试显示,对于 5GB/s 的 Kafka 工作负载,Ursa 的成本只有 Redpanda 等传统引擎的 5%。具体数字是:Ursa 使用 6 个 m6a.large 实例运行 2 小时,总成本约 1 美元;而相同工作负载在 Kafka 上需要 3 个更大的实例和大量磁盘,成本约 20 美元。10 倍的成本差异主要来自跨 AZ 网络(Kafka 6 美元 vs Ursa 0 美元)和存储(Kafka 28 美元 vs Ursa 1.3 美元)。

性能权衡

Ursa 的架构设计做了明确的性能权衡。它牺牲了一定的写入延迟,换取了吞吐量、成本和可扩展性。

由于数据需要先写入 S3 的 WAL 对象,写入延迟比直接写入本地磁盘要高。Ursa 适合延迟不敏感的工作负载,比如数据摄取、日志收集、分析管道。对于需要亚毫秒级延迟的场景(比如在线交易),StreamNative 建议使用经典 Pulsar 引擎,它基于 BookKeeper,可以提供低延迟保证。

但对于大多数场景,Ursa 的延迟是可以接受的。而且由于无领导者设计消除了领导者选举和故障转移的停机时间,系统的可用性实际上更高。某个 broker 故障时,客户端可以立即切换到另一个 broker 继续工作,不会有明显的中断。

吞吐量方面,Ursa 的表现很好。测试显示它可以维持 5GB/s 的吞吐量,而且吞吐量对消息大小不敏感(1KB、4KB、64KB 都能保持稳定)。水平扩展也很平滑,增加 broker 可以线性提升吞吐量。

数据湖仓集成

Ursa 与数据湖仓的集成是原生的,不是通过外部连接器实现的。数据写入 Ursa 后自动转换成 Parquet 格式,并提交到 Iceberg 或 Delta Lake 表。这意味着流数据立即可以被分析工具查询,无需等待 ETL 批处理。

集成支持多个数据湖仓平台。Ursa 原生支持 Snowflake Open Catalog、Databricks Unity Catalog 和 AWS S3 Tables。用户可以选择将数据直接写入自己的数据湖仓,也可以使用 StreamNative 托管的存储。

数据治理也是统一的。通过 Unity Catalog 或 Open Catalog,流数据和批数据使用相同的元数据、权限、血缘追踪。不需要在流系统和分析系统之间同步权限配置。

对于需要写入外部湖仓表的场景,Ursa 的压缩服务可以生成两份 Parquet 文件:一份用于 Ursa 内部存储,一份针对目标 catalog 优化。虽然这会产生两份拷贝,但可以实现 catalog 特定的优化和跨平台的灵活数据共享。

部署模式

Ursa 目前支持 BYOC(Bring Your Own Cloud)模式,用户在自己的 AWS 账户中部署,StreamNative 负责管理。这确保了数据完全在用户控制之下,同时享受托管服务的便利。未来会扩展到 Dedicated 和 Serverless 部署模式。

对于已经在使用经典 Pulsar 引擎的用户,StreamNative 提供了 Ursa Stream Storage 扩展。这个扩展可以添加到现有的 Pulsar 集群,让数据同时写入 BookKeeper(低延迟访问)和 Ursa 存储(湖仓集成)。这提供了一个平滑的升级路径,用户可以先体验湖仓功能,然后再决定是否完全迁移到 Ursa 引擎。

当前限制

Ursa 目前处于早期阶段,有一些功能限制。事务(Transactions)和 topic 压缩(Topic Compaction)还不支持。只支持 Kafka 协议,Pulsar 和 MQTT 协议要等后续版本。只提供基于 S3 的成本优化存储,基于 BookKeeper 的低延迟存储还在开发中。

这些限制意味着 Ursa 目前只适合延迟不敏感的工作负载。对于需要极低延迟或事务支持的场景,需要继续使用经典 Pulsar 引擎。StreamNative 的建议是根据工作负载特征选择合适的引擎:低延迟场景用经典引擎,大规模数据摄取用 Ursa。

评价

Ursa 代表了数据流引擎架构的一次重要创新。无领导者 + 对象存储 + 湖仓原生的组合确实解决了传统流系统的一些根本问题:高成本、难扩展、与分析系统隔离。VLDB 最佳论文奖也证明了学术界对这个方向的认可。

从技术角度看,Ursa 的设计是合理的。消除跨 AZ 复制和本地磁盘确实可以大幅降低成本,无领导者架构确实可以简化运维。流表二元性的实现也很优雅,直接用 Parquet 作为存储格式,避免了数据重复和格式转换。

但也需要看到一些问题。首先是成熟度。Ursa 还很年轻,功能不完整,生产案例有限。宣称的 95% 成本降低是在特定场景下的基准测试结果,实际应用中能否达到这个水平还需要验证。而且这个数字是和传统的多 AZ Kafka 部署对比,如果对比对象是优化过的 Kafka(比如使用分层存储),差距可能没这么大。

其次是性能权衡。牺牲延迟换取成本和吞吐量,这个取舍是否合适取决于具体场景。对于需要低延迟的场景,Ursa 不适用。而对于延迟不敏感的场景,是否真的需要流处理系统,还是直接用批处理就够了?Ursa 试图服务的"大规模数据摄取"场景,实际市场规模有多大,还需要观察。

第三是生态依赖。Ursa 虽然 Kafka 兼容,但底层架构完全不同。遇到问题时,Kafka 社区的经验可能不适用。而且 Ursa 依赖 Oxia、对象存储、lakehouse catalog 等组件,整个技术栈比传统 Kafka 要复杂。虽然 StreamNative 提供托管服务可以屏蔽这些复杂性,但这也意味着用户被锁定在 StreamNative 的平台上。

第四是市场定位。Ursa 主要针对已经在使用数据湖仓的企业,希望简化流数据的摄入。但这个市场已经有成熟的方案(Kafka + Kafka Connect + Iceberg),虽然不够优雅,但能用。用户是否愿意为了更好的架构而迁移到一个新平台,这是个问题。而且 Databricks、Snowflake 等数据湖仓厂商也在优化自己的流摄入能力,Ursa 的窗口期可能不长。

最后是商业模式。StreamNative 是托管服务,用户无法自己部署 Ursa。虽然代码基于 Apache Pulsar,但 Ursa 特有的组件(Oxia、压缩服务)不是开源的。这限制了 Ursa 的传播,也让一些企业用户顾虑。

总体来说,Ursa 是一个技术上很有意思的尝试,在特定场景下确实有价值。如果你的工作负载是大规模的数据摄取,对延迟不敏感,而且已经在使用数据湖仓,那 Ursa 值得考虑。它可以简化架构,降低成本。但如果你需要低延迟、事务支持,或者对新技术比较谨慎,传统的 Kafka 或 Pulsar 可能更合适。

Ursa 是否能成功,取决于 StreamNative 能否在接下来 1-2 年内完善功能、积累案例、建立生态。目前还太早下结论。但至少在技术方向上,无领导者 + 湖仓原生是一个值得探索的方向。