Graphite のチューニングには札束しかなかった話
ネタバレ:SSDにしろ、以上。
そしてややネタエントリーです。
いきさつ
会社でRADIUSサーバーの認証ログを Grafana + Graphite で可視化するツールを作っていまして、開発版を会社の本番サーバーにデプロイしたところ、起動してから数分経つとデータが記録・表示されなくなる不具合が起きました。
サーバーから収集しているログをダンプしてみたり、Graphiteに送るデータをダンプしてみたり、いろいろデバッグしてみたものの原因がわからず途方に暮れてたのですが、結果的に Graphite の統計情報を見ることで原因が判明しました。その大活躍したダッシュボードがコチラ!
開発環境 (Fedora 24 on VirtualBox / 作業用Windows PC)
本番環境 (CentOS 6 on VMware vSphere Hypervisor / ブレードサーバー)
なんと本番環境ではメモリ使用量やキャッシュサイズがどんどん肥大し続けています!ちなみにこのまま放置したところ、そのうち過負荷でダッシュボードにデータがプロットされなくなり、最終的には carbon-cache が OOM killer 先生によって友愛されました。
なお、Graphite の統計情報・上記ダッシュボードについては関連エントリで詳しく述べています。
それにしてもダッシュボードを作ってる最中にダッシュボードの有用性を思い知るとは。いやはや。
速さが足りない!!
よくよくダッシュボードを見てみると、受信したデータポイント(metricsReceived : 緑色) に対し、ディスク書き込んだデータポイント(committedPoints : 黄色) が大幅に少ないことがわかります。そう、ディスクへの書き込みが全く間に合っていないのです。書き込み回数 (updateOperations : 水色) を見てください。虫の息です・・・。
開発用PC VM | 本番サーバー VM | |
---|---|---|
ホストOS | VirtualBox @ Windows 7 | VMware vSphere Hypervisor |
ゲストOS | Fedora 24 | CentOS 6.8 |
CPU / 割り当て | 低電圧Core-i5 2GHz / 2core | Xeon E7 2.4GHz / 8core |
RAM割り当て | 4GB | 4GB |
ストレージ | SATA SSD | SAS 10krpm HDD x2 RAID1 |
ではなぜ本番サーバーだけ書き込みが間に合っていないのでしょうか。最も考えられるのはストレージの違い。でもいくらHDDとはいえ、エンタープライズ向けの1万回転 SAS HDDです。いまどきディスクI/Oが間に合わずシステムが落ちるなんて起こりうるのでしょうか・・・?fio というツールでベンチマークを取ってみました。
ベタな結果ではありますが、HDDはシーケンシャルアクセスはそこそこなものの、ランダムアクセスがダメダメです。
The Architecture of Open Source Applications: Graphite より
Graphite が採用する Whisper はファイルベースのデータベースで、1メトリック=1ファイルというシンプルな構成になっており、先頭のヘッダを読み込んで、その内容に基づき目的のデータポイントを読み書きしています。すなわち細かいリード/ライトが大量に走るということです。
上記ベンチマークでは、"Multi Random R/W" が最もその状況に近いでしょう。SSDパソコンは6000IOPS に対し、HDDサーバーは500IOPS・・・。これはたしかに書き込み間に合わないかも。SSDがこのくらい速いのは分かるのですが、本番サーバーの1MB/sってなんだよ、数年前の低価格パソコンかよ・・・。エンタープライズ 10krpm SAS ってなんだったんだよ・・・。
いいからチューニングだ!!
思うようにパフォーマンスがでない?ならばチューニングを行うべきです。この世の理であり、男と男の約束です。
carbon-cache の設定は /etc/carbon/carbon.conf
の [cache]
セクションに書きます。主要なパラメーターを解説します。
MAX_CACHE_SIZE
キャッシュするデータポイントの上限を設定します。デフォルトは inf
(上限無し)です。キャッシュが満杯になると以後のデータはどんどん捨てられていくようです。本設定はあくまでCPUやメモリが食いつぶされるのを防止するためのもので、パフォーマンスには特に影響ないと思います。
OOM killer のお世話にまでなったので、安全のために設定したかったのですが、キャッシュが溢れた際に大量のトレースバックを吐く不具合に見舞われ、怖いので inf
に戻して運用しています。バグかな?
MAX_UPDATES_PER_SECOND
ディスクへの書き込み頻度を設定します。デフォルトは 500
(500回/秒) です。inf
で制限なしにするとデータを受信するたびにディスクへ書き込もうとするため、かなりのCPU・I/Oリソースを消費します。逆にトラフィックより少ない値にすると、当然書き込みが間に合わないのでデータはキャッシュにたまっていきます。(上記 MAX_CACHE_SIZE
の範囲内である限り)たまったキャッシュはまとめてディスクに書き込まれるため、結果的にスループットが向上し、CPU・I/O負荷も軽減されます。しかしキャッシュを貯めすぎるとこんどはキャッシュのソートや出し入れにCPUパワーを持って行かれ過負荷状態に陥る危険があります。今回のチューニングのキーとなるパラメーターです。
MAX_CREATES_PER_MINUTE
Whisper のファイルを作成する頻度を設定します。デフォルトは 50
(50メトリック/分) です。前述したとおり、Whisper データベースは1メトリック=1ファイルで構築されているため、新しいメトリックを受信すると当然新しいファイルがディスクに作成されますが、この設定はそれを制限しファイルシステムの過負荷を防止します。あくまで新規作成時の設定であり、既存の Whisper ファイルの更新処理には影響ありません。
ただこの設定には罠があり、これだけ毎分なんです。つまりデフォルトだと 0.83メトリック/秒 とあまりに少なすぎます。この上限を超えた場合、初出メトリックのデータはキャッシュにはたまらず即時破棄されるのも注意ポイントです。デフォルト設定でもし10万メトリックを新規登録する場合、すべてのファイルが作成されるまで1.4日もかかってっしまいます。最初これに気づかずデータが歯抜けになり途方に暮れた苦い思い出があります・・・。今回は 6000 (100メトリック/秒) に変更しました。
CACHE_WRITE_STRATEGY
貯まったキャッシュを取り出すアルゴリズムを選択します。デフォルトは sorted
です。解説のアメリカ語がよくわからず、未だに理解できていません。。。学のなさがヤバい。
sorted
: データポイントの数でソートしたリストを作り、リストの上から順にディスクへフラッシュする(?)max
: 常に最もデータポイントの多いメトリックからディスクへフラッシュする。ランダムアクセスが減る。naive
: なにも考えずに取り出す。SSDの場合や、ランダムアクセスを補償できる(ライトバッファ?)場合におすすめ。
なんとなく max
が一番I/O負荷が低いように思えます。これも重要そうなパラメーターです。
WHISPER_AUTOFLUSH
ディスク書き込み時に同期を行うか選択します。デフォルトは False
(同期しない)です。データ永続化の話ですかね?速さ優先なのでもちろん False で。
WHISPER_SPARSE_CREATE / WHISPER_FALLOCATE_CREATE
Whisper ファイル新規作成時の設定。アップデート時のパフォーマンスと関係ないので割愛。
WHISPER_LOCK_WRITES
Whisper ファイルのロック処理を行うかの接待。デフォルトは False
(ロックしない)です。アクセス競合するような使い方はしないので False で。
WHISPER_FADVISE_RANDOM
Graphite 0.10 から追加されるオプションのようです。posix_fadvise() を発行するかを選択します。デフォルトは False
(発行しない)です。必要なくなったキャッシュをOSに通知し解放させることで、キャッシュの効率向上・スラッシング防止が期待できるようです。0.10 はまだ安定版が出ていないので試していません。
$ vmstat -SM 10 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 3 2 866 124 254 434 0 0 2512 8776 35520 57272 23 9 56 12 0 2 1 866 110 254 436 0 0 697 8256 36592 59316 33 9 50 8 0 4 1 866 110 254 441 0 0 1812 5549 37019 61120 29 9 50 11 0 1 2 866 101 255 449 0 0 2655 8168 35035 57074 22 10 56 13 0 6 0 867 145 250 418 0 0 1819 7171 39260 64974 30 10 51 10 0 $ sar -r 11時30分01秒 kbmemfree kbmemused %memused kbbuffers kbcached kbcommit %commit 11時30分01秒 139296 3782212 96.45 232312 1860440 3064788 37.76 11時40分01秒 321900 3599608 91.79 242592 1603500 3142096 38.72 11時50分01秒 137392 3784116 96.50 252884 1626128 3265420 40.24
ちなみにうちの本番環境(メモリ4GB)はスラッシングが発生するほどひどくはないものの、ページキャッシュには全く期待できない(1.6GBしかない)というなんとも微妙な状況。
何の成果も得られませんでしたぁ!
というわけで神パラメーターを求め、早速ベンチマークしてみましょう
SSDの場合
CPU | inf | 3000 update/s | 500 update/s |
---|---|---|---|
sorted | 46% | 29% | 17% |
max | 46% | 33% | 15% |
naive | 44% | 29% | 17% |
I/Oに余裕があるためか、どのアルゴリズムを選択しても変化はありませんでした。アップデート頻度を落としても、その分キャッシュが貯まるだけで特に目立った変化は無し。ただ書き込み処理が減った分CPU使用率が下がったのは発見ですね。SSDの場合、トラフィックが増えていくと先にCPUが行き詰まるはずなので、そのような場合は MAX_UPDATES_PER_SECOND
を調整したいところです。
HDDの場合
CPU | inf | 1000 update/s |
---|---|---|
sorted | 38% | 39% |
max | 102% | 未実施 |
naive | 37% | 35% |
commit | inf | 1000 update/s |
---|---|---|
sorted | 431/s | 454/s |
max | 0/s | 未実施 |
naive | 488/s | 457/s |
cache | inf | 1000 update/s |
---|---|---|
sorted | 546K | 600K |
max | 2973K | 未実施 |
naive | 573K | 629K |
完全にI/Oがカツカツで、指定した制限値に達することもできません。ランダムアクセスが弱いことから CACHE_WRITE_STRATEGY
の設定が効いてくると思いきや、なんと sorted とnaive で有意な差は見られませんでした。RAIDコントローラで吸収されているんでしょうか? 一方で、max にしたところCPUが大暴走。ほとんどディスクフラッシュが行えておらずフン詰まり状態に陥ってしまいました。キャッシュ内の最大値を求める処理に持って行かれてしまったのでしょうか?しかし SSDで MAX・500update/s にしたときにCPU使用率に変化が無かったことからつじつまが合いません。謎です・・・。
というわけでベンチマークの結果、ブレイクスルーは発見されず、HDDの遅さはどうしようもできないという悲しい現実だけが残るのでした。
力こそパワー!
結局有効な手段はなく、たくさんのメモリと高速なストレージが唯一の解決法という結論に至りました。
うちの場合は、自宅で余っていた128GB SSD を Amazon で800円で買った USB3.0 HDDケース に入れて、会社の余っているPCにつなげて暫定 Graphite サーバーにしています。数百万円するブレードサーバーが数千円の USB SSD に負けたのです。
余談:SSDなんですぐ死んでしまうん?
SSDパソコンで試験運用させていたところ、後輩君から「あのパソコン、昨日からたまにピロロンと変な音がなるんですけど?」との報告が。それは定番SMART監視ソフト Crystal Disk Info の通知メロディのことでした。
(;゚д゚) あ、あれ、1日ちょっとでライフタイムが3%も減ってる・・・。ファームのバグかな?
念のため計算してみましょう。開発中のツールを動かすと、常時 25MB/s ほどのディスク書き込みが発生します。ということは1日2.16TB。今回使った crucial M550 128GB の TBW (Total Byte Written) は 72TB ですので、つまり、えーと、33日で寿命・・・。
(((( ;゚д゚))))
愚かにも、サーバー向けSSDがなぜ法外なほどに高価なのかわかった瞬間でした。
もちろん TBW は保証値であり、実施はその数倍書ける場合が多いことが知られていますが、それでも半年持たせるのが関の山です。どうにかしないといけません。ためしに carbon-cache の書き込み頻度をいじってみました。
おお!書き込み頻度(MAX_UPDATES_PER_SECOND
)を減らすと、ディスク書き込み量 も減っています。ボリュームディスカウント恐るべし。(ただ、header の読み込みが1回で済むのでリードが減るのはわかるのですが、書き込み量が減る理屈がよくわかりません・・・)ともかく、たとえば頻度をトラフィック(6000 metrics/s)の 1/8、750 updates/s に設定するとディスク書き込み量を 80% 削減することができます。これだと5ヶ月でTBWに達する計算です。2年くらいなら持ちそう??
というわけでSSDは速いけど、調子乗ってぶん回すと寿命がゴリゴリ減っていくという教訓が得られました。銀の弾丸(SSD)は脆い
まあ本来であれば、Grafana + Graphite なんて超書き込み特化な使い方だと、HDD をちゃんとしたコントローラを使って RAID50 とかにして運用すべきなんだと思います。
SSD TBW 比較
というわけでPCサーバーでSSDを使う場合、TBWにも考慮して選定する必要があります。TBW を公開している主要メーカーのコンシューマー向けSSDを比較してみました。
容量とTBWの両方を考えると、2.5インチ SATA は定番の crucial MX300 がよさそうですね。1TB3万円とはいい時代になったもんです。m.2 MVMe だと Intel と PLEXTOR がそこそこいい感じで、Samsung が性能・値段ともにぶっちぎっています。960 PRO ほしー!!
なお、SanDisk など一部メーカーはサーバー用途に使うとメーカー保証が剥奪される場合があるので、保証規定をよく読んで購入しましょう。基本的に長寿命・長期保証を謳っているのにTBWを非公開にしているメーカーには罠があると思っておいたほうがよさそうです。あと、必要分より1つ上の大容量モデルを選ぶのも寿命を延ばす上では有利です。
以上、時系列データベースは札束で殴れというお話でした。失礼いたしました。