NFS双机热备探究实验

一、实验背景:

公司只有一台NFS服务器,上面存有一些编译工具,通用脚本等,现在该机器比较老旧,出现故障时恢复困难,存在单点故障不说,还会造成线上服务的不稳定,现急需对该服务器进行双机热备高可用,无论哪台挂了,可以自动切换过去。

二、初步设想:

使用两台机器,使用文件同步工具对两个机器的文件保持一致,其中一个挂掉后,将另一个机器改为同样的IP地址,使服务恢复,下面就来进行探究该方法是否可以。

三、实验环境

:          192.168.254.135     Linux版本:CentOS 6.9

:    192.168.254.136    Linux版本:CentOS 6.9

:    192.168.254.129     Linux版本:CentOS 6.9

:192.168.254.100

实验目标:master和slave保存同一份存储文件,无论哪台机器down机,client1和2均不受影响。

四、实验步骤

、yum安装nfs并配置keepalived,实现IP地址漂移。

和slave上:

yum -y install nfs keepalived
           yum -y install nfs-utils nfs-utils-lib nfs4-acl-tools
           chmod 777 /global
           vim /etc/exports
                            /global 192.168.254.0/24(rw,sync,no_root_squash)
                   /etc/init.d/rpcbind start
                  service nfs start
                   vi /etc/selinux/config
                            SELINUX=disabled
                   service iptables stop
                   chkconfig iptables off
                   vim /etc/keepalived/keepalived.conf

两台nfs服务器如何实现主备切换 nfs双机热备_网络

、客户端

                   mount -t nfs 192.168.254.100:/global /global

但是经过试验,使用了keepalived并不能实现双机热备,IP地址可以漂移,但是nfs服务无法自动恢复,必须要umount卸载掉然后重新挂载VIP的/global目录,所以我们就来单机抓包来分析一下根本原因。为了不搞混VIP到底在哪台机器上,我们在这里不使用VIP挂载,使用更改IP地址的方式测试服务是否可以自动恢复。

步骤1:在客户端挂载192.168.254.135这台服务器的/global目录,挂载成功

步骤2:把136这台服务器的IP地址和mac地址都改成和135相同,发现ls /global目录提示Stale file handle。

步骤3:把136关机,135开机,发现global可以自动挂回来。

打开wireshark进行抓包,发现在135关机后把136的IP地址改成135,TCP连接可以连回来,但是NFS连不回来,进行报文分析如下。

客户端和正常的135服务器之间的通信如下:

1、客户端先向服务器端发送NFS V4 NULL Call,此报文中不包含什么有用信息,只包含一个版本号。而服务器端也向客户端返回一个同样的空报文。此为握手阶段。

两台nfs服务器如何实现主备切换 nfs双机热备_两台nfs服务器如何实现主备切换_02

两台nfs服务器如何实现主备切换 nfs双机热备_运维_03

2、紧接着,客户端向服务器端发送NFS报文之PUTROOTFH|GETATTR|GETFH操作。

在这里需要先解释一下FH文件句柄的含义:

RFC协议原文如下:The filehandle in the NFS protocol is a per-server unique identifier for a file system object. The contents of the filehandle are opaque to the client. Therefore, the server is responsible for translating the filehandle to an internal representation of the file system object.[1]

翻译过来就是:NFS协议中的文件句柄是文件系统对象的每服务器唯一标识符。文件句柄的内容对客户端是不透明的。因此,服务器负责将文件句柄转换为文件系统对象的内部表示。

通俗点讲就是文件句柄是文件系统的表示方式,并且对客户端是不透明的。

PUTROOTFH通常用作NFS请求中的第一个操作,用于为后续操作设置上下文。客户端通过使用PUTROOTFH操作,以ROOT 文件句柄启动。PUTROOTFH操作指示服务器将“当前”文件句柄设置为服务器文件系统的ROOT。一旦使用了这个PUTROOTFH操作,客户端就可以使用LOOKUP过程遍历整个服务器的文件树。

而GETATTR操作将获取当前文件句柄指定的文件系统对象的属性。

GETFH是指获取当前文件句柄,此操作返回当前文件句柄值。

两台nfs服务器如何实现主备切换 nfs双机热备_开发工具_04

两台nfs服务器如何实现主备切换 nfs双机热备_网络_05

简单来讲就是客户端要服务器端的/的文件句柄的值,然后服务器告诉他我的/的句柄hash值为0x62d40c52。

两台nfs服务器如何实现主备切换 nfs双机热备_开发工具_06

3、客户端反复进行GETATTR的操作,将服务器端根的属性全部获取到

两台nfs服务器如何实现主备切换 nfs双机热备_运维_07

4、获取完服务器的根的属性之后客户端请求PUTFH,ACCESS,GETATTR三个操作

两台nfs服务器如何实现主备切换 nfs双机热备_运维_08

PUTFH的意思就是我要对这个文件进行操作

ACCESS就是要访问PUTFH的文件,即服务器的/,客户端挨个问:我能不能读?我能不能查找?我能不能修改?我能不能增加?我能不能删除?

客户端请求报文详细信息:

两台nfs服务器如何实现主备切换 nfs双机热备_开发工具_09

然后服务器端就会告诉他:如下图:

两台nfs服务器如何实现主备切换 nfs双机热备_客户端_10

你可以来读、查、删、增、改,但是我只允许你读和查,意思就是你可以来删,但是我不让你删,并不是不能删。

5、那么好,既然你能让我查我就查一查我的/etc/fstab中要挂载谁呢?我要挂载你的/global,于是客户端就先发送了查询请求到服务器端,查一查/下有没有global,如果有的话你把他的文件标识符发给我。

两台nfs服务器如何实现主备切换 nfs双机热备_运维_11

客户端请求报文详细信息:

两台nfs服务器如何实现主备切换 nfs双机热备_两台nfs服务器如何实现主备切换_12

其中:PUTFH是服务器的/的文件标识符,LOOKUP是要挂载的服务器的目录,请求它的GETFH,和我需要的/global的属性。

服务器响应报文详细信息:

两台nfs服务器如何实现主备切换 nfs双机热备_客户端_13

服务器说:你给我的根的FH我这匹配,OK,查询请求可以帮你查,OK,你要的/global的文件标识符是xxx,对应的hash值为0x03168bcf,属性给你。

6、好的,既然你给我了/global的FH我就不必每次都找/了,就像有了中间人牵线之后两个人再联系就不必每次都让中间人联系了一样。直接可以找/global了

两台nfs服务器如何实现主备切换 nfs双机热备_开发工具_14

客户端发送了6次请求获取/global的相关属性。

7、两个人是联系上了,但是能否进入对方的心呢?客户端又问:我能不能读?我能不能查……服务器端当然还是很有礼貌的说:你可以读,你可以查……

两台nfs服务器如何实现主备切换 nfs双机热备_两台nfs服务器如何实现主备切换_15

客户端请求报文:

两台nfs服务器如何实现主备切换 nfs双机热备_网络_16

服务器端响应报文:

两台nfs服务器如何实现主备切换 nfs双机热备_开发工具_17

至此,客户端和服务器端连接建立完毕,下面进入/global,并执行ls命令。

8、ls命令执行时先获取一些属性信息,然后发送READDIR请求,

两台nfs服务器如何实现主备切换 nfs双机热备_客户端_18

客户端请求READDIR报文:

两台nfs服务器如何实现主备切换 nfs双机热备_运维_19

服务器端响应READDIR请求报文:

两台nfs服务器如何实现主备切换 nfs双机热备_运维_20

9、新建一个文件,总共进行了这么多操作,我们一一来看。

两台nfs服务器如何实现主备切换 nfs双机热备_两台nfs服务器如何实现主备切换_21

首先还是权限检查,然后发送客户端ID报文:

两台nfs服务器如何实现主备切换 nfs双机热备_客户端_22

里面包含了客户端的一些关键信息,

服务器端也会返回一个客户端id

两台nfs服务器如何实现主备切换 nfs双机热备_网络_23

然后客户端确认该id,服务器端再次确认。

接下来客户端使用OPEN操作创建文件,操作信息如下图:

两台nfs服务器如何实现主备切换 nfs双机热备_运维_24

里面包含了很多文件相关的信息,例如权限,文件名,FH,客户端ID等等信息。

然后服务器端响应该请求,两者之间互相发送OPEN_CONFIRM确认信息,最后关闭,发送CLOSE报文,完成一次写操作,其他过程类似,不再赘述,总之报文里面信息非常详细。

10、心跳

在之后的一段时间内没有对/global进行任何操作,他们之间仍然周期性的发送心跳包,客户端每隔60秒发送一次更新请求,服务器端来响应。

两台nfs服务器如何实现主备切换 nfs双机热备_开发工具_25

那么如果用另一台机器改成同样的IP地址来作为服务器会发生什么现象呢?

在客户端访问nfs服务器时同样会发出请求报文,请求FH为0x03168bcf的文件,但是服务器端会告诉他,我这没有这个FH的文件,报一个NFS4ERR_STALE的错误,在RFC官网上查询该错误的意思是:无效的文件句柄。参数中给出的文件句柄无效。该文件句柄引用的文件不再存在或访问它已被撤销。

两台nfs服务器如何实现主备切换 nfs双机热备_开发工具_26

到这里,对NFS的报文抓包分析即将接近尾声,证明试图通过keepalived为nfs做高可用的方案是不可行的,原因就是在nfs通信的时候不仅使用TCP连接,更重要的是使用FH文件句柄来识别是否是同一个文件系统,如果不一致的话是无法自动恢复连接的。所以对NFS的高可用应该是用其他方法。或者使用脚本不断检测NFS挂载点是否可用,如果不可用则强行卸载并重新挂载即可。

下面按照官方推荐的NFS高可用方法来做一遍实验,看是否是FH不变。即NFS+DRBD的方式来测试。

测试步骤简略写一下即可,网上很多,不再赘述。

第一步:下载repo yum源,并yun安装drbd。

rpm -Uvh http://www.elrepo.org/elrepo-release-6-8.el6.elrepo.noarch.rpm
yum -y install drbd83-utils kmod-drbd83

第二步:修改配置文件

modprobe drbd
lsmod |grep drbd
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";
cp /etc/drbd.d/global_common.conf /etc/drbd.d/global_common.conf.bak
cp /etc/drbd.d/global_common.conf /etc/drbd.d/global_common.conf.bak

第三步:编辑主配置文件

vim /etc/drbd.d/global_common.conf
      
      
global {
      usage-count yes;
}
common {
      protocol C;
      handlers {
      }
      startup {
            wfc-timeout          240;
            degr-wfc-timeout     240;
            outdated-wfc-timeout 240;
      }
      disk {
            on-io-error detach;
      }
      net {
            cram-hmac-alg md5;
            shared-secret "testdrbd";
      }
      syncer {
            rate 30M;
      }
}

给master和slave主机增加硬盘,然后fdisk分区得到一个设备路径,本例中为:/dev/sdb1。

然后vim /etc/drbd.d/r0.res 编辑

其中 on后面填写主机和备机的主机名,本例为master和slave,device为将来生成的磁盘设备号,写/dev/drbd0即可,disk为刚刚分区之后的磁盘设备路径,address分别写主机和备机的IP地址。

resource r0 {
on master {
      device     /dev/drbd0;
      disk       /dev/sdb1;
      address    192.168.254.135:7898;
      meta-disk  internal;
 }
on slave {
      device     /dev/drbd0;
      disk       /dev/sdb1;
      address        192.168.254.136:7898;
      meta-disk  internal;
 }
}
      drbdadm up r0                     //启动drbd      drbdadm create-md r0   //创建drbd块设备
/etc/init.d/drbd start        //启动drbd服务
ps -ef|grep drbd                  //查看进程
           
root          5174     2  0 02:25     ?        00:00:00 [drbd0_worker]
root          5193     2  0 02:25     ?        00:00:00 [drbd0_receiver]
root          5207     2  0 02:25     ?        00:00:00 [drbd0_asender]
root         5211     18667  0 02:25     pts/0    00:00:00 grep --color drbd

cat /proc/drbd                    //查看状态

两台nfs服务器如何实现主备切换 nfs双机热备_开发工具_27

/etc/init.d/drbd status    //查看状态
drbd driver loaded OK; device status:
version: 8.3.16 (api:88/proto:86-97)
GIT-hash:     a798fa7e274428a357657fb52f0ecf40192c1985 build by phil@Build64R6,     2014-11-24 14:51:37
m:res      cs          ro                 ds                 p       mounted  fstype
0:r0       StandAlone      Secondary/Unknown      UpToDate/DUnknown  r-----


第四步:分区格式化,只在master上做      drbdadm primary --force r0  //只需要主机执行,设置自己为master

mkfs.ext4 /dev/drbd0
mkdir /global
mount /dev/drbd0 /global

再次查看主的状态,发现已经变成connected,Primary/Secondary了,意思就是已经连接,并且自己是主,挂载点是/global,类型是ext4。

两台nfs服务器如何实现主备切换 nfs双机热备_两台nfs服务器如何实现主备切换_28

查看备的状态,发现也是connected,但是自己是Secondary,对方是Primary,没有挂载点。

两台nfs服务器如何实现主备切换 nfs双机热备_开发工具_29


把primary的eth1给ifdown了,然后直接在secondary上进行主的提升(drbdadm primary --force r0),并且给mount上(mount /dev/drbd0 /global),发现在primary上测试拷入的文件已经同步过来了,并且客户端可以直接ls查看,无需重新挂载。

查看备的状态,状态是WFC,意思就是等待连接,因为主已经被我关机了,但是自己变成了Primary,对方为Unknown,现在在客户端对其写入文件,启动主节点。

两台nfs服务器如何实现主备切换 nfs双机热备_运维_30

之后把primary的eth1恢复后,发现没有自动恢复主从关系,经过查询,发现出现了drbd检测出现了Split-Brain 的状况,两个节点各自都standalone了。

两台nfs服务器如何实现主备切换 nfs双机热备_开发工具_31

两台nfs服务器如何实现主备切换 nfs双机热备_运维_32

手动恢复Split-Brain状况:

在secondary上:

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

在primary上:

drbdadm connect r0
drbdadm primary --force r0
mount /dev/drbd0 /global

参考文献:

[1] https://pike.lysator.liu.se/docs/ietf/rfc/56/rfc5661.xml

 



转载于:https://blog.51cto.com/hebutyx/2147013