Graphite のチューニングには札束しかなかった話

ネタバレ:SSDにしろ、以上。

そしてややネタエントリーです。


いきさつ

会社でRADIUSサーバーの認証ログを Grafana + Graphite で可視化するツールを作っていまして、開発版を会社の本番サーバーにデプロイしたところ、起動してから数分経つとデータが記録・表示されなくなる不具合が起きました。

サーバーから収集しているログをダンプしてみたり、Graphiteに送るデータをダンプしてみたり、いろいろデバッグしてみたものの原因がわからず途方に暮れてたのですが、結果的に Graphite の統計情報を見ることで原因が判明しました。その大活躍したダッシュボードがコチラ!

f:id:miyahan:20161111225731p:plain開発環境 (Fedora 24 on VirtualBox / 作業用Windows PC)

f:id:miyahan:20161111225746p:plain本番環境 (CentOS 6 on VMware vSphere Hypervisor / ブレードサーバー)

なんと本番環境ではメモリ使用量やキャッシュサイズがどんどん肥大し続けています!ちなみにこのまま放置したところ、そのうち過負荷でダッシュボードにデータがプロットされなくなり、最終的には carbon-cache が OOM killer 先生によって友愛されました。

なお、Graphite の統計情報・上記ダッシュボードについては関連エントリで詳しく述べています。

それにしてもダッシュボードを作ってる最中にダッシュボードの有用性を思い知るとは。いやはや。


速さが足りない!!

f:id:miyahan:20161117210602p:plain

よくよくダッシュボードを見てみると、受信したデータポイント(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 というツールでベンチマークを取ってみました。

f:id:miyahan:20161117214239p:plain

f:id:miyahan:20161117214641p:plain

ベタな結果ではありますが、HDDはシーケンシャルアクセスはそこそこなものの、ランダムアクセスがダメダメです。

f:id:miyahan:20161117215738p:plain

The Architecture of Open Source Applications: Graphite より

Graphite が採用する Whisper はファイルベースのデータベースで、1メトリック=1ファイルというシンプルな構成になっており、先頭のヘッダを読み込んで、その内容に基づき目的のデータポイントを読み書きしています。すなわち細かいリード/ライトが大量に走るということです。

上記ベンチマークでは、"Multi Random R/W" が最もその状況に近いでしょう。SSDパソコンは6000IOPS に対し、HDDサーバーは500IOPS・・・。これはたしかに書き込み間に合わないかも。SSDがこのくらい速いのは分かるのですが、本番サーバーの1MB/sってなんだよ、数年前の低価格パソコンかよ・・・。エンタープライズ 10krpm SAS ってなんだったんだよ・・・。

f:id:miyahan:20161117221814p:plain


いいからチューニングだ!!

思うようにパフォーマンスがでない?ならばチューニングを行うべきです。この世の理であり、男と男の約束です。

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の場合

f:id:miyahan:20161118024456p:plainf:id:miyahan:20161118024511p:plain

f:id:miyahan:20161118024624p:plainf:id:miyahan:20161118024628p:plain

f:id:miyahan:20161118024638p:plainf:id:miyahan:20161118024642p:plain

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の場合

f:id:miyahan:20161118031355p:plainf:id:miyahan:20161118031358p:plain

f:id:miyahan:20161118031409p:plain

f:id:miyahan:20161118031421p:plainf:id:miyahan:20161118031425p:plain

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 SSDAmazon で800円で買った USB3.0 HDDケース に入れて、会社の余っているPCにつなげて暫定 Graphite サーバーにしています。数百万円するブレードサーバーが数千円の USB SSD に負けたのです。


余談:SSDなんですぐ死んでしまうん?

SSDパソコンで試験運用させていたところ、後輩君から「あのパソコン、昨日からたまにピロロンと変な音がなるんですけど?」との報告が。それは定番SMART監視ソフト Crystal Disk Info の通知メロディのことでした。

f:id:miyahan:20161120203041p:plain

(;゚д゚) あ、あれ、1日ちょっとでライフタイムが3%も減ってる・・・。ファームのバグかな?

念のため計算してみましょう。開発中のツールを動かすと、常時 25MB/s ほどのディスク書き込みが発生します。ということは1日2.16TB。今回使った crucial M550 128GB の TBW (Total Byte Written) は 72TB ですので、つまり、えーと、33日で寿命・・・。

(((( ;゚д゚))))

愚かにも、サーバー向けSSDがなぜ法外なほどに高価なのかわかった瞬間でした。

もちろん TBW は保証値であり、実施はその数倍書ける場合が多いことが知られていますが、それでも半年持たせるのが関の山です。どうにかしないといけません。ためしに carbon-cache の書き込み頻度をいじってみました。

f:id:miyahan:20161120204535p:plain

おお!書き込み頻度(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を比較してみました。

f:id:miyahan:20161120211721p:plain

容量とTBWの両方を考えると、2.5インチ SATA は定番の crucial MX300 がよさそうですね。1TB3万円とはいい時代になったもんです。m.2 MVMe だと IntelPLEXTOR がそこそこいい感じで、Samsung が性能・値段ともにぶっちぎっています。960 PRO ほしー!!

なお、SanDisk など一部メーカーはサーバー用途に使うとメーカー保証が剥奪される場合があるので、保証規定をよく読んで購入しましょう。基本的に長寿命・長期保証を謳っているのにTBWを非公開にしているメーカーには罠があると思っておいたほうがよさそうです。あと、必要分より1つ上の大容量モデルを選ぶのも寿命を延ばす上では有利です。


以上、時系列データベースは札束で殴れというお話でした。失礼いたしました。