腾讯工程师教你玩转 RocksDB

欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~

作者:腾讯云数据库内核团队

原文标题:【腾讯云CDB】教你玩转MyRocks/RocksDB—STATISTICS与后台线程篇

0. Intro

在facebook的MySQL版本(以下称为MyRocks)中,RocksDB是可选的存储引擎。相比于InnoDB引擎,RocksDB的一个重要的优势是它使用更少的磁盘空间。在生产系统中,特别是用户数在亿级以上的互联网应用,磁盘空间是其中比较大的成本之一,而能够使用更少的磁盘空间的RocksDB无疑是具有吸引力的。然而在生产系统中使用新的存储引擎自然有它的潜在风险,除了通过外部的各种benchmark工具测试得到各种性能数据,全方位的内部指标可以帮助我们真正了解数据库内部正在发生的事情,对于性能调优和开发都具有指导意义。而MyRocks通过SHOW ENGINE ROCKSDB STATUS和多个INFORMATION_SCHEMA表等方式提供了较为全面的内部指标。

本文将介绍SHOW ENGINE ROCKSDB STATUS中关于STATISTICS统计值与后台线程的实现原理。在了解实现原理的基础上,便可以较容易地通过扩展功能使它更好地为我们服务。

调用SHOW ENGINE ROCKSDB STATUS指令会返回多行数据,其中包括:

  • STATISTICS:RocksDB引擎所有线程的所有操作的各类count/time的累加,比如rocksdb.block.cache.hit和rocksdb.db.write.micros。
  • BG_THREADS: 后台线程的状态。
  • DBSTATS: 数据库操作的统计。
  • CF_COMPACTION: 各个Column family进行compaction的相关指标统计。
  • MEMORY_STATS: 内存使用情况。

调用SHOW ENGINE ROCKSDB STATUS会返回若干行数据,然而这些数据并非事先存储于某个表格中,而是通过调用位于rocksdb/ha_rocksdb.cc文件中的rocksdb_show_status函数将内存中对应的数值进行规整返回给用户。

1. STATISTICS

根据RocksDB官方相关文档介绍STATISTICS,开启STATISTICS会增加增加5%-10%额外开销。

STATISTICS统计值记录着RocksDB引擎所有线程的所有操作的各类count/time的累加。RocksDB引擎在它的各类操作如Put/Get/Delete中的代码都设立了很多埋点。

以函数GetEntryFromCache为例,它的作用是返回可用的block cache。特别地,可以看到statistics是GetEntryFromCache和block_cache->Lookup的一个参数。没错,就是靠着statistics这个参数它到处收集数据。 当有可用的block cache时,调用了三次RecordTick为其中三个统计值增加计数;没有可用的block cache,同样也为BLOCK_CACHE_MISS和block_cache_miss_ticker增加计数。

Cache::Handle* GetEntryFromCache(Cache* block_cache, const Slice& key,
                                 Tickers block_cache_miss_ticker,
                                 Tickers block_cache_hit_ticker,
                                 Statistics* statistics) {
  auto cache_handle = block_cache->Lookup(key, statistics);
  if (cache_handle != nullptr) {
    PERF_COUNTER_ADD(block_cache_hit_count, 1);
    // overall cache hit
    RecordTick(statistics, BLOCK_CACHE_HIT);
    // total bytes read from cache
    RecordTick(statistics, BLOCK_CACHE_BYTES_READ,
               block_cache->GetUsage(cache_handle));
    // block-type specific cache hit
    RecordTick(statistics, block_cache_hit_ticker);
  } else {
    // overall cache miss
    RecordTick(statistics, BLOCK_CACHE_MISS);
    // block-type specific cache miss
    RecordTick(statistics, block_cache_miss_ticker);
  }

  return cache_handle;
}

1.1 RocksDB的STATISTICS接口

使用STATISTICS的方法也很简单。

它的头文件位于:

include/rocksdb/statistics.h
monitoring/statistics.h

使用方法:

Options options;
options.statistics = rocksdb::CreateDBStatistics();

可选统计级别:

  • kExceptDetailedTimers: 除去mutex等待和压缩的计时
  • kExceptTimeForMutex: 除去mutex等待的计时
  • kAll: 所有

数据统计类型分成两种:

  • ticker:计数,类型是64位无符号整型。用于度量counters (e.g. “rocksdb.block.cache.hit”), cumulative bytes (e.g. “rocksdb.bytes.written”) 或者 time (e.g. “rocksdb.l0.slowdown.micros”)。
  • histogram:统计数据的统计分布,包括最大值、最小值、平均值、中位数、标准差。

统计函数的接口:

  • MeasureTime:函数名有歧义。实际上是把value记录到histogram中。
  • RecordTick:累加ticker。

获取结果的接口:

  • Statistics::getTickerCount:指定ticker type获得count。
  • Statistics::histogramData:指定Histograms type,返回一个HistogramData结构体,成员是统计值,包括最大值、最小值、平均值、中位数、标准差。
  • Statistics::getHistogramString:指定Histograms type,返回直方图可读的字符串。
  • Statistics::ToString():返回可读的字符串,包括所有的ticker和histogram。

1.2 RocksDB的STATISTICS实现

RocksDB实现了StatisticsImpl类,继承了Statistics的接口。

主要接口:

  • getTickerCount
  • histogramData
  • getHistogramString
  • getAndResetTickerCount
  • recordTick
  • measureTime
  • ToString

成员变量:

  • TickerInfo tickers_[INTERNAL_TICKER_ENUM_MAX];
  • HistogramInfo histograms_[INTERNAL_HISTOGRAM_ENUM_MAX];

这里的TickerInfo和HistogramInfo类型的数据结构是相似的:一个线程局部的counter或者time;加上一个非线程局部的统计值用来累加counter或者time。

TickerInfo类型包含两个参数:

ThreadLocalPtr类型(真实类型ThreadTickerInfo)的thread_value,包含:

  • 整型类型的value
  • 指向merged_sum的指针
  • 整型类型的merged_sum
  • HistogreamInfo类型包含两个参数:

ThreadLocalPtr类型(真实类型ThreadHistogramInfo)的thread_value,包含:

  • HistogramImpl类型的value
  • 指向merged_hist的指针
  • 指向merge_lock的指针
  • HistogramImpl类型的merged_hist
  • Mutex类型的merge_lock

事实上,STATISTICS相关实现是比较巧妙的,也是使用STATISTICS仅增加5%-10%的关键。为了避免线程间共享数据导致CPU的cache频繁失效,merged_sum和merged_hist初始化时都是空的,而且当且仅当线程退出时,才调用mergeThreadValue函数将TickerInfo和HistogreamInfo中的线程局部变量累加到merged_sum和merged_hist。

1.3 MyRocks的使用

MyRocks使用了RocksDB提供的接口进行数据统计。通过声明了变量rocksdb_stats,并且随着RocksDB引擎启动时通过rocksdb_init_func函数进行初始化。

rocksdb_stats = rocksdb::CreateDBStatistics();
rocksdb_db_options->statistics = rocksdb_stats;

除了使用所有RocksDB引擎层的统计,MyRocks还通过定义了

commit_latency_stats = new rocksdb::HistogramImpl();

在rocksdb_commit_by_xid和rocksdb_commit两个函数中通过计时的方式,统计了每一次commit所花费的时间。

rocksdb::StopWatchNano timer(rocksdb::Env::Default(), true);
...
commit_latency_stats->Add(timer.ElapsedNanos() / 1000);

在rocksdb_show_status函数中,输出Statistics统计的过程如下:

  1. 如果定义rocksdb_stats,则调用rocksdb_stats->ToString()将统计值转化为可读的字符串;
  2. commit_latency_stats是直方图的类型,输出对应的50%, 95%, 99%, 100%四个位点的对应的值。
  3. 假如定义了is-write-stopped或者actual-delayed-write-rate等Property变量,同样会将它们输出。

2 后台线程

通过调用SHOW ENGINE ROCKSDB STATUS可以得到与BG_THREADS相关结果,它的输出结果类似于:

Type: BG_THREADS
Name: 140173379593984
Status:
thread_type: Low Pri##
cf_name: default
operation_type: Compaction
operation_stage: CompactionJob::ProcessKeyValueCompaction
elapsed_time_ms: 6172.244 ms
BaseInputLevel: 0
BytesRead: 992806363
BytesWritten: 992071408
IsDeletion: 0
IsManual: 0
IsTrivialMove: 0
JobID: 1936
OutputLevel: 5
TotalInputBytes: 1586832446
state_type:

可以看到较多的信息量:这个线程正在进行Compaction,处于CompactionJob::ProcessKeyValueCompaction阶段,已经耗时6172.244 ms,读取的字节数为992806363,写出的字节数为992071408。然而并不包括可能感兴趣的正在进行Compaction的源文件和目标文件等信息。正如文章开头提到的,了解实现原理能够使我们更好地进行扩展。

2.1 thread status的接口与实现

MyRocks中的SHOW ENGINE ROCKSDB STATUS指令展示BG_THREAD的机制使用了RocksDB中关于thread status的接口。

它的头文件位于:

include/rocksdb/env.h
include/rocksdb/thread_status.h
util/thread_operation.h
monitoring/thread_status_updater.h
monitoring/thread_status_util.h

关键类:

ThreadStatusUpdater:存储了各自后台线程的状态和所有后台线程状态的指针。 ThreadStatusUtil:该类只有静态变量和静态方法,推荐通过该类的方法去更新ThreadStatusUpdater中的状态。

使用方法:

  • 将该线程的统计加入ThreadStatusUpdater:调用ThreadStatusUtil::RegisterThread
  • 将该线程的统计从ThreadStatusUpdater删除:调用ThreadStatusUtil::UnregisterThread
  • 其他修改thread status的函数:见monitoring/thread_status_util.h

通过调用env的GetThreadList()函数可以获得当前后台线程的状态,状态的状态值存放于一个vector中。将其中的内容展现出来,类似于下图:

从代码中可以看到,实现thread status的目的展示flush和compaction的运行状态。当然,我们也可以将用户线程的状态存储到thread status,通过调用SHOW ENGINE ROCKSDB STATUS指令展示。

特别地,可以看到compaction特有的状态值有:

enum CompactionPropertyType : int {
    COMPACTION_JOB_ID = 0,
    COMPACTION_INPUT_OUTPUT_LEVEL,
    COMPACTION_PROP_FLAGS,
    COMPACTION_TOTAL_INPUT_BYTES,
    COMPACTION_BYTES_READ,
    COMPACTION_BYTES_WRITTEN,
    NUM_COMPACTION_PROPERTIES
  };

flush特有的状态值有:

  enum FlushPropertyType : int {
    FLUSH_JOB_ID = 0,
    FLUSH_BYTES_MEMTABLES,
    FLUSH_BYTES_WRITTEN,
    NUM_FLUSH_PROPERTIES
  };

2.2 MyRocks/RocksDB的使用

在RocksDB的线程池实现中,每一个启动的后台线程都会通过调用ThreadStatusUtil::RegisterThread加入被观测的后台线程的集合中。

ThreadPoolImpl::Impl::StartBGThreads-->BGThreadWrapper-->ThreadStatusUtil::RegisterThread

在rocksdb_show_status函数中,输出BG_THREAD的过程如下:

  1. 通过调用GetThreadList(&thread_list)获得所有后台线程的ThreadStatus的集合。
  2. 通过遍历ThreadStatus的集合将每一个后台线程的状态依次输出。

3. 小结

本文章介绍了SHOW ENGINE ROCKSDB STATUS指令中关于STATISTICS与BG_THREAD的相关内容。

相关阅读

MySQL 内核深度优化

【腾讯云CDB】深入解析MySQL binlog

【腾讯云CDB】源码分析 · MySQL binlog组提交和Multi-Threaded-Slave



此文已由作者授权腾讯云技术社区发布,转载请注明文章出处

原文地址:https://www.cnblogs.com/qcloud1001/p/8404294.html

时间: 2024-08-29 06:02:47

腾讯工程师教你玩转 RocksDB的相关文章

腾讯工程师教你9小时搞定微信小程序开发

下载地址:百度网盘下载 课程介绍本课程从最基础的微信小程序开发工具使用开始讲起,带你走完从写出第一个 HelloWorld 到构建出第一款属于自己的微信小程序的完整学习路线.课程共有八大模块:模块一:微信小程序介绍与开发准备模块二:上手第一个微信小程序模块三:微信小程序开发框架模块四:微信小程序开发之原生组件模块五:微信小程序开发之原生 API模块六:微信小程序开发进阶之核心技能模块七:微信小程序开发项目实战案例模块八:微信小程序开发实战注意事项与进阶指导 课程详细大纲 原文地址:https:/

教你玩App怎么赚钱(一)

在看这篇文章之前,你一定要接受一下谋哥的观点:金钱就是价值流通的手段,不要高看了钱. 玩App怎么赚钱?貌似谋哥写的文章超级多,把这个最重要的忘记了.说实在的,我为啥要写“玩App"呢?其实就是一种比较轻松的心态.就好像现在我写文章,简直就是神速,那思路就如北大某牛人说的:“诗文如尿崩.”轻松地玩,自己才觉得好玩,爽快,不累. 玩App怎么赚钱这个系列的文章,我打算分三篇来探讨下,具体就是:App前赚钱.App里赚钱.App之外赚钱.当然了,这三个分法,业界貌似没有定论,统统是谋哥我为了自己总结

IOS 教你玩转UITableViewController和TableView

iphone和Ipad开发中UITableViewController和TableView应该是用得比较多得控件.但是你是会因为写这些控件写得多了而厌烦. 所有怎么让这个控件一直能用,怎么让这个控件写起来简单.是很必须.特别是UITableViewController把dataSouce的业务逻辑集成在自己身上而让看起来扎乱无章. 1.解决UITableViewController一直能用下. 那就是自己写个基类的UITableViewController,然后其他的来继承.这样可以把相似的功能

手把手教你玩转SOCKET模型之重叠I/O篇(上)

“身为一个初学者,时常能体味到初学者入门的艰辛,所以总是想抽空作点什么来尽我所能的帮助那些需要帮助的人.我也希望大家能把自己的所学和他人一起分享,不要去鄙视别人索取时的贪婪,因为最应该被鄙视的是不肯付出时的吝啬.” ----- 题记  By PiggyXP(小猪) 前   言   其实我首先应该道歉,因为7月份的时候曾信誓旦旦的说要写一套关于SOCKET所有模型的入门文章以及配套代码,不过没想到后天竟然被美女所迷出去度假了,刚刚回来不久......-_-b其实那些模型的配套代码我已经基本写完了,

手把手教你玩转SOCKET模型之重叠I/O篇(下)

四.     实现重叠模型的步骤 作 了这么多的准备工作,费了这么多的笔墨,我们终于可以开始着手编码了.其实慢慢的你就会明白,要想透析重叠结构的内部原理也许是要费点功夫,但是只是学会 如何来使用它,却是真的不难,唯一需要理清思路的地方就是和大量的客户端交互的情况下,我们得到事件通知以后,如何得知是哪一个重叠操作完成了,继而知道 究竟该对哪一个套接字进行处理,应该去哪个缓冲区中的取得数据,everything will be OK^_^. 下面我们配合代码,来一步步的讲解如何亲手完成一个重叠模型.

手把手教你玩转CSS3 3D技术

手把手教你玩转 CSS3 3D 技术 要玩转css3的3d,就必须了解几个词汇,便是透视(perspective).旋转(rotate)和移动(translate).透视即是以现实的视角来看屏幕上的2D事物,从而展现3D的效果.旋转则不再是2D平面上的旋转,而是三维坐标系的旋转,就包括X轴,Y轴,Z轴旋转.平移同理. 当然用理论来说明,估计你还不明白.下面是3个gif: 沿着X轴旋转 沿着Y轴旋转 沿着Z轴旋转 旋转应该没问题了,那理解平移起来就比较容易了,就是在在X轴.Y轴.z轴移动. 你可能

不止是联网!教你玩转PC自带Wi-Fi网卡

前言:Wi-Fi对于现在的智能手机来说已经是再熟悉不过的配置了,而主板自带Wi-Fi网卡的设计也越来越普及,但有些玩家可能思维还停留在“Wi-Fi网卡 = 连无线网络用的网卡,我用有线就不需要”的层次,因此我们今天就来跟大家谈谈,PC自带Wi-Fi网卡到底能够实现什么样的功能. 不止是联网!教你玩转PC自带Wi-Fi网卡 ●很多主板都自带了Wi-Fi无线网卡 七彩虹 战斧 C.A88AK旗舰版配备板载Wi-Fi网卡 Wi-Fi无线网卡以往一般常见于ITX尺寸的迷你主板上面,主要为了提升主板在客厅

8分钟丨教你玩转 API

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由织云平台团队发表于云+社区专栏 背景 当下,业界越来越多公司在项目架构设计时,会采用微服务架构.微服务架构,可以让我们的产品有更好的扩展性,更好的伸缩性:但同时也会带来微服务的一系列问题,比如微服务接口怎样规范管理?怎样在多团队协作中开放与复用?等等. 同时,业界也在逐渐的引入DevOps理念,来实现开发,测试,运维,运营更紧密的高效配合,提升产品迭代的效率,质量. 这里,织云API平台将从"部门内微服务API开放复用"

完毕port(CompletionPort)具体解释 - 手把手教你玩转网络编程系列之三

手把手叫你玩转网络编程系列之三    完毕port(Completion Port)具体解释                                                              ----- By PiggyXP(小猪) 前 言 本系列里完毕port的代码在两年前就已经写好了,可是因为许久没有写东西了,不知该怎样提笔,所以这篇文档总是在酝酿之中--酝酿了两年之后,最终决定開始动笔了,但愿还不算晚-.. 这篇文档我很具体而且图文并茂的介绍了关于网络编程模型中完毕