l'essentiel est invisible pour les yeux

Monday, March 06, 2006

[Vol.1] RailsとMySQLによる大規模サイト構築実験

大規模サイト構築のための土台を作っていきます。
ASP事業に力を注入するとなると、24H7D動作し続ける安定したサービスのためのインフラがまうます必須になるはずです。

アーキテクト
WEBサーバ 何でもいい。
WEBアプリケーションフレームワーク Ruby on Rails
DB MYSQL

で実験していきます。

とりあえず、必要そうなもの。
1. WEB 負荷分散 ・冗長化
2. DB 負荷分散
3. DB 冗長化
4. Railsの拡張(DBへのコネクション周り)

まず1番。
ロードバランサー使えばできるし現在のドリコムでも、DUOBLOG APIやCMS ASPはクリアしてます。DNSラウンドロビンは、障害検知が不可能なのでNGです。

次は、2番。
クエリは、参照系クエリと更新系クエリに分類されます。
今ドリコムでDBへのクエリを負荷分散させているプロジェクトは(僕の知っているところは)ありません。

次は、3番。
DB自体の冗長化です。
MySQLを使用しているのでDUOBLOG 検索APIがDBの冗長化をサポートしています。
単純なマスタ・スレーブ構成を構築し、Mojavi側でコネクションの切り替え(マスタが死んでいる際はスレーブに接続)を実装しました。

でも、これって完全には冗長化されていませんね。現状参照系クエリの冗長化しか行っていません。通常マスタが死んだ場合はスレーブに引き継ぐことになりますが、フェールバックは手動になります。

次は、4番。
Active Record Clusterをこのために作りました。


やることイパーイなのですが、このシリーズではMySQL自体の冗長化と負荷分散とRails側の拡張を実験していきます。

アーキテクト
次のようなデュアルマスタ構成に複数代のスレーブがぶら下がっている、クラスタがたくさんあると考えてください。



更新系のクエリはLB(負荷分散装置)が振り分け、参照系のクエリについてはRails側で振り分けます。
(参照系クエリもLBで振り分けるようにするか- 考察1)

一つ注意が必要なのは、更新系のクエリは図に示しているLB(ロードバランサ)で分散されるわけではありません。ここでLBをはさんでいるのはあくまでも 冗長性のためです。マスタ間でレプリケーションが行われるため、リクエストの受け付けの負荷分散が出来るだけで本当の意味での負荷分散が出来るわけではあ りません。

(マスタ間でのレプリケーション遅延により発生する、AUTO_INCREMENTシーケンスの衝突による問題を回避するための対策 - 考察2)

では、更新系の負荷分散はどうするか?
このようなクラスタを複数用意します。テーブルによって所属するクラスタ自体を分けてしまいます

(テーブル設計の工夫 - 考察3)

考察と書いたところは、考える必要があるポイントです。
まずは、マスタへのクエリの分散を行うためのLBを構築したいと思います。
Heartbeat + Ldirectordを使用して構築します。

技術的には全く難しいことはしてないんですけど、セットアップが若干めんどくさい。。
レイヤ4スイッチングを使用し、MySQLへクエリを発行し正常に結果を取得できなかったら、DBサーバをハッシュテーブルからはずすだけです。(正確にはWeightを0に設定しリクエストが振り分けられなくする。)

LBはActive-passive構成で組み、DBはActive-Activeで組みます。

セットアップ手順

1. カーネルの再構築
ARP問題を回避するためにパッチを当てたカーネルが必要です。
linux-2.6.11を使用します。最新のlinu-2.6.16でやると、カネパになりました。

http://kernel.org/
ここからカーネルをwget.

# tar jxvf kernel-x.x.x.tar.bz2
# cd kernel-x.x.x

http://www.ssi.bg/~ja/#hidden
ここからカーネルのバージョンにあったパッチをwget.

# patch -p1 < style="font-weight: bold;">2. ネットワーク設定
IPフォワーディングとか隠れデバイスを有効にするための設定を行います。
ARP問題を解決するために、ループバックインタフェースを隠します。
言葉の意味がわからなければ気にしないでください。

/etc/sysctl.conf
を編集します。
次のように設定します。
した二つは、設定に無いので新たに追加します。

net.ipv4.ip_forward = 1

# 隠れデバイスの設定を有効にする
net.ipv4.conf.all.hidden = 1
# ループバックインタフェースを隠す
net.ipv4.conf.lo.hidden = 1

設定が完了すれば、
# /sbin/sysctl -p
で設定が反映されていることを確認します。


3. Heartbeatのインストール
Heartbeatはソースからインストールします。v2.xを使用します。
依存関係が複雑なので必要なプロダクトを先にインスコします。
インスコの順番は次のようにすればまず、間違いはないはず。

1. libgpg-error
2. libgcrypt
3. gnutls
4. libnet
5. heartbeat

Heartbeat以外は
$ ./configure
$ make
$ sudo make install

Heartbeatのみ
$ ./ConfigureMe configure
$ make
$ sudo make install

です。
もし、エラーが出る場合は足りないプロダクトをインスコしてください。


4. ldirectordのインストール

$ cvs -d:pserver:guest@cvs.linux-ha.org:/home/cvs/linux-ha login
$ cvs -z3 -d:pserver:guest@cvs.linux-ha.org:/home/cvs/linux-ha co linux-ha/ldirectord/

login時に要求されるパスワードは、"guest"です。
で完了です。


5. デプロイ
プログラム・設定ファイル類をコピーします。

# cp ldirectord /etc/ha.d/resource.d/
# chmod +x /etc/ha.d/resource.d/ldirectord
# cp ldirectord.cf /etc/ha.d/
# cp /usr/share/doc/heartbeat-2.0.3/authkeys /etc/ha.d/
chmod 600 /etc/ha.d/authkeys

6. 設定
Heartbeatは、この記事あたりを見れば設定できるはず。

Ldirecotordの設定が多少異なります。

以下は、/etc/ha.d/ldirectord.cfの設定サンプル。
192.168.10.226がVIPで、realが実サーバ(マスタ).
requestには実行するSQLクエリ、serviceにはmysql、login, passwd, databaseをそれぞれ指定します。サービスにDBを指定した場合は、recieveディレクティブは使用できません。

virtual=192.168.10.226:3306
real=192.168.10.219:3306 gate 1
real=192.168.10.230:3306 gate 1
fallback=127.0.0.1:3306 gate
service=mysql
request="SHOW VARIABLES;"
# receive="Test Page"
# virtualhost=some.domain.com.au
scheduler=rr
#persistent=600
#netmask=255.255.255.255
protocol=tcp
login="heartbeat"
database="test"
passwd="hogera"

大抵一発では通りません。
デバックしましょう。
ldirectodのデバックは簡単です。-dオプションをつけて起動すると、デバックモードとして起動し、デーモンになりません。

$ /etc/ha.d/resoruce.d/ldirectord /etc/ha.d/ldirectord.cf

出力されたメッセージを見ましょう。
PerlのMySQLモジュールが無いと出ていないですか?
出ている場合は、インスコします。

http://search.cpan.org/dist/DBD-mysql/lib/DBD/mysql.pm
をwget.

$ perl Makefile.PL
$ make
$ sudo make install

もう一度実行します。
モジュールDBDも無いといわれた場合は、CPANからインスコします。

ここからレプリケーションを組んでスレーブ遅延による問題を回避し、
考察点としてあげたあたりをvol2で追求します。

テーブル設計工夫にあたり、Rails側の拡張ももう少し必要になるかもしれませんね。