cw-sakamotoです。 今までNikeのランニングシューズ(特にストリーク6)を好んでいたのですが、最近adidasのjapan boostに浮気気味です。 確かにフィット感がいいですね。sub2も興味がありますが、私の走力*1であれを履くのは恥ずかしいな、と思って、まだ試していません。 匠シリーズも気になるところですが、三村さんがいなくなった今、今後もあのシリーズが続く可能性は低い気がして、手を出していません。
閑話休題。
ChatWorkでは、HBaseを利用しています。利用用途はメッセージDBです。 もともとはAmazon Auroraを利用していましたが、負荷に耐えられないのが目に見てきたため、2016年12月にHBaseやKafkaをベースとしたアーキテクチャへの刷新を行いました。
昨年のAWS Summit TokyoでKafkaと絡めてどのように利用しているのか、の詳細がありますので、興味のある方はご参照ください。
ここ最近、HBaseのcompactionについて、調べる必要があったので、この記事ではその整理とまとめを記載したいと思います。 ただ、自分自身まだ追いきれていないところもあり、連載形式にしたいと思います。
この記事では、HBaseにおける
- compactionの必要性
- {major, minor} compaction のそれぞれの{動き, 発動する条件}の概要
- compactionに関連するパラメータのまとめ
を記載します。
目次
もしこのブログを読まれた方で、間違いを見つけましたら、ぜひ指摘して頂きたいです。 HBaseのversionは、HBase 1.2.0-CDH5.9.0です。
HBaseの概要については、下記がわかりやすいと思います。
なぜcompactionが必要なのか
HBaseはLSM-tree構造*2を採用しており、Wikipediaで言うところの、C0にMemStore, C1にHFile(StoreFile)*3となっています。LSM-treeは、追加していくのは早いのですが、C1(HFile)がどんどん作成されていくので、マージ作業が必要となります。 そこで行われるのがcompactionで、HBaseにはmajor compactionとminor compationの2つがあります。
major compactionは、Store内の全HFileを1つのHFileにまとめるcompactionです。そのため、compaction負荷(IO負荷)が非常に大きいです(minor compactionももちろんそれなりに大きいです)。
minor compactionは、複数のHFileを1つにするcompactionです。
日々flushされたHFileをminor compacitonで少なめにし、major compactionで1つにまとめる、ということが基本的な動作になります。
もちろんminor compactionを挟むのではなく、いきなりmajor compactionというのも条件次第では起こりえます。
※上記の図は下記のブログの図を借用しております
https://acadgild.com/blog/hbase-compactions/
compactionが起きるのはいつか
では、compactionはいつ起きるのでしょうか。
下記のタイミングでcompactionCheckerが走り、条件に合致すると、{major, minor} compactionが行われます。
- MemStoreがflushされたとき
- flushされるのは下記のタイミング
hbase.hregion.memstore.flush.size
に達したか(default 128MB)hbase.regionserver.optionalcacheflushinterval
経過したか(default 60m)- snapshot作成コマンドが実行されたとき
- flushされるのは下記のタイミング
- Regionが作成されたとき
- Regionが作成されるのは下記のタイミング
- RegionのHFileのサイズが、
hbase.hregion.max.filesize
に達した(default 10GB) - commandで明示的にsplitしたとき
- RegionのHFileのサイズが、
- Regionが作成されるのは下記のタイミング
- checker用threadが起動から一定時間経過したとき
- 正確には、
hbase.server.thread.wakefrequency
間隔(default 10s)で起動する、checker用threadが、hbase.server.compactchecker.interval.multiplier
回(default 1000)起動(つまり約166m)したとき
- 正確には、
- hbase-shellでcompactionが実行されたとき
このときmajor compactionもしくはminor compactionが発生する可能性があります。
compactionの条件
compactionの条件ですが、選択したcompaction policyで異なります。HBase 1.2.0-CDH5.9.0では、下記のpolicyが存在します。
- RatioBasedCompactionPolicy
- ExploringCompactionPolicy(default)
- FIFOCompactionPolicy
- StripeCompactionPolicy
compactionのpolicy
上記のpolicyは正確にはminor compactionのアルゴリズムです。 それぞれのアルゴリズムについては、下記をご参照ください。
algorithm | overview | source | memo |
---|---|---|---|
RatioBasedCompactionPolicy | 0.94までデフォルトだったpolicy compacion対象のhfileを左から(古い順から)比較し、compaction対象とするかどうかをする |
hfilesにpolicyを適用するメソッド | ドキュメントの中に例も記載されているのでわかりやすい |
ExploringCompactionPolicy | RatioBasedCompactionPolicy の発展*4(より少ない負荷でcompactionが行われるように)RatioBasedCompactionPolicy は、条件に合致するものがあれば適宜minor compaciton対象となるが、こちらは対象を広げて、候補を探す |
hfilesにpolicyを適用するメソッド | "Keep the selection that removes most files for least size." となるようにcompaction対象を選びます(なるべく多くのファイルを、同じファイル数の場合にはcompaction後のファイルサイズが小さくなる方を選ぶ) |
FIFOCompactionPolicy | TTL切れのものだけを対象にする | compaction対象の選別 | javadoc |
StripeCompactionPolicy | stripe store用のcompaction policyのようだけど、 stripe storeというのがわかっていない |
StripeCompactionPolicyのソース | ここを見ると実際にはExploringCompactionPolicy が適用されるようだmajor compactionはない stripeはこちら |
major compactionが起きる条件
major compactionの条件は、hbaseのドキュメントにはあまり記載がないのですが、いくつかあり、ソースを見る限り、下記のいずれかに合致した場合のようです。このあたりはまだ追いきれていません。
条件1
major compactionが強制 && ユーザがhbase shellでmajor compactionを指定 && storefileすべてがcompaction対象に含められる
が1つめの条件です。ソースのここに該当。
条件2
({[major compactionが強制 && storefileすべてがcompaction対象に含められる] || 対象のstoreのmajor compactionが前回から一定時間経過]} &&
[対象ファイル数がhbase.hstore.compaction.max
(default 10)以下])
が2つめの条件です。ソースのここに該当。
ややこしいので、[], {}, ()でわけました。
一定時間は hbase.hregion.majorcompaction
(default 7days) ± hbase.hregion.majorcompaction.jitter
(default 0.5 -> 3.5days) で、ソースにあるcomConf.getMaxFilesToCompact()
は、hbase.hstore.compaction.max
の値が帰ってきます
条件1,2のどちらにも "storefileすべてがcompaction対象に含められる" と "major compactionが強制" が入っていますが、これはそれぞれ、ソースのisAllFiles
とforceMajor
に対応します。
major compactionの条件でわかっていないところ
isAllFiles
は、名前は単純で、値を入れるのは、candidateFiles.size() == candidateSelection.size();
の結果なのですが、candidateFiles
とcandidateSelection
がわかっていません。
candidateFiles
が、store内の全HFile、candidateSelection
がstore内の全HFileからcompactionに適合しないものを落としたものであるようですが、現状では下記がわかっていません。
- ここで、
candidateSelection
が作成されるが、そこにあるfilesCompacting
がわからないfilesCompacting
は、HStore.javaで定義・作成されているが、何が入るのかがわからない
また、forceMajor
にtrue
が入るのがどのような場合なのかもわかっていません。変数名と条件1から考えるに、ユーザのコマンド指定のときにtrue
が入るのが1つのパターンのようですが、条件2にも入っていて、これがいつtrue
になるのかがわかりません。
ところで、hbase.hstore.compaction.max
というパラメータは、HBaseのドキュメントでは、"The maximum number of StoreFiles which will be selected for a single minor compaction"と記載されていますが、major compactionの条件でもあるので、注意です。
compactionの動きを左右するパラメータ
最後にcompactionの動きに関連するパラメータを記載したいと思います。いくつかはここまでの説明で出てきましたが、それも含めて記載します。
おもにHBase(CDH5)のドキュメントを参考にしています。
parameter | role | default | memo |
---|---|---|---|
hbase.hregion.majorcompaction | Time between major compactions | 604800000 milliseconds (7 days) |
0にすると、時間契機でのmajor compactionは なくなる。この時間はStore毎に計測される |
hbase.hregion.majorcompaction.jitter | A multiplier applied to hbase.hregion.majorcompaction to cause compaction |
0.5 | 7daysの場合は、3.5日 |
hbase.hstore.compaction.ratio | minor compaciton ratio | 1.2 | この値を大きくすると 大きめのminor compactionが起きるようになる |
hbase.offpeak.start.hour | start offpeak hour | -1 | offpeakの設定(開始) |
hbase.offpeak.end.hour | end offpeak hour | -1 | offpeakの設定(終了) |
hbase.hstore.compaction.ratio.offpeak | minor compaciton ratio for more aggressive compaction at offpeak |
5 | minor compactionの比率の変更 offpeak以外の時間帯はこの比率でminor compacitonの判断が行われる |
hbase.hstore.compaction.min | the minimum number of StoreFiles which must be eligible for compaction |
3 | この値よりhfileが少ない場合には minor compacitonは行わない |
hbase.hstore.compaction.max | The maximum number of StoreFiles which will be selected for a single compaction |
10 | compaction対象の最大値 実はmajor compationのパラメータでもある (前述の"major compactionが起きる条件"のところに記載) |
hbase.hstore.compaction.min.size | A StoreFile smaller than this size will always be eligible for minor compaction |
128MB | この値より小さいStoreFileは原則compaction対象になる |
hbase.hstore.compaction.max.size | A StoreFile larger than this size will be excluded from compaction |
Long.MAX_VALUE | この値より大きいStoreFileは原則compaction対象外になる |
hbase.hstore.compaction.max.size.offpeak | A StoreFile larger than this size will be excluded from compaction at offpeak |
hbase.hstore. compaction.max.size と同じ |
ドキュメントにはないが存在するパラメータhbase.hstore.compaction.max.size のoffpeak時の設定 |
hbase.hstore.min.locality.to.skip.major.compact | Potentially improve block locality during major compaction for old regions |
0 | major compactionをdata locality回復を 積極的に行うためのオプションだが、設定方法がいまいちわかっていない(floatで指定) |
hbase.regionserver.thread.compaction.throttle | Threshold for use of two threads for compaction | 2 * hbase.hstore. compaction.max * hbase.hregion. memstore.flush.size |
hbase.hstore.compaction.max = 10hbase.hregion.memstore.flush.size = 128M(memstoreがflushされるサイズ) 2 * 10 * 128M = 2560M この値を超えるcompacitonが実行される場合には、large throtleで、それ以下の場合には、small throttleでcompactionが実行される |
hbase.regionserver.thread.compaction.large | The number of threads to use when the size of HFiles to be compaction is larger than hbase.regionserver. thread.compaction.throttle |
1 | cloudera documentに "The number of threads available to handle small and large compactions, respectively. Never increase either of these options to more than 50% of the number of disks available to HBase."とあるので注意。 結局compactionとは、diskへの書込みなので、 diskの本数の50%より多くしないほうがいい、とのこと |
hbase.regionserver.thread.compaction.small | The number of threads to use when the size of HFiles to be compaction is smaller than `hbase.regionserver. thread.compaction.throttle |
1 | largeと同じ注意点がある |
hbase.server.compactchecker.interval.multiplier | The number that determines how often we scan to see if compaction is necessary |
1000 | 単位はなくて、回数。+1されていく ソース |
hbase.server.thread.wakefrequency | Time to sleep in between searches for work (in milliseconds). Used as sleep interval by service threads such as log roller. |
10 * 1000 | こちらはmiliseconds。 なので、checker用のthreadは、10s間隔で起動し、さらに、1000回起動する (10 * 1000s, 166.666..min)と、compactioncheckerが起動する。 ソース |
hbase.store.delete.expired.storefile | TTLが過ぎたファイルを minor compactionで削除するかどうか |
true | ttlのドキュメント |
最後に
HBaseのcompactionに関して、現時点で理解できている範囲でまとめてみました。 せっかくなので、今回調べて追いきれなかったところや、compactionがソースレベルでどのようなことをしているのか、など、調査を続けたいと思います。 独自にソースを読んでいったところばかりなので、間違いがあれば、ぜひぜひ指摘して頂きたいです。
弊社ではHBaseをガリガリ触りたい!という仲間を大募集しております。 corp.chatwork.com
*1:フルsub3.5程度, ハーフ95分ぐらい
*2:LSM-treeについては、下記がcassandraでの例も含めてわかりやすいです。 Log Structured Merge Tree
*3:HFileとStoreFileは同じ(HFileが慣習で、ソースはStoreFileになっている)ですが、このブログではHFileで統一して記載します。
*4:実際継承しているhbase/ExploringCompactionPolicy.java at cdh5.9.0-release · cloudera/hbase · GitHub