1. drbd简介
DRDB(Distributed Replicated Block Device)由内核模块和相关应用层工具程序组成,主要被用于Linux平台下的高可用(HA)方案之中,实现不同机器上数据的同步,保持数据的一致性。当本地节点的主机出现故障时,远程节点的主机上还会保留有一份完全相同的数据,可以继续使用,以达到高可用的目的。在高可用(HA)解决方案中使用DRBD,可以代替使用一个共享盘阵列存储设备。因为数据同时存在于本地主机和远程主机上,在遇到需要切换的时候,远程主机只需要使用它上面的那份备份数据,就可以继续提供服务了。
如图所示,DRBD位于文件系统的下层,他将磁盘数据的变化同步到对端机器,并不关心上层数据的类型,也不检测上层的错误,例如上层的文件系统崩溃了,DRBD是检测不到的,他同样将数据同步到对端。
DRBD的使用手册非常完备,网上的功能介绍也很多,本文试图从开发者的角度,从代码实现的层面分析DRBD的原理及依赖的相关Linux内核技术。
DRBD是一个虚拟的块设备,实现了一个块设备驱动程序,主设备号是147,每一个DRBD块设备对应一个实际的物理设备,Mount磁盘分区时,使用的是DRBD设备,例如/dev/drbd0等。
与块设备相关的内核组件是非常多的,参见图2,要想理解DRBD的工作原理,首先需要了解Linux文件系统中一个普通的文件I/O操作的执行过程,也就是要对图2所示的结构有一个整体的了解,这里不做深入介绍,可以阅读《Understanding The Linux Kernel》的第12、14、16章节。
通用块层:
Generic Block Layer,通用块层,它处理来自系统中所有块设备发出的请求。通用块层的核心数据结构是一个称为bio的描述符,他描述了块设备的I/O操作。每个bio结构包括一个设备描述符,I/O操作的起始磁盘扇区号和扇区数目,内存段等,几个关键字段如下所示:
2. 案例拓扑图
3. 安装并配置drbd
1) 配置两台linux主机的ip地址
n1.xht.com
n2.xht.com
2)设置两台linux主机的主机名
n1.xht.com
[root@localhost ~]# vim /etc/sysconfig/network
n2.xht.com
[root@localhost ~]# vim /etc/sysconfig/network
3) 要保证两个节点之间可以相互解析,在两台节点上分别配置hosts文件
[root@n1 ~]# vim /etc/hosts
[root@n2 ~]# vim /etc/hosts
4) 为两个节点的磁盘进行分区,要求两个节点上的分区大小要一样
Command (m for help): n
First cylinder (1632-2610, default 1632):
Using default value 1632
Last cylinder or +size or +sizeM or +sizeK (1632-2610, default 2610): +1g
Command (m for help): p
Disk /dev/sda: 21.4 GB, 21474836480 bytes
255 heads, 63 sectors/track, 2610 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Device Boot Start End Blocks Id System
/dev/sda1 * 1 65 522081 83 Linux
/dev/sda2 66 1370 10482412+ 83 Linux
/dev/sda3 1371 1631 2096482+ 82 Linux swap / Solaris
/dev/sda4 1632 2610 7863817+ 5 Extended
/dev/sda5 1632 1754 987966 83 Linux
[root@n2 ~]# fdisk /dev/sda
The number of cylinders for this disk is set to 2610.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)
Command (m for help): p
Disk /dev/sda: 21.4 GB, 21474836480 bytes
255 heads, 63 sectors/track, 2610 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Device Boot Start End Blocks Id System
/dev/sda1 * 1 65 522081 83 Linux
/dev/sda2 66 1370 10482412+ 83 Linux
/dev/sda3 1371 1631 2096482+ 82 Linux swap / Solaris
/dev/sda4 1632 2610 7863817+ 5 Extended
/dev/sda5 1632 1754 987966 83 Linux
5)让两台主机重新识别分区表
[root@n1 ~]# cat /proc/partitions
major minor #blocks name
8 0 20971520 sda
8 1 522081 sda1
8 2 10482412 sda2
8 3 2096482 sda3
8 4 0 sda4
8 5 987966 sda5
[root@n2 ~]# partprobe /dev/sda
[root@n2 ~]# cat /proc/partitions
major minor #blocks name
8 0 20971520 sda
8 1 522081 sda1
8 2 10482412 sda2
8 3 2096482 sda3
8 4 0 sda4
8 5 987966 sda5
6)上传drbd主程序和内核模块程序并安装这两个软件
drbd83-8.3.8-1.el5.centos.i386.rpm GRBD主程序
kmod-drbd83-8.3.8-1.el5.centos.i686.rpm 内核模块
[root@n1 ~]# rpm -ivh drbd83-8.3.8-1.el5.centos.i386.rpm
warning: drbd83-8.3.8-1.el5.centos.i386.rpm: Header V3 DSA signature: NOKEY, key ID e8562897
Preparing... ########################################### [100%]
1:drbd83 ########################################### [100%]
[root@n1 ~]# rpm -ivh kmod-drbd83-8.3.8-1.el5.centos.i686.rpm
warning: kmod-drbd83-8.3.8-1.el5.centos.i686.rpm: Header V3 DSA signature: NOKEY, key ID e8562897
Preparing... ########################################### [100%]
1:kmod-drbd83 ########################################### [100%]
[root@n2 ~]# rpm -ivh drbd83-8.3.8-1.el5.centos.i386.rpm
warning: drbd83-8.3.8-1.el5.centos.i386.rpm: Header V3 DSA signature: NOKEY, key ID e8562897
Preparing... ########################################### [100%]
1:drbd83 ########################################### [100%]
[root@n2 ~]# rpm -ivh kmod-drbd83-8.3.8-1.el5.centos.i686.rpm
warning: kmod-drbd83-8.3.8-1.el5.centos.i686.rpm: Header V3 DSA signature: NOKEY, key ID e8562897
Preparing... ########################################### [100%]
1:kmod-drbd83 ########################################### [100%]
7)查看软件的安装位置
[root@n1 ~]# rpm -ql drbd83
/etc/bash_completion.d/drbdadm
/etc/drbd.conf
/etc/drbd.d/global_common.conf
/etc/ha.d/resource.d/drbddisk
/etc/ha.d/resource.d/drbdupper
/etc/rc.d/init.d/drbd
/etc/udev/rules.d/65-drbd.rules
/etc/xen/scripts/block-drbd
/sbin/drbdadm
/sbin/drbdmeta
/sbin/drbdsetup
/usr/lib/drbd/crm-fence-peer.sh
8)在两个节点上分别执行以下命令
[root@n1 ~]# modprobe drbd
[root@n1 ~]# lsmod |grep drbd
drbd 228528 0
[root@n2 ~]# modprobe drbd
[root@n2 ~]# lsmod |grep drbd
drbd 228528 0
9)在两个节点上编辑drbd的配置文件 :/etc/grbd.conf
[root@n1 ~]# cp /usr/share/doc/drbd83-8.3.8/drbd.conf /etc/
cp:是否覆盖“/etc/drbd.conf”? y
[root@n1 ~]# vim /etc/drbd.conf
[root@n2 ~]# cp /usr/share/doc/drbd83-8.3.8/drbd.conf /etc/
cp:是否覆盖“/etc/drbd.conf”? y
10)在两个节点上编辑global_common.conf文件,编辑之前最好做备份
[root@n1 ~]# cd /etc/drbd.d/
[root@n1 drbd.d]# cp -p global_common.conf global_common.conf.bak
[root@n2 ~]# cd /etc/drbd.d/
[root@n2 drbd.d]# cp -p global_common.conf global_common.conf.bak
[root@n1 drbd.d]# vim global_common.conf
global {
usage-count no; 不统计用法计数(影响性能)
# minor-count dialog-refresh disable-ip-verification
}
common {
protocol C; 使用C类协议当存储到对方的磁盘后才算结束
handlers {
# fence-peer "/usr/lib/drbd/crm-fence-peer.sh";
# split-brain "/usr/lib/drbd/notify-split-brain.sh root";
# out-of-sync "/usr/lib/drbd/notify-out-of-sync.sh root";
# before-resync-target "/usr/lib/drbd/snapshot-resync-target-lvm.sh -p 15 -- -c 16k";
# after-resync-target /usr/lib/drbd/unsnapshot-resync-target-lvm.sh;
}
startup { 启动时延迟配置
wfc-timeout 120;
degr-wfc-timeout 120;
}
disk {
on-io-error detach; 当io出错时拆除磁盘
fencing resource-only;
}
net {
cram-hmac-alg "sha1";通讯时使用sha1加密
shared-secret "xht"; 预共享密钥,双方应相同
}
syncer {
rate 100M; 同步时的速率
}
}
在n2.xht.com上做同样的配置
11)在两个节点上分别编辑资源文件,文件名可随便写,但是不能有空格
[root@n1 drbd.d]# vim wweb.res
resource wweb { 资源名
on n1.xht.com { n1.xht.com的资源
device /dev/drbd0; 逻辑设备名,在/dev/下
disk /dev/sda5; 真实设备名,节点间共享的磁盘或分区
address 192.168.10.1:7789; 节点1的ip地址
meta-disk internal; 磁盘类型
}
on n2.xht.com { n2.xht.com的资源
device /dev/drbd0;
disk /dev/sda5;
address 192.168.10.2:7789;
meta-disk internal;
}
在n2.xht.com上作同样的配置
12)在两个节点上初始化资源wweb
[root@n1 drbd.d]# drbdadm create-md wweb
Writing meta data...
initializing activity log
NOT initialized bitmap
New drbd meta data block successfully created.
[root@n2 drbd.d]# drbdadm create-md wweb
Writing meta data...
initializing activity log
NOT initialized bitmap
New drbd meta data block successfully created.
13) 在两个节点上启动drbd服务
[root@n1 drbd.d]# service drbd start
[root@n2 drbd.d]# service drbd start
14) 查看当前哪台设备室激活设备
[root@n1 drbd.d]# cat /proc/drbd
version: 8.3.8 (api:88/proto:86-94)
GIT-hash: d78846e52224fd00562f7c225bcc25b2d422321d build by [email protected], 2010-06-04 08:04:16
0: cs:Connected ro:Secondary/Secondary ds:Inconsistent/Inconsistent C r----
ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:987896
当前设备的角色/对方的角色 ,可知当前两台设备都未激活,都无权限读取磁盘
或是使用命令drbd-overview 查看当前设备状态
[root@n1 drbd.d]# drbd-overview
0:wweb Connected Secondary/Secondary Inconsistent/Inconsistent C r----
15) 在节点1上执行命令,将当前设备成为主设备
[root@n1 drbd.d]# drbdadm -- --overwrite-data-of-peer primary wweb
[root@n1 drbd.d]# drbd-overview
0:wweb Connected Primary/Secondary UpToDate/UpToDate C r----
16 ) 在节点1上格式化主设备的磁盘
[root@n1 drbd.d]# mkfs -t ext3 /dev/drbd0
17 ) 在节点1上新建挂载点,将/dev/drbd0挂载到上面
[root@n1 drbd.d]# mkdir /mnt/wweb
[root@n1 drbd.d]# mount /dev/drbd0 /mnt/wweb
[root@n1 drbd.d]# cd /mnt/wweb
[root@n1 wweb]# ll
总计 16
drwx------ 2 root root 16384 09-11 16:52 lost+found
产生网页文件index.html
[root@n1 wweb]# vim index.html
18 ) 将n1变为备份设备,n2 变为主设备,在n1上执行命令
[root@n1 ~]# umount /mnt/wweb
[root@n1 ~]# drbdadm secondary wweb
查看当前设备node1的状态,显示:两个节点都为备份节点
[root@n1 ~]# drbdadm role wweb
Secondary/Secondary
在节点2上,将当前设备设置为主设备
[root@n2 drbd.d]# drbdadm primary wweb
[root@n2 drbd.d]# drbdadm role wweb
Primary/Secondary
19 ) 在节点2上格式化/dev/drbd0
[root@n2 drbd.d]# mkfs -t ext3 /dev/drbd0
20 ) 节点2上创建挂载点,将/dev/drbd0 挂载上
[root@n2 drbd.d]# mkdir /mnt/wweb
[root@n2 drbd.d]# mount /dev/drbd0 /mnt/wweb
[root@n2 drbd.d]# cd /mnt/wweb
此时先前的index文件丢失
21) 在n2上/mnt/wweb下创建index.html文件
[root@n2 wweb]# echo "hello n2">index.html
[root@n2 ~]# umount /mnt/wweb
[root@n2 ~]# drbdadm secondary wweb
22)重新设置n1为主
[root@n1 ~]# drbdadm primary wweb
[root@n1 ~]# drbdadm role wweb
Primary/Secondary
23)挂载/dev/drbd0
[root@n1 ~]# mount /dev/drbd0 /mnt/wweb
[root@n1 ~]# cd /mnt/wweb
[root@n1 wweb]# ll
总计 24
-rw-r--r-- 1 root root 9 09-11 17:08 index.html
drwx------ 2 root root 16384 09-11 17:02 lost+found
此时数据已经同步
23)在以上试验中我们知道,只有手动将一个节点设置为主节点时,才可访问该节点下的内容,显然不符合智能化的要求,可以使用heartbeat工具,将drbd作为其资源,实现主节点和 备份节点的自动切换。在两个节点上都安装nfs服务,将分区共享出来,这样客户端就可以看到这些内容。
4. 配置nfs
1)在两个节点上新建挂载点,挂载光盘
[root@n1 ~]# mkdir /mnt/cdrom
[root@n1 ~]# mount /dev/cdrom /mnt/cdrom
[root@n2 ~]# mkdir /mnt/cdrom
[root@n2 ~]# mount /dev/cdrom /mnt/cdrom
2) 在两个节点上编辑nfs的共享清单
[root@n1 ~]# vim /etc/exports
/mnt/wweb 192.168.10.0/24(rw,sync)
[root@n2 ~]# vim /etc/exports
/mnt/wweb 192.168.10.0/24(rw,sync)
3) 在两个节点上导出共享清单
[root@n1 ~]# exportfs –rv
[root@n2 ~]# exportfs –rv
4) 在两个节点上修改nfs的启动脚本文件
[root@n1 ~]# vim /etc/init.d/nfs
5 . 安装配置heartbeat
1) 需要的软件包如下,
heartbeat-2.1.4-9.el5.i386.rpm
heartbeat-devel-2.1.4-9.el5.i386.rpm
heartbeat-gui-2.1.4-9.el5.i386.rpm
heartbeat-pils-2.1.4-10.el5.i386.rpm
heartbeat-stonith-2.1.4-10.el5.i386.rpm
libnet-1.1.4-3.el5.i386.rpm
perl-MailTools-1.77-1.el5.noarch.rpm
2) 并在两个节点上配置yum
# vim /etc/yum.repos.d/rhel-debuginfo.repo
3) 在两个节点上安装heartbeat
# yum localinstall heartbeat-2.1.4-9.el5.i386.rpm heartbeat-pils-2.1.4-10.el5.i386.rpm heartbeat-stonith-2.1.4-10.el5.i386.rpm libnet-1.1.4-3.el5.i386.rpm perl-MailTools-1.77-1.el5.noarch.rpm –nogpgcheck
4) 在两个节点上配置heartbeat
将/usr/share/doc/heartbeat-2.1.4下的文件复制到/etc/ha.d下
# cd /usr/share/doc/heartbeat-2.1.4/
# cp authkeys ha.cf haresources /etc/ha.d/
切换至/etc/ha.d/
编辑ha.cf文件,定义心跳参数
bcast eth0 # Linux 在eth0上监测心跳
node n1.xht.com
node n2.xht.com
编辑authkeys验证文件,进行节点之间的验证
# vim authkeys
auth 3
3 md5 xht
5) 手工创建文件:
#vim /etc/ha.d/resource.d/killnfsd
killall -9 nfsd;
/etc/init.d/nfs restart;
exit 0
6) 修改权限
# chmod 600 authkeys (不能少)
# chmod 755 resource.d/killnfsd
7) 编辑资源文件,两个节点配置一样
n1.xht.com IPaddr::192.168.10.3/24/eth0 drbddisk::wweb Filesystem::/dev/drbd0::/mnt/wweb::ext3 killnfsd
8) 在两个节点上启动heartbeat服务
# service heartbeat start
9) 查看是哪个节点获得了虚拟ip
节点1上:
[root@n1 ~]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:70:3F:F7
inet addr:192.168.10.1 Bcast:192.168.10.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe70:3ff7/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:575 errors:0 dropped:0 overruns:0 frame:0
TX packets:642 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:120878 (118.0 KiB) TX bytes:130368 (127.3 KiB)
Interrupt:67 Base address:0x2000
eth0:0 Link encap:Ethernet HWaddr 00:0C:29:70:3F:F7
inet addr:192.168.10.3 Bcast:192.168.10.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
Interrupt:67 Base address:0x2000
当前设备为主节点
[root@n1 ~]# drbd-overview
0:wweb Connected Primary/Secondary UpToDate/UpToDate C r---- /mnt/wweb ext3 950M 18M 885M 2%
6. 测试
1)在客户端n2.xh.com上新建挂载点,进行挂载
[root@n2 ~]# mkdir /mnt/nfs
[root@n2 ~]# mount 192.168.10.3:/mnt/wweb /mnt/nfs
[root@n2 ~]# cd /mnt/nfs
[root@n2 nfs]# ll
总计 24
-rw-r--r-- 1 root root 9 09-11 17:08 index.html
drwx------ 2 root root 16384 09-11 17:02 lost+found
2) 把n1.xht.com的heartbeat服务停止
可以看到资源立刻转移到n2.xht.com
3)n1.xht.com的服务启动资源又被抢占过来
4) #vim /mnt/nfs/test.sh
//此配置脚本文件的主要作用是为了反复的读写操作
#!bash
while true
do
echo --\<;trying touch x:`date`
touch x
echo \<-----done touch x:`date`
echo
sleep 2
done
把此脚本移动到root的家目录下
[root@n2 nfs]# mv test.sh /root
切换到挂载点下执行该脚本
测试完毕!