掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
0. Intro

在facebook的MySQL版本(以下稱為MyRocks)中,RocksDB是可選的存儲(chǔ)引擎。相比于InnoDB引擎,RocksDB的一個(gè)重要的優(yōu)勢(shì)是它使用更少的磁盤(pán)空間。在生產(chǎn)系統(tǒng)中,特別是用戶數(shù)在億級(jí)以上的互聯(lián)網(wǎng)應(yīng)用,磁盤(pán)空間是其中比較大的成本之一,而能夠使用更少的磁盤(pán)空間的RocksDB無(wú)疑是具有吸引力的。然而在生產(chǎn)系統(tǒng)中使用新的存儲(chǔ)引擎自然有它的潛在風(fēng)險(xiǎn),除了通過(guò)外部的各種benchmark工具測(cè)試得到各種性能數(shù)據(jù),全方位的內(nèi)部指標(biāo)可以幫助我們真正了解數(shù)據(jù)庫(kù)內(nèi)部正在發(fā)生的事情,對(duì)于性能調(diào)優(yōu)和開(kāi)發(fā)都具有指導(dǎo)意義。而MyRocks通過(guò)SHOW ENGINE ROCKSDB STATUS和多個(gè)INFORMATION_SCHEMA表等方式提供了較為全面的內(nèi)部指標(biāo)。
本文將介紹SHOW ENGINE ROCKSDB STATUS中關(guān)于STATISTICS統(tǒng)計(jì)值與后臺(tái)線程的實(shí)現(xiàn)原理。在了解實(shí)現(xiàn)原理的基礎(chǔ)上,便可以較容易地通過(guò)擴(kuò)展功能使它更好地為我們服務(wù)。
調(diào)用SHOW ENGINE ROCKSDB STATUS指令會(huì)返回多行數(shù)據(jù),其中包括:
調(diào)用SHOW ENGINE ROCKSDB STATUS會(huì)返回若干行數(shù)據(jù),然而這些數(shù)據(jù)并非事先存儲(chǔ)于某個(gè)表格中,而是通過(guò)調(diào)用位于rocksdb/ha_rocksdb.cc文件中的rocksdb_show_status函數(shù)將內(nèi)存中對(duì)應(yīng)的數(shù)值進(jìn)行規(guī)整返回給用戶。
1. STATISTICS
根據(jù)RocksDB官方相關(guān)文檔介紹STATISTICS,開(kāi)啟STATISTICS會(huì)增加增加5%-10%額外開(kāi)銷。
STATISTICS統(tǒng)計(jì)值記錄著RocksDB引擎所有線程的所有操作的各類count/time的累加。RocksDB引擎在它的各類操作如Put/Get/Delete中的代碼都設(shè)立了很多埋點(diǎn)。
以函數(shù)GetEntryFromCache為例,它的作用是返回可用的block cache。特別地,可以看到statistics是GetEntryFromCache和block_cache->Lookup的一個(gè)參數(shù)。沒(méi)錯(cuò),就是靠著statistics這個(gè)參數(shù)它到處收集數(shù)據(jù)。
當(dāng)有可用的block cache時(shí),調(diào)用了三次RecordTick為其中三個(gè)統(tǒng)計(jì)值增加計(jì)數(shù);沒(méi)有可用的block cache,同樣也為BLOCK_CACHE_MISS和block_cache_miss_ticker增加計(jì)數(shù)。
- 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的方法也很簡(jiǎn)單。
它的頭文件位于:
- include/rocksdb/statistics.h
- monitoring/statistics.h
使用方法:
- Options options;
- options.statistics = rocksdb::CreateDBStatistics();
可選統(tǒng)計(jì)級(jí)別:
數(shù)據(jù)統(tǒng)計(jì)類型分成兩種:
統(tǒng)計(jì)函數(shù)的接口:
獲取結(jié)果的接口:
1.2 RocksDB的STATISTICS實(shí)現(xiàn)
RocksDB實(shí)現(xiàn)了StatisticsImpl類,繼承了Statistics的接口。
成員變量:
這里的TickerInfo和HistogramInfo類型的數(shù)據(jù)結(jié)構(gòu)是相似的:一個(gè)線程局部的counter或者time;加上一個(gè)非線程局部的統(tǒng)計(jì)值用來(lái)累加counter或者time。
TickerInfo類型包含兩個(gè)參數(shù):
ThreadLocalPtr類型(真實(shí)類型ThreadTickerInfo)的thread_value,包含:
ThreadLocalPtr類型(真實(shí)類型ThreadHistogramInfo)的thread_value,包含:
事實(shí)上,STATISTICS相關(guān)實(shí)現(xiàn)是比較巧妙的,也是使用STATISTICS僅增加5%-10%的關(guān)鍵。為了避免線程間共享數(shù)據(jù)導(dǎo)致CPU的cache頻繁失效,merged_sum和merged_hist初始化時(shí)都是空的,而且當(dāng)且僅當(dāng)線程退出時(shí),才調(diào)用mergeThreadValue函數(shù)將TickerInfo和HistogreamInfo中的線程局部變量累加到merged_sum和merged_hist。
1.3 MyRocks的使用
MyRocks使用了RocksDB提供的接口進(jìn)行數(shù)據(jù)統(tǒng)計(jì)。通過(guò)聲明了變量rocksdb_stats,并且隨著RocksDB引擎啟動(dòng)時(shí)通過(guò)rocksdb_init_func函數(shù)進(jìn)行初始化。
- rocksdb_stats = rocksdb::CreateDBStatistics();
- rocksdb_db_options->statistics = rocksdb_stats;
除了使用所有RocksDB引擎層的統(tǒng)計(jì),MyRocks還通過(guò)定義了
- commit_latency_stats = new rocksdb::HistogramImpl();
在rocksdb_commit_by_xid和rocksdb_commit兩個(gè)函數(shù)中通過(guò)計(jì)時(shí)的方式,統(tǒng)計(jì)了每一次commit所花費(fèi)的時(shí)間。
- rocksdb::StopWatchNano timer(rocksdb::Env::Default(), true);
- ...
- commit_latency_stats->Add(timer.ElapsedNanos() / 1000);
在rocksdb_show_status函數(shù)中,輸出Statistics統(tǒng)計(jì)的過(guò)程如下:
如果定義rocksdb_stats,則調(diào)用rocksdb_stats->ToString()將統(tǒng)計(jì)值轉(zhuǎn)化為可讀的字符串;
commit_latency_stats是直方圖的類型,輸出對(duì)應(yīng)的50%, 95%, 99%, 100%四個(gè)位點(diǎn)的對(duì)應(yīng)的值。
假如定義了is-write-stopped或者actual-delayed-write-rate等Property變量,同樣會(huì)將它們輸出。
2 后臺(tái)線程
通過(guò)調(diào)用SHOW ENGINE ROCKSDB STATUS可以得到與BG_THREADS相關(guān)結(jié)果,它的輸出結(jié)果類似于:
- 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:
可以看到較多的信息量:這個(gè)線程正在進(jìn)行Compaction,處于CompactionJob::ProcessKeyValueCompaction階段,已經(jīng)耗時(shí)6172.244 ms,讀取的字節(jié)數(shù)為992806363,寫(xiě)出的字節(jié)數(shù)為992071408。然而并不包括可能感興趣的正在進(jìn)行Compaction的源文件和目標(biāo)文件等信息。正如文章開(kāi)頭提到的,了解實(shí)現(xiàn)原理能夠使我們更好地進(jìn)行擴(kuò)展。
2.1 thread status的接口與實(shí)現(xiàn)
MyRocks中的SHOW ENGINE ROCKSDB STATUS指令展示BG_THREAD的機(jī)制使用了RocksDB中關(guān)于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
關(guān)鍵類:
使用方法:
通過(guò)調(diào)用env的GetThreadList()函數(shù)可以獲得當(dāng)前后臺(tái)線程的狀態(tài),狀態(tài)的狀態(tài)值存放于一個(gè)vector中。將其中的內(nèi)容展現(xiàn)出來(lái),類似于下圖:
從代碼中可以看到,實(shí)現(xiàn)thread status的目的展示flush和compaction的運(yùn)行狀態(tài)。當(dāng)然,我們也可以將用戶線程的狀態(tài)存儲(chǔ)到thread status,通過(guò)調(diào)用SHOW ENGINE ROCKSDB STATUS指令展示。
特別地,可以看到compaction特有的狀態(tài)值有:
- 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特有的狀態(tài)值有:
- enum FlushPropertyType : int {
- FLUSH_JOB_ID = 0,
- FLUSH_BYTES_MEMTABLES,
- FLUSH_BYTES_WRITTEN,
- NUM_FLUSH_PROPERTIES
- };
2.2 MyRocks/RocksDB的使用
在RocksDB的線程池實(shí)現(xiàn)中,每一個(gè)啟動(dòng)的后臺(tái)線程都會(huì)通過(guò)調(diào)用ThreadStatusUtil::RegisterThread加入被觀測(cè)的后臺(tái)線程的集合中。
- ThreadPoolImpl::Impl::StartBGThreads-->BGThreadWrapper-->ThreadStatusUtil::RegisterThread
在rocksdb_show_status函數(shù)中,輸出BG_THREAD的過(guò)程如下:
3. 小結(jié)
本文章介紹了SHOW ENGINE ROCKSDB STATUS指令中關(guān)于STATISTICS與BG_THREAD的相關(guān)內(nèi)容。

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流