Hatena::ブログ(Diary)

LinuxとApacheの憂鬱 このページをアンテナに追加 RSSフィード

最初はApacheネタで行くつもりが、最近は何でも有りになってきた。
うっかりソフトの世界に来てしまったエンジニアの苦悩・・・

2013-05-20

MongoDBが適さないケース

| 11:37 | MongoDBが適さないケースを含むブックマーク MongoDBが適さないケースのブックマークコメント

> 原文(Why MongoDB is a bad choice for storing our scraped data)

私自身はMongoDBを推進する立場なのだが、確かにMongoDBに適さないケースはある。

闇雲に推進しても結局は全員がアンハッピーになるので、この様なネタもどんどん紹介していこうと思う。

この記事はMongoDBを徹底的に使い尽くしたエンジニアが書いている様で状況が良く解った。

ちょっと難しい所もあるので要点を意訳して、軽く解説を書いてみる。

(もちろん是非原文で読むのをお勧めする)

状況

最初はMongoDBでうまく動いていたが、だんだん苦労が増えてきて

元々のアーキテクチャを刷新するタイミングでMongoDBから別のプロダクトに乗り換える事にした。

システムの規模

詳しく書かれていないが、1ノード辺り数TBとあるのでSharding環境ではないかと思われる。
が、、この手のデータでShardingは難しいのでやってないかもしれない。

ドキュメント

色々なドキュメントを扱っていそうだが、メインは(階層構造が有り得る)小さなクロールログデータを大量に扱う。

データ構造は事前予測不能。

クエリー

PV単位での参照の様な短いクエリーと、ある程度時間を要するクエリー(一括export/delete,フィルタリング,ソートなど)がある。

問題

ロック

MongoDB 2.2以前はReaders-Writerロックなので、長いクエリーが走ったその瞬間から、短いクエリーもロックされる。

WebからのPVを捌く様なシステムの場合、一瞬でもロックが走れば、WEBサーバ上の全てワーカースレッドが潰されてサイトがダウンする。

この為、色々やった

  • MongoDBドライバーを弄りタイムアウトとリトライを上手いことする様にした。(私もやった)
  • 自前でバックエンドストレージを用意してデータを同期。長いクエリーはそちらで実行。
  • データベースを分け、ロックし難いようにする。
  • 高性能サーバに変更。(分散システムのうま味が・・・)
  • 遅延機能?jobでも実装したのだろうか?(Delayed implementing (or disabled) features that need to access a lot of fresh data)
ディスク領域が非効率

これはpaddingFactorの問題(MongoDB 2.4 の性能 徹底評価 - 全件(relocation)1カラムアップデート -でも触れている)をまともに食らったのだろう。

ドキュメントを事前予測できないならば仕方がない。

『ドキュメントを事前予測できない事』

 これこそがMongoDBに適さない最大の理由だろう。

大量のデータベース

結果的に管理しきれない程の大量のデータベースを作る事になった。

またmongodをリスタートする際のチェック時間も膨大になった。

データをソート

大量のデータをソートして出力するのは非現実的だ。

MongoDBで順番を保持できるのは、capped collectionだけだが、これはクロールログには適さない。


実はかなり核心をついた部分だ

性能面
MongoDB 2.4 の性能 徹底評価(レコード長による評価)- シーケンシャルFETCH性能 -で述べたとおり、MongoDBは(特に小さなデータ程)シーケンシャルアクセスしないと性能が出ない
capped collection
性能面、ソートなどは解決できるがアップデート出来ないなど、使い難い
データ順序面
in-placeアップデートを保証できなければ入れた順番は保持されない
ソート
かといって大量データのソートは非現実的

しかしMongoDBに限らず殆どどんなシステムでも結局辛い。MongoDBはロック問題がこれを深刻にしていた(2.2以前)。

このソート問題、私ならPV系はインデックスに頼って、集計系はMongoHadoopで逃がすかもしれない。

Skip + Limitが遅い

そりゃ当然遅いよね・・・
カーソル処理とはいえ、大量の読み飛ばしはキツイ。
こんなの上手く処理できるシステムあるのか??

フィールド名の制限

MongoDBのフィールド名には、dot(.)とdollar($)が使えない。

私もついウッカリやってしまう

メモリー制御

MongoDBはメモリー制御に関する機能を提供していない。

頻繁にアクセスするデータが解っているのに、メモリーから追い出されてしまう。

これは私も不満。
MongoDBは『なるべく自動化しユーザに複雑な制御を求めない』という哲学があるっぽくて
この手のオプションを追加するパッチを作っても受け入れて貰えない。
結局mmapの動きを読んでなんとかするしかない。

データ整合性の問題色々
トランザクション
無いからコードが複雑化する
エラーが取りにくい
例えば存在しないコレクションにinsertしてもエラーにならない。だから余計にコードが複雑化する。
(その通り!不満!!)
Safeモード
Trueじゃない場合の動作がヤバい。
(この辺りはwrite concern使うのが筋かな。。)
スキーマレスの弊害
バグの検知が難しい
(まあ仕方がないね)
ジョブが無い
非正規化データを扱うのにトリガーやトランザクションが無いのはツライ。
(確かに)

まとめ

MongoDBでクロールデータを扱っても巧く行くケースはある。実際我々は暫く使ってきた。

しかしココで述べた様に最早我々の要件には合わなくなった。

(最終的にはhBase Cassandraにした模様)

私自身の見解

同じくログデータはMongoDBでは扱わないだろう。

既に述べられてる事の中では特に、ソートの問題が厳しく、更に時系列データは根本的にShardingに向かない。

カラムベースのCassandraはこの辺りに確かに向いているので、私もそちらに一票。

xx 2014/04/17 00:26 原文読んでませんが、"Delayed implementing (or disabled) features that need to access a lot of fresh data" は「遅延機能」ではなく、「大量の新しいデータにアクセスする必要のあるいくつかの機能の実装を延期したり、あるいは無効にしたりした」ではないでしょうか。