MongoDB 2.2 およびドライバのバージョン 1.3.0 以降では » 優先読み込み をサポートします。これを使えば、レプリカセット環境内でクエリを mongod インスタンスに振り分ける方法を制御できます。 優先読み込みは接続ごとに指定することもできるし、 データベース単位やコレクション単位でも指定できます。 上位で設定された優先順位がデフォルトで引き継がれます (たとえば、MongoCollection の優先読み込み設定は、それに対応する MongoDB インスタンスでの定義を引き継ぎます)。
優先読み込みの指定は、モードとタグセットの組み合わせで行います。 mongod インスタンスの優先順位をどのように決めるのかを指定するのがモードで、 ふさわしい mongod インスタンスの条件を指定するのが » タグセット です。 mongod のインスタンスがそれにふさわしいと認められるのは、直近の mongod インスタンスからの ping 時間が 15ms 以内に収まるときだけです。
MongoClient::RP_PRIMARY 以外のすべての優先読み込みモードは、 古いデータを返す可能性があります。 セカンダリがプライマリの操作を受け取るにはある程度時間がかかるからです。 MongoClient::RP_PRIMARY 以外のモードを選ぶ場合は、 最新のデータではなくてもアプリケーションがうまく動くように作っておかないといけません。
MongoClient::RP_PRIMARY
すべての読み込み操作で、現在のレプリカセットのプライマリだけを使います。 これがデフォルト設定です。プライマリが使えないときは、読み込み操作で例外が発生します。
このモードを選ぶとタグセットは使えません。 MongoClient::RP_PRIMARY のときにタグセットを指定すると、例外が発生します。
MongoClient::RP_PRIMARY_PREFERRED
大半の場合は、読み込み操作をレプリカセットのプライマリから行います。 しかし、もしプライマリが使えない場合 (たとえばフェイルオーバー中の場合など) は、セカンダリのメンバーから読み込みます。
優先読み込みにタグセットが含まれる場合、 クライアントはまずはプライマリから読み込みます。 そして、指定したタグにマッチするセカンダリから読み込みます。 タグにマッチするセカンダリがない場合は、読み込み操作で例外が発生します。
mongos のバージョン 2.2 で、優先読み込みを完全にサポートするようになりました。 それより古いバージョンの mongos インスタンスに接続するときは、 MongoClient::RP_PRIMARY_PREFERRED はクエリをセカンダリに送信します。
MongoClient::RP_SECONDARY
読み込み操作で、レプリカセットのセカンダリだけを使います。 もし使えるセカンダリがない場合は、読み込み操作で例外が発生します。
ほとんどのレプリカセットには少なくとも一つのセカンダリがありますが、 場合によっては、使えるセカンダリが一つもないこともあります。 たとえばプライマリとセカンダリがそれぞれ一つずつで、 どちらかがリカバリ状態や使えない場合のセカンダリをアービターが持っていない場合です。
優先読み込みにタグセットが含まれる場合、 クライアントは指定したタグにマッチするセカンダリを探します。 そして、一番近いグループのセカンダリの中からランダムに直接読み込みを行います。 タグにマッチするセカンダリがない場合は、読み込み操作で例外が発生します。
MongoClient::RP_SECONDARY_PREFERRED
大半の場合は、読み込み操作をレプリカセットのセカンダリから行います。 しかし、もしプライマリだけしかメンバーが存在しない場合は、 プライマリから読み込みます。
優先読み込みにタグセットが含まれる場合、 クライアントは指定したタグにマッチするセカンダリを探します。 そして、一番近いグループのセカンダリの中からランダムに直接読み込みを行います。 タグにマッチするセカンダリがない場合は、読み込み操作で例外が発生します。
MongoClient::RP_NEAREST
ドライバは、ping 時間が最短のメンバーからの遅延が 15ms 以内に収まるメンバーの中から ランダムに 選び、そのメンバーから読み込みます。 MongoClient::RP_NEAREST モードでの読み込みは メンバーの型を意識しないので、プライマリから読まれることもあればセカンダリから読まれることもあります。
このモードにしておくと、読み込み操作のネットワークレイテンシーを最小化できます。 現在のデータと古いデータのどちらを優先するかは設定しません。
タグセットを指定した場合、 クライアントは指定したタグにマッチするメンバーを探します。 そして、一番近いグループのノードの中からランダムに直接読み込みを行います。
注意:
すべての読み込み操作は、指定した優先読み込みモードにマッチするレプリカセットの 一番近いメンバーから行います。 MongoClient::RP_NEAREST モードは、 メンバーがプライマリであるかセカンダリであるかは無視してレイテンシーの低い読み込みを行います。
» タグセット を使うと、カスタムパラメータに基づいて読み込み操作の対象を特定のメンバーに絞り込めます。 タグセットでは、読み込み操作の対象となるメンバーを特定のデータセンターに絞り込んだり、 レポーティングや分析など操作種別ごとにその対象の mongod インスタンスを絞り込んだりできます。
タグセットを指定できるのは、優先読み込みが次のモードの場合です。
MongoClient::RP_PRIMARY_PREFERRED
MongoClient::RP_SECONDARY
MongoClient::RP_SECONDARY_PREFERRED
MongoClient::RP_NEAREST
優先読み込みモードが MongoClient::RP_PRIMARY の場合はタグセットを指定できません。 タグを適用できるのはセカンダリメンバーを選ぶときだけ (ただし、NEAREST モードのときは例外) です。
優先読み込みの設定方法は二通りあります。一つは MongoClient::__construct() に渡す接続 URI で指定する方法で、 このときはクエリ文字列の構文を使います。もうひとつはコアクラスのセッターメソッド群を使う方法で、 このときはタグセット用の配列構文を使います。
優先読み込みモードをクエリ文字列で指定する場合、 readPreferenceTags の値用のタグセットは、 コロンで区切ったキー/値のペアをカンマでつなげた形式になります。
注意:
クエリ文字列内で定義するタグセットには readPreferenceTags という名前を使います。 PHP が URL のクエリ文字列を処理するときとは違って、 readPreferenceTags を複数回指定したとしても上書きされることはありません。 クエリ文字列の中で登場した順に、ドライバがすべてのタグセットをとりまとめます。
マッチするタグセットをドライバが見つけられない場合は、読み込みが失敗します! 適切な代替策を用意しておくのはプログラマの役割です。たとえば readPreferenceTags の値が空なら "no tag set preference" を使うなどです。
例1 接続 URI でのクエリ文字列構文による優先読み込みの設定
<?php
// 一番近いサーバーを優先し、タグは設定しません
$uri = 'mongodb://rs1.example.com,rs2.example.com/';
$uri .= '?readPreference=nearest';
$m = new MongoClient($uri, array('replicaSet' => 'rs'));
// "east" データセンターの一番近いサーバーを選びます
$uri = 'mongodb://rs1.example.com,rs2.example.com/';
$uri .= '?readPreference=nearest';
$uri .= '&readPreferenceTags=dc:east';
$m = new MongoClient($uri, array('replicaSet' => 'rs'));
// "east" データセンターの一番近いサーバーを選び、レポーティング用に使います
// 代替サーバーとして、"west" データセンターのサーバーを使います
$uri = 'mongodb://rs1.example.com,rs2.example.com/';
$uri .= '?readPreference=nearest';
$uri .= '&readPreferenceTags=dc:east,use:reporting';
$uri .= '&readPreferenceTags=dc:west';
$m = new MongoClient($uri, array('replicaSet' => 'rs'));
// "east" データセンターの一番近いサーバーを優先し、
// 代替サーバーとして、"west" データセンターのサーバーを使います。
// それもだめな場合は、タグセットの設定をせずに接続します。
$uri = 'mongodb://rs1.example.com,rs2.example.com/';
$uri .= '?readPreference=nearest';
$uri .= '&readPreferenceTags=dc:east';
$uri .= '&readPreferenceTags=dc:west';
$uri .= '&readPreferenceTags=';
$m = new MongoClient($uri, array('replicaSet' => 'rs'));
?>
例2 タグセット用の配列構文による優先読み込みの設定
<?php
$m = new MongoClient('mongodb://rs1.example.com,rs2.example.com', array(
'replicaSet' => 'rs',
));
// 一番近いサーバーを優先し、タグは設定しません
$m->setReadPreference(MongoClient::RP_NEAREST, array());
// "east" データセンターの一番近いサーバーを優先します
$m->setReadPreference(MongoClient::RP_NEAREST, array(
array('dc' => 'east'),
));
// "east" データセンターの一番近いサーバーを優先し、レポーティング用に使います
// 代替サーバーとして、"west" データセンターのサーバーを使います
$m->setReadPreference(MongoClient::RP_NEAREST, array(
array('dc' => 'east', 'use' => 'reporting'),
array('dc' => 'west'),
));
// "east" データセンターの一番近いサーバーを優先し、
// 代替サーバーとして、"west" データセンターのサーバーを使います。
// それもだめな場合は、タグセットの設定をせずに接続します。
$m->setReadPreference(MongoClient::RP_NEAREST, array(
array('dc' => 'east'),
array('dc' => 'west'),
array(),
));
?>