MongoDB運用に役立つヒント集:パート1
本記事はTricoreが2017年8月2日に公開した記事をもとにしています。
MongoDBは導入のハードルが低く、手軽に使い始められるデータベースです。しかし、実際にアプリケーションを構築し始めると、より複雑な課題に直面することが少なくありません。たとえば、次のような疑問が浮かぶかもしれません。
- レプリカセット内のメンバーを再同期するにはどうすればよいのか?
- クラッシュ後にMongoDBを復旧させるには?
- ファイルの保存・取得にGridFSを使うべきケースはいつか?
- 破損したデータはどうやって修復するのか?
この記事では、MongoDBを使用する際にこうした状況へ対処するための実用的なヒントを紹介します。
ヒント1:データ復旧をrepairコマンドだけに頼らない
データベースがクラッシュし、かつ--journalオプションを付けて運用していなかった場合、そのサーバー上のデータは使用しないでください。
MongoDBのrepairコマンドは、見つけたすべてのドキュメントを走査し、クリーンなコピーを作成します。ただし、この処理には次のような注意点があります。
- 処理に時間がかかる
- 現在使用中と同等のディスク容量が必要になる
- 破損したレコードはスキップされる
さらに、MongoDBのレプリケーション機能では破損したデータを修復できないため、再同期を行う前に、破損している可能性のあるデータを必ず削除しておく必要があります。
ヒント2:レプリカセットメンバーを再同期する
レプリカセットのメンバーを再同期するには、まずセカンダリメンバーとプライマリメンバーがそれぞれ少なくとも1つ、稼働していることを確認します。続いて、Oracleユーザーとしてログインし、MongoDBサービスを停止します。
次に、mongodbユーザーとしてログインし、バックアップフォルダへすべてのデータファイルを移動します。これは問題発生時に復元できるようにするためです。バックアップフォルダに古いファイルが残っている場合は削除して構いません。データファイルの場所がわからない場合は、/etc/mongod.confを確認してください。その後、OracleユーザーとしてMongoDBサービスを起動します。
データベースにログインして状態を検証しましょう。メンバーがレプリカセットに同期されるまでの間は、認証なしでデータベースへアクセスできます。
レプリケーション処理が完了すると、ステータスはSTARTUP2からSECONDARYへと変化します。
ヒント3:小さなバイナリデータにGridFSを使わない
MongoDBは、大きなファイルの保存と取得のためにGridFS仕様を採用しています。GridFSは、大きなバイナリオブジェクトを分割してからデータベースに格納する仕組みです。GridFSでは2つのクエリが必要になります。1つはファイルのメタデータを取得するためのもので、もう1つは中身(コンテンツ)を取得するためのものです。そのため、小さなファイルの保存にGridFSを使うと、アプリケーションが発行するクエリ数が倍になってしまいます。

出典:https://www.slideshare.net
GridFSは、1つのドキュメントには収まりきらないほど大きなデータを保存するために設計されています。目安として、クライアント側で読み込むには大きすぎるデータは、サーバーに一括で読み込むべきではないデータでもあります。代わりの手段はストリーミングです。クライアントへストリーミング配信する予定のデータは、GridFSに適した候補といえます。
ヒント4:ディスクアクセスを最小限に抑える
開発者なら誰でも、RAMからのデータアクセスは高速で、ディスクからのアクセスは低速だと知っています。
ディスクアクセス回数を減らすことが優れた最適化手法であることはご存じかもしれませんが、具体的にどう実現すればよいのか分からない方も多いのではないでしょうか。
1つ目の方法は、ソリッドステートドライブ(SSD)を使うことです。SSDは従来のハードディスクドライブ(HDD)よりも多くのタスクをはるかに高速に処理でき、MongoDBとも非常に相性が良いです。一方で、SSDは容量が小さく価格も高くなりがちです。
次の画像は、SSDとHDDを比較したものです。

出典:https://www.serverintellect.com
ディスクアクセスを減らすもう1つの方法は、RAMを増設することです。ただし、このアプローチにも限界があります。いずれデータ量がRAMの容量を超えてしまうからです。
問題は、テラバイトやペタバイト級のデータをディスク上に保存しながら、アプリケーションが頻繁に要求されるデータには主にメモリ上でアクセスし、ディスクからメモリへのデータ移動をできるだけ少なくするには、どうすればよいかということです。
もしすべてのデータにリアルタイムでランダムにアクセスするのであれば、答えは「大量のRAMが必要」となります。しかし、ほとんどのアプリケーションはそのようには動作しません。新しいデータは古いデータよりも頻繁にアクセスされ、特定のユーザーは他よりも活発で、特定の地域には他よりも多くの顧客が存在します。こうした特性を持つアプリケーションであれば、特定のドキュメントをメモリに保持し、ディスクへのアクセスを極力減らすように設計できます。
ヒント5:クラッシュ後は通常の手順でMongoDBを起動する
ジャーナリングを有効にしていて、システムが復旧可能な形でクラッシュした場合は、通常どおりデータベースを再起動できます。普段使っているオプションをすべて指定してください。特に、ジャーナルファイルを見つけられるように--dbpathを、そして--journalを忘れずに付けましょう。
MongoDBは接続を受け付ける前に、自動的にデータを修復します。大規模なデータセットでは数分かかることもありますが、大規模データに対してrepairを実行する場合と比べれば、はるかに短時間で済みます。
ジャーナルファイルはjournalディレクトリに保存されます。これらのファイルは絶対に削除しないでください。
ヒント6:repairコマンドでデータベースをコンパクト化する
repairコマンドは、端的に言えばmongodumpを実行してからmongorestoreを行うのと同じことで、データのクリーンなコピーを作成します。この過程で、データファイル内の空き領域(「穴」)も取り除かれます。
repairコマンドは処理中に操作をブロックし、現在のデータベースの2倍のディスク容量を必要とします。ただし、別のマシンが利用できるのであれば、mongodumpとmongorestoreを使って同じ処理を手動で行うこともできます。
手動で行う場合は、以下の手順に従ってください。
-
Hyd1マシンをステップダウンさせ、fsyncとlockを実行します。
rs.stepDown() db.runCommand({fsync : 1, lock : 1}) -
Hyd2へファイルをダンプします。
Hyd2$ mongodump --host Hyd1 -
Hyd1のデータファイルのコピーを取り、バックアップとして残します。その後、元のデータファイルを削除し、空のデータ状態でHyd1を再起動します。
-
Hyd2からリストアします。データファイルを復元するには、次のコマンドを入力します。
Hyd2$ mongorestore --host Hyd1 --port 10000 # specify port if it's not 27017
まとめ
これらの改善によって、MongoDBのパフォーマンスは大幅に向上しました。MongoDBの利用を検討している方は、この記事をブックマークしておき、次に新規プロジェクトを始める際に各ヒントを一つずつ確認してみてください。
全2部構成のシリーズ第2部では、大規模企業がMongoDBの有用な機能を適切に設計、最適化、実装するためのヒントを紹介します。
コメントやご質問がある場合は、フィードバックタブをご利用ください。
-
MongoDBのスケーリング手法:シャーディングインフラの構築ガイド
前回のブログ記事では、MongoDBのスケーリングが「いつ」必要になるのかについて解説しました。今回は、MongoDBを「どのように」スケーリングするかに焦点を当てていきます。MongoDB 3.0では、WiredTigerがデフォルトのストレージエンジンとして導入されました。これにより、MongoDBはスケーラビリティに関して2つのアプローチを提供できるようになりました。すなわち、垂直スケーリング(スケールアップ)と水平スケーリング(スケールアウト)です。それぞれのアプローチについて詳しく見ていきましょう。垂直スケーリング(スケールアップ)とは垂直スケーリングは、CPUの数や種類、RAM容量
-
MongoDBのディスク使用量を理解する――領域割り当ての仕組みと最適化の判断基準
はじめにMongoDBを使い始めたばかりの方にとって、そのディスク(スペース)使用量は一見すると分かりにくいものです。本記事では、MongoDBがどのようにディスク領域を割り当てるのか、そしてObjectRocketダッシュボードに表示される使用量情報をどう読み解けばよいのかを解説します。これにより、インスタンスのコンパクション(最適化)が必要なタイミングや、シャードを追加して利用可能領域を拡張すべきタイミングを適切に判断できるようになります。検証環境:5GBシングルシャードのMediumインスタンスまず、5GBのシャード1つで構成された真っさらなMediumインスタンスを用意します。このイン