今回は、
MySQLのレプリケーション機能でWakameは本領を発揮する
一般的に、
より複雑な構成も取れるのですが、
これらの作業に必要な手順は、
基本原理を理解する
まず、
Amazon EC2で試せるスクリプトの概要と準備
参考のために、
スクリプトの動作処理は、
- MySQL Master用datadirとしAmazon EBS Volumeを生成
- 1で生成したAmazon EBS VolumeからAmazon EBS Snapshotを生成
- 2で生成したAmazon EBS SnapshotからMySQL Slave用datadirとしてAmazon EBS Volumeを生成
スクリプトの動作解説
スクリプトの動作前提条件は下記の通りです。
- Amazon EC2インスタンスが起動している事
- 起動しているAmazon EC2インスタンスにAmazon EC2 API Toolsの環境が整っている事
→ ツールの整備方法を参考に環境設定してください。
また、
- _wakame-common.
sh - wakame-ebs-mysql-master-create-volume.
sh - wakame-ebs-mysql-master-init.
sh - wakame-ebs-mysql-master-add-repl-user.
sh - wakame-ebs-mysql-master-make-snapshot.
sh - wakame-ebs-mysql-slave-restore.
sh
各スクリプトの概要は、
なお、
- _wakame-common.
sh - 全スクリプトからincludeされるファイル
- 共通設定項目
- wakame-ebs-mysql-master-create-volume.
h - Amazon EBS Volumeを新規生成
- 生成したAmazon EBS Volumeをデバイス名指定でattach
- Amazon EBS Volume上にファイルシステムを生成
- Amazon EBS VolumeをMySQL Master用datadirとしてマウント
- wakame-ebs-mysql-master-init.
sh - MySQL Master用datadirのオーナーをmysqlへ変更
- MySQL Master用datadirを初期化
- wakame-ebs-mysql-master-add-repl-user.
sh - レプリケーション用MySQLアカウントをMySQL Masterに作成
- wakame-ebs-mysql-master-make-snapshot.
sh - attach済みAmazon EBS Volumeのvolume-idを取得
- MySQL Masterに対し"FLUSH TABLES WITH READ LOCK"でデータが更新されないようにテーブルをロック
- MySQL Masterのポジション情報を取得
- MySQL Slave用にmaster.
infoを生成 - MySQL Master用datadirからAmazon EBS Snapshotを生成
- Amazon EBS Snapshot生成後、
"UNLOCK TABLES;"でMySQL Masterのテーブルロックを解除
- wakame-ebs-mysql-slave-restore.
sh - MySQL Master用datadirをもとに生成したAmazon EBS Snapshotのsnapshot-idを指定し、
Amazon EBS Volumeを新規生成 - Amazon EBS Snapshotから生成したAmazon EBS Volumeを、
Amazon EC2インスタンスIDとデバイス名を指定してattach - attachしたAmazon EBS VolumeをMySQL Slave用datadirとしてマウント
- MySQL Master用datadirをもとに生成したAmazon EBS Snapshotのsnapshot-idを指定し、
実行方法と結果
今回のスクリプトを用いてMySQLレプリケーション構成を構築するには、
どちらのインスタンスでの作業であるかを区別するため、
mysql-common# | 共通 |
mysql-master# | MySQL Maser |
mysql-slave# | MySQL Slave |
まず、
mysql-common# chmod +x wakame-ebs-mysql-create-volume.sh mysql-common# chmod +x wakame-ebs-mysql-master-init.sh mysql-common# chmod +x wakame-ebs-mysql-master-add-repl-user.sh mysql-common# chmod +x wakame-ebs-mysql-master-make-snapshot.sh mysql-common# chmod +x wakame-ebs-mysql-slave-restore.sh
各MySQLのdatadir用ディレクトリを作っておきます。
mysql-master# mkdir -p /home/wakame/mysql/data mysql-slave# mkdir -p /home/wakame/mysql/data-slave
my.
- MySQL Master用my.
cnfのmysqldセクション -
[mysqld] server-id = 1 datadir = /home/
wakame/ mysql/ data log_ bin = /home/ wakame/ mysql/ data/ mysql-bin. log - MySQL Slave用my.
cnfのmysqldセクション [mysqld] server-id = 2 datadir = /home/
wakame/ mysql/ data-slave
それでは、
- wakame-ebs-mysql-master-create-volume.
sh mysql-master# ./
wakame-ebs-mysql-master-create-volume. sh $ ec2-create-volume -z us-east-1c -s 1 ebs_ master_ volume:vol-dbaa45b2 $ ec2-attach-volume -d /dev/ sdm -i i-6dce9f04 vol-dbaa45b2 ATTACHMENT vol-dbaa45b2 i-6dce9f04 /dev/sdm attaching 2009-06-10T07:58:59+0000 . . $ yes | mkfs -t ext3 /dev/ sdm >/dev/null 2>&1 /dev/ sdm on /home/wakame/ type ext3 (rw)mysql/ data - Amazon EBS Volumeを生成。volume-idは
「vol-dbaa45b2」 - デバイス名
「/dev/ sdm 」に 「vol-dbaa45b2」 をattach 「/dev/ sdm 」に 「ext3」 でファイルシステム構築 「/dev/ sdm 」を 「/home/ wakame/ 」mysql/ data にマウント
- Amazon EBS Volumeを生成。volume-idは
- wakame-ebs-mysql-master-init.
sh -
mysql-master# ./
wakame-ebs-mysql-master-init. sh Filesystem 1K-blocks Used Available Use% Mounted on /dev/ sdm 1032088 34072 945588 4% /home/ wakame/ mysql/ data 「/home/ wakame/ 」myql/ data をMySQLデータ領域として初期化
MySQL Masterの起動は今回のスクリプトでは行わないので、
手動で起動します。 mysql-master# /etc/
init. d/ mysql start - wakame-ebs-mysql-master-add-repl-user.
sh -
mysql-master# ./
wakame-ebs-mysql-master-add-repl-user. sh - レプリケーション用MySQLアカウントを登録、
反映
- レプリケーション用MySQLアカウントを登録、
- wakame-ebs-mysql-master-make-snapshot.
sh -
mysql-master# ./
wakame-ebs-mysql-master-make-snapshot. sh volume-id:vol-dbaa45b2 ... flush tables with read lock; ... show master status; ... make master. info $ ec2-create-snapshot vol-dbaa45b2 . . ... unlock tables; >>> snapshot_ id = snap-3b0fcc52 - MySQL Master用datadirのAmazon EBS Volumeのvolume-idを取得。volume-idは
「vol-dbaa45b2」 - MySQL Masterのデータが更新されないように、
テーブルをロック - MySQL Masterのポジション情報を取得
- MySQL Slave用にmaster.
infoを生成、 オーナー変更 「vol-dbaa45b2」 のAmazon EBS Snapshotを生成。snapshot-idは 「snap-3b0fcc52」 - テーブルロックを解除
- MySQL Masterのデータが更新されないように、
- MySQL Master用datadirのAmazon EBS Volumeのvolume-idを取得。volume-idは
- wakame-ebs-mysql-slave-restore.
sh -
mysql-slave# ./
wakame-ebs-mysql-slave-restore. sh snap-3b0fcc52 . ATTACHMENT vol-8caa45e5 i-6dce9f04 /dev/ sdn attaching 2009-06-10T08:18:31+0000 . . /dev/sdn on /home/ wakame/ mysql/ data-slave type ext3 (rw) VOLUME vol-8caa45e5 1 snap-3b0fcc52 us-east-1c in-use 2009-06-10T08:18:18+0000 ATTACHMENT vol-8caa45e5 i-6dce9f04 /dev/ sdn attached 2009-06-10T08:18:31+0000- snapshot-id
「snap-3b0fcc52」 からリストアしてAmazon EBS Volumeを生成。volume-idは 「vol-8caa45e5」 - デバイス名
「/dev/ sdn 」に 「vol-8caa45e5」 をattach 「/dev/ sdn 」を 「/home/ wakame/ 」mysql/ data-slave にマウント
MySQL Slaveの起動は今回のスクリプトでは行わないので、
手動で起動します。 mysql-slave# /etc/
init. d/ mysql start slaveが機能しているかを確認します。
mysql-slave# mysql -uroot mysql> show slave status \G *************************** 1. row *************************** Slave_
IO_ State: Waiting for master to send event Master_ Host: 10. 254. 183. 243 Master_ User: wakame-repl Master_ Port: 3306 Connect_ Retry: 60 Master_ Log_ File: mysql-bin. 000001 Read_ Master_ Log_ Pos: 340 Relay_ Log_ File: mysqld-relay-bin. 000002 Relay_ Log_ Pos: 235 Relay_ Master_ Log_ File: mysql-bin. 000001 Slave_ IO_ Running: Yes Slave_ SQL_ Running: Yes Replicate_ Do_ DB: Replicate_ Ignore_ DB: Replicate_ Do_ Table: Replicate_ Ignore_ Table: Replicate_ Wild_ Do_ Table: Replicate_ Wild_ Ignore_ Table: Last_ Errno: 0 Last_ Error: Skip_ Counter: 0 Exec_ Master_ Log_ Pos: 340 Relay_ Log_ Space: 235 Until_ Condition: None Until_ Log_ File: Until_ Log_ Pos: 0 Master_ SSL_ Allowed: No Master_ SSL_ CA_ File: Master_ SSL_ CA_ Path: Master_ SSL_ Cert: Master_ SSL_ Cipher: Master_ SSL_ Key: Seconds_ Behind_ Master: 0 1 row in set (0. 00 sec) - snapshot-id
MySQLレプリケーション構成にMySQL Slaveが追加され、
これらのスクリプトは便利なのですが、
それでは、
Wakameを使って、MySQLレプリケーションを自動化する
今回は、
WakameにMySQL Slaveの手順を記述する
MySQL SlaveをWakameのサービスとして追加するために、
- /home/
wakame/ corelib/ lib/ wakame/ service. rb - /home/
wakame/ corelib/ lib/ wakame/ configuration_ template. rb - /home/
wakame/ corelib/ config/ template/ mysql-slave/ my-slave. cnf
- /home/
wakame/ corelib/ lib/ wakame/ service. rb - Wakame MasterとWakame Agentに対する処理
- /home/
wakame/ corelib/ lib/ wakame/ configuration_ template. rb - configファイル用テンプレートのパス、
ファイル名を指定
- configファイル用テンプレートのパス、
- /home/
wakame/ corelib/ config/ template/ mysql-slave/ my-slave. cnf - /home/
wakame/ corelib/ lib/ wakame/ configuration_ template. rbで指定されたconfig用テンプレートファイル
- /home/
このうち、
class MySQL_Slave < Property
attr_reader :basedir, :mysqld_datadir, :mysqld_port, :mysqld_server_id, :mysqld_log_bin, :ebs_volume, :ebs_device
def initialize
super()
@max_instances = 5
# ▽ _wakame-common.sh ここから
@template = ConfigurationTemplate::MySQLSlaveTemplate.new()
@basedir = '/home/wakame/mysql'
@mysqld_server_id = nil
@mysqld_port = 3307
@mysqld_datadir = File.expand_path('data-slave', @basedir)
@ebs_volume = 'vol-12ac437b' # master volume_id
@ebs_device = '/dev/sdn' # slave mount point
@ebs_mount_option = 'noatime'
@mysqld_master_host = nil
@mysqld_master_user = 'wakame-repl'
@mysqld_master_pass = 'wakame-slave'
@mysqld_master_port = 3306
@mysqld_master_datadir = File.expand_path('data', @basedir)
# △ _wakame-common.sh ここまで
@duplicable = true
end
# in wakame-master
def before_start(svc, action)
agent_ip = svc.agent.agent_ip
Wakame.log.debug("#{svc.agent}")
Wakame.log.debug("mysql_slave.agent.agent_ip = #{agent_ip}")
# ▽wakame-ebs-mysql-master-make-snapshot.sh ここから
# directory
command = "ssh -i #{Wakame.config.ssh_private_key} -o \"StrictHostKeyChecking no\" -o \"UserKnownHostsFile #{Wakame.config.ssh_known_hosts}\" root@#{agent_ip} \"[ -d #{@mysqld_datadir} ] || mkdir -p #{@mys
qld_datadir}\""
Wakame.log.debug(command)
system(command)
# /dev/ebs_device
command = "ssh -i #{Wakame.config.ssh_private_key} -o \"StrictHostKeyChecking no\" -o \"UserKnownHostsFile #{Wakame.config.ssh_known_hosts}\" root@#{agent_ip} \"[ -b #{@ebs_device} ]\""
Wakame.log.debug(command)
system(command)
if $? == 0
Wakame.log.debug("The EBS volume(slave) device is not ready to attach: #{@ebs_device}")
return
end
vm_manipulator = VmManipulator.create
volume_map = vm_manipulator.describe_volume(@ebs_volume)
Wakame.log.debug("describe_volume(#{@ebs_volume}): #{volume_map.inspect}")
if volume_map['status'] == 'in-use'
# Nothin to be done
else
Wakame.log.debug("The EBS volume(slave) is not ready to attach: #{@ebs_volume}")
return
end
@mysqld_master_host = svc.cluster.fetch_mysql_master_ip
Wakame.log.debug("mysqld_master_host = #{@mysqld_master_host}")
system("echo show master status | /usr/bin/mysql -h#{@mysqld_master_host} -P#{@mysqld_master_port} -u#{@mysqld_master_user} -p#{@mysqld_master_pass}")
if $? != 0
raise "Can't connect mysql master: #{@mysqld_master_host}:#{@mysqld_master_port}"
end
system("echo 'FLUSH TABLES WITH READ LOCK;' | /usr/bin/mysql -h#{@mysqld_master_host} -P#{@mysqld_master_port} -u#{@mysqld_master_user} -p#{@mysqld_master_pass} -s")
master_status = `echo show master status | /usr/bin/mysql -h#{@mysqld_master_host} -P#{@mysqld_master_port} -u#{@mysqld_master_user} -p#{@mysqld_master_pass} -s`.to_s.split(/\t/)[0..1]
# mysql/data/master.info
master_infos = []
master_infos << 14
master_infos << master_status[0]
master_infos << master_status[1]
master_infos << @mysqld_master_host
master_infos << @mysqld_master_user
master_infos << @mysqld_master_pass
master_infos << @mysqld_master_port
master_infos << 60
master_infos << 0
master_infos << ""
master_infos << ""
master_infos << ""
master_infos << ""
master_infos << ""
master_infos << ""
tmp_output_basedir = File.expand_path(Wakame.gen_id, "/tmp")
FileUtils.mkdir_p tmp_output_basedir
master_info = File.expand_path('master.info', tmp_output_basedir)
file = File.new(master_info, "w")
file.puts(master_infos.join("\n"))
file.chmod(0664)
file.close
3.times do |i|
system("/bin/sync")
sleep 1.0
end
# scp master:$datadir/master.info slave:$datadir/master.info
command = "scp -i #{Wakame.config.ssh_private_key} -o \"StrictHostKeyChecking no\" -o \"UserKnownHostsFile #{Wakame.config.ssh_known_hosts}\" #{master_info} root@#{@mysqld_master_host}:#{@mysqld_master_dat
adir}/"
Wakame.log.debug(command)
system(command)
# ssh slave chown mysql:mysql $datadir/master.info
command = "ssh -i #{Wakame.config.ssh_private_key} -o \"StrictHostKeyChecking no\" -o \"UserKnownHostsFile #{Wakame.config.ssh_known_hosts}\" root@#{@mysqld_master_host} chown mysql:mysql #{@mysqld_master_
datadir}/master.info"
Wakame.log.debug(command)
system(command)
# sync
3.times do |i|
command = "ssh -i #{Wakame.config.ssh_private_key} -o \"StrictHostKeyChecking no\" -o \"UserKnownHostsFile #{Wakame.config.ssh_known_hosts}\" root@#{@mysqld_master_host} /bin/sync"
system(command)
sleep 1.0
end
FileUtils.rm_rf tmp_output_basedir
# 2. snapshot
Wakame.log.debug("create_snapshot (#{@ebs_volume})")
snapshot_map = vm_manipulator.create_snapshot(@ebs_volume)
16.times do |i|
Wakame.log.debug("describe_snapshot(#{snapshot_map.snapshotId}) ... #{i}")
snapshot_map = vm_manipulator.describe_snapshot(snapshot_map["snapshotId"])
if snapshot_map["status"] == "completed"
break
end
sleep 1.0
end
if snapshot_map["status"] != "completed"
raise "#{snapshot_map.snapshotId} status is #{snapshot_map.status}"
end
# 3. unlock mysql-master
system("echo 'UNLOCK TABLES;' | /usr/bin/mysql -h#{@mysqld_master_host} -P#{@mysqld_master_port} -u#{@mysqld_master_user} -p#{@mysqld_master_pass}")
# create volume /dev/xxxx
Wakame.log.debug("create_volume_from_snapshot(#{volume_map.availabilityZone}, #{snapshot_map.snapshotId})")
created_volume_from_snapshot_map = vm_manipulator.create_volume_from_snapshot(volume_map["availabilityZone"], snapshot_map["snapshotId"])
volume_from_snapshot_map = created_volume_from_snapshot_map
16.times do |i|
Wakame.log.debug("describe_snapshot(#{snapshot_map.snapshotId}) ... #{i}")
volume_from_snapshot_map = vm_manipulator.describe_snapshot(snapshot_map["snapshotId"])
if volume_from_snapshot_map["status"] == "completed"
break
end
sleep 1.0
end
if volume_from_snapshot_map["status"] != "completed"
raise "#{volume_from_snapshot_map.snapshotId} status is #{volume_from_snapshot_map.status}"
end
# △wakame-ebs-mysql-master-make-snapshot.sh ここまで
# ▽wakame-ebs-mysql-slave-restore.sh(1) ここから
# attach volume
attach_volume_map = vm_manipulator.attach_volume(svc.agent.agent_id, created_volume_from_snapshot_map["volumeId"], @ebs_device)
16.times do |i|
Wakame.log.debug("describe_volume(#{attach_volume_map.volumeId}) ... #{i}")
attach_volume_map = vm_manipulator.describe_volume(created_volume_from_snapshot_map["volumeId"])
if attach_volume_map["status"] == "in-use"
break
end
sleep 1.0
end
if attach_volume_map["status"] != "in-use"
raise "#{attach_volume_map.volumeId} status is #{attach_volume_map.status}"
end
# △wakame-ebs-mysql-slave-restore.sh(1) ここまで
end
# in wakame-agent
def start
# ▽wakame-ebs-mysql-slave-restore.sh(2) ここから
mount_point_dev=`df "#{@mysqld_datadir}" | awk 'NR==2 {print $1}'`
if mount_point_dev != @ebs_device
# sync
3.times do |i|
system("/bin/sync")
sleep 1.0
end
Wakame.log.debug("Mounting EBS volume: #{@ebs_device} as #{@mysqld_datadir} (with option: #{@ebs_mount_option})")
system("/bin/mount -o #{@ebs_mount_option} #{@ebs_device} #{@mysqld_datadir}")
# sync
3.times do |i|
system("/bin/sync")
sleep 1.0
end
end
system(Wakame.config.root + "/config/init.d/mysql-slave start")
# △wakame-ebs-mysql-slave-restore.sh(2) ここまで
end
end
これで、
MySQL_Slaveをサービスに追加
MySQL Slaveの手順を記述するだけではWakameサービス対象には含まれません。Clusterにサービスに追加する必要があります。MySQL_
class WebCluster < ServiceCluster
def initialize(master, &blk)
super(master) {
# サービスの定義を追加
add_service(Apache_WWW.new)
add_service(Apache_APP.new)
add_service(Apache_LB.new)
add_service(MySQL_Master.new)
add_service(MySQL_Slave.new)
# 依存関係の指定
set_dependency(Apache_WWW, Apache_LB)
set_dependency(Apache_APP, Apache_LB)
set_dependency(MySQL_Master, Apache_APP)
set_dependency(MySQL_Master, MySQL_Slave)
end
end
いよいよMySQL_
wakameadmから実行してみる
これ以降、
- MySQL Slaveを増やす
-
以下のコマンドを入力するだけで、
しばらく待てばSlaveが増えるはずです。 # wakameadm propagate_
service Wakame::Service::MySQL_ Slave - MySQL Slaveを移動する
-
以下のように、
移動もできます。単一インスタンスに同居しているSlaveを追い出したりするのに便利です。 # wakameadm migrate_
service {Wakame-Instance-ID}
Wakame 0.4のリリース
6月26日
- ソースコードが書き直されて整理された
- Wakame Agentの設計が変更され、
機能追加と呼び出しが整理された - gem化された
特にソースコードの整理の意義ですが、
現在は、
なお、
今後あくしゅでは、