Elasticsearchでなるべく長期間データ保存をしておきたいけど、データ容量が結構大きい。。。
ということで、圧縮できないかXFSとBTrfsを試してみました。
目的
- データ圧縮してストレージ容量の削減をしたい
観点
- どの程度容量が圧縮されるのか
- 検索速度はどの程度違うのか
- 負荷はどのレイヤがどの程度変わるのか
注意
今回紹介するBtrfsの圧縮機能の状態はまだmostly OKなので利用時はデータの破損等自己責任でお願いします。
備考には(needs verification and source) auto-repair and compression may crashとの記載あり。
Status - btrfs Wiki
XFSとBtrfsについて
各ファイルシステムの紹介は細かく記載してくださっているサイトがあるので、
ご紹介程度にとどめておきます。
試したファイルシステムの設定種類
サーバ名 | OS | Instance Type | ファイルシステム | ファイルシステムオプション(fstab) |
---|---|---|---|---|
ec2-xfs-default | CentOS Linux release 7.2.1511 | t2.medium | xfs | defaults |
ec2-btrfs-default | CentOS Linux release 7.2.1511 | t2.medium | btrfs | defaults |
ec2-btrfs-force-lzo | CentOS Linux release 7.2.1511 | t2.medium | btrfs | noatime,autodefrag,compress-force=lzo,space_cache |
ec2-btrfs-force-zlib | CentOS Linux release 7.2.1511 | t2.medium | btrfs | noatime,autodefrag,compress-force=zlib,space_cache |
試した環境イメージ
投入したデータについて
ec2-dsrc01,02からmetricbeatを使って毎秒以下の通りデータを投入。
$ sudo cat /etc/metricbeat/metricbeat.yml metricbeat.modules: #------------------------------- System Module ------------------------------- - module: system metricsets: # CPU stats - cpu # System Load stats - load # Per CPU core stats - core # IO stats - diskio # Per filesystem stats - filesystem # File system summary stats - fsstat # Memory stats - memory # Network stats - network # Per process stats - process # Sockets (linux only) - socket enabled: true period: 1s processes: ['.*']
ディスク容量の推移
ec2-xfs-defaultとec2-btrfs-defaultではあまり大きな容量の差は見られませんでした。
しかし、ec2-btrfs-force-lzoはec2-btrfs-defaultと比較して3割強、
ec2-btrfs-force-zlibに至っては6割のデータ容量が削減されていることが確認できました。
CPU使用率(USER)の推移
予想に反してbtrfs-zlibの使用率が低い結果になりました。
※全台たまに使用率が跳ねているのは恐らくSegment Mergeが起きていたのではないかと思います。
今回は検証の範囲外のため行っていませんが、もし本当にSegment Mergeであるか確認するなら、
_cluster/settingsのindices.store.throttle.max_bytes_per_sec等を修正すると影響があるかもしれません。
簡単なクエリを投げ続けてみた
以下のような直近1日のCPU使用率を取得するクエリを投げてみました。
なお、get-cpu.shを叩く前に全台Elasticsearchを再起動してメモリキャッシュをクリアさせています。
get-cpu.sh
#!/bin/bash LOG=/tmp/get-average-cpu-24hour-`date +%Y%m%d-%H%M%S`.log # Warmup date >> $LOG echo "start warmup." >> $LOG for i in {1..500} do (time curl -s -XGET {{ ansible_default_ipv4.address }}:9200/metricbeat-*/_search -d @get-average-cpu-24hour.json | jq .) > /dev/null 2>&1 done date >> $LOG echo "stop warmup." >> $LOG date >> $LOG echo "sleep 1m." >> $LOG sleep 60 date >> $LOG # exe date >> $LOG echo "start benchmark." >> $LOG for i in {1..1000} do (time curl -s -XGET {{ ansible_default_ipv4.address }}:9200/metricbeat-*/_search -d @get-average-cpu-24hour.json | jq .) 2>&1 | grep ^real >> $LOG done date >> $LOG echo "stop benchmark." >> $LOG
get-average-cpu-24hour.json
{ "size": 0, "query": { "bool": { "must": [ { "query_string": { "query": "*", "analyze_wildcard": true } }, { "range": { "@timestamp": { "gte": 1491554333990, "lte": 1491640733990, "format": "epoch_millis" } } } ], "must_not": [] } }, "_source": { "excludes": [] }, "aggs": { "2": { "date_histogram": { "field": "@timestamp", "interval": "30m", "time_zone": "Asia/Tokyo", "min_doc_count": 1 }, "aggs": { "1": { "avg": { "field": "system.process.cpu.total.pct" } } } } } }
実行時間
トータル実行時間
btrfsは一度読み込むとメモリ乗っかるせいか、
圧縮オプションによる実行時間はほとんど変わりませんでした。
XFSは2倍強くらいになってしまいました。。。
サーバ名 | 実行時間 |
---|---|
ec2-btrfs-force-zlib | 1m 55s |
ec2-btrfs-default | 1m 56s |
ec2-btrfs-force-lzo | 1m 56s |
ec2-xfs-default | 4m 51s |
単一実行時間の散布図
縦軸:処理時間(秒)
横軸:回数
CPU負荷のかかり方(USER)
ユーザランドのCPU使用率だけ見てみると全台綺麗にCPUを使い切っていて、
負荷のかかりかた自体は大きな違いがあるようではなさそうでした。
DISK IOの負荷のかかり方
- 11:54 - 11:56周辺の山:Elasticsearchを再起動実施タイミング
- 11:59 - 12:01周辺の山:ベンチマーク中
DISKの圧縮が効いていればいるほどDISKのIO Waitが小さく、かつIOが出ているようです。
参考:timelionのクエリ(ec2-xfs-default)
※以下クエリは意図的になるべく見やすくするために意図的に改行を付加してますが、
実際はワンライナーで記載する必要があります。
( .subtract( .es(index=metricbeat-*,metric=max:system.diskio.read.count,q=beat.hostname:ec2-xfs-default), .es(index=metricbeat-*,metric=max:system.diskio.read.count,q=beat.hostname:ec2-xfs-default,offset=-1s) ).label("ec2-xfs-default:read i/o"), .subtract( .es(index=metricbeat-*,metric=max:system.diskio.write.count,q=beat.hostname:ec2-xfs-default), .es(index=metricbeat-*,metric=max:system.diskio.write.count,q=beat.hostname:ec2-xfs-default,offset=-1s) ).label("ec2-xfs-default:write i/o") ).bars(width=1).yaxis(1,max=1500,label="DISK IO Count"), .multiply( .es(index=metricbeat-*,metric=max:system.cpu.iowait.pct,q=beat.hostname:ec2-xfs-default), 100 ).lines(width=1).label("ec2-xfs-default:cpu i/o wait").yaxis(2,max=100,label="CPU IO wait(%)")
念のため3回ほど回してみた
DISKやCPUの負荷傾向は同じ傾向となりました。
結論
- btrfsをデフォルト設定で使ってもDISK容量削減だと意味がなさそう
- 圧縮率を求めるならcompress-forceでlzoかzlibを使う必要がある
- 今回みたいな小さいクエリの場合はXFSよりBtrfsのほうが早い模様
- なぜそうなるのかが追求できていないので全体的な傾向としてBtrfsが早いのか、今回の条件に限りなのかは要確認