まめ畑

ゆるゆると書いていきます

MySQL ClusterとHeartbeat

今回は、MySQL Clusterでクラスター構成を作って、SQL NodeをHeartbeatで冗長化してみてるメモ
Keepalived + LVSも試したい

やること

  • MySQL Clusterを構築してみる
  • 3種類のノードが必要
    • Management Node
    • Data Node
    • SQL Node

今回は以下のような構成
100 sql
101 manage sql
102 data
103 data

インストール

wget http://dev.mysql.com/get/Downloads/MySQL-Cluster-7.1/mysql-cluster-gpl-7.1.3-linux-i686-glibc23.tar.gz/from/http://ftp.jaist.ac.jp/pub/mysql/
tar xzvf mysql-cluster-gpl-7.1.3-linux-i686-glibc23.tar.gz
groupadd mysql
useradd -g mysql mysql
mv mysql-cluster-gpl-7.1.3-linux-i686-glibc23 /usr/local/
cd  /usr/local/
ln -s /usr/local/mysql-cluster-gpl-7.1.3-linux-i686-glibc23/ mysql
cd mysql
chown -R mysql .
chgrp -R mysql .
scripts/mysql_install_db --user=mysql
chown -R root .
chown -R mysql data
bin/mysqld_safe --user=mysql &

cp support-files/my-large.cnf /etc/my.cnf

設定ファイル作成

  • Management Node
mkdir /var/lib/mysqlcluster/
vim /var/lib/mysqlcluster/ndb-config.ini
[ndbd default]
NoOfReplicas= 2
MaxNoOfConcurrentOperations= 10000
DataMemory= 80M
IndexMemory= 24M
TimeBetweenWatchDogCheck= 30000
DataDir= /var/lib/mysqlcluster
MaxNoOfOrderedIndexes= 512

[ndb_mgmd default]
DataDir= /var/lib/mysqlcluster

[ndb_mgmd]
Id=1
HostName=192.168.147.101

[ndbd]
Id= 2
HostName=192.168.147.102

[ndbd]
Id= 3
HostName=192.168.147.103

[mysqld]
Id= 4
HostName=192.168.147.100

[mysqld]
Id= 5
HostName=192.168.147.101
  • 起動
/usr/local/mysql/bin/ndb_mgmd -f /var/lib/mysqlcluster/ndb-config.ini 
  • Data Node
mkdir /var/lib/mysqlcluster
/usr/local/mysql/bin/ndbd --connect-string=192.168.147.101

この状態でManagement Nodeで

/usr/local/mysql/bin/ndb_mgm

を実行し、showを実行すると

Cluster Configuration

                                        • -

[ndbd(NDB)] 2 node(s)
id=2 @192.168.147.102 (mysql-5.1.44 ndb-7.1.3, Nodegroup: 0)
id=3 @192.168.147.103 (mysql-5.1.44 ndb-7.1.3, Nodegroup: 0, Master)

こんな感じで接続されてるのがわかります

  • SQL Node
  • /etc/my.cnfの[mysqld]セクションに追記
  • 全てのSQLノードに設定
skip-innodb
ndbcluster
ndb-connectstring = 192.168.147.101
query_cache_type = 0
query_cache_size= 0

基本的にManagerノードのアドレスを記述するだけ
データの同期がとれなくなる可能性があるのでクエリーキャッシュをOFFにしておく
MySQL Clusterだけを使用するなら、innodbを切っておくと起動の高速化とメモリの節約になる
後は起動するだけ

/usr/local/mysql/bin/mysqld_safe &

この状態でManagement Nodeで接続を確認すると

  • /usr/local/mysql/bin/ndb_mgm
ndb_mgm> show
Cluster Configuration
---------------------
[ndbd(NDB)]     2 node(s)
id=2    @192.168.147.102  (mysql-5.1.44 ndb-7.1.3, Nodegroup: 0)
id=3    @192.168.147.103  (mysql-5.1.44 ndb-7.1.3, Nodegroup: 0, Master)

[ndb_mgmd(MGM)] 1 node(s)
id=1    @192.168.147.101  (mysql-5.1.44 ndb-7.1.3)

[mysqld(API)]   2 node(s)
id=4    @192.168.147.100  (mysql-5.1.44 ndb-7.1.3)
id=5 (not connected, accepting connect from 192.168.147.101)

ndb_mgm> show
Cluster Configuration
---------------------
[ndbd(NDB)]     2 node(s)
id=2    @192.168.147.102  (mysql-5.1.44 ndb-7.1.3, Nodegroup: 0)
id=3    @192.168.147.103  (mysql-5.1.44 ndb-7.1.3, Nodegroup: 0, Master)

[ndb_mgmd(MGM)] 1 node(s)
id=1    @192.168.147.101  (mysql-5.1.44 ndb-7.1.3)

[mysqld(API)]   2 node(s)
id=4    @192.168.147.100  (mysql-5.1.44 ndb-7.1.3)
id=5    @192.168.147.101  (mysql-5.1.44 ndb-7.1.3)

接続されてるのがわかりますね


SQL NodeでSHOW ENGINESを実行するとndbclusterがYESになってます
SHOW ENGINE NDB STATUS\Gでステータスが確認できます

試してみる

  • テーブルを作る

CREATE DATABASE clustertest;
USE clustertest
CREATE TABLE test( id int not null auto_increment, name varchar(100), primary key(id) ) ENGINE=ndbcluster;
INSERT INTO test (id, name) VALUES (1, "hoge");

ENGINE=ndbclusterを指定するだけ

INSERT後に、別のSQL NodeからSELECTをしてみると、今挿入したデータが参照できます
オンラインバックアップやリストア、各設定パラメータの意味などの詳細は第5回 ローリングリスタート! | Think ITを参照して下さい
MySQL ClusterのData Nodeではメモリやディスクを結構消費しますね


ついでにSQL NodeでHeartbeatを使う

  • CentOSだとHeartbeatのパッケージがあります
  • ソースから入れる場合、3系からいくつかのProjectに分割されているので、順番に入れていきます
  • パッケージは2.x系、ソースだと3.x系が提供されています
  • ソースからだとこんな感じでビルドします
wget http://hg.linux-ha.org/glue/archive/glue-1.0.3.tar.bz2
tar -vxjf glue-1.0.3.tar.bz2
cd Reusable-Cluster-Components-glue-1.0.3/
./autogen.sh
./configure
make
make install

wget http://hg.linux-ha.org/heartbeat-STABLE_3_0/archive/STABLE-3.0.2.tar.bz2
tar -vxjf STABLE-3.0.2.tar.bz2 
cd Heartbeat-3-0-STABLE-3.0.2/
./ConfigureMe configure
make
make install
  • yumで入れると
  • エラーがでるのでyumを2回実行
yum -y install heartbeat
yum -y install heartbeat

設定

  • サンプルをコピーする場合は
cp /usr/share/doc/heartbeat-2.1.3/ha.cf /etc/ha.d/
  • vim /etc/ha.d/ha.cf
  • IPは(cluster1: 192.168.147.100, cluster2: 192.168.147.101)
  • 仮想IP: 192.168.147.200
  • cluster1の設定
crm on

# ログの出力先を指定
logfile /var/log/ha-log

# heartbeat の間隔(秒)
keepalive 2

# ノードがダウンしたと判断する時間(秒)
deadtime 30

# ノードがダウンした警告を発する時間(秒)
warntime 10

# 起動時に待つ時間。これを超えるとダウンしていると判断(秒)deadtime の二倍以上推奨
initdead 60

# ブロードキャスト、ユニキャストで使用する UDP ポート番号
udpport 694

# ユニキャストを使う場合にインターフェースと相手ホストの IP アドレスを指定する
ucast eth0 192.168.147.101

# 自動的にフェイルバックするかどうか
auto_failback on

# クラスタのノード名を指定。uname -n で表示される名前を指定する
node    cluster1.test.com
node    cluster2.test.com

# ping 監視する IP アドレスを指定。ipfail のために使います
ping 192.168.147.101

# hearbeatと一緒に起動するプロセスと起動ユーザを指定する
respawn root /usr/lib/heartbeat/ipfail
  • cluster2の設定
crm on

# ログの出力先を指定
logfile /var/log/ha-log

# heartbeat の間隔(秒)
keepalive 2

# ノードがダウンしたと判断する時間(秒)
deadtime 30

# ノードがダウンした警告を発する時間(秒)
warntime 10

# 起動時に待つ時間。これを超えるとダウンしていると判断(秒)deadtime の二倍以上推奨
initdead 60

# ブロードキャスト、ユニキャストで使用する UDP ポート番号
udpport 694

# ユニキャストを使う場合にインターフェースと相手ホストの IP アドレスを指定する
ucast eth0 192.168.147.100

# 自動的にフェイルバックするかどうか
auto_failback on

# クラスタのノード名を指定。uname -n で表示される名前を指定する
node    cluster1.test.com
node    cluster2.test.com

# ping 監視する IP アドレスを指定。ipfail のために使います
ping 192.168.147.100

# hearbeatと一緒に起動するプロセスと起動ユーザを指定する
respawn root /usr/lib/heartbeat/ipfail
  • authkeyを設定する
  • 共通のauthkeyを使用するので、片方のノードでauthkeyファイルを作成し、もう一方のノードへコピーする
  • /etc/ha.d/authkey
  • 公式サイトのauthkeyファイルの作成方法
( echo -ne "auth 1\n1 sha1 "; \
  dd if=/dev/urandom bs=512 count=1 | openssl md5 ) \
  > /etc/ha.d/authkeys

chmod 0600 /etc/ha.d/authkeys
  • haresourcesファイルを作る
  • /etc/ha.d/haresources
  • cluster1の設定

cluster2 192.168.147.200/24/eth0/192.168.147.255

  • cluster2の設定

cluster1 IPaddr2::192.168.147.200/24/eth0/192.168.147.255

  • cib.xmlを編集する
  • まず、haresourcesからcib.xml作成します
  • heartbeat起動時にcib.xmlを直接編集するとメモリ上のデータと整合性がとれなくなる事があるので、別の場所にコピーして編集します
  • 編集はDesignatedノード上で行います。Designatedの確認方法は
crmadmin -D

と入力すると

Designated Controller is: rp1.test.com

のように表示されます

  • 編集完了後、相手にもコピーします
/usr/lib/heartbeat/haresources2cib.py haresources
vim /var/lib/heartbeat/crm/cib.xml
  • 書き出されたファイルが少し間違ってるので編集
<nvpair id="IPaddr2_1_attr_1" name="nic" value="24"/>
<nvpair id="IPaddr2_1_attr_2" name="cidr_netmask" value="eth0"/>

<nvpair id="IPaddr2_1_attr_1" name="nic" value="eth0"/>
<nvpair id="IPaddr2_1_attr_2" name="cidr_netmask" value="24"/>

チェック

crm_verify -x /var/lib/heartbeat/crm/cib.xml 
  • 起動
/etc/rc.d/init.d/heartbeat start


様子を見るには

crm_mon

こんな感じで出力されます

============
Last updated: Tue Jun 15 05:46:37 2010
Current DC: cluster1.test.com (7070ddca-b792-4039-b165-b9fef0fa243b)
2 Nodes configured.
1 Resources configured.
============

Node: cluster1.test.com (7070ddca-b792-4039-b165-b9fef0fa243b): online
Node: cluster2.test.com (7d14d5f4-896f-4ce9-8efd-9bd8f982702b): online

IPaddr2_1       (heartbeat::ocf:IPaddr2):       Started cluster1.test.com

MySQLの生存監視もするcib.xml

 <cib admin_epoch="0" have_quorum="true" ignore_dtd="false" num_peers="2" cib_feature_revision="2.0" ccm_transition="2" generated="true" dc_uuid="1121939e-2ecc-492b-9b5b-a72bb67e9e88" epoch="13" num_updates="1" cib-last-written="Fri Jun 18 10:08:58 2010">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <attributes>
           <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="2.1.3-node: 552305612591183b1628baa5bc6e903e0f1e26a3"/>
           <nvpair id="failback" name="default-resource-stickiness" value="INFINITY"/>
           <nvpair id="failover" name="default-resource-failuer-stickiness" value="-INFINITY"/>
         </attributes>
       </cluster_property_set>
     </crm_config>
     <nodes>
       <node uname="rp2.test.com" type="normal" id="1121939e-2ecc-492b-9b5b-a72bb67e9e88">
         <instance_attributes id="nodes-1121939e-2ecc-492b-9b5b-a72bb67e9e88">
           <attributes>
             <nvpair name="standby" id="standby-1121939e-2ecc-492b-9b5b-a72bb67e9e88" value="off"/>
           </attributes>
         </instance_attributes>
       </node>
       <node uname="rp1.test.com" type="normal" id="9f81fb7d-1278-48d3-a162-a0cb9c215fd4">
         <instance_attributes id="nodes-9f81fb7d-1278-48d3-a162-a0cb9c215fd4">
           <attributes>
             <nvpair name="standby" id="standby-9f81fb7d-1278-48d3-a162-a0cb9c215fd4" value="off"/>
           </attributes>
         </instance_attributes>
       </node>
     </nodes>
     <resources>
       <group id="mysql_grp">
         <primitive class="ocf" type="IPaddr2" provider="heartbeat" id="ipaddr">
           <operations>
             <op id="ipaddr_monitor" name="monitor" interval="5s" timeout="5s" on_fail="restart"/>
             <op id="ipaddr_start" name="start" timeout="5s" on_fail="restart"/>
             <op id="ipaddr_stop" name="stop" timeout="5s" on_fail="restart"/>
           </operations>
           <instance_attributes id="ia_ipaddr">
             <attributes>
               <nvpair id="vip" name="ip" value="192.168.147.200"/>
               <nvpair id="netmask" name="netmask" value="24"/>
               <nvpair id="nic" name="nic" value="eth0"/>
             </attributes>
           </instance_attributes>
           <instance_attributes id="ipaddr">
             <attributes>
               <nvpair name="is_managed" id="ipaddr-is_managed" value="on"/>
             </attributes>
           </instance_attributes>
         </primitive>
         <primitive id="mysql" class="ocf" type="mysql" provider="heartbeat">
           <operations>
             <op id="mysql_monitor" name="monitor" interval="10s" timeout="5s" on_fail="restart"/>
             <op id="mysql_start" name="start" timeout="60s" on_fail="stop"/>
             <op id="mysql_stop" name="stop" timeout="60s" on_fail="stop"/>
           </operations>
           <instance_attributes id="ia_mysql">
             <attributes>
               <nvpair id="mysql_binary" name="binary" value="/usr/bin/mysqld_safe"/>
               <nvpair id="mysql_pid" name="pid" value="/tmp/mysqld.pid"/>
               <nvpair id="mysql_socket" name="socket" value="/var/lib/mysql/mysql.sock"/>
               <nvpair id="mysql_pass" name="root_password"/>
             </attributes>
           </instance_attributes>
         </primitive>
       </group>
     </resources>
     <constraints>
       <rsc_location id="ping_connected" rsc="mysql_grp">
         <rule id="ping_connected_rule" score_attribute="pingd">
           <expression id="ping_connected_expr_defined" attribute="pingd" operation="defined"/>
         </rule>
       </rsc_location>
     </constraints>
   </configuration>
 </cib>