BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース FoursquareのMongoDBが機能停止

FoursquareのMongoDBが機能停止

原文(投稿日:2010/10/15)へのリンク

最近、Foursquareは11時間のサイト全体の機能停止に苦しんだ。この機能停止はMongoDBデータベースの予期しない偏った成長が原因で、監視で検知できなかった。システムの機能停止は断片化が原因だったが、シャードの追加しても解決しなかったことで長期化し、最終的にはデータベースをオフラインにして圧縮する必要があった。この記事ではこの出来事の概要と、システムがダウンしたかについて説明する。また、この件に対するfoursquareと10genの反応についてもお届けする。

Foursquareは位置情報も利用したソーシャルネットワークであり、急成長をしてきた。今年の8月には利用者が300万人に達した。しかし、10月4日に11時間の機能停止を経験してしまった。この急成長による容量の問題が原因だった。Foursquareの運用ディレクターであるNathan Folkman氏は、ブログで、今回の出来事について利用者に対して謝罪するとともに、この問題の詳しい技術的な情報を提供した。その後、10genのCTOであるEliot Horowitz氏がより詳細な事後検証をMongoDBの利用者のメーリングリストに投稿した。10genはMongoDBの開発とサポートを行っており、Foursquareにもサポートを提供している。この事後検証は活発な議論を生み出した。この議論にはFoursquareのエンジニアリングリードであるHarry Heymann氏も参加し、より詳しい技術情報を提供した。

基本的なシステムアーキテクチャ

この出来事に決定的な影響を及ぼしたのはFoursquareのユーザチェックインのデータベースだ。多くの履歴データベースは任意の時に小さなデータにアクセスされる必要があるだけだが、10genのCEOであるDwight Merriman氏によれば、今回の場合は"さまざまな理由からデータベース全体が頻繁にアクセスされるので、基本的にはワーキングセットデータべースと同じ大きさになります。" したがって、このデータベースに必要なメモリはデータベース内のデータの大きさと同じだった。データベースの大きさがマシンのRAMの大きさを超えたらスラッシングが発生し、4つのディスクが扱えるよりも多いI/O要求が発生しただろう。私たち質問に対して、氏は"頻繁にアクセスされているドキュメントの割合はとても高いです。あなたの想像以上でしょう。"と明確に認めた。

はじめはデータベースは66GBのRAMを搭載した単一のEC2インスタンスで動かしていたが、約2ヶ月前、Foursquareはこの容量をほとんど使い切ってしまったので、2シャードのクラスタに移行した。シャードはひとつが66GBのRAMを持つ。また、スレーブへのデータのレプリケーションも行うようにした。この移行後、各シャードはおおよそ33GBのデータを持つようになった。シャード内のデータはパーティショニングによって"ユーザIDによって200のチャンクに均等にされた"ので任意のユーザのデータはすべて単一のシャードが持っていた。

 

機能停止

システムが成長するにつれ、このデータ分割は不均衡に成長した。Eliot Horowitz氏曰く、

どうしてこの問題が発生したのかを想像するのは簡単です。ある一定のユーザが他のユーザよりも活発にこのサービスを利用していると仮定すれば、その活発なユーザのデータ更新がすべて同じシャードへ行ってしまったのではないかと想像できます。

チャンクは200MBを超えるとMongoDBによって100MBづつに分割される。最終的にはシステム全体のデータ量が116GBを超えたとき、片方のシャードの大きさは50GBだったが、もう片方がマシンが利用できるRAMの容量である66GBを超えてしまった。この結果、容量を超えてしまったシャードに対するリクエストに許容できない性能問題が発生した。

回復させるために、チームはデータベースに3つ目のシャードを追加しようとした。このシャードにシステムのデータの5%を転送することですべてのシャードの大きさをRAMの大きさに納めるのが狙いだった。5%だけ転送した理由はEliot Horowitz氏によれば、"サイトのバックアップをなるべく素早く取得するために可能な限り最小限の転送にとどめようとしました。" しかし、転送を行っても容量を超えてしまったシャードの問題は解決しなかった。Eliot Horowitz氏によれば、

...私たちが最終的に発見したのは、問題の原因がshard0のデータの断片化にあるということでした。shard0から5%のデータを新しい3番目のシャードへ転送しても、データが断片化している状態では転送前と同じ量のRAMが必要になってしまうのです。これは、次の事実で説明がつきます。つまり、Foursquareのチェックインドキュメントは小さい(ひとつが約300バイト)ので、チェックインドキュメントの多くは1ページ4KBに収まるということです。なので、5%のデータを転送しても各ページのデータ量を少し減らしただけで、ページそのものは減らなかったのです。


移行したデータを少なかった。というのはデータが小さかったからであり、そして"シャードのキーのオーダーとインサートのオーダーが一致していなかったからです。この結果、データが連続しているチャンクから
データを移行できませんでした。"この性能問題を解決するには、データがあふれてしまったシャードを圧縮するしかなかった。現在のMongoDBではオフラインでのシャードの圧縮しかできない。この圧縮に4時間かかったのは、圧縮自体がデータのボリュームの役割であり、"そのときのEBSボリュームの遅さ"に影響を受けたからだ。この作業が終わったとき、シャードの大きさは5%減り、システムをオンラインに復帰させることができた。機能停止した時間は11時間になった。この問題でデータの消失はなかった。

調査

システムが復旧した後、チームは3番目のシャードを追加しデータを均等にならした。そして、断片化を解消するために各シャードのスレーブを圧縮してから、マスタとスレーブを交換しマスタを圧縮した。最終的には各シャードの大きさは約20GBになった。

Eliot Horowitz氏曰く、

10genのチームは今、データファイルとインデックスの双方をオンラインで徐々に圧縮できるようすることに取り組んでいます。また、この問題はシャードを利用していないシステムにも関係していることを認識しています。より詳しいことはこれから数週間のうちに発表します。

また、次のようにも書いている。

覚えておく必要のある重要なことは、一度容量の限界に到達したとき、
オブジェクトが小さいと停止時間を発生させずに新たに容量を追加するのは難しいということです。
しかし、事前に容量の限界にきていることを事前に察知できれば、停止時間なしで稼働中のシステムに
シャードを追加することができます。


また、Foursquareのチームもコミュニケーションや運用手順の改善を約束した。Folkman氏によれば、

私たちは人為的な機能低下のような、このような状況を促してしまうことを引き続き探しています。これからも高負荷がかかる場合が何度もあるかも知れません。そういうときには、サイト全体がダウンするのではなく、特定の機能が停止する方がいいのは明らかです。


Harry Heymann氏は次のように書いている。

全体としては、私たちはまだfoursquareのMongoDBのファンであり続けていますし、これからも長くMongoDBを使っていけることを期待しています。

 

コミュニティの反応

この事後検証に対していくつかの疑問があがった。

  1. Nat氏は以下のように尋ねた。
    repairDatabase()はマルチコアで利用できますか。 データがチャンクに分かれると仮定すると、平行してチャンクを処理することはできますか。インターネットの世界で4時間の機能停止は永遠に機能停止しているのと同じように感じられます。

    Horowitz氏はこれに答えて、
    今はできません。しかし現在、バックグラウンドでデータの圧縮ができるようにすることに取り組んでいまので
    将来的には全体をオフラインにして圧縮する必要は
    なくなります。
  2. Alex Popescu氏は下記のように尋ねた。
    チャンクの移行やページサイズの問題に対する本当の解決策はありますか。

    Horowitz氏はこれに答えて、
        はい、この問題を和らげるためにオンラインで圧縮できるようにすることに取り組んでいます。
  3. Suhail Doshi氏は下記のように尋ねた。
     思うに、最も明白な論点は、MongoDBのノードが容量を超えてしまうのをどうやって回避するか、
    そして新しいノードを増やす時がいつなのかをどうかって知るか、ということでしょう。
    すべてを監視しているという前提の場合、
    何を調べればいいのか、どう見分ければいいのか。もしスケールの変更をたくさん行う必要があるサービスやそのような特性のあるサービスを
     運営する企業に務めていたら何が起こるでしょう。...スタートアップにとって容量の計画を
     するのは難しいことです。

    Horowitz氏はこれに答えて、
    これはアプリケーションにとても依存します。すべてのインデックスをRAM上に持つ必要がある場合もあれば、
    小さなワーキングセットで済む場合もあります。
    これを決める良い方法のひとつは、10分間にどのくらいの量のデータを確定させるか
    見積もることです。インデックスもドキュメントも同じです。ただし、メモリ上にデータを保持することもディスクから読み出すのも
    同じくらいの時間でできるように
    しておく必要があります。
  4. Nat氏はバックプレッシャーについても質問した。"データがメモリの大きさより大きくなると、この性能も著しく劣化すると思います。"

    Roger Binns氏はこれに付け加えて、
    MongoDBに必要なのは負荷がかかったときに並列処理を減らすことです。
    そうすれば、新しい問い合わせが火に油を注ぐ前に実行している問い合わせを完了させられます。
    下記がこの問題のチケットです。
      http://jira.mongodb.org/browse/SERVER-574


また、ソリッドステートドライブを利用したら性能改善に寄与したかどうかについての議論もあったが、ソリッドステートドライブがどのように性能向上に役に立ったかもしれないのかについて納得のいく説明はなかった。また、ユーザIDでの分割でなぜこのようなデータの不均衡が発生したのか疑問視する声もある。ユーザIDの数は、おそらくほとんど均等に分割されていただろう。したがって、何らかの偏り(例えば、古いユーザが片方のシャードに偏っていた)がデータの不均衡な増加を引き起こしたようだ。

監視とこれからの方針

私たちは10genのCEOであるDwight Merriman氏にインタビューをして、本件についてさらに詳細を聞いた。一般的に巨大なMongoDBを監視するのに最良の方法は何かという問いに対して、多くの監視ツールがあるが、Muninが一般的に使われていてこれにはMongoDB用のプラグインもある、と氏は答えた。また、私たちは次のように尋ねた。

これまでの説明を踏まえると、メモリの不足を検知するためにMongoDBのプロセスが利用しているメモリを監視することはできるはずですが、これは実現可能ですか。

もしデータベースがRAMより大きければ、他のデータベースと同じようにMongoDBはすべてのメモリをキャッシュとして利用しようとします。なのですべてのメモリを使ってしまうことは問題ではありません。むしろ、データベースのワーキングセットがRAMの大きさに近づいていることを検知する必要があります。これはデータベースにとっては難しいことです。ひとつの良い方法は綿密に物理I/Oの増加を監視することです。

氏は、Foursquareの場合は、すべてのデータベースをRAM上に持たせる必要があるので、事前に問題を検知するためには消費メモリかデータベース全体の大きさを監視すれば十分だということを認めた。このことがほのめかすのは、シャードが満杯になってしまう前に問題を見つけるのはかなり簡単だっただろうということだ。だれもデータの不均衡な増加を想定していなかったので、どんな監視を設定したとしても問題を見つけるには不十分だっただろう。

また私たちは、この件を踏まえて開発の優先順にどんな変更があるかを尋ねた。氏はバックグラウンドでのデータの圧縮を可能にすることをすぐに行う予定だと答えた。加えて、Horowitz氏は、MongoDBは"もっと優雅に機能低下するべきだと思います。このあたりの強化もすぐに行う予定です。"と書いた。また、Dwight Merriman氏が言うには、将来的にオブジェクトを再クラスタリングすることで利用していないオブジェクトをディスク上のページに押し出すことができるようになる。そして氏の考えでは、これを実現するためにはメモリマップドファイルが有効だ。Horowitz氏は次のように詳述している。

真の最大の問題は同時並行性です。仮想メモリ側がうまく動作しても、読み込み-書き込みのロックの大きさが粗くなりすぎてしまうのが問題です。
ひとつのスレッドが失敗すると、それが想定以上に大きな性能劣化になります。私たちはこの問題を、処理をより知的にすることや本当の内部コレクションを利用した並列処理にすることで対処するつもりです。

この記事に星をつける

おすすめ度
スタイル

BT