本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权。
文章目录
- 引言
- 以AWS S3为例的对象存储基本特征
- 成本
- 时延
- 吞吐量
- 最优请求大小
- Model for Cloud Storage Retrieval
- CLOUD STORAGE INTEGRATION
- 线程模型概要设计
- Object Scheduler
- 性能
- 结束语
引言
刷完近N年内数据库顶会的时序数据库论文后,我开始把目光投向相关领域的基础方向,vldb2023这篇《Exploiting Cloud Object Storage for High-Performance Analytics》的名字听起来就是一个有趣的主题,且其涉及的内容也和云时序数据库系统关系颇深。
时序数据库本身可以认为是分析性负载,古典的列式存储引擎配合各种奇妙优化后的压缩算法使存储量可以达到原始数据量的百分之十以下(与数据类型有关)。在如今基础架构强调降本增效的大背景下,原本使用Cassandra,Hbase,mysql等不够成本效益的业务倾向于使用时序数据库。一般情况下强大的压缩能力我们认为可以带来成本的大幅度下降,但是在架构不够“弹性”的情况下却无法达到这一美好愿景,举个简单的例子,比如一台16C64G一块3.5T的物理机,分析性需求使得内存和CPU先行到达瓶颈,存储量却大片大片的空余,剩下的存储空间也无法被利用,想要在价格上做到有竞争力,必须提升存储利用率,这里有两个使用存算分离的必要因素:
- 公司基础架构的长期思路一定是为了节省成本而使用比例一致的高密机型,不太可能给在保留CPU/内存比例的情况下减少存储介质的上限
- 不同的业务场景CPU/内存/存储的使用比例不相同,存储计算不分离的情况下资源利用率永远无法全局最优
基于上述考虑,这篇文章事实上是有工程意义的。
本篇文章的贡献我个人认为可以分为如下三个方面:
- 提供一套分析方法决策如何使用对象存储可以在最佳带宽,成本效益以及性能这三个维度达到最优
- 现有S3客户端实现较差,且目前用户倾向于使用多云,作者实现了AnyBlob这样的多云对象存储客户端,其中使用io_uring,优化的域名解析器,使用AES而不是https 这三种策略减少使用对象存储CPU消耗,并在其中支持多云客户端。
- 云存储集成对象存储章节中详细给出实现细节(有没有实践意义另说),其中调度器的设计确实值得思考,其统计访问对象存储和实际引擎处理的资源消耗,给这两种场景动态分配线程,以达到更高的整体吞吐量,这种思路可以用在很多场景中,比如读写分离,快慢查询分离等
以AWS S3为例的对象存储基本特征
成本
主流云厂商对象存储的计费结构类似,本文对于成本效益的讨论也是基于这种计费模式的
- 存储成本
- 查询/修改的API开销
- region间的流量传输费用
2024.2.4 美元到人民币的汇率是7.12,以AWS举例,其存储成本换算成人民币大概是0.163/G/month。
因为部分历史原因,我曾经负责过一段时间腾讯云对象存储索引层,来看看自家产品的成本构成[3],计费模式分为按量计费[4]和资源包[5]。以按量计费为例:
费用组成如上,相比于AWS,多收了数据取回费用,相对应的存储容量费用和API计费腾讯云会比友商便宜一点[6],但是值得一提的是腾讯云读写费用是一致的,但是国外友商是把读写分开计费的。
时延
这里的冷热定义是第一次请求为冷和迭代访问的第二十次为热,基于此分析可以看出几个关键结论:
- 达到吞吐量最大的限制是时延,所以为了达到对象存储的最大吞吐量,必须存在大量并发请求
- 对于8MB以上的对象,对象大小增加一倍,时延会增加近一倍,意味着8MB以上提升对象大小对于吞吐量没有显著提升
- 对于小文件首字节和总体时延基本一致
实验生成随机的16MB数据,上图显示8周访问对象的带宽,因为不同租户间共享带宽,带宽上限存在互相影响的情况,这是这使得延迟其实很难预测
这个结论也比较有趣,图 4 所示的实验访问了随机生成的 16 MiB 对象。每次运行后,在下一次运行前都不会访问存储桶,为减少缓存影响,执行间隔(至少)为 12 小时。
实验显示出S3的平均延迟其实更高,其次S3存在一个最低延迟,且不存在异常值;其他云厂商的时延更低,但是方差更大。
以我的经验,异常值更多和集群相关,虽然运营的安全水位会把资源保持在一定比例下,保证延迟,但是部分集群存在大客户,突发的访问(list/del/get)等会严重影响此存储节点上的其他租户,而分裂本身存在滞后性,所以异常值本身比例不高可以忽略,但是这样的实验可以告诉我们客户端超时值设置为多少是一个合理范围,即测试后PN个9的时延,这样做在API计费的情况下在成本效益和效率之间达到平衡。
吞吐量
对于OLAP负载,最看重的其实是存储的综合吞吐量,因为需要获取大量的数据执行分析,数据不够无法吃满CPU/内存。
上述实验为访问随机生成的16MB对象,使用多个线程同时调用256个请求,每一个数据点都表示1s内获取数据大小的总和,这个实验我们可以获取如下结论:
- get请求本身可以吃满对象存储的带宽
- 不同区域间表现存在差异
最优请求大小
这一节的结论建立在国外友商的计费基础上。
文章认为最优请求大小需要在性能和成本之间做权衡,在计费章节我们看到腾讯云不同于友商,还额外收取了获取数据大小费用,所以本章的结论对于腾讯云其实不适用。
上图展示了分别使用独占和spot模式的EC2不同请求大小下S3的成本效益,可以得到如下结论:
- 16MB更具性价比
Model for Cloud Storage Retrieval
这个公式给出了对象存储在请求量多少时可以吃满带宽,这是有实际意义的,结论可以用在实际的工程实践中。
公式中参数含义分别如下:
- baseLatency:图2的1kb实验,获取数据传输的基础时延中位数,约30ms
- dataLatency:图2的16mb实验的每mb传输时延,获取数据传输的基础时延中位数,约20ms/MB
以S3 100Gbit/s为例计算,假设单对象带宽为50MB/s,需要250个并发请求才可以吃满带宽。
CLOUD STORAGE INTEGRATION
基于云存储分析引擎的设计想要最大化性能必须仔细平衡分析查询引擎与网络组件的资源消耗。
线程模型概要设计
- Table metadata retrieval:在步骤 1 和 2 中,首先请求表元数据,即数据块列表。然后获取所有相关的块元数据,作为开始表扫描数据检索基础数据
- Worker thread scheduling:步骤 3 显示,每个线程都会询问调度程序要处理的任务,如果检索到足够的数据,工作线程就会继续处理数据,如 4A 所示;否则会将线程用于prepare block
- Download preparation:为了使网络带宽达到饱和,必须有足够的检索线程和大量未处理请求来持续下载。在步骤 4B 中,准备工作程序会创建新请求,让检索线程不间断地执行事件循环。对象管理器保存表、块及其列块数据的元数据。如果数据不在内存中,会创建一个新请求,并安排它进行检索,如 5B 所示检索线程获取数据
Object Scheduler
调度器的重点为在平衡数据检索和数据处理的资源使用。
- Balance of retrieval and processing performance:对象调度程序的主要目标是在处理和检索性能之间取得平衡。它将不同的任务分配给可用的工作线程,以实现这种平衡。如果检索性能低于扫描性能,它就会增加检索和准备线程的数量。另一方面,减少检索线程数量会提高处理吞吐量。需要注意的是,检索性能受网络带宽的限制,对象调度程序会考虑网络带宽。
- Processing and retrieval estimations:决策过程需要检索和处理过程中的性能统计。每个处理线程都会跟踪执行时间和处理的数据量。通过汇总数据,我们可以计算出每个线程的平均处理吞吐量。对于网络吞吐量,我们汇总了当前时间周期内的总体检索字节数。
- Balancing retrieval threads and requests:第 2.8 节和第 3.4 节分析了实现吞吐量目标需要多少并发请求以及相应的 AnyBlob 检索器数量。调度器会跟踪用于检索的线程数量,并根据实例带宽规定加以限制。通过计算未处理请求(如列块)的数量,我们可以计算出未处理网络带宽的上限。未处理请求是指当前正在下载或等待检索的已准备好的 HTTP 请求,由于线程数和未处理请求限制了网络带宽,我们的对象调度程序总是要求未处理带宽至少与当前检索线程数可能达到的最大带宽一样高。因此,它会调度足够多的准备工作来匹配检索线程的数量。
- Performance adaptivity:调度程序会计算处理和检索之间的全局比率,以平衡检索和处理性能。该比率用于调整检索线程的数量和带宽。如果处理速度较慢,则准备的数据块较少,调度的检索线程也较少。一些正在运行的检索线程会因为未处理请求减少而停止。这些线程会被安排为处理线程,从而提高全局处理性能。
- Overpreparation:由于不希望检索线程因未准备列而停滞,因此鼓励Overpreparation,调度程序可确保最多 2 倍的所需带宽尚未使用,并据此调度准备工作。
性能
作者将查询分为:
- IO密集型:1,6,19,本地计算和远程计算的性能差距还是比较大,
- 计算密集型:9,18 时延基本接近
结束语
这篇文章于我而言最大的启发有四点:
- 基于对象存储执行分析需求的数据支持
- 基于对象存储执行分析需求的实践经验
- 使用对象调度器平衡数据检索和数据处理的资源使用,这种思路可以用在很多地方
- 基于对象存储性能存在下降(复杂的cache策略可以部分缓解,这里的研究很多[7,8,9,10]),所以这里其实是成本和性能之间的权衡
因为文章基本基于S3的计费模式,带宽讨论,导致这些经验并不是拿来即用的,国内主流公有云对象存储计费与国外不太一样;其次除了阿里云其他家云带宽还没到100Gbit/s,我司的15Gbit/s甚至比华为云还低,这点其实在内部也广为诟病,基本上只能靠拆桶或者联系售后加钱解决问题。
参考:
- Exploiting Cloud Object Storage for High-Performance Analytics vldb2023
- 论文分享:利用对象存储进行高性能数据分析
- 腾讯云对象存储计费概述
- 腾讯云对象存储按量计费
- 腾讯云对象存储资源包
- 腾讯云对象存储按量计费价格
- Crystal: A Unied Cache Storage System for Analytical Databases vldb2021
- Netco: Cache and I/O Management for Analytics over Disaggregated Stores Socc 2018
- FlexPushdownDB: Hybrid Pushdown and Caching in a Cloud DBMS vldb2021
- The Demikernel Datapath OS Architecture for Microsecond-scale Datacenter Systems SOSP2021