Flink RocksDB状态后端优化总结

截至当前,Flink 作业的状态后端仍然只有 Memory、FileSystem 和 RocksDB 三种可选,且 RocksDB 是状态数据量较大(GB 到 TB 级别)时的唯一选择。RocksDB 的性能发挥非常仰赖调优,如果全部采用默认配置,读写性能有可能会很差。

但是,RocksDB 的配置也是极为复杂的,可调整的参数多达百个,没有放之四海而皆准的优化方案。如果仅考虑 Flink 状态存储这一方面,我们仍然可以总结出一些相对普适的优化思路。本文先介绍一些基础知识,再列举方法。

Note:本文的内容是基于我们在线上运行的 Flink 1.9 版本实践得出的。在1.10版本及以后,由于 TaskManager 内存模型重构,RocksDB 内存默认成为了堆外托管内存的一部分,可以免去一些手动调整的麻烦。如果性能仍然不佳,需要干预,则必须将 state.backend.rocksdb.memory.managed 参数设为 false 来禁用 RocksDB 内存托管。

Stae R/W on RocksDB

RocksDB 作为 Flink 状态后端时的读写逻辑与一般情况略有不同,如下图所示。

img

Flink 作业中的每一个注册的状态都对应一个列族(column family),即包含自己独立的 memtable 和 sstable 集合。写操作会先将数据写入活动 memtable,写满之后则会转换为不可变 memtable,并 flush 到磁盘中形成 sstable。读操作则会依次在活动 memtable、不可变 memtable、block cache 和 sstable 中寻找目标数据。另外,sstable 也需要通过 compaction 策略进行合并,最终形成分层的 LSM Tree 存储结构,老生常谈了。

特别地,由于 Flink 在每个检查点周期都会将 RocksDB 的数据快照持久化到文件系统,所以自然也就不需要再写预写日志(WAL)了,可以安全地关闭WAL与fsync。

之前笔者已经详细讲解过 RocksDB compaction 策略,并且提到了读放大、写放大和空间放大的概念,对 RocksDB 的调优本质上就是在这三个因子之间取得平衡。而在 Flink 作业这种注重实时性的场合,则要重点考虑读放大和写放大。

img

Tuning MemTable

memtable 作为 LSM Tree 体系里的读写缓存,对写性能有较大的影响。以下是一些值得注意的参数。为方便对比,下文都会将 RocksDB 的原始参数名与 Flink 配置中的参数名一并列出,用竖线分割。

  • write_buffer_size | state.backend.rocksdb.writebuffer.size 单个 memtable 的大小,默认是64MB。当 memtable 大小达到此阈值时,就会被标记为不可变。一般来讲,适当增大这个参数可以减小写放大带来的影响,但同时会增大 flush 后 L0、L1 层的压力,所以还需要配合修改 compaction 参数,后面再提。

  • max_write_buffer_number | state.backend.rocksdb.writebuffer.count memtable 的最大数量(包含活跃的和不可变),默认是2。当全部 memtable 都写满但是 flush 速度较慢时,就会造成写停顿,所以如果内存充足或者使用的是机械硬盘,建议适当调大这个参数,如4。

  • min_write_buffer_number_to_merge | state.backend.rocksdb.writebuffer.number-to-merge 在 flush 发生之前被合并的 memtable 最小数量,默认是1。举个例子,如果此参数设为2,那么当有至少两个不可变 memtable 时,才有可能触发 flush(亦即如果只有一个不可变 memtable,就会等待)。调大这个值的好处是可以使更多的更改在 flush 前就被合并,降低写放大,但同时又可能增加读放大,因为读取数据时要检查的 memtable 变多了。经测试,该参数设为2或3相对较好。

Tuning Block/Block Cache

block 是 sstable 的基本存储单位。block cache 则扮演读缓存的角色,采用 LRU 算法存储最近使用的 block,对读性能有较大的影响。

  • block_size | state.backend.rocksdb.block.blocksize block 的大小,默认值为4KB。在生产环境中总是会适当调大一些,一般32KB比较合适,对于机械硬盘可以再增大到128~256KB,充分利用其顺序读取能力。但是需要注意,如果 block 大小增大而 block cache 大小不变,那么缓存的 block 数量会减少,无形中会增加读放大。

  • block_cache_size | state.backend.rocksdb.block.cache-size block cache 的大小,默认为8MB。由上文所述的读写流程可知,较大的 block cache 可以有效避免热数据的读请求落到 sstable 上,所以若内存余量充足,建议设置到128MB甚至256MB,读性能会有非常明显的提升。

Tuning Compaction

compaction 在所有基于 LSM Tree 的存储引擎中都是开销最大的操作,弄不好的话会非常容易阻塞读写。建议看官先读读前面那篇关于 RocksDB compaction 策略的文章,获取一些背景知识,这里不再赘述。

  • compaction_style | state.backend.rocksdb.compaction.style compaction 算法,使用默认的 LEVEL(即 leveled compaction)即可,下面的参数也是基于此。

  • target_file_size_base | state.backend.rocksdb.compaction.level.target-file-size-baseL1层单个 sstable 文件的大小阈值,默认值为64MB。每向上提升一级,阈值会乘以因子 target_file_size_multiplier(但默认为1,即每级sstable最大都是相同的)。显然,增大此值可以降低 compaction 的频率,减少写放大,但是也会造成旧数据无法及时清理,从而增加读放大。此参数不太容易调整,一般不建议设为256MB以上。

  • max_bytes_for_level_base | state.backend.rocksdb.compaction.level.max-size-level-base L1层的数据总大小阈值,默认值为256MB。每向上提升一级,阈值会乘以因子 max_bytes_for_level_multiplier(默认值为10)。由于上层的大小阈值都是以它为基础推算出来的,所以要小心调整。建议设为 target_file_size_base 的倍数,且不能太小,例如5~10倍。

  • level_compaction_dynamic_level_bytes | state.backend.rocksdb.compaction.level.use-dynamic-size 这个参数之前讲过。当开启之后,上述阈值的乘法因子会变成除法因子,能够动态调整每层的数据量阈值,使得较多的数据可以落在最高一层,能够减少空间放大,整个 LSM Tree 的结构也会更稳定。对于机械硬盘的环境,强烈建议开启。

Generic Parameters

  • max_open_files | state.backend.rocksdb.files.open 顾名思义,是 RocksDB 实例能够打开的最大文件数,默认为-1,表示不限制。由于sstable的索引和布隆过滤器默认都会驻留内存,并占用文件描述符,所以如果此值太小,索引和布隆过滤器无法正常加载,就会严重拖累读取性能。

  • max_background_compactions/max_background_flushes | state.backend.rocksdb.thread.num 后台负责 flush 和 compaction 的最大并发线程数,默认为1。注意 Flink 将这两个参数合二为一处理(对应 DBOptions.setIncreaseParallelism() 方法),鉴于 flush 和 compaction 都是相对重的操作,如果 CPU 余量比较充足,建议调大,在我们的实践中一般设为4。

除了上述设置参数的方法之外,用户还可以通过实现 ConfigurableRocksDBOptionsFactory 接口,创建 DBOptions 和 ColumnFamilyOptions 实例来传入自定义参数,更加灵活一些。看官可参考 Flink 预先定义好的几个 RocksDB 参数集(位于 PredefinedOptions 枚举中)获取更多信息。

RocksDB使用场景和特性

img

  存储和访问数百PB的数据是一个非常大的挑战,开源的RocksDB就是FaceBook开放的一种嵌入式、持久化存储、KV型且非常适用于fast storage的存储引擎。   传统的数据访问都是RPC,但是这样的话访问速度会很慢,不适用于面向用户的实时访问的场景。随着fast storage的流行,越来越多的应用可以通过在flash中管理数据并快速直接的访问数据。这些应用就需要使用到一种嵌入式的database。   使用嵌入式的database的原因有很多。当数据请求频繁访问内存或者fast storage时,网路延时会增加响应时间,比如:访问数据中心网络耗时可能就耗费50ms,跟访问数据的耗时一样多,甚至更多。这意味着,通过RPC访问数据有可能是本地直接访问耗时的两倍。另外,机器的core数越来越多,storage-IOPS的访问频率也达到了每秒百万次,传统数据库的锁竞争和context 切换会成为提高storage-IOPS的瓶颈。所以需要一种容易扩展和针对未来硬件趋势可以定制化的database,RocksDB就是一种选择。   RocksDB是基于Google的开源key value存储库LevelDB,主要满足以下目标:

1、适用于多cpu场景

  商业服务器一般会有很多cpu核,要开发一个随着CPU 核数吞吐量也随之增大的数据库是很困难的,更别提是线性的递增关系。但是,RocksDB是可以高效地运行在多核服务器上。一个优点是RocksDB提供的语义比传统的DBMS更简单。例如:RocksDB支持MVCC,但是仅限于只读的transaction。另一个优点是数据库在逻辑上分片为read-only path和read-write path。这两种方法可以降低锁竞争,而降低锁竞争是支持高并发负载的前提条件。

2、高校利用storage(更高的IOPS、高效的压缩、更少的写磨损)

  现在的存储设备都可以支持到每秒10w的随机读,如果有10块存储卡的话就可以支持每秒100w的随机读。RocksDB可以在这种快速存储上高效运行且不会成为性能瓶颈。   和实时更新的B-tree相比,RocksDB有更好的压缩和更小的写放大。RocksDB由于压缩更优,所以占用更少的storage;由于更小的写放大,flash 设备可以更持久。

3、弹性架构,支持扩展

  RocksDB支持扩展。比如,我们可以新增一个merge operator,这样就可以使用write-only来替代read-modify-write。然而,read和Write是会增加存储的读写IOPS。在写频繁的负载下,这种措施可以降低IOPS。

4、支持IO-bound、in-memory、write-once

  IO-bound workload是指数据库大小远大于内存且频繁地访问storage。in-memory workload是指数据库数据都在内存中且仍然使用storage来持久化存储DB。write-once workload是指大部分的key都只会写入一次或者insert且没有更新操作。现在RocksDB很好支持IO-bound,要想更好地支持in-memory,需要做一些工作。支持write-once的话,还有很多遗留问题待解决。

  RocksDB不是一个分布式的DB,而是一个高效、高性能、单点的数据库引擎。RocksDB是一个持久化存储keys和values的c++ library。keys 和values可以是任意的字节流,且按照keys有序存储。后台的compaction会消除重复的和已删除的key。RocksDB的data以log-structured merge tree的形式存储。RocksDB支持原子的批量写入操作以及前向和后向遍历。   RocksDB采用“可插拔式”的架构,所以很容易替换其中的组件,允许用户很容易在不同的负载和硬件设备上进行调优。

img

1441593_10151976018697200_1580274673_n.png

  比如,用户可以添加不同的压缩模块(snappy, zlib, bzip, etc),且使用不同模块时不用修改源码。这可用于在不同负载下通过配置使用不同的压缩算法。同理,用户可以在compaction时加载个性化的compaction filter来处理keys,例如,可以实现DB的key的"expire-time"功能。RocksDB有可插拔式的API,所以应用可以设计个性化的数据结构来cache DB的写数据,典型应用就是prefix-hash,其中一部分key使用hash存储,剩下的key存储在B-tree。storage file的实现也可以定制开发,所以用户可以实现自己的storage file格式。   RocksDB支持两种compaction style(level style和universal style)。这两种style可做读放大、写放大、空间放大之间做tradeoff。compaction也支持多线程,所以打的DB可以支持高性能的compaction。   RocksDB也提供在线的增量备份接口,也支持bloom filters,这可以在range-scan时降低IOPS。   RocksDB可以充分挖掘使用flash的IOPS,在随机读、随机写和bulk load时性能优于LevelDB。在随机写和bulk load时,性能优于LevelDB 10倍,在随机读时性能优于LevelDB 30%。   LevelDB是单线程执行compaction,在特定的server workload下表现堪忧,但是RocksDB在IO-bound workload下性能明显优于LevelDB。在测试中发现,LevelDB发生频繁的write-stall,这严重影响了DB的99%延迟,另外也发现,把文件mmap到OS cache会引入读性能瓶颈。测试表明,应用不能充分使用flash的高性能,这是因为数据的带宽瓶颈引起了LevelDB的写放大。通过提高写速率和降低写放大,可以避免很多问题,同时提高RocksDB性能。 RocksDB的典型场景(低延时访问): 1、需要存储用户的查阅历史记录和网站用户的应用 2、需要快速访问数据的垃圾检测应用 3、需要实时scan数据集的图搜索query 4、需要实时请求Hadoop的应用 5、支持大量写和删除操作的消息队列

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/473476.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小程序应用市场的前世今生

最开始的开始,为软件开发者提供软件发布、运营和推广服务的平台称之为软件应用市场,其发展经历了以下3个阶段: 起源阶段:应用市场的起源可以追溯到桌面互联网时代,当时软件的开发和分发主要依靠软件网站。软件开发者可…

【每日一题】 2024年2月汇编(下)

🔥博客主页: A_SHOWY🎥系列专栏:力扣刷题总结录 数据结构 云计算 数字图像处理 力扣每日一题_ 【2.16】103.二叉树的锯齿形层序遍历 103. 二叉树的锯齿形层序遍历https://leetcode.cn/problems/binary-tree-zigzag-level-or…

python课后习题一

题目: 1. 2. 解题过程: 1. """计算年数和天数""" minute int(input("请输入分钟数:")) hours minute // 60 days hours // 24 years days // 365 last_days days % 365 print(f"{minut…

Sora后时代文生视频的探索

一、写在前面 按常理,这里应该长篇大论地介绍一下Sora发布对各行业各方面产生的影响。不过,这类文章已经很多了,我们今天主要聊聊那些已经成熟的解决方案、那些已经可以“信手拈来”的成果,并以此为基础,看看Sora发布…

ArcGIS Pro与R:携手优化生态系统服务评估流程

生态系统服务是指生态系统所形成的用于维持人类赖以生存和发展的自然环境条件与效用,是人类直接或间接从生态系统中得到的各种惠益。联合国千年生态系统评估(Millennium ecosystem assessment,MA)提出生态系统服务包括供给、调节、…

【动态三维重建】Deformable 3D Gaussians 可变形3D GS用于单目动态场景重建(CVPR 2024)

主页:https://ingra14m.github.io/Deformable-Gaussians/ 代码:https://github.com/ingra14m/Deformable-3D-Gaussians 论文:https://arxiv.org/abs/2309.13101 文章目录 摘要一、前言二、相关工作2.1 动态场景的神经渲染2.2 神经渲染加速 三…

mac硬盘拷贝到另外硬盘 苹果电脑怎么拷贝到移动硬盘

在当今的信息时代,数据的存储和传输是我们日常生活和工作中不可或缺的一部分。我们经常需要使用各种硬盘来保存和备份我们的数据,比如内置硬盘、移动硬盘、U盘等。但是,不同的硬盘可能使用不同的文件系统,这给我们的数据拷贝带来了…

java 数据结构 排序算法

目录 排序 插入排序 直接插入排序 希尔排序( 缩小增量排序 ): 直接选择排序 堆排序 交换排序 冒泡排序 快速排序递归 Hoare法 挖坑法 前后指针法 快速排序优化 快速排序非递归 归并排序 归并排序非递归 排序算法复杂度及稳定性分析 计数排序 排序…

【论文阅读】Masked Autoencoders Are Scalable Vision Learners

Masked Autoencoders Are Scalable Vision Learners 引用: He K, Chen X, Xie S, et al. Masked autoencoders are scalable vision learners[C]//Proceedings of the IEEE/CVF conference on computer vision and pattern recognition. 2022: 16000-16009. 论文链…

wireshark抓tcp包使用指南

本博文源于笔者不断探索加上去网络总结获得的经验,撰写wireshark如何抓tcp包 文章目录 1、打开wireshark2、选择网络源3、搜索ip地址与tcp条件4、看灰色的条纹 1、打开wireshark 2、选择网络源 选择自己当前的ip地址适用于的网络源,比如这里选择“以太…

ETH Gas 之 Base Fee Priority Fee

前情回顾 ETH网络 之 Gas EIP-1559 EIP-1559 EIP-1559是以太坊改进提案(Ethereum Improvement Proposal),旨在改进以太坊的交易费用机制。该提案引入了一种新的交易费用模型,以提高交易费用的可预测性和网络的效率。我们本文各…

故障诊断 | 一文解决,GRNN广义回归神经网络的故障诊断(Matlab)

文章目录 效果一览文章概述专栏介绍模型描述源码设计参考资料效果一览 文章概述 故障诊断 | 一文解决,GRNN广义回归神经网络的故障诊断(Matlab) 专栏介绍

拥抱DevOps,开启数字化转型的加速器

在数字化浪潮席卷全球的今天,企业面临着前所未有的挑战与机遇。为了保持竞争力并适应快速变化的市场需求,数字化转型已成为企业发展的必由之路。而在这一过程中,DevOps作为一种全新的开发与运维理念,正逐渐成为推动企业数字化转型…

数据库设计三大范式

第一范式 确保每列保持原子性 即数据库表中的所有字段值都是不可分解的原子值 如果地址这个字段频繁访问, 则将地址这个属性重新划分为 省份 城市,详细地址等部分进行存储,这样才算是满足数据库的第一范式 第二范式 确保表中的每列都和主…

Python基础入门 --- 6.数据容器

文章目录 Python基础入门第六章:6.数据容器6.1 列表6.1.1 列表下标索引6.1.2 列表常用操作查找指定某元素的下标修改指定位置的元素值插入元素追加元素方式1追加元素方式2删除元素删除某元素在列表中的第一个匹配项清空列表统计某元素在列表中的数量统计列表元素个数…

vue+elementUI实现树形穿梭框

1.实现效果 2.整体思路 将左侧选中的节点移动到右侧,还要保持树结构,意味着移动子节点,需要把该子节点对应的父节点甚至父节点的父节点一并移到右侧形成一个新的树结构,树结构的层级和原来的树保持一致,只是右侧展示…

全国媒体公关服务资源分析,媒体邀约资源包括哪些?-51媒体网

传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 全国媒体公关服务资源分析是一个涵盖多方面的复杂议题,主要涉及到不同媒体类型、传播渠道、以及公关策略等多个维度。在当前媒体环境下,媒体公关服务资源主要包括…

机器人路径规划:基于斑翠鸟优化算法(Pied Kingfisher Optimizer ,PKO)的机器人路径规划(提供MATLAB代码)

一、机器人路径规划介绍 移动机器人(Mobile robot,MR)的路径规划是 移动机器人研究的重要分支之,是对其进行控制的基础。根据环境信息的已知程度不同,路径规划分为基于环境信息已知的全局路径规划和基于环境信息未知或…

【论文阅读】通过组件对齐评估和改进 text-to-SQL 的组合泛化

Measuring and Improving Compositional Generalization in Text-to-SQL via Component Alignment NAACL 2022| CCF B Abstract 在 text-to-SQL 任务中,正如在许多 NLP 中一样,组合泛化是一个重大挑战:神经网络在训练和测试分布不同的情况…

Python 深度学习第二版(GPT 重译)(二)

四、入门神经网络:分类和回归 本章涵盖 您的第一个真实世界机器学习工作流示例 处理矢量数据上的分类问题 处理矢量数据上的连续回归问题 本章旨在帮助您开始使用神经网络解决实际问题。您将巩固从第二章和第三章中获得的知识,并将所学应用于三个新…