Rocksdb 获取当前db内部的有效key个数 (估值)
文章目錄
- 1. 基本接口
- 2. Memtable key個(gè)數(shù)統(tǒng)計(jì)
- 3. Immutable Memtable key個(gè)數(shù)統(tǒng)計(jì)
- 4. Sstables key個(gè)數(shù)統(tǒng)計(jì)
- 5. 疑問
Rocksdb因?yàn)槭茿ppendOnly 方式寫入,所以沒有辦法提供db內(nèi)部唯一key個(gè)數(shù)的接口(可能存在多版本的key,對(duì)用戶來說只有一個(gè)userkey,但是rocksdb認(rèn)為是多個(gè)internal key)。
不過Rocksdb支持提供獲取大概非刪除key 的internal-key的個(gè)數(shù)接口,也能讓用戶對(duì)寫入的key有一個(gè)大體量級(jí)的估計(jì)。
本文相關(guān)rocksdb代碼版本是6.4.6
1. 基本接口
可以通過如下接口來獲取:
uint64_t int_num;
dbfull()->GetIntProperty("rocksdb.estimate-num-keys", &int_num)
這一部分key組成從Rocksdb的寫入整體架構(gòu)來看應(yīng)該由三部分組成:
- memtable-keys
- imm memtable-keys
- sstables-keys
實(shí)際獲取的時(shí)候還需要將刪除key(DeleteType)過濾掉。
具體estimate-num-keys的底層實(shí)現(xiàn)接口是:
bool InternalStats::HandleEstimateNumKeys(uint64_t* value, DBImpl* /*db*/,Version* /*version*/) {// Estimate number of entries in the column family:// Use estimated entries in tables + total entries in memtables.const auto* vstorage = cfd_->current()->storage_info(); uint64_t estimate_keys = cfd_->mem()->num_entries() + // memtable 的keyscfd_->imm()->current()->GetTotalNumEntries() + // imm 的keysvstorage->GetEstimatedActiveKeys(); // sstables 的keysuint64_t estimate_deletes = // 刪除keyscfd_->mem()->num_deletes() + cfd_->imm()->current()->GetTotalNumDeletes();*value = estimate_keys > estimate_deletes * 2? estimate_keys - (estimate_deletes * 2): 0;return true;
}
2. Memtable key個(gè)數(shù)統(tǒng)計(jì)
針對(duì)memtable中的keys的統(tǒng)計(jì)會(huì)獲取mem()->num_entries()中的num_entries_的個(gè)數(shù),memtable即active-memtable 在寫入路徑中達(dá)到write-buffer-size閾值之前有且僅有一個(gè),所以只需要看一下當(dāng)前的用戶進(jìn)程中這一個(gè)memtable中寫入的key的個(gè)數(shù)即可,而這個(gè)數(shù)據(jù)會(huì)在Add memtable的時(shí)候同步更新。
3. Immutable Memtable key個(gè)數(shù)統(tǒng)計(jì)
針對(duì)immutable memtable的keys統(tǒng)計(jì),因?yàn)檫@種只讀的memtable可能存在多個(gè),由一個(gè)鏈表進(jìn)行管理,后續(xù)統(tǒng)一進(jìn)行flush,所以獲取對(duì)應(yīng)的有效key以及刪除key的個(gè)數(shù)的話只需要逐個(gè)累加immutable memtable中的key的個(gè)數(shù)即可。
uint64_t MemTableListVersion::GetTotalNumEntries() const {uint64_t total_num = 0;for (auto& m : memlist_) {total_num += m->num_entries();}return total_num;
}
這一些有效key的更新是在Status MemTable::Add()函數(shù)中進(jìn)行更新的,包括后續(xù)的num_deletes_的個(gè)數(shù)也一樣。
4. Sstables key個(gè)數(shù)統(tǒng)計(jì)
這個(gè)數(shù)據(jù)的統(tǒng)計(jì)也是我們想要的數(shù)據(jù)主體,因?yàn)榇蠖鄶?shù)的時(shí)候 我們數(shù)據(jù)還是會(huì)持久化到sst文件之中的。
針對(duì)sst的有效key的個(gè)數(shù)統(tǒng)計(jì)是通過如下接口實(shí)現(xiàn)的:
大體邏輯是
- 如果發(fā)現(xiàn)sst文件個(gè)數(shù)為0,則直接返回0。
這個(gè)場(chǎng)景接口也說明了,在用戶寫入少量 key沒有達(dá)到觸發(fā)flush的條件時(shí),這里獲取到的數(shù)據(jù)就是0 - 如果當(dāng)前統(tǒng)計(jì)的有效key的個(gè)數(shù)
current_num_non_deletions_比實(shí)際的刪除key的個(gè)數(shù)還少,則也認(rèn)為這一些有效key后續(xù)都會(huì)被刪除,也返回0 - 有效key的個(gè)數(shù) 通過
current_num_non_deletions_ - current_num_deletions_即可獲得 - 為了防止返回的key數(shù)量過多(compaction完成之后會(huì)伴隨著文件的刪除),這里會(huì)重新逐層獲取一下sst文件數(shù)量,和實(shí)際統(tǒng)計(jì)的sst文件數(shù)量做一個(gè)比值再乘上一步有效key的個(gè)數(shù) – 雙重保險(xiǎn)
uint64_t VersionStorageInfo::GetEstimatedActiveKeys() const {// Estimation will be inaccurate when:// (1) there exist merge keys// (2) keys are directly overwritten// (3) deletion on non-existing keys// (4) low number of samplesif (current_num_samples_ == 0) {return 0;}if (current_num_non_deletions_ <= current_num_deletions_) {return 0;}uint64_t est = current_num_non_deletions_ - current_num_deletions_;uint64_t file_count = 0;for (int level = 0; level < num_levels_; ++level) {file_count += files_[level].size();}if (current_num_samples_ < file_count) {// casting to avoid overflowingreturnstatic_cast<uint64_t>((est * static_cast<double>(file_count) / current_num_samples_));} else {return est;}
}
而實(shí)際的這一些指標(biāo)的填充都是VersionStorageInfo::UpdateAccumulatedStats 這個(gè)函數(shù)中,這個(gè)函數(shù)的調(diào)用鏈實(shí)際能貫穿到compaction ,如下調(diào)用鏈
DBImpl::BackgroundCompaction // compaction執(zhí)行入口VersionSet::LogAndApply // compaction 執(zhí)行結(jié)束前需要更新manifest的version信息VersionSet::ProcessManifestWrites // manifest更新入口Version::PrepareApply // 更新各個(gè)指標(biāo)Version::UpdateAccumulatedStats // 更新當(dāng)前version內(nèi)所有層的所有文件元信息VersionStorageInfo::UpdateAccumulatedStats // 更新每一個(gè)sst文件的元信息
最后一個(gè)函數(shù)的的更新一個(gè)sst文件元數(shù)據(jù)指標(biāo)方式如下:
void VersionStorageInfo::UpdateAccumulatedStats(FileMetaData* file_meta) {assert(file_meta->init_stats_from_file);accumulated_file_size_ += file_meta->fd.GetFileSize();accumulated_raw_key_size_ += file_meta->raw_key_size;accumulated_raw_value_size_ += file_meta->raw_value_size;accumulated_num_non_deletions_ +=file_meta->num_entries - file_meta->num_deletions;accumulated_num_deletions_ += file_meta->num_deletions;current_num_non_deletions_ +=file_meta->num_entries - file_meta->num_deletions;current_num_deletions_ += file_meta->num_deletions;current_num_samples_++;
}
5. 疑問
可以看到以上代碼中
current_num_non_deletions_的數(shù)值是file_meta->num_entries - file_meta->num_deletions; ,已經(jīng)減去了當(dāng)前文件被刪除的數(shù)據(jù)條目,細(xì)心的同學(xué)可能會(huì)發(fā)現(xiàn)估算sst文件內(nèi)key的個(gè)數(shù)的函數(shù)GetEstimatedActiveKeys中有一行代碼uint64_t est = current_num_non_deletions_ - current_num_deletions_;,這里又減了一次統(tǒng)計(jì)的刪除key,有點(diǎn)奇怪。
針對(duì)刪除類型的key減了兩次,這里想一想,rocksdb寫入一個(gè)刪除類型的key肯定表示需要?jiǎng)h除之前一個(gè)已經(jīng)存在的key,所以我們想要保證返回的是有效key,需要減掉當(dāng)前刪除key個(gè)數(shù)的兩倍才行。
總結(jié)
以上是生活随笔為你收集整理的Rocksdb 获取当前db内部的有效key个数 (估值)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 麒麟丸多少钱一盒
- 下一篇: 求一个爱的句子大全个性签名!