ウェブサイト及びサーバー監視の プレミアム製品

Server Densityについて

当社の時系列グラフを支える技術 – 一日に20億、月に30TBに及ぶドキュメント

Server Density(サーバーデンシティ)社は月に30TBに及ぶサーバからの受信データポイントを処理し、単純なLinuxシステムのロードアベレージから18カ国からのウェブサイトレスポンスタイムまで多岐にわたる顧客データ監視しています。これらすべてのデータはMongoDBにリアルタイムに入力され、顧客がグラフを閲覧したり、ダッシュボードのアップデートやレポート作成時に出力されます。

当社では MongoDBを2009年半ばから使用しており これまでデータベースのスケーリングに関して多くのことを学んできました。当社は複数のMongoDBクラスタを使用していますが、本記事ではこれまでの履歴データを保存しているクラスタに注目し、当社がどのようなスケーリングを行なったかを解説致します。

1. 専用ハードウェア及びSSDの使用

当社のMongoDBインスタンスはすべてソフトレイヤー社の2つのデータセンターにある専用のサーバーにて処理されています。なぜならば、当社はかつて仮想化において苦い経験をしたためです。その際には、ホストに対するコントロールがないにもかかわらず、データベースはディスクI/Oのパフォーマンス保証をせねばなりませんでした。共用ストレージ(例:SAN)ではEBS上のAWSのプロビジョンIOPS (SSDに保存)などから保証されたスループットが手に入らなければ、これを実現することは難しいです。
MongoDBはCPUに依存するオペレーションが稀であるため(通常インデックスの作成などに限られる)CPUに関するボトルネックはありませんが、問題はCPUスチール、つまりホスト上で他のゲスト同士がCPUリソースを取り合うことです。

当社ではこの問題を解決するために専用ハードウェアに移動することで、CPUスチールの可能性やその他の妨げとなる利用者を取り除くという手法を取っています。またローカルSSDにデータベースパスを配置することで、共用ストレージを使用する際に生じる問題を回避しています。

仮想化された、あるいは専用ハードウェアでMongoDBを管理する方法についてはMongoDBワールドで6月に詳しく解説します。

2. 改善された同時実行性の利点により複数のデータベースを使用する

SSDでデータベースパスを実行するのは手始めとしてはいいですが、複数のデータベースにデータを分散し、他のデータベースのジャーナルを含むそれぞれのデータベースを別々のSSDに振り分けることで、より優れたパフォーマンスを実現することができます。

MongoDBのロッキングはデータベースレベルで行なわれるため、コレクションをそれぞれのデータベースに移動させることで分散が可能になります。これはデータの書き込みスケーリングと共に読み取りも行なう時に特に重要となります。もし同じディスク上にデータベースを保存し続ければ、ディスク自身がスループットの限界となってしまいます。このことは、それぞれのデータベースをデータベース別ディレクトリオプションを用いてそれぞれのSSDに入れることで改善されます。何台ものSSDは特にランダムな読み取りや書き込みを行う際に、IOPS数や各オペレーションのレイテンシに関連するI/Oレイテンシを軽減する点で助けとなります。これはメモリーマップデータが連続的かつシンクロ的にフラッシュされるWindows環境ではさらに顕著になります。つまり、複数のSSDがこれらの軽減に役立っていると言えます。

ジャーナルは常にディレクトリ内にあるため、最初のステップとしてそのままSSDにマウントすることができます。書き込みはすべてジャーナルを通して行なわれ、後にディスクにフラッシュされるため、もしもジャーナルへの書き込みが成功した時に書き込み確認が返されるならば、ひとつのSSD上でこれらを行うことで書き込みがより早くなり、クエリー時間が向上します。とはいうものの、データベース別ディレクトリオプションを有効にすれば、異なる目標に対する最適化にも柔軟に対応できます。例えば、もしコストを抑えたいのであれば、あるデータベースをいくつかのSSDに、他のデータベースは異なるタイプのディスク(あるいはEBS PIOPSボリューム)に入れることもできます。

注意すべきことは、MongoDBが作動している状態でスナップショットに基づいたファイルシステムを起動し、ジャーナルを異なるディスク(あるいは異なるファイルシステム)に移動させることは不可能であるという点です。この場合はMongoDBをシャットダウンし(さらなる書き込みを防ぐため)、スナップショットを行う必要があります。

3. 一様分布にハッシュベースのシャーディングを使用する

当社がモニターするすべてのアイテムは(サーバーなど)それぞれのMongoIDを持ち、このMongoIDはメトリックデータを保存するためのシャードキーとして用いられます。

クエリーインデックスはアイテムID(例:サーバーID)、メトリックタイプ(例:ロードアベレージ)やタイムレンジにつけられていますが、すべてのクエリーがアイテムIDを持つのでシャードキーとして十分に機能します。しかしながら、重要なことは一つのアイテムIDの下にドキュメントが多すぎないことであり、多すぎた場合はジャンボチャンクとなり移動させることができなくなってしまいます。ジャンボチャンクとはデータのスプリットに失敗した状態であり、サイズをオーバーしているもののそれ以上細かく分解することができない状態を指します。

シャードチャンクが均等に分配されるために当社ではMongoDB 2.4のハッシュドシャードキーファンクショナリティーを使用しています。ハッシュドシャードキーは均等分配に適していますが、クエリー内でハッシュドフィールドを使用しない場合、ターゲットでない分配クエリーまたは収集クエリーが使用されるため、かえってパフォーマンスを阻害してしまいます。

4. TTLインデックスを使用してMongoDBにデータ消去をさせる

当社のほとんどの顧客が唯一関心を持っていることは、短期間の高解析度のデータと長期間のより一般的なトレンドであるため、当社では時系列データを平均値化しオリジナルデータを消去しています。実際には、当社では実際の値と後で引出す平均値を算出するために必要な合計値/個数を構成する値をそれぞれ挿入しています。クエリー時間によって当社では平均値あるいは実際値のいずれかを読み込んでいますが、クエリーレンジが長過ぎる場合には送り返すデータポイントが多くなりすぎる恐れがあります。しかし、この方法を用いることで、バッチプロセスなしで済むので、計算を待つことなくすべてのデータをリアルタイムで提供することが可能になります。

一定期間を過ぎたデータの消去はTTLインデックスを用いて行われています。これは高解析データがどの程度の期間必要なのかという顧客調査に基づいて設定されています。TTLインデックスをデータ消去に用いることは、バッチプロセスで消去するより効率的で、MongoDBによって正確なタイミングで行なわれます。

多大なデータを入力及び消去することは、データ断片化の恐れが伴いますが、TTLインデクスを用いることにより自動でPowerOf2Sizesが起動して、ディスク使用をより効率的にします。MongoDB 2.6以降ではこのストレージオプションはデフォルトに設定されています。

5. クエリー及びスキーマデザインをケアする

無数のアップデートを行なうことで、ドキュメントが大きくなる場合には、パフォーマンスは最も落ちます。書き込み後にドキュメントサイズが大きくなると、ドキュメント全体を再び読み込み、それを異なる部分のデータファイルに新たなロケーション情報と共に書き込みする必要が生じるので、既存のドキュメントをアップデートするよりはるかに多くの時間を要します。

従って、このような状況を避け、ネットワーク上で送信されなければならないものを最小化する適切な変更子を使って、ドキュメントがアップデートできるような、スキーマとクエリーをデザインすることが重要です。ドキュメントのアップデートの際に、やってはいけないことの一例は、アプリケーションを通してドキュメントの読み込みとアップデートをし、その後データベースに書き込むことです。それよりもむしろ、セットや消去、増分といった適切なコマンドを用いて直接ドキュメントを修正することが望ましいといえます。

このことは同時にBSONデータタイプ及び未割当ドキュメントに注意を払うことを意味しますが、これはMongoDBスキーマデザインの落とし穴で触れた内容です。

6. ネットワークスループット及びパケット数を考慮する

100Mbpsのネットワークで十分であるという考えは、通常時はさておきセカンダリのレプリカセットメンバーとの再同期が必要な場合など特別なイベントの際には問題につながりかねません。

データベースをクローンする際、MongoDBはデータ転送を迅速に行うためOplogのロールオーバー前に、可能な限り多くのネットワークを使うことになります。通常のオペレーションの際に50-60Mbpsが使用されている場合、100Mbpsネットワークでは大した余裕がなく、スループットの限界のために再同期が滞ってしまいます。

さらにネットワークを通して行われるパケット通信量(これは重要な生スループットに限られない)にも気を配る必要があります。膨大な量のパケット通信はクオリティの低いネットワーク機器では処理しきれません。当社でも数年前に利用していたホストプロバイダーでこの問題に直面しました。結果としてパケットのロスに陥り、診断が難しくなります。

結論

スケーリングは増分の過程であり、すべてを解決してくれる一つの方法が存在するわけではありません。しかしながら、これらすべての微調整や最適化は1の書き込み確認での、1秒単位で何千もの書き込みオペレーションや10ミリセカンド当たりのレスポンスタイムに貢献してくれます。

最終的には、このすべては当社の顧客が、信じられない程高速にグラフをロードできることができることを保証するものであり、 その一方で、当社はデータが素早く安全に書き込まれ、継続的にデータが大きくなるに伴ってスケーリングできることを理解しています。