目录
一、DRBD简介
1. 工作原理
2. DRBD 支持的底层设备
3. DRBD资源
4. DRBD 配置工具
5. DRBD与RAID1区别
6. DRBD与共享存储
二、DRBD安装配置
1. 实验环境
2. 配置前准备
3. 下载安装DRBD
4. 配置DRBD
四、测试MySQL数据同步
五、heartbeat+DRBD+mysql高可用方案
1. 配置
(1)编辑配置文件ha.cf
(2)编辑认证文件authkeys
(3)编辑资源配置文件haresources
(4)建立插件软连接
(5)创建脚本文件
(6)启动heartbeat
2. 测试
(1)停掉node1上的mysqld,查看服务是否切换到node2
(2)停掉node2的heartheat,查看服务是否切换回node1
(3)node1重启,查看服务是否切换到node2
(4)测试脑裂
参考:
大多数MySQL高可用解决方案都是基于MySQL自带的各种复制技术。本质上是将一个实例上的数据更新或事务,在其它实例上进行重放,从而完成数据复制。当生产实例出现问题无法提供服务时,应用连接切换到其它实例,实现数据库服务持续可用。从这个角度看,使用DRBD实现MySQL高可用的方式则完全不同,它与MySQL复制毫无关系,可以说是另辟蹊径。
DRBD的全称是Distributed Replicated Block Device,即分布式复制块设备,是一个用软件实现的、无共享的、服务器之间镜像块设备内容的存储复制解决方案。DRBD是镜像块设备,是按数据位镜像成一样的数据块。简单说DRBD是实现活动节点存储数据更动后自动复制到备用节点相应存储位置的软件,是一种数据块级别的物理复制。
图1是官方文档里给出的DRBD工作栈模型,可以看到DRBD需要运行在各个节点上,且是运行在节点主机的内核中,所以DRBD是内核模块,在Linux 2.6.33版本起开始整合进内核。
图1中假设左节点为活动节点(primary),右节点为备用节点(secondary)。左节点接收到数据发往内核的数据通路,DRBD在数据通路中注册钩子检查数据,当发现接收到的数据是发往到自己管理的存储位置,就复制另一份,一份存储到本机的DRBD存储设备,另一份就发给TCP/IP协议栈,通过网卡网络传输到另一节点主机的网上TCP/IP协议栈。而另一节点运行的DRBD模块同样在数据通路上检查数据,当发现传输过来的数据时,就存储到DRBD存储设备对应的位置。
如果左节点宕机,右节点可以在高可用集群中成为活动节点,把接收到的数据先存储到本地,当左节点恢复上线时,再把宕机后右节点变动的数据镜像到左节点。镜像过程完成后还需要返回成功/失败的回应消息,这个回应消息可以在传输过程中的不同位置返回,如图上的A/B/C标识位置,可以分为三种复制模式:
DRBD需要在底层设备上构建出一个块设备。对于用户来说,一个DRBD设备,就像是一块物理的磁盘,可以在DRBD设备内创建文件系统。DRBD所支持的底层设备类别包括:磁盘或者是磁盘的一个分区;soft raid 设备;LVM的逻辑卷;EVMS(Enterprise Volume Management System,企业卷管理系统)卷;或其它任何块设备。
DRBD资源定义DRBD管理的存储空间及相关信息,主要配置以下四个选项:
DRBD主要有以下三个配置工具:
RAID1也是实现不同存储设备间的数据镜像备份,不同的是RAID1各存储设备是连接一个RAID控制器接入到一台主机上的,而DRBD是通过网络实现不同节点主机存储设备数据的镜像备份。
如果各节点访问同一个数据文件都是在同一个存储空间内的,就是说数据共享的就一份,则这个存储空间就共享存储。而DRBD定义上就指出了“无共享”——不同节点存储设备空间是镜像,DRBD可以直接应用在主备模型的集群中,也可通过高可用软件如corosycn应用在双主模型集群中,不过这就需要DML/OCFS2/GFS2等分布式集群文件系统为双主读写的时候分配锁。还有就是DRBD为NFS共享存储提供高可用镜像备份。
IP与主机名:
172.16.1.125 node1
172.16.1.126 node2
软件环境:
CentOS Linux release 7.2.1511 (Core)
DRBD 9.0.20
MySQL 5.6.14
DRBD:
磁盘分区:/dev/sdb 5G
DRBD设备:/dev/drbd0
DRBD资源:mysql
mount点:/mnt
在安装配置DRBD前,需要做一些准备工作,以下步骤需要在两个节点都执行。
(1)设置静态IP
编辑网卡配置文件,将BOOTPROTO设置为static,如node1的内容如下:
[root@node1~]#cat /etc/sysconfig/network-scripts/ifcfg-ens32
# Generated by dracut initrd
NAME="ens32"
DEVICE="ens32"
ONBOOT=yes
NETBOOT=yes
UUID="adb62466-2361-405e-ada9-b48fe7c09546"
IPV6INIT=yes
BOOTPROTO=static
TYPE=Ethernet
IPADDR=172.16.1.125
NETMASK=255.255.255.0
GATEWAY=172.16.1.254
DNS1=172.16.1.10
重启网络服务:
service network restart
(2)配置域名解析
编辑/etc/hosts文件配置域名解析,如node1的内容如下:
[root@node1~]#cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
172.16.1.125 node1
172.16.1.126 node2
(3)禁用SELINUX与防火墙
systemctl stop firewalld
systemctl disable firewalld
(4)设置双向ssh免密
node1上执行:
ssh-keygen -t rsa
ssh-copy-id 172.16.1.126
node2上执行:
ssh-keygen -t rsa
ssh-copy-id 172.16.1.125
(5)设置NTP时钟同步
yum install ntp
systemctl enable ntpd.service
service ntpd start
在两个节点执行以下命令:
# 导入GPG-KEY,用于验证签名
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
# 安装yum源
yum install https://www.elrepo.org/elrepo-release-7.0-4.el7.elrepo.noarch.rpm
# 安装drbd和内核相关软件包
yum install -y drbd90-utils kmod-drbd90 kernel*
# 因为升级了内核,需要重启系统
reboot
重启向内核加载drbd模块并确认:
[root@node2~]#modprobe drbd
[root@node2~]#lsmod | grep drbd
drbd_transport_tcp 22144 1
drbd 568697 3 drbd_transport_tcp
libcrc32c 12644 4 xfs,drbd,ip_vs,nf_conntrack
[root@node2~]#
DRBD的主配置文件为/etc/drbd.conf,为了管理的便捷性,目前通常会将些配置文件分成多个部分,且都保存至/etc/drbd.d目录中,主配置文件中仅使用”include”指令将这些配置文件片断整合起来。通常,/etc/drbd.d目录中的配置文件为global_common.conf和所有以.res结尾的文件。其中global_common.conf中主要定义global段和common段,而每一个.res的文件用于定义一个资源。
在配置文件中,global段仅能出现一次,且如果所有的配置信息都保存至同一个配置文件中而不分开为多个文件的话,global段必须位于配置文件的最开始处。common段则用于定义被每一个资源默认继承的参数,可以在资源定义中使用的参数都可以在common段中定义。实际应用中,common段并非必须,但建议将多个资源共享的参数定义为common段中的参数以降低配置文件的复杂度。
resource段则用于定义drbd资源,每个资源通常定义在一个单独的位于/etc/drbd.d目录中的以.res结尾的文件中。资源在定义时必须为其命名,名字可以由非空白的ASCII字符组成。每一个资源段的定义中至少要包含两个host子段,以定义此资源关联至的节点,其它参数均可以从common段或drbd的默认中进行继承而无须定义。
下面的操作在node1上完成。(1)查看主配置文件/etc/drbd.conf,内容如下:
[root@node1~]#cat /etc/drbd.conf
# You can find an example in /usr/share/doc/drbd.../drbd.conf.example
include "drbd.d/global_common.conf";
include "drbd.d/*.res";
[root@node1~]#
/etc/drbd.conf主配置文件里面配置了包含关系,不需要做任何修改,直接使用即可。(2)配置global_common.conf文件内容如下。
[root@node1~]#cat /etc/drbd.d/global_common.conf
global {
usage-count no; # 不让官方统计drbd的使用情况
}
common {
protocol C; # 使用DRBD的同步协议,数据可靠性高
disk {
on-io-error detach; # 配置I/O错误处理策略为分离
}
}
on-io-error策略可能为以下选项之一:
/etc/drbd.d/global_common.conf是全局配置文件,这里只设置了使用统计量、同步协议、I/O错误处理策略三项。该文件中还有一些其它选项,每个选项的含义在安装后的样例文件中都有相应说明。
(3)配置资源文件/etc/drbd.d/mysql.res内容如下,资源文件名要和资源名一样。
[root@node1 ~]# cat /etc/drbd.d/mysql.res
resource mysql { # 资源名称
disk /dev/sdb; # 磁盘分区
device /dev/drbd0; # DRBD设备
meta-disk internal; # 元数据存储方式
on node1 {
device /dev/drbd0;
disk /dev/sdb;
address 172.16.1.125:7789; # 节点1地址
}
on node2 {
device /dev/drbd0;
disk /dev/sdb;
address 172.16.1.126:7789; # 节点2地址
}
}
metadata有两种存储方式internal和external,存储方式是在每个resource配置段中指定的。配置成使用internal意味着DRBD把它的metadata和实际生产数据存储于相同的底层物理设备中。该存储方式是在设备的最后位置留出一个区域来存储metadata。
(4)将配置文件远程复制到node2
scp -rp /etc/drbd.d/* node2:/etc/drbd.d/
(5)初始化设备元数据
分别在两节点上创建DRBD设备元数据:
drbdadm create-md mysql
(6)启动DRBD资源
分别在两节点上启动DRBD资源:
drbdadm up mysql
(7)查看节点角色
当前两台均为备机:
[root@node1~]#drbdadm role mysql
Secondary
(8)将node1设置primary
在node1执行:
[root@node1~]#drbdadm --force primary mysql
[root@node1~]#drbdadm role mysql
Primary
Parimary表示资源目前为主,并且可能正在被读取或写入,如果不是双主只会出现在两个节点中的其中一个节点上。Secondary表示资源目前为从,正常接收对等节点的更新。
(9)在主节点对磁盘进行格式化
[root@node1~]#mkfs.xfs /dev/drbd0
meta-data=/dev/drbd0 isize=512 agcount=4, agsize=327668 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=0, sparse=0
data = bsize=4096 blocks=1310671, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal log bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
因为文件系统的挂载只能在Primary节点进行,所以也只有在设置了主节点后才能对DRBD设备进行格式化,这样就会连格式化后的全部信息都镜像到另一个节点。
(10)在主节点挂在设备
mount /dev/drbd0 /mnt
(11)查看状态
查看两个节点的磁盘状态和资源状态:
[root@node1/mnt]#drbdadm dstate mysql
UpToDate/UpToDate
[root@node1/mnt]#drbdadm cstate mysql
Connected
节点的硬盘有可能为下列状态之一:
一个资源可能有以下连接状态中的一种:
1. 将MySQL数据目录设置为DRBD挂载点
在my.cnf配置文件中修改设置:
datadir = /mnt/
2. 启动mysql服务
# 停止mysql服务
service mysql stop
# 将数据目录拷贝到挂载点
cp -r /data/* /mnt/
# 将数据目录的属主改为MySQL
chown -R mysql:mysql /mnt/
# 启动mysql服务
service mysql start
3. 建立数据库表
create database db1;
use db1;
create table t1 (a int);
insert into t1 select 1;
commit;
4. 手工执行主从切换,验证数据同步
(1)将node1降为从
service mysql stop
umount /mnt
drbdadm secondary mysql
(2)将node2升为主,并启动mysql服务
drbdadm primary mysql
mount /dev/drbd0 /mnt
chown -R mysql:mysql /mnt
service mysql start
(3)验证数据同步
mysql> select * from db1.t1;
+------+
| a |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
可以看到数据已经同步,在node2上已经有了新建的库表数据。
前面的DRBD环境充其量只是一个容灾配置,还算不上高可用方案。设想当主节点的MySQL数据库出现问题时,需要人为发现故障,并手工执行主从切换,这个过程不可避免的长时间停止服务。要保证主服务器不间断服务,需要实现自动故障转移,与DRBD一起使用比较多的是Heartbeat。顾名思义,Heartbeat像是在主从两个DRBD之间接了一条心跳线,当从节点接收不到主节点的心跳时接管服务。Heartbeat双机热备软件来保证数据库服务的稳定性和连续性,数据一致性由DRBD来保证。默认情况下只有一台MySQL实例在工作,当主MySQL服务器出现问题后,系统将自动切换到备机上继续提供服务。这个方案的优点显而易见:安全性、稳定性、可用性高,出现故障自动切换;但缺点也彰明较著:只有一台服务器提供服务,成本相对较高,不方便扩展,可能会发生脑裂。
实验环境的架构如图2所示。
前面已经完成了DRBD+mysql的安装部署,下面配置heartbeat。heartbeat的安装参见“https://wxy0327.blog.csdn.net/article/details/81188814#%E4%BA%8C%E3%80%81%E5%AE%89%E8%A3%85Heartbeat”
node1上的ha.cf文件内容如下:
[root@node1 ~]# cat /usr/local/heartbeat/etc/ha.d/ha.cf
debugfile /var/log/ha-debug
logfile /var/log/ha-log
logfacility local0
keepalive 1
deadtime 30
warntime 10
initdead 120
udpport 694
bcast ens32
ucast ens32 172.16.1.126
auto_failback off
node node1
node node2
ping 172.16.1.254
respawn hacluster /usr/local/heartbeat/libexec/heartbeat/ipfail
apiauth ipfail gid=haclient uid=hacluster
[root@node1 ~]#
节点2上的/usr/local/heartbeat/etc/ha.d/ha.cf文件只有一个配置项与节点1不同。
ucast ens32 172.16.1.125
节点1与节点2上的authkeys文件相同,内容如下:
[root@node1 ~]# cat /usr/local/heartbeat/etc/ha.d/authkeys
auth 1
1 crc
所有节点的haresources文件相同,内容如下:
[root@node1 ~]# cat /usr/local/heartbeat/etc/ha.d/haresources
node1 IPaddr::172.16.1.101/24/ens32 drbddisk::mysql Filesystem::/dev/drbd0::/mnt::xfs mysql
在两个节点执行以下命令:
cd /usr/local/heartbeat/etc/ha.d
chmod 600 authkeys
ln -svf /usr/local/heartbeat/lib64/heartbeat/plugins/RAExec/* /usr/local/heartbeat/lib/heartbeat/plugins/RAExec/
ln -svf /usr/local/heartbeat/lib64/heartbeat/plugins/* /usr/local/heartbeat/lib/heartbeat/plugins/
在两个节点的heartbeat资源目录下创建脚本文件:
cp /etc/ha.d/resource.d/drbddisk /usr/local/heartbeat/etc/ha.d/resource.d/
[root@node1 ~]# more /usr/local/heartbeat/etc/ha.d/resource.d/mysql
chown -R mysql:mysql /mnt/
service mysql start
[root@node1 ~]# more /home/mysql/mysql_check.sh
#!/bin/bash
. /home/mysql/.bashrc
count=1
while true
do
mysql -uroot -p123456 -S /data/mysql.sock -e "show status;" > /dev/null 2>&1
i=$?
ps aux | grep mysqld | grep -v grep > /dev/null 2>&1
j=$?
if [ $i = 0 ] && [ $j = 0 ]
then
sleep 3
else
if [ $i = 1 ] && [ $j = 0 ]
then
sleep 3
else
if [ $count -gt 5 ]
then
break
fi
let count++
continue
fi
fi
done
/etc/init.d/heartbeat stop
在两个节点上启动HeartBeat服务,先启动node1,再启动node2。
systemctl start heartbeat
systemctl enable heartbeat
systemctl status heartbeat
如下所示,此时VIP绑定在node1上:
客户端通过VIP可以正常访问MySQL:
C:\Users\wxy>mysql -h172.16.1.101 -uroot -p123456 -e "select * from db1.t1"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------+
| a |
+------+
| 1 |
+------+
当启动heartbeat时同时启动ipfail来检测心跳,hacluster为启动heartbeat时的用户 ,也就是说ipfail和heartbeat都是用hacluster这个用户来运行。heartbeat和ipfail进程如下所示:
# 首先启动mysql检测脚本,因为heartheat不检查服务的可用性,需要通过自定义脚本实现
nohup /home/mysql/mysql_check.sh &
# 停止mysqld
service mysql stop
node1的heartbeat进程停止,VIP和DRBD都切换到node2,客户端可以正常访问MySQL,自动切换成功。
# 先启动node1的heartheat
systemctl start heartbeat
# 停止node2的heartheat,也可以使用 iptables -I INPUT -p icmp -j DROP 禁用 ping
systemctl stop heartbeat
node2的heartbeat进程停止,VIP和DRBD都切换回node1,客户端可以正常访问MySQL,自动切换成功。
# 先启动node2的heartheat
systemctl start heartbeat
# node1重启
reboot
VIP和DRBD都切换到node2,客户端可以正常访问MySQL,自动切换成功。
# 停止node1的heartbeat服务
systemctl stop heartbeat
# 停止node2的heartbeat服务
systemctl stop heartbeat
# 在node1上添加防火墙策略,拒绝node2的广播包
iptables -A INPUT -i ens32 -p udp -s 172.16.1.126 --dport 694 -j DROP
# 在node2上添加防火墙策略,拒绝node1的广播包
iptables -A INPUT -i ens32 -p udp -s 172.16.1.125 --dport 694 -j DROP
# 启动node1的heartbeat服务
systemctl start heartbeat
# 启动node2的heartbeat服务
systemctl start heartbeat
在超过initdead定义的时间后,两个节点都绑定了同一个VIP,都挂载了DRDB盘,都启动了MySQL服务,都可以进行MySQL的读写。它们之间各自为政,不知道对方的存在,出现的脑裂。
由于两节点之间在指定的时间内,无法互相检测到对方心跳而各自启动故障转移功能,取得了资源以及服务的所有权,此时的两节点都还活着并作正常运行,这样会导致资源冲突,最严重的就是两台主机同时占用一个VIP的地址,当用户写入数据的时候可能会分别写入到两端,这样可能会导致两节点数据不一致或造成数据丢失,这种情况被称为裂脑。
一般来说,裂脑的发生,主要是由以下的几个原因导致的:
发生脑裂的时候,对业务的影响是及其严重的,有的时候甚至是致命的。如:两节点之间发生脑裂,导致互相竞争同一个IP资源,就如同我们局域网内常见的IP地址冲突一样,两个机器就会有一个或者两个不正常,影响用户正常访问服务器。如果是应用在数据库或者是存储服务这种极重要的高可用上,那就导致用户发布的数据间断的写在两台服务器上的恶果,最终导致数据难以恢复。
实际的生产环境中,我们可以从以下几个方面来防止裂脑的发生: