Yii2のDB Connectionはmaster slaveを切り替えてくれる

Yii2アドベントカレンダー2014の23日目に無謀にも挑戦させてもらいました拙ブログですが

Qiitaじゃなくていいのかなと思いつつこちらに書かせてもらいます。

Yii2って?

他の方々が充分説明してくれているので簡単にご紹介を。

フレームワークが群雄割拠の様相を呈しているPHPですがYiiがその中の一つになります。

そのYiiの進化版がYii2ってわけです。

1の頃からかなり便利だったYiiですが2になってもっと便利に。

データベースの負荷分散について

言語に関わらずWEBアプリケーションの開発に携わっている人なら少なからず経験があるはず。

データベースの負荷が下がらない

これです。

アプリケーション側での発行SQLの見直しやデータベーステーブルのINDEX最適化、

重い処理は定期実行にする等色んな対策はあるとして

アクセスが増えて負荷が上がっている

そんな嬉しい悲鳴な時も大いにあるわけです。

いくらチューニングしても単純に今の負荷にサーバースペックが追いつかない場合はもうサーバーを増強とかするしか無い状態に。

データベースを増強する

一言に増強と言っても単にスペックを上げたサーバーに置き換える方法もありますが

第一の策として割とお手軽に導入しやすいのが

データベースをmasterとslaveの2台(以上)構成にする

この方法が比較的コストも少なく抑えられ、採用されやすい方法ですな。

masterとslave2台(以上)構成にするのは具体的に言うと

  • master 更新を行うデータベース
  • slave 参照を行うデータベース

の二種類に分けて、masterへ書き込みや更新が行われたら、その内容を

slaveへ同期し、参照はそのslaveへ対して行うことで負荷を分散する構成になります。

一般的なアプリケーションの場合、データベースへの接続は書き込みより読み込みの方が

圧倒的に多いので読み込み用データベースのslave増やすことで更に負荷に対応するなんて事も。

アプリケーション側での変更が必要

データベース的にはmasterとslaveを分けることで負荷分散できたバンザーイ(゚∀゚)

で済むけどアプリケーション側はそうもいかない。

既存のアプリケーションの更新系の処理と参照系の処理に分類して…

そいつらのデータベース接続を全部masterとslaveに分けて…

と、やらなければいかん事がいっぱい。

Yii2なら更新と参照でDB接続を切り替えてくれる

これです。

やっと本題。

さっき書いたmasterとslaveの処理変更をYii2側で設定しておけば

発行されるSQLから判定して自動で振り分けてくれると!

なんて便利、素敵。

ドキュメントとしては こちらの Replication and Read-Write Splitting の項目から

まずはmasterとslaveの接続先を設定

[
    'class' => 'yii\db\Connection',

    // masterの設定
    'dsn' => 'dsn for master server',
    'username' => 'master',
    'password' => '',

    // slaveの設定
    'slaveConfig' => [
        'username' => 'slave',
        'password' => '',
        'attributes' => [
            // use a smaller connection timeout
            PDO::ATTR_TIMEOUT => 10,
        ],
    ],

    // slaveを複数設定
    'slaves' => [
        ['dsn' => 'dsn for slave server 1'],
        ['dsn' => 'dsn for slave server 2'],
        ['dsn' => 'dsn for slave server 3'],
        ['dsn' => 'dsn for slave server 4'],
    ],
]

そうするとこんな感じにSQLの内容からmasterとslaveを振り分けてくれると。

// DB接続を設定
$db = Yii::createObject($config);

// このSELECTクエリはslaveに
$rows = $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();

// このUPDATEクエリはmasterに
$db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();

ただそうなると気になるのがトランザクション。

// トランザクションをmasterに対して開始
$transaction = $db->beginTransaction();

try {
    // SELECTも含めてmasterにクエリを発行
    $rows = $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
    $db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();

    $transaction->commit();
} catch(\Exception $e) {
    $transaction->rollBack();
    throw $e;
}

トランザクションを開始するとデフォルトはちゃんと全てのクエリがmasterに。

ちゃうねん今はslaveにトランザクションしたいねんって時は明示的にslaveに対してトランザクションをする。

$transaction = $db->slave->beginTransaction();

masterとslaveが完全同期じゃない場合とかでmasterを参照したい場合はこんな感じ

$rows = $db->useMaster(function ($db) {
    return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
});

それかslaveを無効にする

$db->enableSlaves = false;

とまぁ細かいところも至れり尽くせりで。

これがもっと前にあったらあの時の炎上は無かったのになぁ…

なんて人も多そうな。

まとめ

まぁ何しか、Yiiは( ・∀・)イイ!! ってことです。

本当に「気が効いている」フレームワークな印象。

それがさらにYii2になってパワーアップ。

さらに便利で気持ち良いコードが書けるように。

Yii「どうせお前らこんな機能欲しかったんやろー用意しといたったでー」

自分「くやしい!でも使っちゃう!」

ってな脳内会話がされることもしばしば。

Yiiは日本語の情報が少ないせいか、なかなか国内での採用は少ないですが(1のドキュメントはほぼ日本語訳されてる)

こんな( ・∀・)イイ!!ものはどんどん使っていきましょうー

コメントを残す

メールアドレスが公開されることはありません。