一、DRBD介绍

介绍部分来自:http://www.ywnds.com/?p=6619
1 DRBD基本功能
Distributed Replicated Block Device(DRBD)是一种基于软件的,无共享,复制的存储解决方案,在服务器之间的对块设备(硬盘,分区,逻辑卷等)进行镜像。
DRBD是将不同机器上的两块大小相同的硬盘或是两个分区让它们的每一位都对齐,从而当用户空间有数据要存储到主节点磁盘时,工作在内核空间的DRBD会监控数据,一旦发现数据是要存储到定义了DRBD的分区上后,就会把数据复制一份通过网络传送到备用节点上来。备用节点上运行一个服务时刻可以接收对方发来的数据,然后接到内核中,内核中的DRBD接收到数据后通过内核保存到磁盘上。双方式通过DRBD协议按位存储数据。
在高可用(HA)中使用DRBD功能,可以代替使用一个共享盘阵。本地(主节点)与远程主机(备节点)的数据可以保证实时同步。当本地系统出现故障时,远程主机上还会保留有一份相同的数据,可以继续使用。需要说明一点的是DRBD只支持两个节点不支持多节点。
2、DRBD部署模式
①、主从模式
DRBD主从架构中,主节点可以读写数据而从节点不能读写,连挂载都不允许,否则会造成文件系统崩溃,但是主从的节点可以相互切换,如可以把主节点分区卸载后把主节点转为从,然后把分区挂在到从节点上,再把从转为主。
②、双主模式
由于DRBD是在两台独立的机器上实现数据块同步,所以单凭在一个节点上写数据时施加锁机制而另外一个节点要写数据时看不到对方施加的锁,因此会照成数据损坏。但是如果把DRBD用在高可用集群中就可以实现双主模型,在高可用中把DRBD定义成主从资源基于分布式文件锁DLM加集群文件系统gfs或ocfs,这样一来当一端在写入数据时因为是DLM+GFS,所以就会通知给另外一端的DRBD从而避免数据损坏(双主模型并不是并行读写)。
3、DRBD数据同步模式
由于DRBD将数据发送给对端服务器之后还要确定对方的回应以确定数据是否安全存储,然后DRBD程序才退出,最终应用程序完成数据存储。这样一来DRBD发送数据并接收到回应的时间就是应用程序执行的过程时间。所以又涉及到了数据安全跟性能之间平衡了,DRBD提供了异步、半同步、同步等工作方式。
①、异步复制
异步复制协议。一旦本地磁盘写入已经完成,数据包已在发送队列中,则写被认为是完成的。在一个节点发生故障时,可能发生数据丢失,因为被写入到远程节点上的数据可能仍在发送队列。尽管,在故障转移节点上的数据是一致的,但没有及时更新。这通常是用于地理上分开的节点。

②、半同步复制
内存同步(半同步)复制协议。一旦本地磁盘写入已完成且复制数据包达到了对等节点则认为写在主节点上被认为是完成的。数据丢失可能发生在参加的两个节点同时故障的情况下,因为在传输中的数据可能不会被提交到磁盘。

③、同步复制
同步复制协议。只有在本地和远程节点的磁盘已经确认了写操作完成,写才被认为完成。没有任何数据丢失,所以这是一个群集节点的流行模式,但I / O吞吐量依赖于网络带宽。
一般使用协议C,但选择C协议将影响流量,从而影响网络时延。为了数据可靠性,我们在生产环境使用时须慎重选项使用哪一种协议。

二、DRBD主从模式安装配置

1、安装前期准备

①、准备两块独立磁盘
[root@node-001 ~]# fdisk -l | grep /dev/vdb
Disk /dev/vdb: 107.4 GB, 107374182400 bytes, 209715200 sectors

[root@node-002 ~]# fdisk -l | grep /dev/vdb
Disk /dev/vdb: 107.4 GB, 107374182400 bytes, 209715200 sectors

②、关闭防火墙和SELINUX
systemctl stop firewalld
setenforce 0

③、我们需要修改hosts文件保证hosts之间能够互相访问
[root@node-001 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
10.17.2.140 sz-xh_42f-op-test-docker-001
10.17.2.47 sz-xh_42f-op-test-docker-002
10.17.2.45 node-001
10.17.2.13 node-002

[root@node-002 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
10.17.2.140 sz-xh_42f-op-test-docker-001
10.17.2.47 sz-xh_42f-op-test-docker-002
10.17.2.45 node-001
10.17.2.13 node-002

④、在node-001修改ssh互信
[root@node-001 ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
17:12:68:f3:bb:96:47:eb:6b:45:12:21:16:57:92:1b root@node-001
The key's randomart image is:
+--[ RSA 2048]----+
|       .=.++.    |
|      +. +E.     |
|     . o. .+     |
|        ..o..    |
|        S..o     |
|        ... .    |
|         + o     |
|        + +      |
|       . +o.     |
+-----------------+
[root@node-001 ~]# ssh-copy-id node-002
The authenticity of host '[node-002]:65300 ([10.17.2.13]:65300)' can't be established.
ECDSA key fingerprint is 48:5e:de:e1:d7:b6:f5:55:54:7f:3c:2b:39:70:a8:74.
Are you sure you want to continue connecting (yes/no)? yes
/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@node-002's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'node-002'"
and check to make sure that only the key(s) you wanted were added.

⑤、在node-001和node-002上设置时钟同步
[root@node-001 ~]# crontab -e
*/5 * * * * ntpdate cn.pool.ntp.org   ###添加任务 

[root@node-002 ~]# crontab -e
*/5 * * * * ntpdate cn.pool.ntp.org   ###添加任务

在node-001和node-002上可以看到已经添加时间任务:

[root@node-001 ~]# crontab -l
*/5 * * * * ntpdate cn.pool.ntp.org
[root@node-002 ~]# crontab -l
*/5 * * * * ntpdate cn.pool.ntp.org 

2、开始安装drbd包

在node-001和node-002操作
[root@node-001 ~]# yum install gcc gcc-c++ make glibc flex kernel kernel-devel kernel-headers -y
[root@node-001 ~]# rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
[root@node-001 ~]# rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
[root@node-001 ~]# yum install -y kmod-drbd84 drbd84-utils

[root@node-002 ~]# yum install gcc gcc-c++ make glibc flex kernel kernel-devel kernel-headers -y
[root@node-002 ~]# rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
[root@node-002 ~]# rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
[root@node-002 ~]# yum install -y kmod-drbd84 drbd84-utils

3、主配置文件

/etc/drbd.conf #主配置文件 
/etc/drbd.d/global_common.conf #全局配置文件
/etc/drbd.conf说明 
主配置文件中包含了全局配置文件及”drbd.d/”目录下以.res结尾的文件
# You can find an example in  /usr/share/doc/drbd.../drbd.conf.example
include "drbd.d/global_common.conf";
include "drbd.d/*.res"; 

4、修改配置文件

[root@node-001 ~]# cat /etc/drbd.d/global_common.conf
# DRBD is the result of over a decade of development by LINBIT.
# In case you need professional services for DRBD or have
# feature requests visit http://www.linbit.com

global {
    usage-count no; #是否参加DRBD使用统计,默认为yes。官方统计drbd的装机量,改为no

    # Decide what kind of udev symlinks you want for "implicit" volumes
    # (those without explicit volume <vnr> {} block, implied vnr=0):
    # /dev/drbd/by-resource/<resource>/<vnr>   (explicit volumes)
    # /dev/drbd/by-resource/<resource>         (default for implict)
    udev-always-use-vnr; # treat implicit the same as explicit volumes

    # minor-count dialog-refresh disable-ip-verification
    # cmd-timeout-short 5; cmd-timeout-medium 121; cmd-timeout-long 600;
}

common {
    protocol C;      #使用DRBD的同步协议,添加这一行
    handlers {
        # These are EXAMPLE handlers only.
        # They may have severe implications,
        # like hard resetting the node under certain circumstances.
        # Be careful when choosing your poison.

        pri-on-incon-degr "/usr/lib/drbd/notify-pri-on-incon-degr.sh; /usr/lib/drbd/notify-emergency-reboot.sh; echo b > /proc/sysrq-trigger ; reboot -f";
        pri-lost-after-sb "/usr/lib/drbd/notify-pri-lost-after-sb.sh; /usr/lib/drbd/notify-emergency-reboot.sh; echo b > /proc/sysrq-trigger ; reboot -f";
        local-io-error "/usr/lib/drbd/notify-io-error.sh; /usr/lib/drbd/notify-emergency-shutdown.sh; echo o > /proc/sysrq-trigger ; halt -f";
        # 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;
        # quorum-lost "/usr/lib/drbd/notify-quorum-lost.sh root";
    }

    startup {
        # wfc-timeout degr-wfc-timeout outdated-wfc-timeout wait-after-sb
    }

    options {
        # cpu-mask on-no-data-accessible

        # RECOMMENDED for three or more storage nodes with DRBD 9:
        # quorum majority;
        # on-no-quorum suspend-io | io-error;
    }

    disk {
        on-io-error detach; #配置I/O错误处理策略为分离
        #size on-io-error fencing disk-barrier disk-flushes
        # disk-drain md-flushes resync-rate resync-after al-extents
        # c-plan-ahead c-delay-target c-fill-target c-max-rate
        # c-min-rate disk-timeout
    }

    net {
        # protocol timeout max-epoch-size max-buffers
        # connect-int ping-int sndbuf-size rcvbuf-size ko-count
        # allow-two-primaries cram-hmac-alg shared-secret after-sb-0pri
        # after-sb-1pri after-sb-2pri always-asbp rr-conflict
        # ping-timeout data-integrity-alg tcp-cork on-congestion
        # congestion-fill congestion-extents csums-alg verify-alg
        # use-rle
    }
    syncer {
        rate 1024M;    #设置主备节点同步时的网络速率
    }
}

注释: on-io-error 策略可能为以下选项之一 
detach 分离:这是默认和推荐的选项,如果在节点上发生底层的硬盘I/O错误,它会将设备运行在Diskless无盘模式下 
pass_on:DRBD会将I/O错误报告到上层,在主节点上,它会将其报告给挂载的文件系统,但是在此节点上就往往忽略(因此此节点上没有可以报告的上层) 
-local-in-error:调用本地磁盘I/O处理程序定义的命令;这需要有相应的local-io-error调用的资源处理程序处理错误的命令;这就给管理员有足够自由的权力命令命令或是脚本调用local-io-error处理I/O错误 
定义一个资源 

5、创建资源文件

在node-001和node-002分别创建/etc/drbd.d/git.res并写入
resource git { #资源名称
protocol C; #使用协议
meta-disk internal;
device /dev/drbd1; #DRBD设备名称
syncer {
verify-alg sha1;# 加密算法
}
net {
allow-two-primaries;
}
on node-001 {
disk /dev/vdb;
address 10.17.2.45:7789; #设置DRBD监听地址与端口
}
on node-002 {
disk /dev/vdb;
address 10.17.2.13:7789;
}
}

6、启用drbd

modprobe drbd
drbdadm create-md git
drbdadm up git
rbdadm -- --force primary git

配置对端节点
ssh node-002 "drbdadm create-md git"
ssh node-002 "modprobe drbd"
ssh node-002 "drbdadm up git"

报错:Command 'drbdmeta 1 v08 /dev/vdb internal apply-al' terminated with exit code 255
解决:dd if=/dev/zero of=/dev/vdb bs=1M count=100

7、创建文件系统

文件系统只能挂载在主(Primary)节点上,因此在设置好主节点后才可以对DRBD设备进行格式化操作格式化文件系统
Primary:当前节点为主;在前面为当前节点 
Secondary:备用节点为次 
查看当前节点角色
[root@node-001 ~]# drbdadm role git
Secondary/Primary

[root@node-002 data]# drbdadm role git
Primary/Secondary
可知primary节点是004,在节点004上执行以下命令
mkfs.ext4 /dev/drbd1
mount /dev/drbd1 /data

查看drbd状态使用cat /proc/drbd 或drbd-overview
[root@node-002 data]# drbd-overview
NOTE: drbd-overview will be deprecated soon.
Please consider using drbdtop.

 1:git/0  SyncTarget Primary/Secondary Inconsistent/UpToDate /data xfs 100G 33M 100G 1% 
    [=====>..............] sync'ed: 31.4% (66744/97164)M     

8、切换主备测试是否同步成功

在node-002创建数据并执行降级操作,切换为备节点
创建测试文件
[root@node-002 data]# touch /data/testfile.{1..4}
[root@node-002 data]# ll /data
total 0
-rw-r--r-- 1 root root 0 Jun 14 09:20 testfile.1
-rw-r--r-- 1 root root 0 Jun 14 09:20 testfile.2
-rw-r--r-- 1 root root 0 Jun 14 09:20 testfile.3
-rw-r--r-- 1 root root 0 Jun 14 09:20 testfile.4
执行降级操作
[root@node-002 data]# cd ~
[root@node-002 ~]# umount /data
[root@node-002 ~]# drbdadm secondary git
[root@node-002 ~]# drbd-overview
NOTE: drbd-overview will be deprecated soon.
Please consider using drbdtop.

 1:git/0  SyncTarget Secondary/Secondary Inconsistent/UpToDate 
    [=======>............] sync'ed: 44.1% (54340/97164)M    

在node-001执行升级操作,切换为primary节点
[root@node-001 ~]# drbdadm primary git
[root@node-001 ~]# drbdadm role git
Primary/Secondary
[root@node-001 ~]# mount /dev/drbd1 /data
[root@node-001 ~]# ll /data
total 0
-rw-r--r-- 1 root root 0 Jun 14 09:20 testfile.1
-rw-r--r-- 1 root root 0 Jun 14 09:20 testfile.2
-rw-r--r-- 1 root root 0 Jun 14 09:20 testfile.3
-rw-r--r-- 1 root root 0 Jun 14 09:20 testfile.4

至此,数据同步成功,DRBD主从模式部署完成

9、常用命令操作

①、资源的连接状态详细介绍,如何查看资源连接状态?

[root@node-001 ~]# drbdadm cstate git
SyncSource

资源的连接状态;一个资源可能有以下连接状态中的一种
StandAlone 独立的:网络配置不可用;资源还没有被连接或是被管理断开(使用 drbdadm disconnect 命令),或是由于出现认证失败或是脑裂的情况
Disconnecting 断开:断开只是临时状态,下一个状态是StandAlone独立的
Unconnected 悬空:是尝试连接前的临时状态,可能下一个状态为WFconnection和WFReportParams
Timeout 超时:与对等节点连接超时,也是临时状态,下一个状态为Unconected悬空
BrokerPipe:与对等节点连接丢失,也是临时状态,下一个状态为Unconected悬空
NetworkFailure:与对等节点推动连接后的临时状态,下一个状态为Unconected悬空
ProtocolError:与对等节点推动连接后的临时状态,下一个状态为Unconected悬空
TearDown 拆解:临时状态,对等节点关闭,下一个状态为Unconected悬空
WFConnection:等待和对等节点建立网络连接
WFReportParams:已经建立TCP连接,本节点等待从对等节点传来的第一个网络包
Connected 连接:DRBD已经建立连接,数据镜像现在可用,节点处于正常状态
StartingSyncS:完全同步,有管理员发起的刚刚开始同步,未来可能的状态为SyncSource或PausedSyncS
StartingSyncT:完全同步,有管理员发起的刚刚开始同步,下一状态为WFSyncUUID
WFBitMapS:部分同步刚刚开始,下一步可能的状态为SyncSource或PausedSyncS
WFBitMapT:部分同步刚刚开始,下一步可能的状态为WFSyncUUID
WFSyncUUID:同步即将开始,下一步可能的状态为SyncTarget或PausedSyncT
SyncSource:以本节点为同步源的同步正在进行
SyncTarget:以本节点为同步目标的同步正在进行
PausedSyncS:以本地节点是一个持续同步的源,但是目前同步已经暂停,可能是因为另外一个同步正在进行或是使用命令(drbdadm pause-sync)暂停了同步
PausedSyncT:以本地节点为持续同步的目标,但是目前同步已经暂停,这可以是因为另外一个同步正在进行或是使用命令(drbdadm pause-sync)暂停了同步
VerifyS:以本地节点为验证源的线上设备验证正在执行
VerifyT:以本地节点为验证目标的线上设备验证正在执行

②、查看角色

[root@node-001 ~]# drbdadm role git
Primary/Secondary

Parimary 主:资源目前为主,并且可能正在被读取或写入,如果不是双主只会出现在两个节点中的其中一个节点上
Secondary 次:资源目前为次,正常接收对等节点的更新
Unknown 未知:资源角色目前未知,本地的资源不会出现这种状态

③、查看硬盘状态命令
[root@node-001 ~]# drbdadm dstate git
UpToDate/Inconsistent

本地和对等节点的硬盘有可能为下列状态之一:
Diskless 无盘:本地没有块设备分配给DRBD使用,这表示没有可用的设备,或者使用drbdadm命令手工分离或是底层的I/O错误导致自动分离
Attaching:读取无数据时候的瞬间状态
Failed 失败:本地块设备报告I/O错误的下一个状态,其下一个状态为Diskless无盘
Negotiating:在已经连接的DRBD设置进行Attach读取无数据前的瞬间状态
Inconsistent:数据是不一致的,在两个节点上(初始的完全同步前)这种状态出现后立即创建一个新的资源。此外,在同步期间(同步目标)在一个节点上出现这种状态
Outdated:数据资源是一致的,但是已经过时
DUnknown:当对等节点网络连接不可用时出现这种状态
Consistent:一个没有连接的节点数据一致,当建立连接时,它决定数据是UpToDate或是Outdated
UpToDate:一致的最新的数据状态,这个状态为正常状态

④、启动、停止资源

启动资源  drbdadm up git
停止资源  drbdadm down git

git:为资源名称;当然也可以使用all表示[停用|启用]所有资源

⑤、升级和降级资源

升级资源 drbdadm primary git
降级资源 drbdadm secondary git
同步资源 drbdadm -- --overwrite-data-of-peer primary git

git:为资源名称。在单主模式下的DRBD,两个节点同时处于连接状态,任何一个节点都可以在特定的时间内变成主;但两个节点中只能一为主,如果已经有一个主,需先降级才可能升级;在双主模式下没有这个限制。