系统:CentOS 5.4
IP分配:
HA1 eth0:192.168.0.66 eth1:192.168.10.1
HA2 eth0:192.168.0.69 eth1:192.168.10.2
VIP 192.168.0.120
DRBD(Distributed Replicated Block Device),DRBD
号称是 “网络 RAID”,开源软件,由LINBIT 公司开发。DRBD实际上是一种块设备的实现,主要被用于Linux平台下的高可用(HA)方案之中。他有内核模块和相关程序而组成,通过网络通信来同步镜像整个设备,有点类似于一个网络RAID-1的功能。也就是说当你将数据写入本地的DRBD设备上的文件系统时,数据会同时被发送到网络中的另外一台主机之上,并以完全相同的形式记录在文件系统中。本地节点与远程节点的数据可以保证实时的同步,并保证IO的一致性。所以当本地节点的主机出现故障时,远程节点的主机上还会保留有一份完全相同的数据,可以继续使用,以达到高可用的目的。
一、安装DRBD
在HA1和HA2上安装DRBD。
wget http://oss.linbit.com/drbd/8.3/drbd-8.3.5.tar.gz
[root@HA1 ~]# tar xzvf drbd-8.3.5.tar.gz
[root@HA1 ~]# cd drbd-8.3.5
[root@HA1 drbd-8.3.5]# make clean all
[root@HA1 drbd-8.3.5]# make install
[root@HA1 drbd-8.3.5]# cd
[root@HA1 ~]# vi /etc/drbd.conf
global {
usage-count yes; # 是否参加使用者统计,yes为参加
}
common {
syncer { rate 100M; } # 设置网络同步速率,建议改为实际网络速率
}
# 一个DRBD设备(即:/dev/drbdX),叫做一个"资源"。
resource "r0" {
protocol C; # 数据同步协议,C表示收到远程主机的写入确认后才认为写入完成
startup {
}
disk {
on-io-error detach;
}
handlers {
split-brain "/usr/lib/drbd/notify-split-brain.sh
root"; # 自动修复脑裂问题
}
net {
# 设置主备机之间通信使用的信息算法.
cram-hmac-alg sha1;
shared-secret "FooFunFactory";
# 自动修复脑裂问题
after-sb-0pri discard-zero-changes;
after-sb-1pri discard-secondary;
after-sb-2pri disconnect;
}
syncer {
}
# 每个主机的说明以"on"开头,后面是主机名
on HA1 {
device /dev/drbd0;
disk /dev/sdb;
# 设置DRBD的监听端口,用于与另一台主机通信
address 192.168.0.66:7789;
# metadata的存放位置
# internal表示将metadata存放到drbd挂在的磁盘分区的最后的位置上
meta-disk internal;
}
on HA2 {
device /dev/drbd0;
disk /dev/sdb;
address 192.168.0.69:7789;
meta-disk internal;
}
}
DRBD将数据的各种信息块保存在一个专用的区域里,这些metadata包括了
a,DRBD设备的大小
b,产生的标识
c,活动日志
d,快速同步的位图
metadata的存储方式有内部和外部两种方式,使用哪种配置都是在资源配置中定义的
内部metadata:内部metadata存放在同一块硬盘或分区的最后的位置上
优点:metadata和数据是紧密联系在一起的,如果硬盘损坏,metadata同样就没有了,同样在恢复的时候,metadata也会一起被恢复回来
缺点:metadata和数据在同一块硬盘上,对于写操作的吞吐量会带来负面的影响,因为应用程序的写请求会触发metadata的更新,这样写操作就会造成两次额外的磁头读写移动。
外部metadata:外部的metadata存放在和数据磁盘分开的独立的块设备上
优点:对于一些写操作可以对一些潜在的行为提供一些改进
缺点:metadata和数据不是联系在一起的,所以如果数据盘出现故障,在更换新盘的时候就需要人为的干预操作来进行现有node对心硬盘的同步了
[root@HA1 ~]# scp /etc/drbd.conf HA2:/etc/
初始化并启动两个系统上的 DRBD 服务:
[root@HA1 ~]# drbdadm create-md r0
[root@HA1 ~]# service drbd start
Starting DRBD resources: [ d(r0) s(r0) n(r0) ].
将 HA1 配置为主节点:
[root@HA1 ~]# drbdadm --overwrite-data-of-peer primary
r0
两个设备开始同步数据:
[root@HA2 ~]# service drbd status
drbd driver loaded OK; device status:
version: 8.3.5 (api:88/proto:86-91)
GIT-hash: ded8cdf09b0efa1460e8ce7a72327c60ff2210fb build
by root@HA2, 2009-11-13 01:58:29
m:res cs ro ds p mounted fstype
… sync’ed: 0.6% (6108/6140)M
0:r0 SyncTarget Secondary/Primary Inconsistent/UpToDate
C
………
[root@HA2 ~]# service drbd status
drbd driver loaded OK; device status:
version: 8.3.5 (api:88/proto:86-91)
GIT-hash: ded8cdf09b0efa1460e8ce7a72327c60ff2210fb
build by root@HA2, 2009-11-13 01:58:29
m:res cs ro ds p mounted fstype
… sync’ed: 45.6% (3344/6140)M
0:r0 SyncTarget Secondary/Primary Inconsistent/UpToDate
C
………
同步数据完成:
[root@HA2 ~]# service drbd status
drbd driver loaded OK; device status:
version: 8.3.5 (api:88/proto:86-91)
GIT-hash: ded8cdf09b0efa1460e8ce7a72327c60ff2210fb build
by root@HA2, 2009-11-13 01:58:29
m:res cs ro ds p mounted fstype
… sync’ed:100.0% (4/6140)M
0:r0 SyncTarget Secondary/Primary Inconsistent/UpToDate
C
[root@HA2 ~]# service drbd status
drbd driver loaded OK; device status:
version: 8.3.5 (api:88/proto:86-91)
GIT-hash: ded8cdf09b0efa1460e8ce7a72327c60ff2210fb build
by root@HA2, 2009-11-13 01:58:29
m:res cs ro ds p mounted fstype
0:r0 Connected Secondary/Primary UpToDate/UpToDate
C
[root@HA1 ~]# cat /proc/drbd
version: 8.3.5 (api:88/proto:86-91)
GIT-hash: ded8cdf09b0efa1460e8ce7a72327c60ff2210fb
build by root@HA1, 2009-11-13 01:53:51
0: cs:Connected ro:Primary/Secondary
ds:UpToDate/UpToDate C r—-
ns:6291228 nr:0 dw:0 dr:6291228 al:0
bm:384 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:0
两个节点上的块设备都完全同步之后,使用诸如ext3的文件系统格式化主节点上的
DRBD 设备。
[root@HA1 ~]# mkfs.ext3 /dev/drbd0
测试DRBD服务:
手动挂载DRBD设备,并测试写入文件。
[root@HA1 ~]# mount -o rw /dev/drbd0
/data/
[root@HA1 ~]# echo “This is a test line.”
> /data/test.txt
卸载DRBD设备并将HA1设置为从设备。
[root@HA1 ~]# umount /data/
[root@HA1 ~]# drbdadm secondary r0
将HA2设置为主设备。
[root@HA2 ~]# drbdadm primary r0
[root@HA2 ~]# service drbd status
drbd driver loaded OK; device status:
version: 8.3.5 (api:88/proto:86-91)
GIT-hash: ded8cdf09b0efa1460e8ce7a72327c60ff2210fb
build by root@HA2, 2009-11-13 01:58:29
m:res cs ro ds p mounted fstype
0:r0 Connected Primary/Secondary UpToDate/UpToDate
C
挂载DRBD设备并验证能够读出在HA1上写入的文件。
[root@HA2 ~]# mount -o rw /dev/drbd0
/data/
[root@HA2 ~]# cat /data/test.txt
This is a test line.
卸载DRBD设备并将HA2设置为从设备。
[root@HA2 ~]# umount /data/
[root@HA2 ~]# drbdadm secondary r0
将HA1设置为主设备。
[root@HA1 ~]# drbdadm primary r0
查看HA2的DRDB状态:
[root@HA2 ~]# service drbd status
drbd driver loaded OK; device status:
version: 8.3.5 (api:88/proto:86-91)
GIT-hash: ded8cdf09b0efa1460e8ce7a72327c60ff2210fb
build by root@HA2, 2009-11-13 01:58:29
m:res cs ro ds p mounted fstype
0:r0 Connected Secondary/Primary UpToDate/UpToDate
C
在HA1和HA2上配置hosts
[root@HA1 ~]# cat /etc/hosts
# Do not remove the following line, or various programs
# that require network functionality will fail.
127.0.0.1 vpc localhost.localdomain localhost
::1 localhost6.localdomain6 localhost6
192.168.10.1 HA1
192.168.10.2 HA2
在HA1和HA2上配置时间同步:
[root@HA1 ~]# crontab -e
*/5 * * * * /usr/sbin/ntpdate ntp.api.bz
二、在HA1和HA2安装MySQL和Nginx并将数据迁移到/data目录
[root@HA1 ~]# yum install -y mysql-server
[root@HA1 ~]# cat /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
user=mysql
bind-address=192.168.0.120
[root@HA1 ~]# cp -r /var/lib/mysql/ /data/
[root@HA1 ~]# cd /data/
[root@HA1 data]# chown -R mysql.mysql
mysql/
[root@HA1 data]# service mysqld start
Starting MySQL: [ OK ]
[root@HA1 data]# service mysqld stop
Stopping MySQL: [ OK ]
注意:数据迁移只需在HA1上做。
安装Nginx略,具体见Nginx 0.7.x + PHP 5.2.8(FastCGI)搭建胜过Apache十倍的Web服务器(http://blog.s135.com/post/366/)
[root@HA1 ~]# chkconfig --level 2345
mysqld off
[root@HA2 ~]# chkconfig --level 2345
mysqld off
注意:不要在外部启动HA使用的资源,一切让HA去控制。
编写nginx lsb资源代理脚本(注意nginx安装路径):
[root@HA1 ~]# cat /etc/init.d/nginxd
#!/bin/sh
# source function library
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0
RETVAL=0
prog="nginx"
nginxDir=/usr/local/nginx
nginxd=$nginxDir/sbin/nginx
nginxConf=$nginxDir/conf/nginx.conf
nginxPid=$nginxDir/nginx.pid
nginx_check()
{
if [[ -e $nginxPid ]]; then
ps aux |grep -v grep |grep -q nginx
if (( $? == 0 )); then
echo "$prog already running..."
exit 1
else
rm -rf $nginxPid &> /dev/null
fi
fi
}
start()
{
nginx_check
if (( $? != 0 )); then
true
else
echo -n $"Starting $prog:"
daemon $nginxd -c $nginxConf
RETVAL=$?
echo
[ $RETVAL = 0 ] && touch /var/lock/subsys/nginx
return $RETVAL
fi
}
stop()
{
echo -n $"Stopping $prog:"
killproc $nginxd
RETVAL=$?
echo
[ $RETVAL = 0 ] && rm -f /var/lock/subsys/nginx
$nginxPid
}
reload()
{
echo -n $"Reloading $prog:"
killproc $nginxd -HUP
RETVAL=$?
echo
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
reload)
reload
;;
status)
status $prog
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|restart|reload|status}"
RETVAL=1
esac
exit $RETVAL
[root@HA1 ~]# chmod +x /etc/init.d/nginxd
[root@HA1 ~]# scp /etc/init.d/nginxd
HA2: /etc/init.d/nginxd
三、安装配置corosync和pacemaker
corosync是基于OpenAIS构建的集群引擎,可替代heartbeat进行心跳检测。
The Corosync Cluster Engine is an open
source project Licensed under the BSD License derived
from the OpenAIS project. OpenAIS uses a UDP multicast
based communication protocol to periodically check for
node availability.
[root@HA1 ~]# wget -O /etc/yum.repos.d/pacemaker.repo
http://clusterlabs.org/rpm/epel-5/clusterlabs.repo
[root@HA1 ~]# wget ftp://ftp.pbone.net/mirror/centos.karan.org/el5/extras/testing/i386/RPMS/libesmtp-1.0.4-6.el5.kb.i386.rpm
[root@HA1 ~]# rpm -ivh libesmtp-1.0.4-6.el5.kb.i386.rpm
[root@HA1 ~]# yum install -y pacemaker
corosync
[root@HA1 ~]# corosync-keygen
Corosync Cluster Engine Authentication
key generator.
Gathering 1024 bits for key from /dev/random.
Press keys on your keyboard to generate
entropy.
Writing corosync key to /etc/corosync/authkey.
[root@HA1 ~]# scp /etc/corosync/authkey
HA2:/etc/corosync/
[root@HA1 ~]# cp /etc/corosync/corosync.conf.example
/etc/corosync/corosync.conf
[root@HA1 ~]# vi !$
# Please read the corosync.conf.5 manual page
compatibility: whitetank
totem {
version: 2
secauth: off
threads: 0
interface {
ringnumber: 0
bindnetaddr: 192.168.10.0
mcastaddr: 226.94.1.1
mcastport: 5405
}
}
logging {
fileline: off
to_stderr: yes
to_logfile: yes
to_syslog: yes
logfile: /var/log/corosync.log
debug: off
timestamp: on
logger_subsys {
subsys: AMF
debug: off
}
}
amf {
mode: disabled
}
service {
# Load the Pacemaker Cluster Resource Manager
ver: 0
name: pacemaker
use_mgmtd: yes
}
[root@HA1 ~]# scp /etc/corosync/corosync.conf HA2:/etc/corosync/corosync.conf
[root@HA1 ~]# service corosync start
Starting Corosync Cluster Engine (corosync):
[ OK ]
[root@HA1 ~]# chkconfig --level 2345
corosync on
在HA2上执行:
[root@HA2 ~]# chown root:root /etc/corosync/authkey
[root@HA2 ~]# chmod 400 /etc/corosync/authkey
[root@HA2 ~]# service corosync start
Starting Corosync Cluster Engine (corosync):
[ OK ]
[root@HA2 ~]# chkconfig --level 2345
corosync on
四、配置CRM资源
[root@HA1 ~]# crm
crm(live)# configure
crm(live)configure# node HA1
crm(live)configure# node HA2
# 配置drbd原始资源
crm(live)configure# primitive drbd ocf:linbit:drbd \
params drbd_resource="r0" \
meta migration-threshold="10"
# 配置drbd资源监控
crm(live)configure# monitor drbd 30s:20s
# 配置文件系统原始资源
crm(live)configure# primitive fs ocf:heartbeat:Filesystem
\
params device="/dev/drbd0" directory="/data"
fstype="ext3"
# 配置mysql原始资源,使用lsb代理
crm(live)configure# primitive mysqld lsb:mysqld
# 配置nginx原始资源,使用lsb代理
crm(live)configure# primitive nginxd lsb:nginxd
# 配置共享IP原始资源
crm(live)configure# primitive vip ocf:heartbeat:IPaddr2
\
params ip="192.168.0.120" nic="eth0:0"
# 创建资源组保障资源在某一节点上按顺序启动和停止
crm(live)configure# group mysql-group fs vip mysqld
nginxd
# 配置drbd主资源约束
crm(live)configure# ms ms-drbd-mysql drbd \
meta master-max="1" master-node-max="1"
clone-max="2" clone-node-max="1"
notify="true"
# 配置资源位置约束,保证mysql-group资源组启动在drbd主资源上
crm(live)configure# colocation mysql-on-drbd inf: mysql-group
ms-drbd-mysql:Master
# 配置资源启动顺序约束,保证drbd启动后启动mysql-group资源组
crm(live)configure# order mysql-after-drbd inf: ms-drbd-mysql:promote
mysql-group:start
crm(live)configure# property $id="cib-bootstrap-options"
\
expected-quorum-votes="2" \
stonith-enabled="false" \
no-quorum-policy="ignore" \
start-failure-is-fatal="false"
crm(live)configure# commit
crm(live)configure# end
crm(live)#
五、测试
[root@HA1 ~]# crm status
============
Last updated: Fri Nov 20 22:47:51 2009
Stack: openais
Current DC: HA2 -- partition with quorum
Version: 1.0.6-f709c638237cdff7556cb6ab615f32826c0f8c06
2 Nodes configured, 2 expected votes
2 Resources configured.
============
Online: [ HA1 HA2 ]
Master/Slave Set: ms-drbd-mysql
Masters: [ HA1 ]
Slaves: [ HA2 ]
Resource Group: mysql-group
fs (ocf::heartbeat:Filesystem): Started
HA1
vip (ocf::heartbeat:IPaddr2): Started
HA1
mysqld (lsb:mysqld): Started HA1
nginxd (lsb:nginxd): Started HA1
关闭HA1,在HA2上查看HA状态:
[root@HA2 ~]# crm_mon -i1
============
Last updated: Sat Nov 21 01:31:13 2009
Stack: openais
Current DC: HA2 - partition WITHOUT
quorum
Version: 1.0.6-f709c638237cdff7556cb6ab615f32826c0f8c06
2 Nodes configured, 2 expected votes
2 Resources configured.
============
Online: [ HA2 ]
OFFLINE: [ HA1 ]
Master/Slave Set: ms-drbd-mysql
Masters: [ HA2 ]
Stopped: [ drbd:1 ]
Resource Group: mysql-group
fs (ocf::heartbeat:Filesystem): Started
HA2
vip (ocf::heartbeat:IPaddr2): Started
HA2
mysqld (lsb:mysqld): Started HA2
nginxd (lsb:nginxd): Started HA2
启动HA1,资源自动迁移到HA1:
[root@HA1 ~]# crm_mon -i1
============
Last updated: Mon Nov 23 15:42:52 2009
Stack: openais
Current DC: HA2 - partition with quorum
Version: 1.0.6-f709c638237cdff7556cb6ab615f32826c0f8c06
2 Nodes configured, 2 expected votes
2 Resources configured.
============
Online: [ HA1 HA2 ]
Master/Slave Set: ms-drbd-mysql
Masters: [ HA1 ]
Slaves: [ HA2 ]
Resource Group: mysql-group
fs (ocf::heartbeat:Filesystem): Started HA1
vip (ocf::heartbeat:IPaddr2): Started HA1
mysqld (lsb:mysqld): Started HA1
nginxd (lsb:nginxd): Started HA1
手动迁移资源到HA2
[root@HA1 ~]# crm resource migrate mysql-group HA2
[root@HA2 ~]# crm_mon -i1
============
Last updated: Mon Nov 23 15:43:42 2009
Stack: openais
Current DC: HA2 - partition with quorum
Version: 1.0.6-f709c638237cdff7556cb6ab615f32826c0f8c06
2 Nodes configured, 2 expected votes
2 Resources configured.
============
Online: [ HA1 HA2 ]
Master/Slave Set: ms-drbd-mysql
Masters: [ HA2 ]
Slaves: [ HA1 ]
Resource Group: mysql-group
fs (ocf::heartbeat:Filesystem): Started HA2
vip (ocf::heartbeat:IPaddr2): Started HA2
mysqld (lsb:mysqld): Started HA2
nginxd (lsb:nginxd): Started HA2
六、解决脑裂(split brain)问题:
在“双机热备”高可用(HA)系统中,当联系2个节点的“心跳线”断开时,本来为一整体、动作协调的HA系统,就分裂成为2个独立的个体。由于相互失去了联系,都以为是对方出了故障,2个节点上的HA软件像“裂脑人”一样,“本能”地争抢“共享资源”、争起“应用服务”,就会发生严重后果:或者共享资源被瓜分、2边“服务”都起不来了;或者2边“服务”都起来了,但同时读写“共享存储”,导致数据损坏(常见如数据库轮询着的联机日志出错)。
对付HA系统“裂脑”的对策大概有以下几条:
1)添加冗余的心跳线,例如双线跳线。尽量减少“裂脑”发生机会。
2)启用磁盘锁。正在服务一方锁住共享磁盘,“裂脑”发生时,让对方完全“抢不走”共享磁盘资源。但使用锁磁盘也会有一个不小的问题,如果占用共享盘的一方不主动“解锁”,另一方就永远得不到共享磁盘。现实中假如服务节点突然死机或崩溃,就不可能执行解锁命令。后备节点也就接管不了共享资源和应用服务。于是有人在HA中设计了“智能”锁。即,正在服务的一方只在发现心跳线全部断开(察觉不到对端)时才启用磁盘锁。平时就不上锁了。
3)设置仲裁机制。例如设置参考IP(如网关IP),当心跳线完全断开时,2个节点都各自ping一下 参考IP,不通则表明断点就出在本端,不仅“心跳”、还兼对外“服务”的本端网络链路断了,即使启动(或继续)应用服务也没有用了,那就主动放弃竞争,让能够ping通参考IP的一端去起服务。更保险一些,ping不通参考IP的一方干脆就自我重启,以彻底释放有可能还占用着的那些共享资源。
手动解决DRBD脑裂问题:
[root@HA2 ~]# drbdadm down all
[root@HA2 ~]# drbdadm create-md all
|