MyRocks之bloomfilter

zysql發表於2017-09-04

title: MySQL · mysql · myrocks之Bloom filter

author: 張遠

Bloom filter 簡介

Bloom filter用於判斷一個元素是不是在一個集合裡,當一個元素被加入集合時,通過k個雜湊函式將這個元素對映成一個位陣列中的k個點,把它們置為1。檢索時如果這些點有任何一個為0,則被檢元素一定不在;如果都是1,則被檢元素很可能在。這就是布隆過濾器的基本思想。
優點:布隆過濾器儲存空間和插入/查詢時間都是常數O(k)。
缺點:有一定的誤算率,同時標準的Bloom Filter不支援刪除操作。
Bloom Filter通過極少的錯誤換取了儲存空間的極大節省。

bloom filter

設集合元素個數為n,陣列大小為m, 雜湊函式個數為k

有一個規律是當 k=m/n*ln2 時,誤算率最低。參考Bloom_filter wiki

rocksdb與bloom filter

rocksdb中memtable和SST file都屬於集合類資料且不需要刪除資料,比較適合於Bloom filter.

rocksdb memtable和SST file都支援bloom filter, memtable 的bloom filter陣列就儲存在記憶體中,而SST file的bloom filter持久化在bloom filter中.

  • SST Bloom filter
    SST Boomfilter 在Flush生成SST files時通過計算產生,分為兩個階段

    1. 將prefix_extrator指定的key字首加入到HASH表hash_entries_中
    2. 將hash_entries_所有對映到Bloom filter的陣列中

SST Bloom filter相關引數有

filter_policy=bloomfilter:10:false;
whole_key_filtering=0
prefix_extractor=capped:24
partition_filters=false

其中prefix_extractor=capped:24, 表示最多取字首24個位元組,另外還有fixed:n方式表示只取字首n個位元組,忽略小於n個位元組的key. 具體可參考CappedPrefixTransform,FixedPrefixTransform

filter_policy=bloomfilter:10:false;其中bits_per_key_=10, bits_per_key_實際就是前面公式k=m/n*ln2 中的m/n. 從而如下計算k即num_probes_的方式

 void initialize() {
    // We intentionally round down to reduce probing cost a little bit
    num_probes_ = static_cast<size_t>(bits_per_key_ * 0.69);  // 0.69 =~ ln(2)
    if (num_probes_ < 1) num_probes_ = 1;
    if (num_probes_ > 30) num_probes_ = 30;
  }

use_block_based_builder_表示是使用block base filter還是full filter
partition_filters 表示時否使用partitioned filter,SST資料有序排列,按block_size進行分割槽後在生產filter,index_on_filter block儲存分割槽範圍. 開啟partition_filters 需配置index_type =kTwoLevelIndexSearch

filter 引數優先順序如下 block base > partitioned > full. 比如說同時指定use_block_based_builder_=true和partition_filters=true實際使用的block based filter

whole_key_filtering,取值true, 表示增加全key的filter. 它和字首filter並不衝突可以共存。

螢幕快照 2017-08-30 下午5.14.07.png

  • memtable Bloom filter
    memtable 在每次Add資料時都會更新Bloom filter.

Bloom filter提供引數memtable_prefix_bloom_size_ratio,其值不超過0.25, Bloom filter陣列大小為write_buffer_size* memtable_prefix_bloom_size_ratio.
memtable Bloom filter 中的num_probes_取值硬編碼為6

另外引數cache_index_and_filter_blocks可以讓filter資訊快取在block cache中。

MyRocks和bloom filter

在myrocks中,Bloom filter是全域性的,設定了Bloom filter後,所有表都有Bloom filter。Bloom filter和索引是繫結在一起的。也就是說,表在查詢過程中,如果可以用到某個索引,且設定了Bloom filter,那麼就有可能會用到索引的Bloom filter.

MyRocks可以使用Bloom filter的條件如下,詳見函式can_use_bloom_filter

  • 必須是索引字首或索引全列的等值查詢
  • 等值字首的長度應該符合prefix_extrator的約定

我們可以通過以下兩個status變數來觀察Bloom filter使用情況
rocksdb_bloom_filter_prefix_checked:是否使用了Bloom filter
rocksdb_bloom_filter_prefix_useful:使用Bloom filter判斷出不存在
rocksdb_bloom_filter_useful:BlockBasedTable::Get介面使用Bloom filter判斷出不存在

設定引數rocksdb_skip_bloom_filter_on_read可以讓查詢不使用Bloom filter。

示例

最後給個示例
引數設定如下,使用partitioned filter

rocksdb_default_cf_options=write_buffer_size=64k;block_based_table_factory={filter_policy=bloomfilter:10:false;whole_key_filtering=0;partition_filters=true;index_type=kTwoLevelIndexSearch};prefix_extractor=capped:24

SQL

CREATE TABLE t1 (id1 INT, id2 VARCHAR(100), id3 BIGINT, value INT, PRIMARY KEY (id1, id2, id3)) ENGINE=rocksdb collate latin1_bin;
let $i = 1;
while ($i <= 10000) {
  let $insert = INSERT INTO t1 VALUES($i, $i, $i, $i);
  inc $i;
  eval $insert;
}

# case 1: 等值條件prefix長度 < 24, 用不Bbloom filter
select variable_value into @c from information_schema.global_status where variable_name=`rocksdb_bloom_filter_prefix_checked`;
select variable_value into @u from information_schema.global_status where variable_name=`rocksdb_bloom_filter_prefix_useful`;
select count(*) from t1 WHERE id1=100 and id2 =`10`;
count(*)
0
select (variable_value-@c) > 0 from information_schema.global_status where variable_name=`rocksdb_bloom_filter_prefix_checked`;
(variable_value-@c) > 0
0
select (variable_value-@u) > 0 from information_schema.global_status where variable_name=`rocksdb_bloom_filter_prefix_useful`;
(variable_value-@u) > 0
0

# case 2: 符合使用Bbloom filter的條件,且成功判斷出不存在
select variable_value into @c from information_schema.global_status where variable_name=`rocksdb_bloom_filter_prefix_checked`;
select variable_value into @u from information_schema.global_status where variable_name=`rocksdb_bloom_filter_prefix_useful`;
select count(*) from t1 WHERE id1=100 and id2 =`00000000000000000000`;
count(*)
0
select (variable_value-@c) > 0 from information_schema.global_status where variable_name=`rocksdb_bloom_filter_prefix_checked`;
(variable_value-@c) > 0
1
select (variable_value-@u) > 0 from information_schema.global_status where variable_name=`rocksdb_bloom_filter_prefix_useful`;
(variable_value-@u) > 0
1


相關文章