CentOS下实现Heartbeat+DRBD+MySQL双机热备硬件故障自动切换高可用(HA)方案

方案简介

本方案采用Heartbeat双机热备软件来保证数据库的高稳定性和连续性,数据的一致性由DRBD这个工具来保证。默认情况下只有一台mysql在工作,当主mysql服务器出现问题后,系统将自动切换到备机上继续提供服务,当主数据库修复完毕,又将服务切回继续由主mysql提供服务。

方案优缺点

优点:安全性高、稳定性高、可用性高,出现故障自动切换。

缺点:只有一台服务器提供服务,成本相对较高,不方便扩展,可能会发生脑裂。

软件介绍

Heartbeat介绍

官方站点:http://linux-ha.org/wiki/Main_Page

heartbeat可以把资源(VIP地址及程序服务)从一台有故障的服务器快速的转移到另一台正常的服务器提供服务,heartbeat和keepalived相似,heartbeat可以实现failover(故障转移)功能,但不能实现对后端的健康检查

DRBD介绍

官方站点:http://www.drbd.org/

DRBD(Distribute Replicated Block Device) :分布式复制块设备 在高可用性网络中,实现多个节点之间的存储一致性,当一个节点的磁盘内容变化后,自动将数据同步到其他节点上。镜像设备可以是硬盘、分区或逻辑卷只有主设备才能对自己的磁盘读取、写入、挂载,从设备必须变为主设备才能操作磁盘。它是一个基于块设备级别在远程服务器直接同步和镜像数据的软件,用软件实现的、无共享的、服务器之间镜像块设备内容的存储复制解决方案。它可以实现在网络中两台服务器之间基于块设备级别的实时镜像或同步复制(两台服务器都写入成功)/异步复制(本地服务器写入成功),相当于网络的RAID1,由于是基于块设备(磁盘,LVM逻辑卷),在文件系统的底层,所以数据复制要比cp命令更快。DRBD已经被MySQL官方写入文档手册作为推荐的高可用的方案之一

DRBD是一种块设备,可以被用于高可用(HA)之中.它类似于一个网络RAID-1功能.当你将数据写入本地 文件系统时,数据还将会被发送到网络中另一台主机上.以相同的形式记录在一个文件系统中。 本地(主节点)与远程主机(备节点)的数据可以保证实时同步.当本地系统出现故障时,远程主机上还会 保留有一份相同的数据,可以继续使用.在高可用(HA)中使用DRBD功能,可以代替使用一个共享盘阵.因为数据同时存在于本地主机和远程主机上,切换时,远程主机只要使用它上面的那份备份数据,就可以继续进行服务了。

DRBD工作原理

提供两个大小相同的分区,在数据流的层次上构建一个磁盘镜像,就如同raid1,所以又被称为分布式raid

主从架构:primary/secondary
默认结构,两节点的所有存储属性,内容皆相同;
同一时刻只能有一个节点上线(即从节点,读写皆不可),主节点接到数据后,将数据备份到磁盘,同时传递给从节点,并存放到磁盘中.此时文件系统可以使用本地文件系统:ext2 ext3 xfs等

双主模型:
同一时刻可以有两个节点同时工作,即组内节点皆上线;
节点必须为集群文件系统,如:GFS2;OCFS2(本身提供高可用功能)
必须支持分布式文件锁(内核支持),主节点写入的时候,从节点就从文件锁得知对方在写入;
高可用集群的底层文件信息通道(必须将DRBD做成集群资源).

简言之:
Master/Master模式:
1、文件系统必须为集群文件系统如:GFS2;OCFS2(本身提供高可用功能)
2、使用高可用环境
3、使用分布式锁DLM

Master/Slave模式:
1、可以使用普通文件系统
2、可以切换主从角色
3、如果需要为高可用提供存储空间,需要将DRBD作为HA的一个资源
4、从节点不可读、不可写、不可挂载

因为drbd工作在内核,故需要用户空间工具提供规则,所以它由用户空间工具和内核模块组成,就如同iptables和LVS一样.drbd共有两部分组成:内核模块和用户空间的管理工具。其中drbd内核模块代码已经整合进Linux内核2.6.33以后的版本中,因此,如果您的内核版本高于此版本的话,你只需要安装管理工具即可;否则,您需要同时安装内核模块和管理工具两个软件包,并且此两者的版本号一定要保持对应。

不支持多个从,至少当前不支持

用户空间工具

告知内核哪个分区是drbd设备

drbdadm    /usr/local/drbd/etc/drbd.d/
    |__ drbdadm primary resource_name      升级为主节点
    |__ drbdadm secondary resource_name    降级为备节点

drbdsetup
drbdmeta

查看drbd状态,有两种方法
cat /proc/drbd
service drbd status

工作模式

DRBD有三种工作模式告知上层进程写入完成:A异步(异步的传输),B半同步(同步到内存),C同步(同步到对方的磁盘上)
A模式:主节点接到数据,只保证发送到本地网卡的数据缓冲区(性能最好),即数据一旦写入磁盘并发送到网络中就认为完成了写入操作。
B模式:主节点接到数据,保证数据发送到从节点缓冲区,且存到了从节点的内核区,但是是否数据存储到从节点的硬盘,则不清楚。即收到接收确认就认为完成了写入操作。
C模式:主节点接到数据,保证数据发送到从节点缓冲区,同时接到从节点存到从节点硬盘的信息(安全最高)。即收到写入确认就认为完成了写入操作。

简言之:
ProtocolA:异步,数据被送到TCP/IP协议缓冲区就宣布复制完成
ProtocolB:半同步,也称内存同步,数据发送到从节点的内存接收缓冲区
ProtocolC:同步,数据写到对方的磁盘

如何解决故障后自动切换

利用高可用的底层信息通道(如HA的heartbeat或者corosync)+pacemaker进行资源监控,将drbd定义为资源,且drbd资源有主从之分.

方案拓扑

1

方案适用场景

适用于数据库访问量不太大,短期内访问量增长不会太快,对数据库可用性要求非常高的场景。

这只是高可用的其中一种方案,生产环境如果数据库访问量大不推荐使用,因为DRBD会使数据库性能严重下降。

测试环境介绍

(如下所示,均已关闭防火墙及selinux,生产环境自行开放端口)
关闭防火墙:

service iptables stop
chkconfig iptables off 

关闭SELinux:

sed -i -e "s/=enforcing/=disabled/g" /etc/selinux/config
setenforce 0 

更多详情请参考 CentOS关闭SELinux的方法:http://www.3mu.me/centos%E5%85%B3%E9%97%ADselinux%E7%9A%84%E6%96%B9%E6%B3%95/

主机名             ip               系统                DRBD磁盘                heartbeat版本
db-server-01    192.168.0.10    centos6.2 64bit         /dev/sda5                  3.0.4
db-server-02    192.168.0.20    centos6.2 64bit         /dev/sda5                  3.0.4

软件安装以及环境配置

(1)安装drbd依赖组件(两台机器,安装以后重启系统,因为会升级内核版本,不重启会对不上内核版本,有知道不用重启的童鞋请给我留言^_^):

yum install -y make gcc gcc-c++ kernel kernel-devel kernel-headers perl flex 

注意:安装的kernel-devel的内核源码(内核源码路径/usr/src/kernel/)和当前系统的kernel版本(uname -r)不一致的话需要把当前内核更新一下。#yum update kernel-版本号

修改默认引导内核为最新版本内核,默认更新后最新的内核排在最上面,不用修改。如果不是就按照下面方法修改。

修改/etc/grub.conf 查看最新的内核版本排在第几个,从0开始。title开头的行是内核。将default=设置为要启动的内核顺序数。

重启服务器

(2)下载软件安装(两台机器操作一样)

# uname -r #查看内核版本,在2.6.33及以上的内核中有DRBD

如果没有,则需要自己制作或者采用第三方rpm包
一定要使用与内核相匹配的包(google或者rpmfind(http://rpmfind.net)搜索)
drbd与linux内核的关系,可以参考:http://www.alexclouds.net/?p=332

wget http://oss.linbit.com/drbd/8.4/drbd-8.4.2.tar.gz
#安装drbd源码包
tar xf drbd-8.4.2.tar.gz 
cd drbd-8.4.2
./configure --prefix=/usr/local/drbd --with-km #--with-km是启用内核模块 
#make KDIR=/usr/src/kernels/2.6.32-431.11.2.el6.x86_64/   #KDIR=指定的系统内核源码路径,根据实际情况设置。很多童鞋无法加载drbd模块,多半是正在运行的内核版本和新安装的不相符
make KDIR=/usr/src/kernels/`uname -r`/ # 自动识别内核版本 
make install
mkdir -p /usr/local/drbd/var/run/drbd
cp /usr/local/drbd/etc/rc.d/init.d/drbd /etc/rc.d/init.d
chmod 755 /etc/init.d/drbd
#安装drbd模块
#drbd是作为内核模块运行的,但是我们在安装的时候程序并没有创建相应的内核模块,故需要我另行创建drbd模块,并载入内核。
cd drbd
make clean
make KDIR=/usr/src/kernels/`uname -r`/
cp drbd.ko /lib/modules/`uname -r`/kernel/lib/
modprobe drbd #执行命令加载drbd模块到内核

检查是否加载了drbd模块

[root@192.168.0.10 ~]# lsmod | grep drbd
drbd                  314246  0 
libcrc32c               1246  1 drbd

通过lsmod检查是否已经成功,如果有类似内容输出,则表示drbd安装成功了
(3)DRBD配置
前提准备:提供两个大小相同的磁盘或者磁盘分区空间

drbd_resource组成: resource_name device disk network
global{}基本没意义的配置
common{}定义drbd设备共享的属性信息(磁盘信息,网络信息,认证信息),可能存在多组drbd设备,每组包含一个主从
剩余配置信息是不同的属性
每一组drbd叫做drbd资源(资源名必须是小写字符),资源之间以套接字方式互相通信
每一组drbd,主从所在的磁盘分区必须大小相等

配置之前需要先使用fdisk对 /dev/sda进行分区

[root@192.168.0.10 ~]# df -HT
Filesystem    Type     Size   Used  Avail Use% Mounted on
/dev/sda2     ext4      19G   2.6G    16G  15% /
tmpfs        tmpfs     121M      0   121M   0% /dev/shm
/dev/sda1     ext4     204M    52M   141M  27% /boot
/dev/sda5     ext4      34G   185M    32G   1% /data

我这里两台机器之前都已经分区了,由于是自己笔记本上的虚拟机,所以懒得加磁盘了,我直接把 /data/卸载,然后格式化/dev/sda5,我两台机器都这样操作,如果你有空的磁盘,照样需要进行分区,比如可以将一个1T的盘分一个区就行了。
具体的分区方法可以参考:heartbeat+DRBD+NFS(参考文中的分区部分):http://jialiang10086.blog.51cto.com/4496483/1030989

[root@192.168.0.10 ~]# umount /data/         
[root@192.168.0.10 ~]# mkfs.ext4 /dev/sda5
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
2048000 inodes, 8185344 blocks
409267 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=4294967296
250 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks: 
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
        4096000, 7962624

Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 28 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.
[root@192.168.0.10 ~]# fdisk -l

Disk /dev/sda: 53.7 GB, 53687091200 bytes
255 heads, 63 sectors/track, 6527 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000eb0ff

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1          26      204800   83  Linux
Partition 1 does not end on cylinder boundary.
/dev/sda2              26        2321    18432000   83  Linux
/dev/sda3            2321        2451     1048576   82  Linux swap / Solaris
/dev/sda4            2451        6528    32742400    5  Extended
/dev/sda5            2451        6528    32741376   83  Linux

我这里还要在/etc/fstab里面注释一项:

#UUID=33958004-e8a7-4135-844f-707a5537e86a /data                   ext4    defaults        1 2

否则重启机器的时候提示无法挂载,会无法启动的。

要保证两个节点之间可以相互解析,在两台节点上分别配置hosts文件
修改/etc/hosts文件,两台服务器操作一样。

192.168.0.10    db-server-01
192.168.0.20    db-server-02

如果主机名与测试的主机名不一至,会报错,所以需要先改主机名。修改主机名的方法如下:
1、首先有一个治标不治本的方法,就是执行:hostname 新名称
ok logout 后在进入 主机名就换了,但是这个方法是临时修改的,重启后名称就会恢复回去
2、永久修改主机名

第一步:
#hostname secondNamenode
第二步:
修改/etc/sysconfig/network中的hostname
第三步:
修改/etc/hosts文件

# uname -n 查看当前的主机名

drbd配置只需要修改/usr/local/drbd/etc/drbd.d/global_common.conf配置文件即可,修改后如下(两台服务器配置一样):

[root@192.168.0.10 ~]# cat /usr/local/drbd/etc/drbd.d/global_common.conf
global { 
	usage-count no;  #是否给官方发送统计报告(影响性能),这个不用说,还是关了吧
}
#定义drbd节点的共同点属性
common { syncer { rate 30M; } }       #设置主备节点同步时的网络速率最大值,单位是字节,视带宽而定 

#定义一个资源
#一个DRBD设备(即:/dev/drbdX),叫做一个"资源"。里面包含一个DRBD设备的主备节点的的ip信息,底层存储设备名称,设备大小,meta信息存放方式,drbd对外提供的设备名等等。
resource r0 {                         #创建一个资源,名字叫"r0" 
        protocol C;                   #选择的是drbd的C 协议(数据同步协议,C为收到数据并写入后返回,确认成功) 
        startup {
        }
        disk {
                on-io-error detach; # 配置I/O错误处理策略为分离 
        }
        net {
			cram-hmac-alg "sha1"; #设置主备机之间通信使用的信息算法。通讯时使用sha1加密
			shared-secret "abc"; #设置加密密钥,双方应相同
        }
		#每个主机的说明以"on"开头,后面是主机名.在后面的{}中为这个主机的配置.
        on db-server-01 {            #设定一个节点,分别以各自的主机名命名 
                device /dev/drbd0;   #逻辑设备名,在/dev/下。设定资源设备/dev/drbd0 指向实际的物理分区 /dev/sda5
                disk /dev/sda5; #真实设备名,节点间共享的磁盘或分区
                address 192.168.0.10:7888;  #设定监听地址以及端口 
                meta-disk internal;
        }
        on db-server-02 {
                device /dev/drbd0;
                disk /dev/sda5;
                address 192.168.0.20:7888;
                meta-disk internal;     #internal表示将drbd自己的源数据放在drbd资源磁盘空间中
        }
}

注意:
1) drbd每个配置项结尾有一个分号,注意不要犯语法上的错误
2) 配置drbd-8.4时不要生搬硬套8.3的配置项,因为8.4的配置文件发生了很多的变化,如取消了syncer配置段,把这部分选项分配给了disk和net;disk增加了一些新的选项,如disk-timeout等。
(4)DRBD的管理与维护:

创建DRBD资源

配置好drbd以后,就需要使用命令创建配置的drbd资源,使用如下命令(两台服务器操作一样):

[root@192.168.0.10 ~]# dd if=/dev/zero of=/dev/sda5 bs=1M count=100  #不这样做的话,在创建资源的时候报错
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 3.34339 s, 31.4 MB/s

以上故障原因分析
如果你在这步之前已经给/dev/sda5格式化的话,这里会报错,并且无法继续,报错内容如下:

md_offset ...........
al_offset ...........
bm_offset ...........
Found ext3 filesystem which uses 
Device size would be truncated, which
would corrupt data and result in
'access beyond end of device' errors.
You need to either
* use external meta data (recommended)
* shrink that filesystem first
* zero out the device (destroy the filesystem)
Operation refused.
Command 'drbdmeta

根据报错和官方描述的大概意思就是:有了文件系统,会被认为该设备已经被使用,不能被drbd所使用,最好的解决办法就是低格硬盘破坏该文件系统~
官方的方法如下:
破坏文件系统 :

dd if=/dev/zero bs=1M count=1 of=/dev/sda5 

创建matadata
在启动DRBD之前,需要分别在两台主机的hdb分区上,创建供DRBD记录信息的数据块。初始化资源,创建元数据库信息:

[root@192.168.0.10 ~]# drbdadm create-md r0                             
Writing meta data...
initializing activity log
NOT initializing bitmap
New drbd meta data block successfully created.
success

此处可能会报 Command ‘drbdmeta 0 v08 /dev/sda5 internal create-md’ terminated with exit code 40 错误,解决办法:首先看提示命令中的磁盘是否是你配置文件中的磁盘,如果不是,说明生效的配置文件不是你所认为的那个,其次,如果是,说明配置文件没错,那么可以使用dd命令往对应磁盘中输入些数据,初始化磁盘文件格式。此处磁盘分区是sda5,故命令如下:dd if=/dev/zero of=/dev/sda5 bs=100M count=1,也即上边执行的dd命令
(5)DRBD的启动与状态查看(分别在两台服务器启动)

[root@192.168.0.10 ~]# /etc/init.d/drbd start               
Starting DRBD resources: [
     create res: r0
   prepare disk: r0
    adjust disk: r0
     adjust net: r0
]
.....
[root@192.168.0.20 ~]# /etc/init.d/drbd start
Starting DRBD resources: [
     create res: r0
   prepare disk: r0
    adjust disk: r0
     adjust net: r0
]
.

查看drbd的状态:

[root@192.168.0.10 ~]# /etc/init.d/drbd status
drbd driver loaded OK; device status:
version: 8.4.2 (api:1/proto:86-101)
GIT-hash: 7ad5f850d711223713d6dcadc3dd48860321070c build by root@db-server-01, 2014-04-18 21:15:57
m:res  cs         ro                   ds                         p  mounted  fstype
0:r0   Connected  Secondary/Secondary  Inconsistent/Inconsistent  C

[root@192.168.0.10 ~]# watch -n1 "cat /proc/drbd" # 或使用此命令进行实时查看状态变化

注意:如果你的drbd状态一直显示cs:WFConnection ro:Secondary/Unknown ds:Inconsistent/DUnknown,而/var/log/messages又无报错,请查看iptables和selinux是否关闭。

对输出的含义解释如下:
ro表示角色信息,第一次启动drbd时,两个drbd节点默认都处于Secondary状态,
Primary/Secondary(代表这个是主节点)
Secondary/Primary(代表这个是副节点)
ds是磁盘状态信息,“Inconsistent/Inconsisten”,即为“不一致/不一致”状态,表示两个节点的磁盘数据处于不一致状态。
UpToDate/Inconsistent(正在同步,数据还没有一致)
UpToDate/UpToDate (同步完成,数据一致)
Ns表示网络发送的数据包信息,以K为字节
Dw是磁盘写信息
Dr是磁盘读信息

从上面的信息中可以看出此时两个节点均处于Secondary状态,都还没有主节点。设置当前节点(192.168.0.10)为主节点,并进行格式化和挂载 。

drbdadm -- --overwrite-data-of-peer primary all #或drbdadm primary --force all

#第一次执行完此命令后,在后面如果需要设置哪个是主节点时,就可以使用另外一个命令:
#/sbin/drbdadm primary r0或者/sbin/drbdadm primary all
#对drbd的设备进行格式化,此操作只在primary服务器上进行Secondary服务器起来后什么都不需要操作。
mkfs.ext4 /dev/drbd0
mkdir /data
#把主机上的DRBD设备挂载到一个目录上进行使用。备机的DRBD设备无法被挂载,因为它是用来接收主机数据的,由DRBD负责操作。
mount /dev/drbd0 /data/

需要注意的是,只需要在主节点上进行格式化,且只能在主节点上挂载,若主节点下线,从节点上线,则从节点可以直接挂载,不需要再次格式化.集群中只有primary服务器可以挂载设备,secondary挂载会报错。
在另外一台服务器创建挂载目录,也创建/data

[root@192.168.0.20 ~]# mkdir /data

注意:在DRBD从服务器上只需要创建挂载目录即可,不能同时进行挂载,否则会报错。即只有DRDB的主服务器挂载目录,从不挂载,在进行故障迁移升级为主时才需要挂载。
查看一下drbd的状态(可以看见还在同步):

[root@192.168.0.10 ~]# /etc/init.d/drbd status
drbd driver loaded OK; device status:
version: 8.4.2 (api:1/proto:86-101)
GIT-hash: 7ad5f850d711223713d6dcadc3dd48860321070c build by root@db-server-01, 2014-04-18 21:15:57
m:res  cs          ro                 ds                     p  mounted  fstype
...    sync'ed:    13.7%              (27596/31972)M
0:r0   SyncSource  Primary/Secondary  UpToDate/Inconsistent  C  /data    ext4

等数据同步完成以后再次查看状态,可以发现节点已经变成实时状态,且节点已经有了主次。
(6)mysql安装,我这里为了简单直接安装编译好的二进制软件包(两台服务器都需要安装,操作一样,只是第二台mysql不需要初始化数据)

注意:两台服务器上的mysql用户的uid和gid要一样。不然切换后会导致mysql数据目录的属主不正确而启动失败。

[root@192.168.0.10 ~]# wget http://cdn.mysql.com/Downloads/MySQL-5.5/mysql-5.5.37-linux2.6-x86_64.tar.gz
[root@192.168.0.10 ~]# tar xf mysql-5.5.37-linux2.6-x86_64.tar.gz -C /usr/local/
[root@192.168.0.10 ~]# cd /usr/local/
[root@192.168.0.10 local]# ln -s mysql-5.5.37-linux2.6-x86_64/ mysql
[root@192.168.0.10 local]# groupadd mysql
[root@192.168.0.10 local]# useradd -r -g mysql mysql
[root@192.168.0.10 local]# cd mysql
[root@192.168.0.10 mysql]# chown -R mysql .
[root@192.168.0.10 mysql]# chgrp -R mysql .
[root@192.168.0.10 mysql]# mkdir /data/mysql
[root@192.168.0.10 mysql]# chown -R mysql.mysql /data/mysql/
[root@192.168.0.10 mysql]# /usr/local/mysql/scripts/mysql_install_db --user=mysql --datadir=/data/mysql/ --basedir=/usr/local/mysql
[root@192.168.0.10 mysql]# chown -R root .
[root@192.168.0.10 mysql]# cp support-files/my-medium.cnf /etc/my.cnf
[root@192.168.0.10 mysql]# cp support-files/mysql.server /etc/init.d/mysqld
[root@192.168.0.10 mysql]# chmod 755 /etc/init.d/mysqld 
[root@192.168.0.10 mysql]# egrep 'datadir|basedir' /etc/my.cnf       #两台服务器上的mysql配置文件都加入这里的配置 
datadir=/data/mysql
basedir=/usr/local/mysql                                

(7)手动切换drbd的主从。看另外一台服务器是否有数据(自动切换需要使用heartbeat,后面介绍):

[root@192.168.0.10 ~]# ll /data/
total 20
drwx------ 2 root  root  16384 Apr 18 22:16 lost+found
drwxr-xr-x 5 mysql mysql  4096 Apr 18 23:01 mysql
[root@192.168.0.20 ~]# ll /data/
total 0
[root@192.168.0.10 ~]# /etc/init.d/drbd status
drbd driver loaded OK; device status:
version: 8.4.2 (api:1/proto:86-101)
GIT-hash: 7ad5f850d711223713d6dcadc3dd48860321070c build by root@db-server-01, 2014-04-18 21:15:57
m:res  cs         ro                 ds                 p  mounted  fstype
0:r0   Connected  Primary/Secondary  UpToDate/UpToDate  C  /data    ext4

可以看见当前服务器是主,也就是数据在这台服务器上,另外一台服务器是没有数据的。下面进行手动切换

主切换成从,需要先卸载文件系统,再执行降级为从的命令:

[root@192.168.0.10 ~]# umount /data/
[root@192.168.0.10 ~]# drbdadm secondary all

从切换成主,要先执行升级成主的命令然后挂在文件系统:

[root@192.168.0.20 ~]# drbdadm  primary all
[root@192.168.0.20 ~]# mount /dev/drbd0 /data/
[root@192.168.0.20 ~]# ll /data/
total 20
drwx------ 2 root  root  16384 Apr 18 22:16 lost+found
drwxr-xr-x 5 mysql mysql  4096 Apr 18 23:01 mysql
[root@192.168.0.20 ~]# /etc/init.d/drbd status
drbd driver loaded OK; device status:
version: 8.4.2 (api:1/proto:86-101)
GIT-hash: 7ad5f850d711223713d6dcadc3dd48860321070c build by root@db-server-02, 2014-04-18 21:22:55
m:res  cs         ro                 ds                 p  mounted  fstype
0:r0   Connected  Primary/Secondary  UpToDate/UpToDate  C  /data    ext4

可以看见已经成功切换成主,并且mysql初始化数据也存在了。

DRBD脑裂后的处理

当DRBD出现脑裂后,会导致drbd两边的磁盘数据不一致,在确定要作为从的节点上切换成secondary,并放弃该资源的数据:

drbdadm secondary r0
drbdadm -- --discard-my-data connect r0

在要作为primary的节点重新连接secondary(如果这个节点当前的连接状态为WFConnection的话,可以省略),使用如下命令连接:

drbdadm connect r0

(8)Heartbeat安装(两台服务器)

需要添加epel源,centos默认自己没有该软件包,当然你可以自己源码编译。

rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

yum install heartbeat -y

创建DRBD脚本文件drbddisk:(两台服务器)

注意:

此处是一个大坑,因为默认yum安装Heartbeat,不会在/etc/ha.d/resource.d/创建drbddisk脚本,估计是版本太新了吧。记得前两年都不会这样的。囧。而且也无法在安装后从本地其他路径找到该文件。此处也是因为启动Heartbeat后无法PING通虚拟IP,最后通过查看/var/log/ha-log日志,找到一行ERROR: Cannot locate resource script drbddisk,然后进而到/etc/ha.d/resource.d/路径下发现竟然没有drbddisk脚本,最后在google上找到该代码,创建该脚本(或者从drbd的源码中的scripts目录中复制drbddisk脚本到/etc/ha.d/resource.d/),终于测试通过:

[root@192.168.0.20 ~]# chmod 755 /etc/ha.d/resource.d/drbddisk 
[root@192.168.0.20 ~]# cat /etc/ha.d/resource.d/drbddisk 
#!/bin/bash
#
# This script is inteded to be used as resource script by heartbeat
#
# Copright 2003-2008 LINBIT Information Technologies
# Philipp Reisner, Lars Ellenberg
#
###

DEFAULTFILE="/etc/default/drbd"
DRBDADM="/sbin/drbdadm"

if [ -f $DEFAULTFILE ]; then
 . $DEFAULTFILE
fi

if [ "$#" -eq 2 ]; then
 RES="$1"
 CMD="$2"
else
 RES="all"
 CMD="$1"
fi

## EXIT CODES
# since this is a "legacy heartbeat R1 resource agent" script,
# exit codes actually do not matter that much as long as we conform to
#  http://wiki.linux-ha.org/HeartbeatResourceAgent
# but it does not hurt to conform to lsb init-script exit codes,
# where we can.
#  http://refspecs.linux-foundation.org/LSB_3.1.0/
#LSB-Core-generic/LSB-Core-generic/iniscrptact.html
####

drbd_set_role_from_proc_drbd()
{
local out
if ! test -e /proc/drbd; then
ROLE="Unconfigured"
return
fi

dev=$( $DRBDADM sh-dev $RES )
minor=${dev#/dev/drbd}
if [[ $minor = *[!0-9]* ]] ; then
# sh-minor is only supported since drbd 8.3.1
minor=$( $DRBDADM sh-minor $RES )
fi
if [[ -z $minor ]] || [[ $minor = *[!0-9]* ]] ; then
ROLE=Unknown
return
fi

if out=$(sed -ne "/^ *$minor: cs:/ { s/:/ /g; p; q; }" /proc/drbd); then
set -- $out
ROLE=${5%/**}
: ${ROLE:=Unconfigured} # if it does not show up
else
ROLE=Unknown
fi
}

case "$CMD" in
   start)
# try several times, in case heartbeat deadtime
# was smaller than drbd ping time
try=6
while true; do
$DRBDADM primary $RES && break
let "--try" || exit 1 # LSB generic error
sleep 1
done
;;
   stop)
# heartbeat (haresources mode) will retry failed stop
# for a number of times in addition to this internal retry.
try=3
while true; do
$DRBDADM secondary $RES && break
# We used to lie here, and pretend success for anything != 11,
# to avoid the reboot on failed stop recovery for "simple
# config errors" and such. But that is incorrect.
# Don't lie to your cluster manager.
# And don't do config errors...
let --try || exit 1 # LSB generic error
sleep 1
done
;;
   status)
if [ "$RES" = "all" ]; then
   echo "A resource name is required for status inquiries."
   exit 10
fi
ST=$( $DRBDADM role $RES )
ROLE=${ST%/**}
case $ROLE in
Primary|Secondary|Unconfigured)
# expected
;;
*)
# unexpected. whatever...
# If we are unsure about the state of a resource, we need to
# report it as possibly running, so heartbeat can, after failed
# stop, do a recovery by reboot.
# drbdsetup may fail for obscure reasons, e.g. if /var/lock/ is
# suddenly readonly.  So we retry by parsing /proc/drbd.
drbd_set_role_from_proc_drbd
esac
case $ROLE in
Primary)
echo "running (Primary)"
exit 0 # LSB status "service is OK"
;;
Secondary|Unconfigured)
echo "stopped ($ROLE)"
exit 3 # LSB status "service is not running"
;;
*)
# NOTE the "running" in below message.
# this is a "heartbeat" resource script,
# the exit code is _ignored_.
echo "cannot determine status, may be running ($ROLE)"
exit 4 #  LSB status "service status is unknown"
;;
esac
;;
   *)
echo "Usage: drbddisk [resource] {start|stop|status}"
exit 1
;;
esac

exit 0

(9)heartbeat配置

Hearbeat的配置主要包括三个配置文件,authkeys,ha.cf和haresources的配置,下面就分别来看看:

Authkerys的配置(两台服务器配置一样)

这个文件用来配置密码认证方式,支持3种认证方式,crc,md5和sha1,从左到右安全性越来越高,消耗的资源也越多。因此如果heartbeat运行在安全的网路之上,比如私网,那么可以将验证方式设置成crc,master和backup的authkeys配置一样。我的authkeys文件配置如下:

[root@192.168.0.10 ~]# cat /etc/ha.d/authkeys 
auth 1                    # 采用何种加密方式   
1 crc                       # 无加密   
#2 sha1 HI!            # 启用sha1的加密方式   
#3 md5 Hello!       # 采用md5的加密方式   
[root@192.168.0.10 ~]# chmod 600 /etc/ha.d/authkeys # 该文件必须设置为600权限,不然heartbeat启动会报错

注意:该文件权限必须是600

ha.cf的配置(两台机器稍微有点区别),Primary(192.168.0.10)如下:

[root@192.168.0.10 ~]# cat /etc/ha.d/ha.cf 
debugfile /var/log/ha-debug #调试日志文件
logfile /var/log/ha-log #系统运行日志文件
logfacility local0 #日志记录等级
keepalive 2 
#心跳频率,2表示2秒;200ms则表示200毫秒
deadtime 15 
 #节点死亡时间,就是过了15秒后还没有收到心跳就认为主节点死亡
#bcast eth1 #采用udp广播播来通知心跳,建议在备用节点不只一台时使用

#mcast eth1 225.0.0.1 694 1 0 #采用udp多播来通知心跳,建议在备用节点不只一台时使用

#ucast eth1 10.0.0.64 #采用udp单播来通知心跳,注意:这一项在2个节点IP
ucast eth1 192.168.0.20
#采用单播的方式,IP地址指定为对方IP 
auto_failback off 
#当Primary机器发生故障切换到Secondary机器后Primary恢复后是否进行切回操作 (最好是我们根据需求手动进行切换)
node db-server-01  #主节点名称,与uname -n显示必须一致,不是域名
node db-server-02 #备用节点名称

Secondary(192.168.0.20)如下:

[root@192.168.0.20 ~]# cat /etc/ha.d/ha.cf 
logfile /var/log/ha-log 
#定义Heartbeat的日志名字及位置 
logfacility local0 
keepalive 2 
#设定心跳(监测)时间为2秒 
deadtime 15 
#设定死亡时间为15秒 
ucast eth1 192.168.0.10
#采用单播的方式,IP地址指定为对方IP 
auto_failback off
#当Primary机器发生故障切换到Secondary机器后Primary恢复后是否进行切回操作(一般我们可以看需求,否则不用自动切换) 
node db-server-01
node db-server-02

haresources的配置(两台机器配置一样):

[root@192.168.0.10 ~]# cat /etc/ha.d/haresources 
db-server-01 IPaddr::192.168.0.88/24/eth1 drbddisk::r0 Filesystem::/dev/drbd0::/data::ext4  mysqld 

注:该文件内IPaddr,Filesystem等脚本存放路径在/etc/ha.d/resource.d/下,也可在该目录下存放服务启动脚本(例如:mysqld),将相同脚本名称添到/etc/ha.d/haresources内容中,从而跟随heartbeat启动而启动该脚本。

IPaddr::192.168.0.88/24/eth1:用IPaddr脚本配置浮动VIP

drbddisk::r0:用drbddisk脚本实现DRBD主从节点资源组的挂载和卸载

Filesystem::/dev/drbd0::/data::ext4:用Filesystem脚本实现磁盘挂载和卸载

不知什么原因,以上配置会有问题,以下配置正常

[root@192.168.0.10 ~]# cat /etc/ha.d/haresources 
db-server-02 192.168.1.88 drbddisk::r0 Filesystem::/dev/drbd0::/data::ext4  mysqld

更多heartbeat配置说明请参考 Heartbeat安装配置小结:http://www.linuxidc.com/Linux/2012-11/73834.htm
(10)heartbeat的管理

配置好heartbeat之后,需要将mysql从自启动服务器中去掉,因为主heartbeat启动的时候会挂载drdb文件系统以及启动mysql,切换的时候会将主上的mysql停止并卸载文件系统,从上会挂载文件系统,并启动mysql。因此需要做如下操作(两台服务器):

[root@192.168.0.10 ~]# chkconfig mysqld off
[root@192.168.0.10 ~]# chkconfig heartbeat off
[root@192.168.0.10 ~]# chkconfig drbd off     
[root@192.168.0.10 ~]# cat /etc/rc.local 
#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

touch /var/lock/subsys/local
modprobe drbd              #必须先加载模块,这也是因为将启动命令放在这里的原因
/etc/init.d/drbd start
/etc/init.d/heartbeat start

到这里heartbeat+drbd+mysql高可用环境就搭建结束了。接下来进行测试。

高可用测试

对主Primary/Secondary模型的drbd服务来讲,在某个时刻[只能有一个节点为Primary],因此,要切换两个节点的角色,只能在先将原有的Primary节点设置为Secondary后,才能将原来的Secondary节点设置为Primary。
(1)在第一台服务器上面启动mysql服务。(192.168.0.10)

[root@192.168.0.10 ~]# /etc/init.d/mysqld start
Starting MySQL.The server quit without updating PID file (/[FAILED]ql/db-server-01.pid).
[root@192.168.0.10 ~]# ll /data/
total 0

怎么回事?/data/下面为空。这里是因为我们在前面已经把这个节点变为Secondary

[root@192.168.0.10 ~]# /etc/init.d/drbd status
drbd driver loaded OK; device status:
version: 8.4.2 (api:1/proto:86-101)
GIT-hash: 7ad5f850d711223713d6dcadc3dd48860321070c build by root@db-server-01, 2014-04-18 21:15:57
m:res  cs         ro                 ds                 p  mounted  fstype
0:r0   Connected  Secondary/Primary  UpToDate/UpToDate  C
[root@192.168.0.10 ~]# 

我们现在需要手动切换回来。才能启动mysql

[root@192.168.0.20 ~]# umount /data/
[root@192.168.0.20 ~]# drbdadm secondary all
[root@192.168.0.20 ~]# 
[root@192.168.0.10 ~]# drbdadm  primary all
[root@192.168.0.10 ~]# mount /dev/drbd0 /data/
[root@192.168.0.10 ~]# ll /data/
total 20
drwx------ 2 root  root  16384 Apr 18 22:16 lost+found
drwxr-xr-x 5 mysql mysql  4096 Apr 18 23:01 mysql
[root@192.168.0.10 ~]# /etc/init.d/drbd status
drbd driver loaded OK; device status:
version: 8.4.2 (api:1/proto:86-101)
GIT-hash: 7ad5f850d711223713d6dcadc3dd48860321070c build by root@db-server-01, 2014-04-18 21:15:57
m:res  cs         ro                 ds                 p  mounted  fstype
0:r0   Connected  Primary/Secondary  UpToDate/UpToDate  C  /data    ext4

可以看见已经切换回来了,我们现在可以启动mysql了。

[root@192.168.0.10 ~]# /etc/init.d/mysqld start             
Starting MySQL.......                                      [  OK  ]
[root@192.168.0.10 ~]# mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.5.37-log MySQL Community Server (GPL)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

(2)在两台服务器上面启动heartbeat

[root@192.168.0.10 ~]# /etc/init.d/heartbeat start
Starting High-Availability services: INFO:  Resource is stopped
Done.
[root@192.168.0.20 ~]# /etc/init.d/heartbeat start
Starting High-Availability services: INFO:  Resource is stopped
Done.
[root@192.168.0.10 ~]# ip addr | grep eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 192.168.0.10/24 brd 192.168.0.255 scope global eth1
    inet 192.168.0.88/24 brd 192.168.0.255 scope global secondary eth1

可以看见虚拟ip192.168.0.88已经存在了。说明成功了。我们看看heartbeat的日志就能发现。

[root@192.168.0.10 ~]# tail -n 20 /var/log/ha-log  
harc(default)[5598]:    2014/04/19_00:25:21 info: Running /etc/ha.d//rc.d/status status
Apr 19 00:25:22 db-server-01 heartbeat: [5591]: info: Comm_now_up(): updating status to active
Apr 19 00:25:22 db-server-01 heartbeat: [5591]: info: Local status now set to: 'active'
Apr 19 00:25:22 db-server-01 heartbeat: [5591]: info: Status update for node db-server-02: status active
harc(default)[5618]:    2014/04/19_00:25:22 info: Running /etc/ha.d//rc.d/status status
Apr 19 00:25:33 db-server-01 heartbeat: [5591]: info: remote resource transition completed.
Apr 19 00:25:33 db-server-01 heartbeat: [5591]: info: remote resource transition completed.
Apr 19 00:25:33 db-server-01 heartbeat: [5591]: info: Initial resource acquisition complete (T_RESOURCES(us))
/usr/lib/ocf/resource.d//heartbeat/IPaddr(IPaddr_192.168.0.88)[5671]:   2014/04/19_00:25:33 INFO:  Resource is stopped
Apr 19 00:25:33 db-server-01 heartbeat: [5635]: info: Local Resource acquisition completed.
harc(default)[5752]:    2014/04/19_00:25:33 info: Running /etc/ha.d//rc.d/ip-request-resp ip-request-resp
ip-request-resp(default)[5752]: 2014/04/19_00:25:33 received ip-request-resp IPaddr::192.168.0.88/24/eth1 OK yes
ResourceManager(default)[5775]: 2014/04/19_00:25:33 info: Acquiring resource group: db-server-01 IPaddr::192.168.0.88/24/eth1 drbddisk::r0 Filesystem::/dev/drbd0::/data::ext4 mysqld
/usr/lib/ocf/resource.d//heartbeat/IPaddr(IPaddr_192.168.0.88)[5803]:   2014/04/19_00:25:33 INFO:  Resource is stopped
ResourceManager(default)[5775]: 2014/04/19_00:25:33 info: Running /etc/ha.d/resource.d/IPaddr 192.168.0.88/24/eth1 start
IPaddr(IPaddr_192.168.0.88)[5926]:      2014/04/19_00:25:34 INFO: Adding inet address 192.168.0.88/24 with broadcast address 192.168.0.255 to device eth1
IPaddr(IPaddr_192.168.0.88)[5926]:      2014/04/19_00:25:34 INFO: Bringing device eth1 up
IPaddr(IPaddr_192.168.0.88)[5926]:      2014/04/19_00:25:34 INFO: /usr/libexec/heartbeat/send_arp -i 200 -r 5 -p /var/run/resource-agents/send_arp-192.168.0.88 eth1 192.168.0.88 auto not_used not_used
/usr/lib/ocf/resource.d//heartbeat/IPaddr(IPaddr_192.168.0.88)[5900]:   2014/04/19_00:25:34 INFO:  Success
/usr/lib/ocf/resource.d//heartbeat/Filesystem(Filesystem_/dev/drbd0)[6030]:     2014/04/19_00:25:34 INFO:  Running OK

激动的时刻到了,我们测试一下自动切换。我们先看看两台服务器的状态:

[root@192.168.0.10 ~]# df -HT
Filesystem    Type     Size   Used  Avail Use% Mounted on
/dev/sda2     ext4      19G   3.5G    15G  20% /
tmpfs        tmpfs     121M      0   121M   0% /dev/shm
/dev/sda1     ext4     204M    52M   141M  27% /boot
/dev/drbd0    ext4      33G   216M    32G   1% /data
[root@192.168.0.20 ~]# df -HT
Filesystem    Type     Size   Used  Avail Use% Mounted on
/dev/sda2     ext4      19G   4.9G    13G  28% /
tmpfs        tmpfs     121M      0   121M   0% /dev/shm
/dev/sda1     ext4     204M    52M   141M  27% /boot

可以看见挂载在第一台服务器。

测试方法:

1.停掉master上的mysqld,看看是否切换(因为heartheat不检查服务的可用性,因此需要通过额外的脚本来实现)。
2.停掉master的heartheat看看是否能正常切换。
3.停掉master的网络或者直接将master系统shutdown,看看能否正常切换。
4.启动master的heartbeat看看是否能正常切换回来。
5.重新启动master看看能否切换,过程是否OK。
注意:这里说的切换是指是不是已经将mysql停掉、是否卸载了文件系统等等。

我就停止master(192.168.0.10)上的heartbeat来测试是否会自动切换,这里除了第一条无法实现,其他的都可以切换:

[root@192.168.0.10 ~]# /etc/init.d/heartbeat stop
Stopping High-Availability services: Done.
[root@192.168.0.10 ~]# df -HT
Filesystem    Type     Size   Used  Avail Use% Mounted on
/dev/sda2     ext4      19G   3.5G    15G  20% /
tmpfs        tmpfs     121M      0   121M   0% /dev/shm
/dev/sda1     ext4     204M    52M   141M  27% /boot
[root@192.168.0.10 ~]# /etc/init.d/drbd status
drbd driver loaded OK; device status:
version: 8.4.2 (api:1/proto:86-101)
GIT-hash: 7ad5f850d711223713d6dcadc3dd48860321070c build by root@db-server-01, 2014-04-18 21:15:57
m:res  cs         ro                 ds                 p  mounted  fstype
0:r0   Connected  Secondary/Primary  UpToDate/UpToDate  C

可以看见已经切换了,我们看另外一台机器的情况:

[root@192.168.0.20 ~]# df -HT
Filesystem    Type     Size   Used  Avail Use% Mounted on
/dev/sda2     ext4      19G   4.9G    13G  28% /
tmpfs        tmpfs     121M      0   121M   0% /dev/shm
/dev/sda1     ext4     204M    52M   141M  27% /boot
/dev/drbd0    ext4      33G   216M    32G   1% /data
[root@192.168.0.20 ~]# netstat -nltp | grep 3306 | grep -v grep
tcp        0      0 0.0.0.0:3306                0.0.0.0:*                   LISTEN      5542/mysqld         

可以发现已经切换过来,mysql也自动启动了。之前是没有启动的。
复制代码

[root@192.168.0.20 ~]# ip addr | grep eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 192.168.0.20/24 brd 192.168.0.255 scope global eth1
    inet 192.168.0.88/24 brd 192.168.0.255 scope global secondary eth1
[root@192.168.0.20 ~]# mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.5.37-log MySQL Community Server (GPL)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

可以看见,一切正常呢。如果我们查看日志,就可以看见到底发生了什么。

[root@192.168.0.20 ~]# tail -n 10 /var/log/ha-log 
ResourceManager(default)[4768]: 2014/04/19_00:36:42 info: Running /etc/ha.d/resource.d/Filesystem /dev/drbd0 /data ext4 start
Filesystem(Filesystem_/dev/drbd0)[5131]:        2014/04/19_00:36:42 INFO: Running start for /dev/drbd0 on /data
/usr/lib/ocf/resource.d//heartbeat/Filesystem(Filesystem_/dev/drbd0)[5122]:     2014/04/19_00:36:42 INFO:  Success
ResourceManager(default)[4768]: 2014/04/19_00:36:43 info: Running /etc/init.d/mysqld  start
mach_down(default)[4741]:       2014/04/19_00:36:46 info: /usr/share/heartbeat/mach_down: nice_failback: foreign resources acquired
mach_down(default)[4741]:       2014/04/19_00:36:46 info: mach_down takeover complete for node db-server-01.
Apr 19 00:36:46 db-server-02 heartbeat: [4637]: info: mach_down takeover complete.
Apr 19 00:36:58 db-server-02 heartbeat: [4637]: WARN: node db-server-01: is dead
Apr 19 00:36:58 db-server-02 heartbeat: [4637]: info: Dead node db-server-01 gave up resources.
Apr 19 00:36:58 db-server-02 heartbeat: [4637]: info: Link db-server-01:eth1 dead.

对于mysqld服务挂掉的情况无法实现自动切换,所以需要一个脚本来帮助我们完成,我这里有个简单的脚本,能实现当mysqld服务不可用时进行自动切换,当进行切换时发送邮件等。该脚本放在主服务器执行,也就是运行mysqld服务的服务器上执行。

[root@192.168.0.20 ~]# cat mysqlmon.sh 
#!/bin/bash
trap 'echo  PROGRAM INTERRUPTED; exit 1'  INT
username=root
password=123456
n=0
log='/var/log/mysqlmon.log'
while true
do
    if /usr/local/mysql/bin/mysql  -u${username} -p${password} -e "use test"   >&/dev/null
    then
        echo `date +"%Y-%m-%d  %H:%M:%S"`  mysqld is alive!  >> ${log}
        n=0
    else
        echo  "`date +"%Y-%m-%d  %H:%M:%S"`  mysqld  cannot be  connected!"  >> ${log}
        n=$[n + 1]
        if [ $n -eq 3 ]
        then
            /etc/init.d/heartbeat stop
            echo  "`date +"%Y-%m-%d  %H:%M:%S"`  mysqld  switched to backup!" >> ${log}
            echo "`date +"%Y-%m-%d  %H:%M:%S"`  mysqld  switched to backup" | mutt -s "mysqld switched to backup" saltstack@163.com
            break
        fi
    fi
    sleep 10
done

说明:脚本中使用mutt命令发送邮件,如果系统中没有安装,可以使用yum安装

yum -y install mutt

挂在后台执行:

[root@192.168.0.10 ~]# nohup mysqlmon.sh &

停止mysqld服务,看是否进行切换以及发送邮件:

[root@192.168.0.10 ~]# /etc/init.d/mysqld stop
Shutting down MySQL.                                       [  OK  ]

邮件截图:
2

[root@192.168.0.20 ~]# df -HT
Filesystem    Type     Size   Used  Avail Use% Mounted on
/dev/sda2     ext4      19G   4.9G    13G  28% /
tmpfs        tmpfs     121M      0   121M   0% /dev/shm
/dev/sda1     ext4     204M    52M   141M  27% /boot
/dev/drbd0    ext4      33G   216M    32G   1% /data
[root@192.168.0.20 ~]# netstat -nltp | grep 3306
tcp        0      0 0.0.0.0:3306                0.0.0.0:*                   LISTEN      13771/mysqld        

可能存在的问题

报错1:
问题描述:设备被其他人占用,无法停止或者下线资源
0: State change failed: (-12) Device is held open by someone
解决办法:查看是否有设备挂载,umount即可
报错2:
问题描述:0:mydrbd WFConnection Primary/Unknown UpToDate/DUnknown C r—–,即总有一个节点是未知状态
解决办法:
主节点上执行:
drbdadm connect all
从节点上执行:
drbdadm -- --discard-my-data connect all
报错3:
configure: error: Cannot build utils without flex, either install flex or pass the –without-utils option.
解决办法:
yum -y intalls flex
报错4:
make: [check-kdir] error 1
解决办法:yum install -y kernel-devel
报错5:
SORRY, kernel makefile not found.
You need to tell me a correct KDIR,
  Or install the neccessary kernel source packages.
报错6:
‘drbd’ not defined in your config (for this host).
这个因为没有加载到drbd模块
报错7:
启动报错:
Command ‘drbdmeta 0 v08 /dev/sdb1 internal create-md’ terminated with exit code 40
这是因为sdb1已经有文件系统了,已经有数据存在了
解决方法:
[root@node1 ~]# dd if=/dev/zero bs=1M count=1 of=/dev/sdb1

总结

搭建还不算复杂,但是也踩了不少坑,比如yum安装的heartbeat没有drbddisk脚本。该方案的优点是安全性高、稳定性高、可用性高,出现故障自动切换,但是缺点也很明显,只有一台服务器提供服务,成本相对较高。不方便扩展。可能会发生脑裂。当mysql服务挂掉或者不可用的情况下不能进行自动切换,需要通过crm模式实现或者额外的脚本实现(比如shell脚本监测到master的mysql不可用就将主上的heartbeat停掉,这样就会切换到backup中去)。监控也特别重要,可以使用nagios或者zabbix监控。

附录

主备节点切换的两种方式

主备节点切换有两种方式,分别是停止drbd服务切换和正常切换,依次介绍:

停止drbd服务切换

关闭主节点服务,此时挂载的drbd分区就自动在主节点卸载了,然后在备用节点执行切换命令:

[root@drbd2 ~]#drbdadm primary all
此时会报错:
2: State change failed: (-7) Refusing to be Primary while peer is not outdated
Command 'drbdsetup 2 primary' terminated with exit code 11
因此,必须在备用节点执行如下命令:
[root@drbd2 ~]#drbdsetup /dev/drbd0 primary –o
或者
[root@drbd2~]#drbdadm -- --overwrite-data-of-peer primary all

此时就可以正常切换了。
当在备用节点执行切换到主节点命令后,原来的主用节点自动变为备用节点。无需在主用节点再次执行切换到备用节点的命令。

正常切换

在主节点卸载磁盘分区,然后执行

[root@drbd1 ~]#drbdadm secondary all
如果不执行这个命令,直接在备用节点执行切换到主节点的命令,会报错:
2: State change failed: (-1) Multiple primaries not allowed by config
Command 'drbdsetup 2 primary' terminated with exit code 11
接着,在备用节点执行
[root@drbd2 ~]#drbdadm primary all
最后在备用节点挂载磁盘分区即可:
[root@drbd2 ~]#mount /dev/drbd0 /mnt

DRDB各种状态查看

查看资源的连接状态

[root@node1 ~]# drbdadm cstate r0
Connected
资源的连接状态;一个资源可能有以下连接状态中的一种
StandAlone 独立的:网络配置不可用;资源还没有被连接或是被管理断开(使用 drbdadm disconnect 命令),或是由于出现认证失败或是脑裂的情况
Disconnecting 断开:断开只是临时状态,下一个状态是StandAlone独立的
Unconnected 悬空:是尝试连接前的临时状态,可能下一个状态为WFconnection和WFReportParams
Timeout 超时:与对等节点连接超时,也是临时状态,下一个状态为Unconected悬空
BrokerPipe:与对等节点连接丢失,也是临时状态,下一个状态为Unconected悬空
NetworkFailure:与对等节点推动连接后的临时状态,下一个状态为Unconected悬空
ProtocolError:与对等节点推动连接后的临时状态,下一个状态为Unconected悬空
TearDown 拆解:临时状态,对等节点关闭,下一个状态为Unconected悬空
WFConnection:等待和对等节点建立网络连接
WFReportParams:已经建立TCP连接,本节点等待从对等节点传来的第一个网络包
Connected 连接:DRBD已经建立连接,数据镜像现在可用,节点处于正常状态
StartingSyncS:完全同步,有管理员发起的刚刚开始同步,未来可能的状态为SyncSource或PausedSyncS
StartingSyncT:完全同步,有管理员发起的刚刚开始同步,下一状态为WFSyncUUID
WFBitMapS:部分同步刚刚开始,下一步可能的状态为SyncSource或PausedSyncS
WFBitMapT:部分同步刚刚开始,下一步可能的状态为WFSyncUUID
WFSyncUUID:同步即将开始,下一步可能的状态为SyncTarget或PausedSyncT
SyncSource:以本节点为同步源的同步正在进行
SyncTarget:以本节点为同步目标的同步正在进行
PausedSyncS:以本地节点是一个持续同步的源,但是目前同步已经暂停,可能是因为另外一个同步正在进行或是使用命令(drbdadm pause-sync)暂停了同步
PausedSyncT:以本地节点为持续同步的目标,但是目前同步已经暂停,这可以是因为另外一个同步正在进行或是使用命令(drbdadm pause-sync)暂停了同步
VerifyS:以本地节点为验证源的线上设备验证正在执行
VerifyT:以本地节点为验证目标的线上设备验证正在执行

查看资源角色的命令

[root@node1 ~]# drbdadm role r0
Primary/Secondary (在前面为当前节点)
Parimary 主:资源目前为主,并且可能正在被读取或写入,如果不是双主只会出现在两个节点中的其中一个节点上
Secondary 次:资源目前为次,正常接收对等节点的更新
Unknown 未知:资源角色目前未知,本地的资源不会出现这种状态

查看硬盘状态

[root@node1 ~]# drbdadm dstate r1
UpToDate/UpToDate
本地和对等节点的硬盘有可能为下列状态之一:
Diskless 无盘:本地没有块设备分配给DRBD使用,这表示没有可用的设备,或者使用drbdadm命令手工分离或是底层的I/O错误导致自动分离
Attaching:读取无数据时候的瞬间状态
Failed 失败:本地块设备报告I/O错误的下一个状态,其下一个状态为Diskless无盘
Negotiating:在已经连接的DRBD设置进行Attach读取无数据前的瞬间状态
Inconsistent:数据是不一致的,在两个节点上(初始的完全同步前)这种状态出现后立即创建一个新的资源。此外,在同步期间(同步目标)在一个节点上出现这种状态
Outdated:数据资源是一致的,但是已经过时
DUnknown:当对等节点网络连接不可用时出现这种状态
Consistent:一个没有连接的节点数据一致,当建立连接时,它决定数据是UpToDate或是Outdated
UpToDate:一致的最新的数据状态,这个状态为正常状态

查看同步进度

[root@node1 ~]# cat /proc/drbd 或者 执行/usr/local/drbd/sbin/drbd-overview 或者 service drbd status
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by root@localhost.localdomain, 2016-04-24 20:16:24
0: cs:SyncSource ro:Primary/Secondary ds:UpToDate/Inconsistent C r—–
ns:2767088 nr:0 dw:0 dr:2774680 al:0 bm:168 lo:0 pe:1 ua:7 ap:0 ep:1 wo:f oos:18202972
[=>………………] sync’ed: 13.3% (17776/20476)M
finish: 0:12:59 speed: 23,344 (22,492) K/sec
由此可见:进度已经完成了13.3%,传输速度大概22M/S
注:
ds是磁盘状态信息
dw是磁盘写信息
dr是磁盘读信息

cat /proc/drbd 、/usr/local/drbd/sbin/drbd-overview 或者 service drbd status执行后显示的信息格式会有所不同

1

注意点

1)mount drbd设备以前必须把设备切换到primary状态。
2)两个节点中,同一时刻只能有一台处于primary状态,另一台处于secondary状态。
3)处于secondary状态的服务器上不能加载drbd设备。
4)主备服务器同步的两个分区大小最好相同,这样不至于浪费磁盘空间,因为drbd磁盘镜像相当于网络raid 1。

参考资料:
Heartbeat+DRBD+MySQL高可用方案:http://www.cnblogs.com/gomysql/p/3674030.html
HA-DRBD Heartbeat 建置 MySQL 高可用性:http://wiki.weithenn.org/cgi-bin/wiki.pl?HA-DRBD_Heartbeat_%E5%BB%BA%E7%BD%AE_MySQL_%E9%AB%98%E5%8F%AF%E7%94%A8%E6%80%A7
drbd与linux内核:http://www.alexclouds.net/?p=332
Centos6.3下DRBD安装配置笔记:http://www.showerlee.com/archives/295

扩展阅读:
Mysql+Heartbeat+Drbd生产环境高可用部署若干问题解惑:http://oldboy.blog.51cto.com/2561410/515345/
DRBD项目实施之NFS高可用架构(NFS+Heartbeat+Drbd):http://os.51cto.com/art/201412/461533_all.htm
DRBD架构详解(原创):http://czmmiao.iteye.com/blog/1773079
Centos6.3下DRBD+HeartBeat+NFS配置笔记:http://www.showerlee.com/archives/293

发表评论?

2 条评论。

  1. 大神,真的感谢你这篇文章,你的一个个注意,解决了我两个星期的困扰。我配置集群的时候怎么也切换不了,主从,之后发现是mysql权限问题,但是怎么改权限,都只能启动一个库,另一个权限都会出问题。看了你这篇文章我的问题解决了。没有别的表示,只能在这里,由衷的说声谢谢你!

    • 大神称不上,能对你有所帮助我也感到很高兴,我在研究这个课题时也是花了不少精力,掉过不少坑,文中的注意事项基本上都是自己掉过的坑,然后总结记录下来,以便以后查阅少犯错误。

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据