生产环境下的高可用NFS文件服务器

分布式复制块设备(distributed replicated block device)是一种基于linux 的软件组件,由内核模块和相关程序组成(linux2.6.33之后的内核自带),可通过网络镜像促进共享存储的替换,也就是说,当你将数据写入本地DRBD设备上的文件系统时,数据会同时被发送到网络上的另外一台主机上,以完全相同的形式记录在一个文件系统中。本节点与远程节点的数据可以保证实时同步,并且可以保证I/O的一致性。以达到高可用的目的。
DRBD的工作原理如下图所示。
DRBD

我们可以这样理解DRBD,它其实就是网络的RAID-1,两台服务器中就算其中某台因电源或者主板损坏也不会对数据有任何的影响,而真正的热切换用heartbeat来实现,这样的切换过程跟keepalived类似,非常短暂且不需要人为干预。
DRBD需要构建在底层设备之上,DRBD的位置处于文件系统以下,比文件系统更加靠近操作系统内核及IO栈。
DRBD需要构建出一个块设备来。对于用户来说,一个DRBD设备,就像是一块物理磁盘,(类似于组建好的raid)
可以在磁盘内创建文件系统。
下面介绍DRBD+heartbeat+NFS的详细配置过程。

做好整个环境的准备工作

两台服务器都设置好hosts文件和进行ntpd对时。
主服务器:nfs1,单独拿一块硬盘sdb作为DRBD.
主服务器:nfs2,单独拿一块硬盘sdb作为DRBD.
网络结构很简单,如下:
nfs1 eth0:192.168.2.5,eth1:10.0.0.5 (心跳线)。
nfs2 eth0:192.168.2.6,eth1:10.0.0.6 (心跳线)。

DRBD对外的VIP地址是:192.168.2.3,这是通过heartbeat来实现的,原理跟keepalived类似,它通过在某台服务器的eth0:0上绑定,如果遇到故障就转移,达到HA的目的。这同时也是对外提供NFS服务的IP.

(nfs1)为仅主节点端配置
(nfs2)为仅从节点端配置
(nfs1,nfs2)为主从节点都需配置

/etc/hosts的配置如下,两台机器上都一样配置
192.168.2.5 nfs1
192.168.2.6 nfs2
本着简单高效的原则,两台服务器之间的心跳检测直接用交叉线连接。为了文件安全,建议使用RAID-5。
然后进行时间同步:
ntpdate ntp.sjtu.edu.cn #这个时间服务器是上海交大的

DRBD的安装配置过程

1)安装开始 (nfs1,nfs2)
cd /usr/local/src
wget http://oss.linbit.com/drbd/8.4/drbd-8.4.3.tar.gz
yum install gcc gcc-c++ make glibc flex kernel-devel kernel-headers -y
注意:安装kernel-devel一定要和你uname -r 看到的内核版本一致,建议kernel-devel用本地源安装,不要用网络源安装
tar zxf drbd-8.4.3.tar.gz
cd drbd-8.4.3
./configure --prefix=/usr/local/drbd --with-km
注意:--with-km是启用内核模块
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/
chkconfig --add drbd
chkconfig drbd on

加载DRBD模块
modprobe drbd

2)查看模块是否加载成功
lsmod | grep drbd
drbd 278955 0
libcrc32c 841 1 drbd

如果出现"Could not determine uts_release"错误,我们要检查是否安装了新的内核,还要记得重启机器,否则也不能安装成功。
3)DRBD程序安装完成后主要生成命令drbdsetup,drbdadmin,配置文件/etc/drbd.conf、启动文件/etc/init.d/drbd及模块文件drbd.ko

4)确认两台要镜像的机器是否正常,它们之间的网络是否通畅,需要加载的硬盘是否处于umount状态。

5)两台机器将/dev/sdb1互为镜像,这里只列出nfs1的操作步骤:
yum -y install portmap nfs-utils
mkdir /drbd
创建共享目录,用vim可以编辑/etc/exports文件,内容如下:(nfs1,nfs2)
/drbd 192.168.2.0/255.255.255.0(rw,no_root_squash,no_all_squash,sync)

NFS不需要启动,也不需要开机自动运行,这些都由heartbeat来完成。
6)编辑/usr/local/drbd/etc/drbd.conf配置DRBD,两台机器上同样配置。(nfs1,nfs2)

resource r0{
protocol C;
startup { wfc-timeout 0; degr-wfc-timeout 120;}
disk { on-io-error detach;}
net{
  timeout 60;
  connect-int 10;
  ping-int 10;
  max-buffers 2048;
  max-epoch-size 2048;
}
syncer { rate 800M;}             #最大同步数据速度

on nfs1 {                        #on开头,后面是主机名称
device /dev/drbd0;      #drbd设备名称
disk /dev/sdb1;              #drbd0使用的磁盘分区为sdb1
address 10.0.0.5:7788; #设置drbd监听地址与端口
meta-disk internal;
}
on nfs2 {                            #on开头,后面是主机名称
device /dev/drbd0;          #drbd设备名称
disk /dev/sdb1;                 #drbd0使用的磁盘分区为sdb1
address 10.0.0.6:7788;    #设置drbd监听地址与端口
meta-disk internal;
}
}

7)在两台机器上都创建硬件设备DRBD,命令如下
mknod /dev/drbd0 b 147 0

8)在启动DRBD前,需要分别在两台机器的hdb1分区上创建供DRBD记录信息的数据块,分别在两台机器上执行如下命令:
drbdadm create-md r0
命令显示如下结果:

		--== This is a new installation of DRBD ==--
Please take part in the global DRBD usage count at http://usage.drbd.org.

The counter works anonymously. It creates a random number to identify
your machine and sends that random number, along with the kernel and
DRBD version, to usage.drbd.org.

The benefits for you are:
 * In response to your submission, the server (usage.drbd.org) will tell you
   how many users before you have installed this version (8.4.3).
 * With a high counter LINBIT has a strong motivation to
   continue funding DRBD's development.

http://usage.drbd.org/cgi-bin/insert_usage.pl?nu=2580642927742615245&git=89a294209144b68adb3ee85a73221f964d3ee515

In case you want to participate but know that this machine is firewalled,
simply issue the query string with your favorite web browser or wget.
You can control all of this by setting 'usage-count' in your drbd.conf.

* You may enter a free form comment about your machine, that gets
  used on usage.drbd.org instead of the big random number.
* If you wish to opt out entirely, simply enter 'no'.
* To count this node without comment, just press [RETURN]

按两次回车,就会显示success表示drbd块创建成功
再次输入该命令:
drbdadm create-md r0
成功激活r0
2016-03-22_103357

9)现在可以启动DRBD了,分别在两台机器上执行,如下:
/etc/init.d/drbd start
现在可以查看DRBD当前的状态,在nfs1上执行如下命令:
/etc/init.d/drbd status
次命令执行后的结果如下:

drbd driver loaded OK; device status:
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by root@nfs2, 2016-03-22 10:09:14
m:res  cs         ro                   ds                         p  mounted  fstype
0:r0   Connected  Secondary/Secondary  Inconsistent/Inconsistent  C

ro下面显示的Secondary/Secondary 表示两台主机的状态都是备机状态,ds是磁盘状态,显示其状态不一致。这是因为DRBD无法判断哪一方为主机,应该以哪一方的磁盘数据作为标准数据。
所以我们要初始化一个主机,在nfs1上执行。

10)初始化nfs1(这一步只需要在主节点点操作)
drbdsetup /dev/drbd0 primary --force

再次查看DRBD当前的状态,命令输出如下:
[root@nfs1 ~]# /etc/init.d/drbd status|tail -1
0:r0 Connected Primary/Secondary UpToDate/Inconsistent C

现在主备机状态分别是“主/备”,主机磁盘状态是“实时”,备机状态是不一致。
在第3行中可以看到数据正在同步,即主机正在将磁盘上的数据传递到备机上。
设置完之后的第一次同步耗时会比较长,因为需要把整个分区数据同步一遍,所以如果是做实验的话,把这个分区弄小一点。
同步完成后,我们再看看DRBD的状态
[root@nfs2 ~]# cat /proc/drbd
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by root@nfs2, 2016-03-22 10:09:14
0: cs:Connected ro:Secondary/Primary ds:UpToDate/UpToDate C r-----
ns:0 nr:1110020 dw:1110020 dr:0 al:0 bm:65 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0

现在磁盘状态都是“实时”,表示数据同步完成了。

drbd状态信息解释:
ro 是角色信息,Secondary/Primary说明了当前主机是Secondary节点,另外一台是Primary节点
ds 是磁盘状态,显示数据是否一致,(如果显示UpToDate/UpToDate表示同步没有延时。)
ns 是网络发送的数据包,以K字节计算
dw 是磁盘写操作
dr 是磁盘读操作
11)DRBD的使用。现在可以把主机的DRBD设备挂载到一个目录上使用。备机的DRBD设备无法被挂载,因为它是用来接收主机数据的,由DRBD负责操作。
在nfs1主服务器上执行如下操作
mkfs.ext4 /dev/drbd0
mount /dev/drbd0 /drbd
2016-03-22_110635
现在就可以对/drbd分区进行读写操作了。
注意:从节点上不允许对DRBD设备进行任何操作,包括只读。所有的读写操作只能在主节点上进行,只有当主节点挂掉时,从节点才能提升成为主节点,继续进行读写操作。
到这里,DRBD的安装算成功了。

heartbeat的配置过程

1)在两台机器上分别安装heartbeat,命令如下
yum install heartbeat -y
2)nfs1上的/etc/ha.d/hd.cf文件内容如下:

logfile /var/log/ha-log
logfacility local0
keepalive 2              # 心跳监测时间
deadtime 5               # 备用节点5秒内没检测到主机心跳,确认对方故障
ucast eth1 10.0.0.6      #对方心跳线IP,线上环境可以用多条直连交叉线来做心跳线
auto_failback off        #主服务器修复后从服务器不放弃该资源,直到从服务器故障,如果主服务器的配置比从高,可以设on
node nfs1 nfs2

nfs2上的/etc/ha.d/hd.cf文件内容如下:

logfile /var/log/ha-log
logfacility local0
keepalive 2
deadtime 5
ucast eth1 10.0.0.5
auto_failback off
node nfs1 nfs2

3)编辑双击互联验证文件vim /etc/ha.d/authkeys (nfs1,nfs2)
auth 1
1 sha1 hqidi.com #使用sha1验证,密码为:hqidi.com
将/etc/ha.d/authkeys 设为600的权限,命令如下
chmod 600 /etc/ha.d/authkeys
4)编辑群集资源文件/etc/ha.d/haresources:(两台机器上配置一样都是nfs1开头)
nfs1 IPaddr::192.168.2.3/24/eth0 drbddisk::r0 Filesystem::/dev/drbd0::/drbd::ext4 killnfsd
该文件内IPaddr,Filesystem等脚本存放路径在/etc/ha.d/resource.d/下,也可在该目录下存放服务启动脚本(例如:mysql,www),将相同脚本名称添加到/etc/ha.d/haresources内容中,从而跟随heartbeat启动而启动该脚本。

IPaddr::192.168.2.3/24/eth0:用IPaddr脚本配置浮动VIP
drbddisk::r0:用drbddisk脚本实现DRBD主从节点资源组的挂载和卸载
Filesystem::/dev/drbd0::/data::ext4:用Filesystem脚本实现磁盘挂载和卸载

5)编辑脚本文件killnfsd,用来重启NFS服务:
注:因为NFS服务切换后,必须重新mount NFS共享出来的目录,否则会报错(待验证)
# vi /etc/ha.d/resource.d/killnfsd
-----------------
killall -9 nfsd; /etc/init.d/nfs restart;exit 0
-----------------
赋予执行权限:
# chmod 755 /etc/ha.d/resource.d/killnfsd

6)创建DRBD脚本文件drbddisk:(node1,node2)

# vi /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

赋予执行权限:
# chmod 755 /etc/ha.d/resource.d/drbddisk
在两个节点上启动HeartBeat服务,先启动node1:(node1,node2)
# service heartbeat start
# chkconfig heartbeat on
这里用CMD能够PING通虚IP 192.168.2.3,而且arp -a 192.168.2.3和192.168.2.5的mac地址相同,表示配置成功。

重启NFS服务:
# service rpcbind restart
# service nfs restart
# chkconfig rpcbind on
# chkconfig nfs off
这里设置NFS开机不要自动运行,因为/etc/ha.d/resource.d/killnfsd 该脚本内容控制NFS的启动。

7)最终测试
在另外一台LINUX的客户端挂载虚IP:192.168.2.3,挂载成功表明NFS+DRBD+HeartBeat大功告成.
yum install -y nfs-utils
mount -t nfs 192.168.2.3:/drbd /data

[root@tianqi ~]# df -Th|tail -1
192.168.2.3:/drbd nfs 988M 1.4M 934M 1% /data

测试DRBD+HeartBeat+NFS可用性

1.向挂载的/tmp目录传送文件,忽然重新启动主端DRBD服务,查看变化
经本人测试能够实现断点续传
2.正常状态重启Primary主机后,观察主DRBD状态是否恢复Primary并能正常被客户端挂载并且之前写入的文件存在,可以正常再写入文件。
经本人测试可以正常恢复,且客户端无需重新挂载NFS共享目录,之前数据存在,且可直接写入文件。
3.当Primary主机因为硬件损坏或其他原因需要关机维修,需要将Secondary提升为Primary主机,如何手动操作?
如果设备能够正常启动则按照如下操作,无法启动则强行提升Secondary为Primary,待宕机设备能够正常启动,若“脑裂”,再做后续修复工作。
首先先卸载客户端挂载的NFS主机目录
# umount /tmp
(nfs1)
卸载DRBD设备:
# service nfs stop
# umount /data
降权:
# drbdadm secondary r0
查看状态,已降权
# service drbd status
-----------------
drbd driver loaded OK; device status:
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by root@drbd1.example.com, 2013-05-27 20:45:19
m:res cs ro ds p mounted fstype
0:r0 Connected Secondary/Secondary UpToDate/UpToDate C
-----------------
(nfs2)
提权:
# drbdadm primary r0
查看状态,已提权:
# service drbd status
----------------
drbd driver loaded OK; device status:
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by root@drbd2.example.com, 2013-05-27 20:49:06
m:res cs ro ds p mounted fstype
0:r0 Connected Primary/Secondary UpToDate/UpToDate C
----------------
这里还未挂载DRBD目录,让Heartbeat帮忙挂载:
注:若重启过程中发现Heartbeat日志报错:
ERROR: glib: ucast: error binding socket. Retrying: Permission denied
请检查selinux是否关闭
# service heartbeat restart
# service drbd status
-----------------------
drbd driver loaded OK; device status:
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by root@drbd2.example.com, 2013-05-27 20:49:06
m:res cs ro ds p mounted fstype
0:r0 Connected Primary/Secondary UpToDate/UpToDate C /data ext4
------------------------
成功让HeartBeat挂载DRBD目录
重新在客户端做NFS挂载测试:
# mount -t nfs 192.168.2.3:/data /tmp
# ll /tmp
------------------
1 10 2 2222 3 4 5 6 7 8 9 lost+found orbit-root
------------------
重启刚刚被提权的主机,待重启查看状态:
# service drbd status
------------------------
drbd driver loaded OK; device status:
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by root@drbd2.example.com, 2013-05-27 20:49:06
m:res cs ro ds p mounted fstype
0:r0 WFConnection Primary/Unknown UpToDate/DUnknown C /data ext4
------------------------
HeartBeat成功挂载DRBD目录,drbd无缝连接到备份节点,客户端使用NFS挂载点对故障无任何感知。
4.测试最后刚才那台宕机重新恢复正常后,他是否会从新夺取Primary资源?
重启后不会重新获取资源,需手动切换主从权限方可。
注:vi /etc/ha.d/ha.cf配置文件内该参数:
--------------------
auto_failback off
--------------------
表示服务器正常后由新的主服务器接管资源,另一台旧服务器放弃该资源
5.以上都未利用heartbeat实现故障自动转移,当线上DRBD主节点宕机,备份节点是否立即无缝接管,heartbeat+drbd高可用性是否能够实现?
首先先在客户端挂载NFS共享目录
# mount -t nfs 192.168.2.3:/data /tmp
a.模拟将主节点nfs1 的heartbeat服务停止,则备节点nfs2是否接管服务?
(nfs1)
# service drbd status
----------------------------
drbd driver loaded OK; device status:
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by root@drbd1.example.com, 2013-05-27 20:45:19
m:res cs ro ds p mounted fstype
0:r0 Connected Primary/Secondary UpToDate/UpToDate C /data ext4
----------------------------
# service heartbeat stop
(nfs2)
# service drbd status
----------------------------------------
drbd driver loaded OK; device status:
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by root@drbd2.example.com, 2013-05-27 20:49:06
m:res cs ro ds p mounted fstype
0:r0 Connected Primary/Secondary UpToDate/UpToDate C /data ext4
-----------------------------------------
从机无缝接管,测试客户端是否能够使用NFS共享目录
# cd /tmp
# touch test01
# ls test01
------------------
test01
------------------
测试通过。。。
b.模拟将主节点宕机(直接强行关机),则备节点nfs2是否接管服务?
(nfs1)
强制关机,直接关闭nfs1虚拟机电源
(nfs2)
# service drbd status
-------------------------------
drbd driver loaded OK; device status:
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by root@drbd2.example.com, 2013-05-27 20:49:06
m:res cs ro ds p mounted fstype
0:r0 WFConnection Primary/Unknown UpToDate/DUnknown C /data ext4
-------------------------------
从机无缝接管,测试客户端是否能够使用NFS共享目录
# cd /tmp
# touch test02
# ls test02
------------------
test02
------------------
待nfs1恢复启动,查看drbd状态信息:
# service drbd status
------------------------------
drbd driver loaded OK; device status:
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by root@drbd2.example.com, 2013-05-27 20:49:06
m:res cs ro ds p mounted fstype
0:r0 Connected Primary/Secondary UpToDate/UpToDate C /data ext4
-------------------------------
nfs1已连接上线,处于UpToDate状态,测试通过。

原创文章,转载请注明: 转载自笛声

本文链接地址: 生产环境下的高可用NFS文件服务器

暂无评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注