Spotifyのモニタリング part 1:これまでの経緯

monitoring-banner

これは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つのインスタンスに組み合わせました。

monitoring-host-to-riemann
全てのホストは、少なくとも2つのRiemannインスタンスと通信する

Riemann上にLyceumというライブラリを構築したことで、全てのチームが隔離された名前空間にルールを入れられるgitリポジトリをセットアップできるようになりました。このセットアップなら、エンジニアは再現可能な結合テストの検討と定義に集中できます。そして、リポジトリを公開して本番環境に変更を直接デプロイする自信がつき、「テストに合格すれば、きちんと動くと確信できる」というスタンスに変わりました。これは非常にうまくいきました。Clojureはトリガ条件式よりもはるかに分かりやすい言語であり、gitベースのレビュープロセスは私たちの開発方法により適していたのです。

グラフ作成

これについては試行を繰り返しました。初期のスタックは、収集したデータ全てに対応するMunin型のプラグインでした。標準のメトリクスもありましたが、最も重要なのはサービスメトリクスでした。

エンジニアが扱いやすいように、プッシュ型のアプローチに切り替えるのが望ましいということになりました。メトリクスを定義する複雑な過程のために採用が遅れてしまうということが、Muninで得た経験から分かりました。プル型のアプローチでは、何をどこで読みこむかを設定しておく必要があります。プッシュ型では、なるべく一般的なプロトコルを使って、最も近いAPIにサンプルを送りこむだけです。コレクタに発見される間もないほど、短時間の一時的なタスクを考えてみましょう。プッシュ型にとって、これは問題ではありません。なぜなら、メトリクスを送るタイミングをタスク自体が制御するからです。

もっと詳しく知りたい方は、sFlowAlan Gilesの記事がこのテーマを掘り下げているので、ご覧ください。

私たちの最初の実験は、経験を積むために、collectdGraphiteに基づいた一般的な解決策をデプロイすることでした。パフォーマンステストによれば、1つのGraphiteノードから取り出せる垂直方向のスケーラビリティでは不十分でした。

whisperの書き出しパターンは、多くのファイルに対するランダムな検索と書き出しを伴いました。1つがそれぞれの系列に対して行います。また、全てをがむしゃらにダウンサンプリングすると、償却コストが高くなります。

Graphiteはシャーディングとリバランスが難しいため、コストが非常に高くなりました。近頃は、バックエンドのCyaniteを使用することにより、こうした問題のうちいくつかは解決されたかもしれません。しかし私たちにとって、Graphiteにはまだ理論的なハードルがあります。それは、階層的なネーミングです。

データの階層

Graphiteでは、典型的な時系列は以下のようにネーミングされます。

monitoring-hierarchy

実際には様々なスタイルがありますが、上記のネーミングは、固定階層と見なされます。この方式が非常に有効な場合もありますが、本質的に階層的ではないものもあります。しかし、特定のサイトで全てのサーバを選択したいならば、よく考えてみる必要があります。

私たちの選択肢は2つです。サーバ名がインフラに対して一貫していると期待して、ワイルドカード検索を行うことです。もしくは、この問題に対処するべく、ネーミングの階層を改編するという方法もあります。

monitoring-hierachy-add

このタイプのリファクタリングは難しいと言えます。

正解はありません。サイトがフィルタリングの主要な手段であるべきと考えるチームもあれば、ロールに関心があるチームもあるでしょう。どちらの要件も、メリットは同じくらいあるかもしれません。ですから、弱点はネーミング体系なのです。

タグ

ここで、全く異なる発想からこの問題を180度転換させて、時系列のアイデンティティがタグのセットで構成されると考えてみます。

前出の例を見てみると、既存の階層をタグのセットにマッピングすることもできます。

monitoring-hierarchy-mapping
このことが考慮されているフィルタリングシステムでは、エンジニアが、時系列の大きなプールを付属するコンポーネントによって”様々な切り口から詳細に分析”できます。相互運用性の増大を図っているのです。

このように、厳密に順守しなければならない階層はありません。ルール(「サイト」と「ホスト」は必ずあります)によって、構造の一部には階層があるかもしれませんが、必須ではなく、遵守する必要もありません。

AtlasPrometheusOpenTSDBInfluxDBKairosDBは全て、タグを使用するデータベースです。AtlasとPrometheusは十分に検討対象となったでしょうが、当時は入手できませんでした。OpenTSDBは、私たちのHBaseの操作経験が足りないため却下となりました。InfluxDBは未成熟で、セルフサービスを推進する上で必要な機能が欠けていました。KairosDBは最高の候補と思われたので、大掛かりな試験運用を行いました。しかしパフォーマンスと安定性に問題があることが分かり、試みは不成功に終わりました。私たちは、このプロジェクトがコミュニティへの関与に欠けている上に、進むべき方向へ向かっていないと感じていました。

KairosDBに触発されて、私たちは新しいプロジェクトを開始しました。小さな概念実証により予想通りの結果が得られたので、実証を続けるとともに名前を付けました。それが「Heroic」です。

引き続き次回の投稿もご覧ください。次回は、私たちのスケーラブルな時系列データベースであるHeroicをご紹介します。

Creative Commons License
バナー写真はMartin Parmが撮影し、Creative Commons Attribution-ShareAlike 2.0 International Licenseの下に提供されています。