2015年12月15日
Spotifyのモニタリング part 1:これまでの経緯
(2015-11-16)by John-John Tedro
本記事は、原著者の許諾のもとに翻訳・掲載しております。
これはSpotifyのモニタリングについて 2回に分けてご紹介 するシリーズの第1回です。この記事では、これまでの経緯や、直面した難題とそれに対する取り組みをお話ししたいと思います。
Spotifyの運用のモニタリングは、2つのシステムを組み合わせて始まりました。Zabbixと、 RRDベース の自前で作成したグラフ作成システム「sitemon」です。sitemonは、データ収集に Munin を使っていました。ZabbixはSREチームが所有し、sitemonはバックエンドのインフラチームが運用していました。当時は小さな会社だったので、各自で問題を解決するのが普通でした。この方式を採用した理由は何よりも、最初に問題に取り組んだ担当者が選んだためでした。
2013年の終わりには、 セルフサービスと運用責任の分担 に力を入れ始めます。私たちは、個々のホストを監視するのはやめて、サービスの全体を論理的に見るようにしたいと考えました。しかし、個々のホストに重点を置くZabbixはそれに向いておらず、Zabbixを運用できるのはSREチームのメンバーだけでした。インフラは 大きく 成長しており、負荷が増大するにつれ、システムに問題が生じ始めていました。
自分たちでできるだけの手当てを試み、チーフアーキテクトが現状の負荷で約1カ月分のメトリクスを保持できるインメモリのsitemonの置換プログラムを書きました。それで 一息 つく時間は取れましたが、遅くとも1年後にはシステムが持たなくなると予想できました。この経験から生まれたのが、新しいチーム「Hero」です。Heroの目的は、Spotifyのモニタリングシステムを”改修”して、将来に対応できるようにすることでした。そのためには何でもやりました。取り組みの過程を以下にご紹介します。
サービスとしてのアラート
最初に手をつけた問題がアラートです。
私たちは、Zabbixをさらに開発することを考えました。Zabbixは、アラート条件のチェックに トリガ条件式 を用いています。システムでは多くのビット腐敗が生じており、理解しがたいトリガや、不完全または不正なトリガが多数実行されていました。この状況を受けて、次期アラートシステムの要件の1つを決めました。理解を深めリグレッションを避けるため、トリガのテストを簡単に行えるということです。Zabbixのスケーラビリティも懸念の1つでした。今後2年に予想されるシステムの規模でZabbixを運用できる確信がなかったのです。
私たちは Monitorama EU に参加して Riemann に出会い、ヒントを得ました。Riemannとは、分散システムをモニタリングするツールです。Riemannはスケーラビリティをすぐに提供してくれるわけではありませんが、ステートレスの原則が取られているため、負荷を分割して分散しやすくなります。そこで、サービスにおける全てのホストを、同じルールを実行している少なくとも2つのインスタンスに組み合わせました。
全てのホストは、少なくとも2つのRiemannインスタンスと通信する
Riemann上に Lyceum というライブラリを構築したことで、全てのチームが隔離された名前空間にルールを入れられるgitリポジトリをセットアップできるようになりました。このセットアップなら、エンジニアは再現可能な結合テストの検討と定義に集中できます。そして、リポジトリを公開して本番環境に変更を直接デプロイする自信がつき、「テストに合格すれば、きちんと動くと確信できる」というスタンスに変わりました。これは非常にうまくいきました。Clojureはトリガ条件式よりもはるかに分かりやすい言語であり、gitベースのレビュープロセスは私たちの開発方法により適していたのです。
グラフ作成
これについては試行を繰り返しました。初期のスタックは、収集したデータ全てに対応するMunin型のプラグインでした。標準のメトリクスもありましたが、最も重要なのはサービスメトリクスでした。
エンジニアが扱いやすいように、プッシュ型のアプローチに切り替えるのが望ましいということになりました。メトリクスを定義する複雑な過程のために採用が遅れてしまうということが、Muninで得た経験から分かりました。プル型のアプローチでは、何をどこで読みこむかを設定しておく必要があります。プッシュ型では、なるべく一般的なプロトコルを使って、最も近いAPIにサンプルを送りこむだけです。コレクタに発見される間もないほど、短時間の一時的なタスクを考えてみましょう。プッシュ型にとって、これは問題ではありません。なぜなら、メトリクスを送るタイミングをタスク自体が制御するからです。
もっと詳しく知りたい方は、 sFlow と Alan Giles の記事がこのテーマを掘り下げているので、ご覧ください。
私たちの最初の実験は、経験を積むために、 collectd と Graphite に基づいた一般的な解決策をデプロイすることでした。パフォーマンステストによれば、1つのGraphiteノードから取り出せる垂直方向のスケーラビリティでは不十分でした。
whisper の書き出しパターンは、 多くの ファイルに対するランダムな検索と書き出し を伴いました。1つがそれぞれの系列に対して行います。また、全てをがむしゃらにダウンサンプリングすると、償却コストが高くなります。
Graphiteはシャーディングとリバランスが難しいため、コストが非常に高くなりました。近頃は、バックエンドの Cyanite を使用することにより、こうした問題のうちいくつかは解決されたかもしれません。しかし私たちにとって、Graphiteにはまだ理論的なハードルがあります。それは、階層的なネーミングです。
データの階層
Graphiteでは、典型的な時系列は以下のようにネーミングされます。
実際には様々なスタイルがありますが、上記のネーミングは、固定階層と見なされます。この方式が非常に有効な場合もありますが、本質的に階層的ではないものもあります。しかし、特定の サイト で全てのサーバを選択したいならば、よく考えてみる必要があります。
私たちの選択肢は2つです。サーバ名がインフラに対して一貫していると期待して、ワイルドカード検索を行うことです。もしくは、この問題に対処するべく、ネーミングの階層を改編するという方法もあります。
このタイプのリファクタリングは 難しい と言えます。
正解はありません。 サイト がフィルタリングの主要な手段であるべきと考えるチームもあれば、 ロール に関心があるチームもあるでしょう。どちらの要件も、メリットは同じくらいあるかもしれません。ですから、弱点はネーミング体系なのです。
タグ
ここで、全く異なる発想からこの問題を180度転換させて、時系列のアイデンティティがタグのセットで構成されると考えてみます。
前出の例を見てみると、既存の階層をタグのセットにマッピングすることもできます。
このことが考慮されているフィルタリングシステムでは、エンジニアが、時系列の大きなプールを付属するコンポーネントによって”様々な切り口から詳細に分析”できます。相互運用性の増大を図っているのです。
このように、厳密に順守しなければならない階層はありません。ルール(「サイト」と「ホスト」は必ずあります)によって、構造の一部には階層がある かもしれません が、必須ではなく、遵守する必要もありません。
Atlas 、 Prometheus 、 OpenTSDB 、 InfluxDB 、 KairosDB は全て、タグを使用するデータベースです。AtlasとPrometheusは十分に検討対象となったでしょうが、当時は入手できませんでした。OpenTSDBは、私たちのHBaseの操作経験が足りないため却下となりました。InfluxDBは未成熟で、セルフサービスを推進する上で必要な機能が欠けていました。KairosDBは最高の候補と思われたので、大掛かりな試験運用を行いました。しかしパフォーマンスと安定性に問題があることが分かり、試みは不成功に終わりました。私たちは、このプロジェクトがコミュニティへの関与に欠けている上に、進むべき方向へ向かっていないと感じていました。
KairosDBに触発されて、私たちは新しいプロジェクトを開始しました。小さな概念実証により予想通りの結果が得られたので、実証を続けるとともに名前を付けました。それが「Heroic」です。
引き続き次回の投稿もご覧ください。次回は、私たちのスケーラブルな時系列データベースであるHeroicをご紹介します。
バナー写真はMartin Parmが撮影し、 Creative Commons Attribution-ShareAlike 2.0 International License の下に提供されています。
株式会社リクルート プロダクト統括本部 プロダクト開発統括室 グループマネジャー 株式会社ニジボックス デベロップメント室 室長 Node.js 日本ユーザーグループ代表
- Twitter: @yosuke_furukawa
- Github: yosuke-furukawa