冗長化

nullpopopo_sakura人知れずこっそりとこのサイトをさくらのVPS HDDプラン(2G) 1台からさくらのVPS SSDプラン (2G) 2台へ移行しました。もともとnginxでメモリキャッシュを効かせたり、DBもクエリキャッシュを効かせたりしていたのですが、SSDにしたらnginxのキャッシュをメモリに持たせなくてもよいのでは?という安直な理由で乗り換えてみました。

結果、当然表示が速くなったのと、今まで以上に同時アクセス数が増えたときのストレスがなくなったので、移行して正解だったのですが、WordPressの移行でちょっとハマったところなどをメモしておきます。

…続きを読む

wordpressをActive/Standbyで冗長化したはよいが、実は運用で悩んでいる。単に文字列だけのエントリを投稿するだけであれば、サーバの肩寄せなどせず、単にDBへポンポン放り込んでくれるからである。一方で、以下のような場合は肩寄せ運用をしなくてはならない。

    • 画像つきエントリの投稿
    • プラグインやテーマの追加、削除、アップデート
    • テーマの編集

これらの作業はすべて、Apacheがファイルシステムに書き込みを加えるという共通項がある。対策としては、

    • 書き込みを加える対象以外のApacheを止めて、台数分作業を繰り返す
    • wp-adminなどの特定ディレクトリだけ片寄せする
    • POSTだけ片寄せして、裏でrsyncやlsyncdを使って同期する

くらいであろうか。2~3台程度のサーバであれば、手オペが少々面倒くさいだけで済むが、片寄せを自動化するとなると、WordPressのURLの構造をきちんと理解しないといけないし、もしURL構造の仕様変更があったらそれに追随しなければならない。さりとて、DocumentRootをNASやiSCSIなどで共有したら、単一障害点になってしまう。。。

さらにもう1点、一番重要なのは、エントリの書き手に余計な負担を与えてしまうこと。「画像つきエントリ投稿したけりゃバックエンドのApacheを片方止めてくださーい」なんて、言えないですよねー。なので、ブログの冗長化は自己満足ならいいけど、仕事でやるんだったらここまで考えたほうがいいです。大手のブログの中の人はどうしているのだろう。。。

1件のコメント

wordpress突然ですが、WordPressを冗長化したいと思いませんか?1台サーバが落ちてもサービス影響を最小限に、しかもサーバ代以外のお金をかけず冗長化できる方法があるんですよ奥さん。

■ NW構成

下記の図のようなNW構成で実現可能です。

DBはマルチマスタにせず、マスターDBはServer #1 とし、Server #2、および以降スケールアウトするマシンはすべてSlaveとします。

■ 障害パターン

Server #2 の全体障害および部分障害がおきても、DNSラウンドロビンによりServer #1へアクセスした場合は影響がありません。Server #2のMySQLが落ちていても、Server #1のMySQLが生きている限り影響はありません。Server #1の全体障害およびDB障害の際は、エントリの投稿やコメントをつけたりなどの更新系は止まっても、サイト閲覧には支障ありません。

 

■ 用意するもの

WEB+DBサーバ 2台 ( CentOS 6.3 にて動作確認済 )

Master = 192.168.0.10
Slave = 192.168.0.11
WordPress ( http://ja.wordpress.org/よりダウンロード )
HyperDB ( http://wordpress.org/extend/plugins/hyperdb/よりダウンロード )

■ まずは普通に WordPress をインストールする

2台のサーバに、WordPress をインストールします。ApacheやMySQL、PHPのパッケージはそれぞれOSの標準リポジトリからインストールで大丈夫ですが、バーチャルホストのServerNameだけは同じ値にしておいてください。この時点で特別な設定は何一つ不要です。 wp-config.php のホスト名は、2台ともlocalhostのままでOKです。

さて、2台のサーバでそれぞれ動作確認ができたら、DBのレプリケーション設定を行います。

 

■ MySQLのレプリケーション設定

とみぞーノート さんの手順そのままでOKです。いわゆる「Master-Slave構成」というやつを構築します。2台のサーバで異なる設定を投入するので、各手順の前に [Master] [Slave] を書いておきます。

● [Master] /etc/my.cnf の[mysqld]セクションに、バイナリログ取得設定とサーバIDを追加

# vi /etc/my.cnf
[mysqld]
log-bin
server-id=1

設定反映後、mysqldを再起動します。

● [Master] レプリケーション用アカウント作成

SlaveからMasterへ接続する際のアカウントを、Master側で作成しておきます。mysqlにログイン後、以下のコマンドを実行します。パスワードは一例ですので必ず変更してくださいね。

mysql> GRANT REPLICATION SLAVE ON *.* TO repl@192.168.0.10 BY 'PASSWORD-HOGEHOGE';

● [Master] テーブルに書き込みロックを行う

Master側のデータを手動コピーする前に、テーブルロックを行います。

mysql> FLUSH TABLES WITH READ LOCK;

● [Master] バイナリログの確認を行う

バイナリログの名前(File)と位置(Position)を確認します。テーブルロック中にやらないと、どんどん数字がインクリメントされてしまうので注意しましょう。

mysql> SHOW MASTER STATUS;
+-------------------+----------+--------------+------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| mysqld-bin.000001 |      106 |              |                  |
+-------------------+----------+--------------+------------------+

● [Master] データベースをtarコマンドでバックアップする

Master側のデータベースを手動バックアップし、Slave側へSCPなどで転送します。

# cd /var/lib/mysql
# ls -l | grep <WordPressのDB>
# tar czf <WordPressのDB>.tar.gz <WordPressのDB>

● [Master] テーブルロックを解除する

mysql> UNLOCK TABLES;

マスター側のMySQL設定は以上になります。続いてSlave側の設定を行います。

● [Slave] 静止状態を確保し、データベースをコピーする

Master側からコピーしてきたアーカイブを展開します。書き込みを防止するため、mysqldは止めておきましょう。

# /etc/init.d/mysqld stop
# cd /var/lib/mysql
# mv <WordPressのDB> <WordPressのDB>.orig
# tar xvzf <WordPressのDB>.tar.gz

● [Slave] Slave側のmy.cnfにserver-idを設定し、mysqldを再起動する

Master側と同じく、[mysqld]セクションにserver-idを追加します。他のサーバと被らないようにしましょう。

# cp -p /etc/my.cnf /etc/my.cnf.orig
# vi /etc/my.cnf
server-id=2
# /etc/init.d/mysqld start

 

● [Slave] Master側へ接続するためのパラメータを設定する

SlaveとなるMySQLサーバへログインし、以下SQL文を投入します。

mysql> CHANGE MASTER TO
       MASTER_HOST='192.168.0.10'
       MASTER_USER='repl'
       MASTER_PASSWORD='PASSWORD-HOGEHOGE'
       MASTER_LOG_FILE='mysqld-bin.000001'
       MASTER_LOG_POS=106;

 

● [Slave] レプリケーションを開始する

以下のコマンドを実行し、192.168.0.11のほうのサーバをSlaveにします。

mysql> START SLAVE;

 

■ [Master][Slave] HyperDB のダウンロードとファイルコピー

以降の作業は、MasterとSlaveの両方で実施します。

// アーカイブのダウンロード

# wget http://downloads.wordpress.org/plugin/hyperdb.zip
# unzip hyperdb.zip

// ファイルコピー

# cp -p db-config.php <WordPressインストールディレクトリ>
# cp -p db.php <WordPressインストールディレクトリ>/wp-content/

 

■ [Master][Slave] db-config.php 設定

Master側とSlave側の動作を設定します。ソース内の赤太文字が追加部分となります。

# cd <WordPressインストールディレクトリ>
# vi db-config.php

217~224行目周辺 修正前

$wpdb->add_database(array( 'host' => DB_HOST, // If port is other than 3306, use host:port. 'user' => DB_USER, 'password' => DB_PASSWORD, 'name' => DB_NAME,));

217~224行目周辺 修正後

$wpdb->add_database(array( 'host' => DB_HOST, // If port is other than 3306, use host:port. 'user' => DB_USER, 'password' => DB_PASSWORD, 'name' => DB_NAME, 'write' => 1, 'read' => 1,));

230~239行目周辺 修正前

$wpdb->add_database(array( 'host' => DB_HOST, // If port is other than 3306, use host:port. 'user' => DB_USER, 'password' => DB_PASSWORD, 'name' => DB_NAME, 'write' => 0, 'read' => 1, 'dataset' => 'global', 'timeout' => 0.2, )

);

230~239行目周辺 修正後

$wpdb->add_database(array( 'host' => DB_HOST_RO, // If port is other than 3306, use host:port. 'user' => DB_USER, 'password' => DB_PASSWORD, 'name' => DB_NAME, 'write' => 0, 'read' => 1, 'dataset' => 'global', 'timeout' => 0.2, )

);

 

■ [Master][Slave] DB接続先変更

Master、Slaveの両方で、DB接続先を変更します。

# cd <WordPressインストールディレクトリ>
# cp -p wp-config.php wp-config.php.orig
# vi wp-config.php

修正前

define('DB_HOST', 'localhost');

修正後

//define('DB_HOST', 'localhost');
define('DB_HOST', '192.168.0.10');
define('DB_HOST_RO', '192.168.0.11');

以上でWordPressの冗長化作業は終了です。それでは確認してみましょう。

 

■ 確認項目

  1. Master側で記事を投稿し、Slave側にも記事が反映されていること
  2. Slave側で記事を投稿し、Master側にも記事が反映されていること
  3. Slave側のmysqldを止めても、サイト閲覧に問題がないこと
  4. Slave側のmysqldを止めても、記事の投稿ができること
  5. Master側のmysqldを止めても、サイト閲覧に問題がないこと

ここまで確認できれば、WordPressの冗長化は終了です。ね、簡単でしょう?

またまたお金をかけずに冗長化しようシリーズです(笑)。今回はCentOS 5.2でbonding設定を行ったのでメモ。NICはeth0とeth1があるので、これを組み合わせてbond0にします。今回行う設定は以下の通り。

bond0のIPアドレス・・・192.168.0.100/24
bond0にまとめるインターフェイス・・・eth0とeth1
IPv6は設定しない

1. bondingモジュールの読み込み

[root@ishikari ~]# cd /etc/modprobe.d/
[root@ishikari modprobe.d]# vi bonding
alias bond0 bonding
option bond0 miimon=100 mode=1 primary=eth0

今回はNICの監視をMIIにやらせます。

2. bondingインターフェースの定義

[root@ishikari ~]# cd /etc/sysconfig/network-scripts/
[root@ishikari network-scripts]# vi ifcfg-bond0
DEVICE=bond0
BOOTPROTO=static
BROADCAST=192.168.0.255
IPADDR=192.168.0.100
IPV6ADDR=
IPV6PREFIX=
NETMASK=255.255.255.0
NETWORK=192.168.0.0
ONBOOT=yes

3. bondインターフェースへethXデバイスを参加させる

既存のeth0とeth1にIPアドレスを設定せず、bond0のslaveとして振舞うように設定する。

[root@ishikari network-scripts]# vi ifcfg-eth0
# Realtek Semiconductor Co., Ltd. RTL-8169 Gigabit Ethernet
DEVICE=eth0
BOOTPROTO=static
ONBOOT=yes
MASTER=bond0
SLAVE=yes

[root@ishikari network-scripts]# vi ifcfg-eth1
# Intel Corporation 82540EM Gigabit Ethernet Controller
DEVICE=eth1
BOOTPROTO=static
ONBOOT=yes
MASTER=bond0
SLAVE=yes

あとはネットワークの再起動をするだけ。
# /etc/init.d/network restart

確認してみる。
$ /sbin/ifconfig
bond0     Link encap:Ethernet  HWaddr 00:90:CC:E9:2D:DD
          inet addr:192.168.0.100  Bcast:192.168.0.255  Mask:255.255.255.0
          inet6 addr: fe80::290:ccff:fee9:2ddd/64 Scope:Link
          UP BROADCAST RUNNING MASTER MULTICAST  MTU:1500  Metric:1
          RX packets:226686 errors:0 dropped:0 overruns:0 frame:0
          TX packets:254940 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:53590591 (51.1 MiB)  TX bytes:65817477 (62.7 MiB)

eth0      Link encap:Ethernet  HWaddr 00:90:CC:E9:2D:DD
          inet6 addr: fe80::290:ccff:fee9:2ddd/64 Scope:Link
          UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
          RX packets:226686 errors:0 dropped:0 overruns:0 frame:0
          TX packets:254942 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:53590591 (51.1 MiB)  TX bytes:65817801 (62.7 MiB)
          Interrupt:193 Base address:0xa000

eth1      Link encap:Ethernet  HWaddr 00:90:CC:E9:2D:DD
          UP BROADCAST SLAVE MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)
          Base address:0xecc0 Memory:fe100000-fe120000

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:8019 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8019 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:943061 (920.9 KiB)  TX bytes:943061 (920.9 KiB)

はいできたー。あとはケーブルを片方ずつひっこ抜いて、通信が途切れないのを確認すればOK。
ね、簡単でしょ?

※ 注意点
非bond環境からbonding環境にするときはそのままモジュールを読み込めばよいが、bonding環境から非bond環境に戻すときは、ネットワークの再起動だけじゃなくてOSごと再起動したほうがよい。