Google Vortex流式存储引擎分析

作者:archimekai,转载请注明出处

参考文献: Edara, P., Forbesj, J., & Li, B. (2024). Vortex: A Stream-oriented Storage Engine For Big Data Analytics. Companion of the 2024 International Conference on Management of Data, 175--187. https://doi.org/10.1145/3626246.3653396

文章目录

Vortex: A Stream-oriented Storage Engine For Big Data Analytics

免责声明:为了行文连贯,本文中掺杂了一些笔者的推测,请务必对照原论文阅读以免被误导。欢迎批评指正!

为什么?

在数据流(continuous stream)上的数据分析,缩短了从数据产生,到洞察见解的时间。为了更好地支持数据流上的分析,Google BigQuery构建了Vortex系统以支持实时分析。Vortex是一个把数据流放在首要位置的存储系统,其既能支持流式分析,又能支持批处理。借助于Vortex,BigQuery能够支持PB级数据的亚秒级导入和查询。

现有批量数据处理的问题

  • 新鲜度:流式数据处理对数据新鲜度的要求较高,现有的离线批量数据导入架构(新鲜度在小时级、天级)无法满足。
  • 数据丢失:生成流式数据的应用,通常运行在资源高度受限的环境中。这样的应用难以在本地缓存较多数据,常常需要对数据进行采样以减少数据量,导致数据流式。
  • 多次拷贝:批量数据处理中需要多次将中间结果写入临时存储,增加了数据处理时延,难以进行数据管理

路线选择

  • 路线一:将现有的批处理改造为支持处理流式数据(Spark)
  • 路线二:专门为流式数据处理构建系统,然后将这个系统也用在批处理上(Flink)

Vortex选择了后者。

是什么?

Vortex是一个专为(流式)追加写(append)优化的存储引擎。

  • 在架构上,Vortex是高度分布式的,在*region粒度(TODO 待确认)*进行数据复制(可用性较高)的存储引擎
  • 在可扩展性上,vortex的数据面和控制面均是分布式的,能够支持单表PB级数据
  • 在API上,Vortex为批处理和流处理提供了统一的API
  • 在事务能力上,Vortex的所有API均支持ACID性质
  • 在性能上,vortex提供亚秒级写入的SLA,这样客户端无需预留很大的buffer缓存要写入的数据
  • 在数据类型上,Vortex支持结构化和半结构化数据(见Dremel论文,本次不介绍)

下面本文将从核心概念,架构,API,写入读取流程等方面对Vortex进行分析,并总结一些vortex设计中值得我们借鉴的思路。

核心概念

如上图所示,stream是Vortex的核心概念,笔者将围绕stream展开介绍。

vortex stream

Vortex Stream(下文简称stream)是基于BigQuery Table的抽象。在同一个BigQuery Table上,可以同时存在多个stream,因此一个BigQuery Table也可以被视为多个stream的集合。

stream是用来承载写入和读取操作的实体。用户将要写入的行追加到stream的末尾(注意每个stream在当前时刻的末尾都是确定的)。当前已写入stream的行数,也被叫做stream的长度(length)。每一个写入stream的行,都会获得一个row offset。一个客户端可以创建一个或多个stream并发写入同一张表。一张表可以支持上万个客户端同时写入(从而能够达到很快的并发写入速度)。

同一个stream可以被多个reader并发读取。

在Vortex系统内部,一个stream由若干个streamlet组成,一个streamlet又由若干个fragment组成。

streamlet

streamlet由一组连续的行组成,是数据持久性(数据复制)管理的最小单位。为了保证数据的持久性(durability),每行数据(每个streamlet)至少要被写入两个borg cluster才会被认为写入成功。一个stream由一个或多个streamlet组成。stream中最多有一个streamlet是可写的,其必然是stream中的最后一个streamlet。对于可写的streamlet,其元信息(例如streamlet的当前长度)由stream server管理,spanner中保存的元信息仅作为缓存使用。对于已经写完的streamlet,spanner中会保存准确的元信息。

备注:streamlet有点类似于CU。

fragment

streamlet中的行可以进一步被分为若干组连续的行,被叫做fragment。也即一个streamlet由若干个fragment组成。fragment是数据物理存储管理的最小单位。fragment保存在colossus文件系统中的日志文件内。

fragment的大小按如下方式确定:(1)fragment不能太大,以便存储优化服务能比较快地把WOS转换为ROS (2)fragment不能太小,以免在元信息中创建太多的fragment,加重元信息管理的负担。 当向Fragment中写入数据时,Stream Server会缓存最大2MB的数据再写入。

每个fragment上还带有两个时间戳:creation_timestamp, deletion_timestamp。数据读取请求同样携带着一个快照时间戳snapshot_timestamp,通过比较这三个时间戳,可以判断fragment是否对数据读取请求可见。fragment可见的条件为:creation_timestamp <= snapshot_timestamp < deletion_timestamp

Fragment File Format: 如下图所示,文件头中有一个File Map。File Map列出了相同streamlet中的所有已经写入过的Fragment的信息。文件头中还有一个TrueTime时间戳。当数据写入后,还会在文件尾写入一个布隆过滤器,写入一个定长的文件尾。对于BUFFERED类型的流,在进行flush时,还会向Fragment中记录一个元信息,以保存flush时提交到了哪个row offset。

streamlet和fragment对用户不可见,相关信息记录在Spanner中。

WOS与ROS

WOS:write optimized storage format。当数据通过vortex的写入API进入系统后,首先以这种格式存储。顾名思义,这种格式对写入速度比较友好。

ROS: read optimized storage format。数据被写入一段时间后,会被后台的整理任务整理为ROS格式。ROS的主要由两种,也即capacitor和parquet。

架构

如上图所示,vortex中主要包括stream server, SMS, SOS三个组件。在客户端运行着vortex的client library。

Stream Server

stream server组成vortex的数据平面。stream server负责管理streamlet和fragment的元信息,并通过事务日志和检查点的方式确保上述元信息被持久化。Fragment被存储在colossus上的日志文件中,检查点、事务日志同样也被存储在colossus中。每个borg cluster中常常有上百个stream server。

  • Fragment文件:见上文
  • 日志文件:日志文件中会多保存一份File Map,以便BigQuery读取数据时,能直接通过Stream Server的日志文件确认有哪些fragments要读取

SMS

SMS即stream metadata server。SMS组成vortex的控制平面。SMS管理stream,streamlet、fragment,并将streamlet分配给某一个Stream Server负责处理。

SOS

SOS即Storage Optimization Service。将WOS转为ROS,并将旧数据标记为已删除。SOS以LSM树的方式维护Fragments。首先,SOS将WOS转换为ROS,同时减少Fragment的数量。SOS还会在后台进行自动数据聚簇。

Thick Client Library

之所以叫做厚客户端,是因为vortex的客户端可以绕过SMS直接同stream server交互,并且支持故障重试。

负载均衡和故障恢复

BigQuery的框架中,每个用户的工作负载由一个主borg cluster和一个辅borg cluster负责处理。具体到Vortex的处理逻辑,当用户使用Vortex写入数据时,优先由主borg cluster进行处理。当主borg cluster暂时不可用时,vortex会透明地转移到辅borg cluster上继续处理。

主borg cluster是以table为粒度进行分配的。也就是说,一个table只能有一个主borg cluster负责处理,多个table的负载可以被均衡到多个borg cluster上。一个table的元信息由主borg cluster中的一个SMS负责处理。Google的数据应用程序负载均衡服务Slicer会监控SMS的状态,当SMS不可用时,Slicer会自动将table的管理任务迁移到主borg cluster中的其他SMS上。当某个SMS负载过高时,Slicer同样会执行类似的迁移动作。由于table的元信息由Spanner管理,元信息的一致性可以由Spanner保证。

核心API示例

enum StreamType {
STREAM_TYPE_UNBUFFERED = 0,
STREAM_TYPE_BUFFERED = 1,
STREAM_TYPE_PENDING = 2,
};
CreateStreamOptions options;
options.set_stream_type(STREAM_TYPE_UNBUFFERED);
Stream s = CreateStream(table_name, options);


RowSet row_set;
// Populate row_set from the input data and the schema.
// ...
// Append data to the end of a Stream.
AppendStreamResponse response = AppendStream(s, row_set,
[row_offset]);

Status status = FlushStream(s, row_offset)

std::vector<Stream> streams = GetStreams();
Status status = BatchCommitStreams(streams);

Status status = FinalizeStream(s);

写入流程

大体流程如下:

  • vortex client发送写入请求到SMS
  • SMS找到或创建一个未使用的stream,并确保有一个stream server上已创建该stream的streamlet。
  • SMS告诉客户端streamlet id和stream server的地址。
  • 客户端建立一条到stream server的长连接,以便向streamlet写入数据。

推测的细节如下:
client slicer SMS stream server colossus spanner 本图为推测 CreateStream select a SMS based on load,etc CreateStream select a stream server based on load,etc 返回id,地址给客户端 Create Streamlet data transfer (AppendStream(streamletid)) 何时创建frag? create fragment snappy compress encrypt write frag loop [max buffer 2MB] finish fragment update metadata loop [fragments] flush stream write commit record create new stream let 重复上面的写入过程 FinalizeStream client slicer SMS stream server colossus spanner

备注:默认情况下,Vortex不会应用主键约束。也就是用户可以创建主键,但是Vortex仍然允许主键重复。如果用户希望确保主键的唯一性,用户在写入数据时应该只使用UPSERT,DELETE这两种操作,这样vortex就会按照主键的语义操作数据。

读取流程

推测的读取流程如下:
client bigquery spanner Stream Server colossus select xxx gen_snapshot_time() get_frags() (if ss is online,把ss当成缓存用) get_frags() get_frags() (ROS+WOS) filter frags based on snapshot_time read data in frags until last record client bigquery spanner Stream Server colossus

关键点:BigQuery支持直接从colossus上读取vortex所写入的文件。

总结

Vortex中以下设计值得学习:

  • 面向写入和读取,使用不同的存储格式,从而兼顾写入性能和读取性能
  • 使用thick client library,减轻服务器的压力
  • 写入需要server的,但是读取可以不要server,直接让客户端从分布式存储上读,从而降低存储成本
相关推荐
Data跳动2 小时前
Spark内存都消耗在哪里了?
大数据·分布式·spark
woshiabc1112 小时前
windows安装Elasticsearch及增删改查操作
大数据·elasticsearch·搜索引擎
lucky_syq3 小时前
Saprk和Flink的区别
大数据·flink
lucky_syq3 小时前
流式处理,为什么Flink比Spark Streaming好?
大数据·flink·spark
袋鼠云数栈3 小时前
深入浅出Flink CEP丨如何通过Flink SQL作业动态更新Flink CEP作业
大数据
小白学大数据4 小时前
如何使用Selenium处理JavaScript动态加载的内容?
大数据·javascript·爬虫·selenium·测试工具
15年网络推广青哥5 小时前
国际抖音TikTok矩阵运营的关键要素有哪些?
大数据·人工智能·矩阵
节点。csn5 小时前
Hadoop yarn安装
大数据·hadoop·分布式
arnold665 小时前
探索 ElasticSearch:性能优化之道
大数据·elasticsearch·性能优化
NiNg_1_2347 小时前
基于Hadoop的数据清洗
大数据·hadoop·分布式