概要
本連載では第4回ではレプリケーション、第5回ではシャーディングについて説明してきましたが、今回はレプリケーションとシャーディングを組み合わせた構成について紹介します。この構成を取ることにより、データを冗長化させつつも、分割して配置することができるため、可用性と読み取り性能を両方向上させることができます。
前回のシャーディングの構成では、単一のmongodをシャーディングサーバに割り当てていましたので、その1つのmongodが障害になると、シャーディングの機能が停止してしまうという問題がありました(図1参照)。
これを解決するために、シャーディングサーバに単一のmongodではなくレプリカセットを割り当てます。これによりレプリカセット内のmongodに障害が発生してもシャーディングの機能が停止しない構成にすることができます(図2参照)。
さらに信頼性を高めたい場合は、configサーバを冗長化することができます。configサーバの冗長化は、レプリカセットの非同期レプリケーションとは違い、2フェーズコミットによる同期レプリケーションになります。詳しくはdocs.mongodb.org/manual/administration/sharded-clusters/#config-servers>公式マニュアルを参照ください。
続いて、実際にレプリケーションとシャーディングを組み合わせた構成を作っていきます。
実際に構築する
構築する構成
今回は4台のサーバを使ってレプリカセットとシャーディングを組み合わせた構成を作ります。具体的には、3つのレプリカセットrs0,rs1,rs2をシャードサーバに割り当て、シャーディングを行います。また、レプリカセットを構成するmongodはそれぞれ別のサーバ(サーバA、サーバB、サーバC)上で動作させます。さらにサーバごとにプライマリが1つになるようにします。
configサーバとmongosサーバはフロントサーバ上で動作させます。configサーバの冗長化は行いません。ですので今回は4つのサーバを用います。
4つのサーバが用意できない場合は、1つのサーバで作ることも可能です。全てポートが分かれているためです。その場合、各サーバのIPアドレスを設定する箇所を変更してください。
準備
まず全てのサーバに同じバージョンのMongoDBをダウンロードし展開しておきます。また、dataディレクトリとlogディレクトリを作成します。
レプリカセットの作成
最初に、レプリカセットrs0を作ります。各サーバで以下のコマンドを実行し、mongodを起動してください。ポイントは--replSetオプションでレプリカセットを指定する点です。
[注意]
1つのmongodでジャーナルファイルに3G程度のディスク容量が必要です。試しに使うだけでディスク容量を節約したい場合は、ジャーナルは必要ないので、--nojournalオプションを追加してジャーナルの機能を止めてください。
次にサーバAにてレプリケーションの設定を行います。サーバAにて設定を行うのはサーバAをプライマリにするためです。
[注意]
IPアドレスは、1つのレプリカセット内でループバックインターフェース(localhostや127.0.0.1)とネットワークインターフェースを混在させることはできません。つまり(サーバAのIP)の部分は、サーバAのネットワークインターフェースのIPアドレスにしてください。
続いて、レプリカセットrs1を同様に作成していきます。
まずmongodを起動します。
続いてレプリケーションを設定しますが、今度はサーバBをプライマリにするためサーバBのmongoシェルで作業します。
最後に、レプリカセットrs2を同様に作成していきます。
まずmongodを起動します。
続いてレプリケーションを設定を行いますが、今度はサーバCにて作業を実施します。
シャーディングの設定
いよいよ、レプリカセットをシャードサーバに割り当てて、シャーディングを構成していきます。まずフロントサーバにて、configサーバとmongosを起動します。この手順は前回の記事の手順と同じですので、詳しい解説は前回をご覧ください。
[注意]
チャンクサイズを1に設定しているのは、シャーディングの動作を確認しやすくするためです。実運用ではシステムの要件に合わせた値に設定してください。
続いて、mongosサーバにmongoシェルで接続して、シャードサーバを追加してきます。mongodを単体で登録する場合とは違い、レプリカセットを登録します。
最後にデータを投入し、そのデータに対してシャーディングを有効にします。この手順も前回の記事の手順と同じです。
次は実際にサーバ障害を発生させ、挙動を観察します。
障害時の動作実験
これまでの作業で、シャーディング構成はできていますが、ここでは障害を発生させ、処理を続けられるか確認します。
まず、以下のコマンドによりクライアント相当の簡単なプログラムを動かします。
このコマンドは2秒に1回logdbデータベースのlogsコレクション数をカウントしているので、ずっと10000が表示されているはずです。このコマンドはmongoシェルの--evalオプションを用いて、DBの中身をカウントするコマンドを実行し、それをwatchコマンドにより2秒に1回実行しています。
この状態でサーバCの障害を想定して、サーバCのmongodをすべて落としてください(より本格的にやりたい人はサーバCの電源を落としても良いですw)。
するとどうでしょうか? フロントサーバのdb.logs.count()コマンドは、フェイルオーバー中は失敗するもの、数秒のうちにフェイルオーバーが完了し、その後は成功すると思います。現時点でのシステムの状態を確認してみましょう。
まずシャーディングの状況ですが、以下のコマンドで確認します。
見てわかるように、シャーディングの状況は何ひとつ変わっていません。mongosからはレプリカセットしか管理していないため、各mongodの状態までは管理していません。
続いてレプリカセットの状況確認です。
おそらく、サーバAかサーバBのどちらかがプライマリになっていると思います。また、サーバCは"(not reachable/healthy)"と表示されていると思います。
次回のテーマ
今回はレプリケーションとシャーディングを組み合わせた構成について紹介しました。本構成を用いることで、可用性と読み取り性能を両方向上させることができます。
次回の記事ではMonogoDBでサイズの大きなファイルを扱う機能である、GridFSについて紹介する予定です。