NFS双机热备探究实验

一、实验背景:

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

二、初步设想:

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

三、实验环境

         master          192.168.254.135     Linux版本:CentOS 6.9

         slave    192.168.254.136    Linux版本:CentOS 6.9

         client    192.168.254.129     Linux版本:CentOS 6.9

         VIP192.168.254.100

         实验目标:masterslave保存同一份存储文件,无论哪台机器down机,client12均不受影响。

四、实验步骤

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

            masterslave上:

                   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双机热备探究实验_第1张图片

         2、客户端

                   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关机后把136IP地址改成135TCP连接可以连回来,但是NFS连不回来,进行报文分析如下。

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

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

image.png

image.png

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是指获取当前文件句柄,此操作返回当前文件句柄值。

image.png

NFS双机热备探究实验_第2张图片

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

NFS双机热备探究实验_第3张图片

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

NFS双机热备探究实验_第4张图片

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

image.png

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

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

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

NFS双机热备探究实验_第5张图片

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

NFS双机热备探究实验_第6张图片

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

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

image.png

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

NFS双机热备探究实验_第7张图片

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

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

NFS双机热备探究实验_第8张图片

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

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

NFS双机热备探究实验_第9张图片

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

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

image.png

客户端请求报文:

NFS双机热备探究实验_第10张图片

服务器端响应报文:

NFS双机热备探究实验_第11张图片

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

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

image.png

客户端请求READDIR报文:

NFS双机热备探究实验_第12张图片

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

NFS双机热备探究实验_第13张图片

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

NFS双机热备探究实验_第14张图片

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

NFS双机热备探究实验_第15张图片

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

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

NFS双机热备探究实验_第16张图片

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

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

NFS双机热备探究实验_第17张图片

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

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

10、心跳

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

NFS双机热备探究实验_第18张图片

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

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

image.png

到这里,对NFS的报文抓包分析即将接近尾声,证明试图通过keepalivednfs做高可用的方案是不可行的,原因就是在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;

      }

}

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

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

其中 on后面填写主机和备机的主机名,本例为masterslavedevice为将来生成的磁盘设备号,写/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                    //查看状态

image.png

       /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

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

image.png

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

image.png

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

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

image.png

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

image.png

image.png

手动恢复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