当前位置: 首页 > 编程日记 > 正文

Rocksdb 的 BlobDB key-value 分离存储插件

前言

还是回到传统的 LSM-tree 中,我们key-value 写入时以append形态存放到一个data-block中,多个data-block+metablock 之类的数据组织成一个sst。当我们读数据以及compaction的时候读到key 之后则很方便得读取到对应的value,一次I/O能够将key-value完全从磁盘读上来。但这种存储方式在大value场景下引入了非常多的读写放大,读写性能都会非常差。

所以Wisckey提出了key-value分离,且业界也有了一些不错的实现,包括Tikv/Titan, DGraph/badger等应用在工业界的实现案例。

但是,这一些对于使用rocksdb作为存储生态的用户来说还是不够方便,titan虽然是以rocksdb的插件形态存在的,但是很多rocksdb支持的功能还不够完善(checkpoint/backup, Trasaction 等需求量比较大的场景),所以虽然基本功能实现了,但还是没有办法得到更加广泛的应用。

这个时候rocksdb 社区的BlobDB经过长久的开发和完善,在旧版本的基础上实现了一个全新的BlobDB版本。

支持的特性

文章标题说的是分离存储插件,其实本身并不是插件的形态了, 这个新版本已经完全融入到rocksdb之中,支持的特性:

  1. rocksdb的基本操作接口不需要任何变动,DB::Put,DB::Get 等仍然继续使用(Merge不支持),开启k/v分离,只需要打开enable_blob_files=true 以及设置 min_blob_size就可以了(简直不要太方便,当然,titan没有做成这样也可能是因为这样与rocksdb代码耦合太多了, 不方便跟进社区的版本)。
  2. Recovery 异常重放
  3. 压缩
  4. atomic flush
  5. compaction filter( 支持 用户选择读取value,有一些用户使用compaction filter 只想要key的操作,这个时候不需要将value再回传了 )
  6. Checkpoints
  7. 备份
  8. 事务
  9. 文件级别的checksum
  10. sst-filem-manager(后续支持ingest会比较方便)

当然还有一些特性暂时不支持:

  • Merge 接口写入大value (这个特性的优先级后续会比较高,主要update场景的需求量还是很大)
  • EventListener
  • Secondary Instance (离线读取场景)
  • ingest blob file(这个场景需求也会大一些,高效的离线导入)

GC 实现

这里简单描述一下BlobDB的key-value分离存储实现。

  1. 分离场景其实比较简单,在Flush/Compaction过程中判断是否开启key/value分离, 且判读写入的value是否是超过设置的min_blob_size,超过则通过blob_file_builder 将key-value写入到.blob文件中且对应的key+key-index则仍然存放在sst中,否则key-value都存放在sst中。
  2. 重点是GC的实现,当然可以通过设置enable_blob_garbage_collection控制是否开启关闭GC。GC的调度不同于Titan的传统GC,通过EventLister 在Compaction完成之后触发,而是类似于Titan的level merge GC ,在Compaction过程中如果开启了GC,会将大value读出来,写入到新的blobfile,旧的blobfile 则会后续通过后台清理线程集中清理。

这种方式的GC实现 因为没有办法避免大value的读取,当数据量足够大的时候,compaction调度的GC引入的磁盘大量的读写导致的长尾也是无法接受的,所以社区也只能提供了可开启关闭的GC的参数来交给用户控制。

关于BlobDB中的option都是可以通过SetOptions来运行时动态变更。

性能测试

从测试结果来看,大value下的BlobDB和 TitanDB 读写性能接近,对于Rocksdb生态的用户来说BlobDB 在功能上的优势还是更受欢迎的。

测试bench mark:
测试版本:master分支
测试工具:db_bench
硬件:64core cpu + 512G mem + 3T NVMe-SSD

关闭key/value分离 随机写入性能:

numactl --cpubind=0 --membind=0 ./db_bench \--benchmarks=fillrandom,stats \--num=30000000 \--threads=16 \--writes=1000000 \--db=./db-test \--wal_dir=./db-test \--duration=120 \--key_size=16 \--value_size=8192 \-max_background_compactions=16 \-max_background_flushes=7 \-subcompactions=8 \-compression_type=none \-enable_pipelined_write=true \

在这里插入图片描述
下面是随机写入场景中的磁盘I/O情况,其中磁盘I/O达到1G及以上的时间底层都是有compaction调度的,带着大value 进行compaction,整体的读写代价还是很大的,可以看到磁盘偶尔会有超过2G的带宽占用,这对于只有152M的用户写入来说实在是太大的放大了。
(关于磁盘I/O没有读流量,是因为内存比较大,db数据量比较小,大多数的数据还都会被缓存在操作系统page-cache,所以compaction过程中的读基本都会命中page-cache)
在这里插入图片描述

作为对比,开始测试BlobDB,使用如下benchmark

numactl --cpubind=0 --membind=0 ./db_bench \--benchmarks=fillrandom,stats \--num=30000000 \--threads=16 \--writes=1000000 \--db=./db-test \--wal_dir=./db-test \--duration=120 \--key_size=16 \--value_size=8192 \-max_background_compactions=16 \-max_background_flushes=7 \-subcompactions=8 \-compression_type=none \-enable_pipelined_write=true \-enable_blob_files=true \-min_blob_size=4096 \-enable_blob_garbage_collection=true

很明显,吞吐相比于使用rocksdb来存放大value 提升了倍。
在这里插入图片描述
再看看磁盘I/O情况,因为我们也开启了GC,所以这个过程中会有GC的调度。从磁盘带宽来看,整体的吞吐还是比较均匀的,即使compaction + GC 一起存在,并不会有像未开启key/value分离那样的巨量I/O出现,因为不必要的key/value的value读取并不会被调度起来。
在这里插入图片描述

关于读性能的测试,大家可以变更benchmark为--benchmarks=readrandom,指定--use_existing_db=1--use_existing_keys=1来保证key的100%命中就好。当然,blobdb的使用在一批热点key的集中update场景下还是需要注意GC带来的带宽占用(热点update会让GC调度的频率更高,重复写入的key多,blob文件中失效的key也会很多),如果想要保持稳定的latency,软件层的优化就是限速了,或者动态开启关闭GC(业务低峰开启GC,高峰关闭GC)。

相关文章:

Java项目:(前端vue后台java微服务)在线考试系统(java+vue+springboot+mysql+maven)

源码获取:博客首页 "资源" 里下载! 考试流程: 用户前台注册成为学生 管理员后台添加老师,系统将该用户角色上升为老师 老师登录,添加考试,添加题目,发布考试 考生登录前台参加考试&#xff0c…

C++实现stack【栈】

要求: //****file: stack.h/*对stack进行初始化检查stack为空,或已满将整数压入到stack中从stack里弹出整数 不移除任何袁术,讲过stack的内容输出到标准输出Stack类的私有成员如下:一个用于打印错误信息的私有哦成员函数三个私有数…

c#操作Excel整理总结

大家好,这是我在工作中总结的关于C#操作Excel的帮助类,欢迎大家批评指正! using System; using System.Collections.Generic; using System.Data; using System.Data.OleDb; using System.IO; using Aspose.Cells;namespace MusicgrabTool {p…

C++ std::function<void(int)> 和 std::function<void()> 作为函数参数的注意事项

前言 std::function 作为标准库提供的函数指针&#xff0c;使用起来还是比较方便的&#xff0c;不过在使用过程中有一些需要注意的细节&#xff0c;这里做一个简单的记录。 基本使用 头文件: #include <functional>语法&#xff1a;std::function<return_type(args…

Java项目:网上电商系统(java+SSM+mysql+maven+tomcat)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a;本系统分用户前台和管理员后台。 前台展示后台管理&#xff0c;前台界面可实现用户登录&#xff0c;用户注 册&#xff0c;商品展示&#xff0c;商品明细展示&#xff0c;用户…

C# SQLiteHelper

1 public class SQLiteHelpers2 {3 /// <summary> 4 /// ConnectionString样例&#xff1a;DatasourceTest.db3;Poolingtrue;FailIfMissingfalse 5 /// </summary> 6 public static string ConnectionStri…

[Git] 拉开发分支的代码报错

Git拉开发分支的代码报错&#xff1a; fatal: The remote end hung up unexpectedly fatal: early EOF fatal: index-pack failed 解决办法&#xff1a; git config --global core.compression -1 转载于:https://www.cnblogs.com/MasterMonkInTemple/p/10754596.html

C++ 通过模版工厂实现 简单反射机制

前言 我们知道Java/Python这种语言能够很好得 支持反射。反射机制 就是一种用户输入的字符串到对应实现方法的映射&#xff0c;比如http接口中 用户传入了url&#xff0c;我们需要调用该url对应的方法/函数对象 从而做出对应的操作。 而C 并没有友好得支持这样的操作&#xf…

计算机世界的“十六进制”为什么如此重要

在计算机世界中,十六进制扮演着不可或缺的角色。它以其紧凑的表示形式、与二进制的天然对应关系以及在各个领域的广泛应用,成为了计算机科学中的一把重要工具。总体而言,计算机需要十六进制并非偶然,它是一种为了更好地满足人类理解和处理数据的需求而产生的工具,为计算机科学的发展和应用提供了便利和支持。

面试官:如何实现10亿数据判重?

以 Java 中的 int 为例,来对比观察 BitMap 的优势,在 Java 中,int 类型通常需要 32 位(4 字节*8),而 BitMap 使用 1 位就可以来标识此元素是否存在,所以可以认为 BitMap 占用的空间大小,只有 int 类型的 1/32,所以有大数据量判重时,使用 BitMap 也可以实现。所以数据库去重显然是不行的。而使用集合也是不合适的,因为数据量太大,使用集合会导致内存不够用或内存溢出和 Full GC 频繁等问题,所以此时我们的解决方案通常是采用布隆过滤器来实现判重。

Java项目:校园二手市场系统(java+SSM+mysql+maven+tomcat)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述&#xff08; IW文档&#xff09; 功能&#xff1a;本系统分用户前台和管理员后台。 本系统用例模型有三种&#xff0c;分别是游客、注册用户和系统管 理员。下面分别对这三个角色的功能进行描…

php中$_REQUEST、$_POST、$_GET的区别和联系小结

php中$_REQUEST、$_POST、$_GET的区别和联系小结 作者&#xff1a; 字体&#xff1a;[增加 减小] 类型&#xff1a;转载php中有$_request与$_post、$_get用于接受表单数据&#xff0c;当时他们有何种区别&#xff0c;什么时候用那种最好。1. $_REQUEST php中$_REQUEST可以获取以…

uva 315 (poj 1144 求割点)

题意&#xff1a;给你一张无向图&#xff0c;求割点的个数。 思路&#xff1a;输入稍微处理一下接着直接套模版。 1 #include <iostream>2 #include <cstdio>3 #include <cstring>4 #include <cstdlib>5 #include <cmath>6 #include <algorit…

SQL学习之计算字段的用法与解析

一、计算字段 1、存储在数据库表中的数据一般不是应用程序所需要的格式。大多数情况下,数据表中的数据都需要进行二次处理。下面举几个例子。 (1)、我们需要一个字段同时显示公司名和公司地址&#xff0c;但这两个信息存储在不同表的列中。 (2)、省份、城市、邮政编码存储在不同…

手把手教你 用C++实现一个 可持久化 的http_server

前言 本文介绍一个有趣的 通过C实现的 持久化的http_server demo&#xff0c;这样我们通过http通信之后的数据可以持久化存储&#xff0c;即使server挂了&#xff0c;数据也不会丢失。我们的http_sever 也就能够真正得作为一个后端server了。 本身持久化这个能力是数据库提供…

【SVN多用户开发】代码冲突解决办法

SVN是一款集中式的代码存储工具&#xff0c;可以帮助多个用户协同开发同一应用程序。 但是SVN不能完全代替人工操作&#xff0c;有时也需要程序员自己进行沟通确认有效的代码。 下面就简单的看一下&#xff0c;常见的代码冲突以及解决方法。 总结起来&#xff0c;无非是&#x…

Java项目:在线宠物商店系统(java+SSM+mysql+maven+tomcat)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a;本系统分用户前台和管理员后台。 系统包括用户的注册登录&#xff0c;狗狗的展示购物车添加以及下 单支付购买&#xff0c;后台有管理员用户&#xff0c;可以操作狗狗的品种&…

字符串中的数字排序

2019独角兽企业重金招聘Python工程师标准>>> public static String getBusiScope(String busiScope){ String regex "\\d{1,2}"; String busiStr""; Pattern pattern Pattern.compile(regex); Matcher matcher pattern.matcher(busiScope…

oo第二单元总结

第二单元总结 第一次作业 一、设计策略 本次作业采用FAFS算法&#xff0c;可直接用输入线程与电梯线程交互&#xff0c;调度器暂时不需要参与&#xff0c;故一共设计三个类三线程&#xff1a;Main类、elevator类及input类&#xff0c;main线程、elevator线程及input线程。main线…

Rocksdb iterator 的 Forward-scan 和 Reverse-scan 的性能差异

前言 最近在读 MyRocks 存储引擎2020年的论文&#xff0c;因为这个存储引擎是在Rocksdb之上进行封装的&#xff0c;并且作为Facebook 内部MySQL的底层引擎&#xff0c;用来解决Innodb的空间利用率低下 和 压缩效率低下的问题。而且MyRocks 在接入他们UDB 之后成功达成了他们的…

Java知多少(29)覆盖和重载

在类继承中&#xff0c;子类可以修改从父类继承来的方法&#xff0c;也就是说子类能创建一个与父类方法有不同功能的方法&#xff0c;但具有相同的名称、返回值类型、参数列表。如果在新类中定义一个方法&#xff0c;其名称、返回值类型和参数列表正好与父类中的相同&#xff0…

Java项目:清新论坛系统(java+SSM+mysql+maven+tomcat)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a;本系统分用户前台和管理员后台。 用户前台主要功能有&#xff1a; 用户注册 用户登录 浏览帖子 回复帖子 修改个人资料 管理员后台的功能有&#xff1a; 管理论坛版块 用户管…

JUnit4.11 理论机制 @Theory 完整解读

最近在研究JUnit4&#xff0c;大部分基础技术都是通过百度和JUnit的官方wiki学习的&#xff0c;目前最新的发布版本是4.11&#xff0c;结合代码实践&#xff0c;发现官方wiki的内容或多或少没有更新&#xff0c;Theory理论机制章节情况尤为严重&#xff0c;不知道这章wiki对应的…

树链剖分——线段树区间合并bzoj染色

线段树区间合并就挺麻烦了&#xff0c;再套个树链就更加鬼畜&#xff0c;不过除了代码量大就没什么其他的了。。 一些细节&#xff1a;线段树每个结点用结构体保存&#xff0c;pushup等合并函数改成返回一个结构体&#xff0c;这样好写一些 struct Seg{int lc,rc,tot;Seg(){lcr…

MyRocks: 为facebool 的社交图谱服务的LSM-tree存储引擎

文章目录概览1. UDB 架构2. UDB 表格式3. Rocksdb&#xff1a;针对flash存储优化过的第三方库3.1 Rocksdb架构3.2 为什么选择Rocksdb4. MyRocks / Rocksdb 开发历程4.1 设计目标4.2 性能挑战4.2.1 降低CPU的消耗4.2.2 降低range-scan 的延时消耗4.2.3 磁盘空间和Compaction 的一…

Java项目:精品酒店管理系统(java+SSM+mysql+maven+tomcat)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a;主要功能主要功能会员管理&#xff0c;住客管理&#xff0c;房间管 理&#xff0c;系统管理&#xff0c;以及一些重要数据的展示导出维护等等; 二、项目运行 环境配置&…

iOS自动布局一

Align: Pin&#xff1a; 转载于:https://www.cnblogs.com/123qw/p/4404167.html

C#实现路由器断开连接,更改公网ip

publicstaticvoidDisconnect(){stringurl "断 线"; stringuri "http://192.168.1.1/userRpm/StatusRpm.htm?Disconnect"System.Web.HttpUtility.UrlEncode(url, System.Text.Encoding.GetEncoding("gb2312")) "&wan1"; str…

Go中的iota

当时在学习Iota这个知识点的时候仅仅是一笔掠过&#xff0c;比如这种 const(aiotab c) 一眼看出他怎么使用的时候就觉得自己已经懂得了 再到后来看到这样的例子 const&#xff08;a 5*iotab c &#xff09;以及 const&#xff08;a 1<<(10*iota)bc &#xff09; 第一…

从 SSLTLS 的底层实现来看 网络安全的庞大复杂体系

文章目录前言1. HTTP协议通信的问题1.1 tcpdump 抓取http 请求包1.2 报文分析1.3 HTTP 协议问题2. SSL & TLS 协议的基本介绍和历史演进3. TLS 1.2 实现加密传输的过程3.1 TLS HandShake 协议概览3.2 第一次握手&#xff1a;ClientHello3.3 第二次握手&#xff1a;从Server…