DRBD (Distributed Replicated Block Device)分布式复制块设备,它是 Linux 平台上的分散式储存系统,通常用于高可用性(high availability, HA)集群中。DRBD 类似磁盘阵列的RAID 1(镜像),只不过 RAID 1 是在同一台电脑内,而 DRBD 是透过网络。

DRBD Resource:DRBD所具有的几种属性
   resource name:可以使用除空白字符外的任意ACSII表中的字符;
   drbd设备:drbd的设备的访问路径,设备文件/dev/drbd#;
   disk:各节点为组成此drbd设备所提供的块设备,通常是一个磁盘分区;
   网络属性:节点间为了实现跨主机磁盘镜像而使用的网络配置;
   注意:用户空间工具与drdb与内核中使用的模块版本要保持一致,只有在使用drbdadm工具时才会读取配置文件,对多个资源的公共配置,可以提取出来只配置一次,通常保存在Common中,此外还有global配置,这种配置跟资源本身没有关系的;

drbd的组成部分:第一部分用户空间工具;第二部分是内核模块(在2.6.33及以后版本的内核直接在内核中就有了)
   用户空间工具:跟内核版本关系比较松散,只要是能适用于CentOS 6及对应硬件平台的就OK; 
   内核模块:必须与当下内核版本严格对应;其中drbd内核模块代码已经整合进Linux内核2.6.33以后的版本中,因此,如果您的内核版本高于此版本的话,你只需要安装管理工具即可;否则,您需要同时安装内核模块和管理工具两个软件包,并且此两者的版本号一定要保持对应。

进程间通信的三种方式:消息序列、旗语及共享内存:

什么是消息队列:
   消息被发送到队列中,"消息队列"是在消息的传输过程中保存消息的容器。消息队列管理器在将消息从它的源中继到它的目标时充当中间人。队列的主要目的是提供路由并保证消息的传递;如果发送消息时接收者不可用,消息队列会保留消息,直到可以成功地传递它;消息队列就是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。消息队列是随内核持续的。    

什么是旗语、什么是信号量:
   Linux的旗语就是操作系统原理中的信号量,有PV操作,释放旗语会自动唤醒下一个等待获取旗语的进程;
   为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它,也就是说信号量是用来调协进程对共享资源的访问的。
信号量是一个特殊的变量,程序对其访问都是原子操作,且只允许对它进行等待(即P(信号变量))和发送(即V(信号变量))信息操作。最简单的信号量是只能取0和1的变量,这也是信号量最常见的一种形式,叫做二进制信号量。而可以取多个正整数的信号量被称为通用信号量。

什么是共享内存:
   顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样。而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。


数据存储的几种类型:

   DAS:(Direct Attach Srorage)直接附加存储,DAS这种存储方式与我们普通的PC存储架构一样,外部存储设备都是直接挂接在服务器内部总线上,数据存储设备是整个服务器结构的一部分。是指将存储设备通过SCSI接口或光纤通道直接连接到一台计算机上。


   NAS:(Network Attach Srorage)网络附加存储,它就是个文件服务器,是文件系统级别,NAS和传统的文件存储服务或直接存储设备不同的地方在于NAS设备上面的操作系统和软件只提供了数据存储、数据访问、以及相关的管理功能;此外,NAS设备也提供了不止一种文件传输协议。NAS系统通常有一个以上的硬盘,而且和传统的文件服务器一样,通常会把它们组成RAID来提供服务;有了NAS以后,网络上的其他服务器就可以不必再兼任文件服务器的功能。NAS的型式很多样化,可以是一个大量生产的嵌入式设备,也可以在一般的计算机上运行NAS的软件。

NAS用的是以文件为单位的通信协议,例如像是NFS(在UNIX系统上很常见)或是SMB(常用于Windows系统)。NAS所用的是以文件为单位的通信协议,大家都很清楚它们的运作模式,相对之下,存储区域网络(SAN)用的则是以区块为单位的通信协议、通常是通过SCSI再转为光纤通道或是iSCSI。(还有其他各种不同的SAN通信协议,像是ATA over Ethernet和HyperSCSI,不过这些都不常见。)

  SAN:(Storage Area Network)存储区域网络,把SCSI协议借助于其它网络协议实现传送的;1991年,IBM公司在S/390服务器中推出了ESCON(Enterprise System Connection)技术。它是基于光纤介质,最大传输速率达17MB/s的服务器访问存储器的一种连接方式。在此基础上,进一步推出了功能更强的ESCON Director(FC SWitch),构建了一套最原始的SAN系统。
它是一种高速网络或子网络,提供在计算机与存储系统之间的数据传输。存储设备是指一台或多台用以存储计算机数据的磁盘设备,通常指磁盘阵列。

DAS、NAS和SAN三种存储方式比较  
   存储应用最大的特点是没有标准的体系结构,这三种存储方式共存,互相补充,已经很好满足企业信息化应用。
从    连接方式上对比,DAS采用了存储设备直接连接应用服务器,具有一定的灵活性和限制性;NAS通过网络(TCP/IP,ATM,FDDI)技术连接存储设备和应用服务器,存储设备位置灵活,随着万兆网的出现,传输速率有了很大的提高;SAN则是通过光纤通道(Fibre Channel)技术连接存储设备和应用服务器,具有很好的传输速率和扩展性能。三种存储方式各有优势,相互共存,占到了磁盘存储市场的70%以上。SAN和NAS产品的价格仍然远远高于DAS.许多用户出于价格因素考虑选择了低效率的直连存储而不是高效率的共享存储。
   客观的说,SAN和NAS系统已经可以利用类似自动精简配置(thin provisioning)这样的技术来弥补早期存储分配不灵活的短板。然而,之前它们消耗了太多的时间来解决存储分配的问题,以至于给DAS留有足够的时间在数据中心领域站稳脚跟。此外,SAN和NAS依然问题多多,至今无法解决。


DRBD在远程传输上支持三种模式:
   1、异步:所谓异步就是指数据只需要发给本地的TCP/IP协议栈就可以了,本地存完就OK;而DRBD只需要把数据放到TCP/IP协议栈,放到发送队列中准备发送就返回了;这种方式更高效;
   2、半同步:数据已经发送到对方的TCP/IP协议栈上,对方的TCP/IP协议栈已经把数据接收下来了就返回,数据存不存下来就不管了;
   3、同步:数据必须确保对方把数据写入对方的磁盘再返回的就叫同步;这种方式数据更可靠;

官方提供的DRBD的工作流程图:

   wKiom1NgbRPzAB4LAABNdBRd5XE362.gif



==================DRBD + Corosync、Pacemaker实现DRBD角色自动切换==============


在运行drbd时,他并不会自动完成角色的切换,那怎么让它具有这样的功能呢,这里就得用到Corosync+Pacemaker了,结合corosync+pacemaker的drbd就可以自动完成角色的切换,一旦一个drbd的节点出现故障就可以自动切换到别一个节点上继续提供服务,那接下来我们就来配置一下drbd + corosync、pacemaker的实现;


   第一步:配置两个节点上的双机互信,这步我前面的博文中已经写到过了,可以参数前面的博文:CentOS 6.5 heartbeat高可用集群的详解实现以及工作流程


   第二步:安装DRBD程序包,这一步一定要格外注意版本匹配问题:
内核模块程序包一定要跟你的系统内核保持一致,uname -r查看你的内核版本,内核模块的版本必须要严格对应,而用户空间的模块就不那么严格要求了,两个节点的时间也需要保持一致性;
drbd-8.4.3-33.el6.x86_64.rpm   -->用户空间工具
drbd-kmdl-2.6.32-431.el6-8.4.3-33.el6.x86_64.rpm   -->内核空间模块,这个必须要跟内核版本保持一致

   wKioL1Ng767jDONvAACWfkcB7WQ111.jpg

   wKiom1Ng8AOzkV6kAAA75slrSoQ957.jpg

# yum -y install drbd-8.4.3-33.el6.x86_64.rpm drbd-kmdl-2.6.32-431.el6-8.4.3-33.el6.x86_64.rpm        每个节点都需要安装上这两个程序包

   安装完成可以看一下drbd的配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# vim /etc/drbd.conf   主配置文件
# vim /etc/drbd.d/global_common.conf  全局和common的配置
global {   #全局配置
         usage-count no;    #这个为yes表示如果你本机可以连接互联网时drbd会通过互联网收集到你安装drbd的信息,官方统计说又多了一个人使用drbd实例,不用可以改为no
         # minor-count dialog-refresh disable-ip-verification
}
common {
         handlers {     #处理器
                 # These are EXAMPLE handlers only.
                 # They may have severe implications,
                 # like hard resetting the node under certain circumstances.
                 # Be careful when chosing 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" ;    定义了一旦本地节点发生IO错误时应该怎么处理
                 # 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(等待另一个节点上线的超时时长)
                 # degr-wfc-timeout(等待超时后做降级处理)
                 # outdated-wfc-timeout(过期的等待超时)
                 # wait-after-sb(脑裂之后等待多长时长)
         }
         options {
                 # cpu-mask on-no-data-accessible
         }
         disk {
                 on-io-error detach;
                 # size max-bio-bvecs 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 C;
                 cram-hmac-alg  "sha1" ;
                 shared-secret  "drbd.tanxw.com" ;
                 # protocol timeout max-epoch-size max-buffers unplug-watermark
                 # 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 1000M;
         }
}

保存退出。


  第三步:为两个节点准备等同大小的磁盘分区,分区好之后不需要格式化,分好区并且识别出就可以了;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
[root@node2 drbd.d] # fdisk /dev/sda
WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
          switch off the mode ( command  'c' ) and change display  units  to
          sectors ( command  'u' ).
Command (m  for  help): p
Disk  /dev/sda : 85.9 GB, 85899345920 bytes
255 heads, 63 sectors /track , 10443 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical /physical ): 512 bytes / 512 bytes
I /O  size (minimum /optimal ): 512 bytes / 512 bytes
Disk identifier: 0x000e89e2
    Device Boot      Start         End      Blocks   Id  System
/dev/sda1    *           1          26      204800   83  Linux
Partition 1 does not end on cylinder boundary.
/dev/sda2               26        7859    62914560   8e  Linux LVM
/dev/sda3             7859        9164    10489446   8e  Linux LVM
Command (m  for  help): n
Command action
    e   extended
    p   primary partition (1-4)
e
Selected partition 4
First cylinder (9165-10443, default 9165):
Using default value 9165
Last cylinder, +cylinders or +size{K,M,G} (9165-10443, default 10443):
Using default value 10443
Command (m  for  help): n
First cylinder (9165-10443, default 9165):
Using default value 9165
Last cylinder, +cylinders or +size{K,M,G} (9165-10443, default 10443): +3G
Command (m  for  help): p
Disk  /dev/sda : 85.9 GB, 85899345920 bytes
255 heads, 63 sectors /track , 10443 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical /physical ): 512 bytes / 512 bytes
I /O  size (minimum /optimal ): 512 bytes / 512 bytes
Disk identifier: 0x000e89e2
    Device Boot      Start         End      Blocks   Id  System
/dev/sda1    *           1          26      204800   83  Linux
Partition 1 does not end on cylinder boundary.
/dev/sda2               26        7859    62914560   8e  Linux LVM
/dev/sda3             7859        9164    10489446   8e  Linux LVM
/dev/sda4             9165       10443    10273567+   5  Extended
/dev/sda5             9165        9557     3156741   83  Linux
Command (m  for  help): w
The partition table has been altered!
Calling ioctl() to re- read  partition table.
WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
Syncing disks.
[root@node2 drbd.d] # kpartx -af /dev/sda
device-mapper: reload ioctl on sda1 failed: Invalid argument
create /reload  failed on sda1
device-mapper: reload ioctl on sda2 failed: Invalid argument
create /reload  failed on sda2
device-mapper: reload ioctl on sda3 failed: Invalid argument
create /reload  failed on sda3
device-mapper: reload ioctl on sda4 failed: Invalid argument
create /reload  failed on sda4
device-mapper: reload ioctl on sda5 failed: Invalid argument
create /reload  failed on sda5
[root@node2 drbd.d] # partx -a /dev/sda
BLKPG: Device or resource busy
error adding partition 1
BLKPG: Device or resource busy
error adding partition 2
BLKPG: Device or resource busy
error adding partition 3
[root@node2 drbd.d] # partx -a /dev/sda
BLKPG: Device or resource busy
error adding partition 1
BLKPG: Device or resource busy
error adding partition 2
BLKPG: Device or resource busy
error adding partition 3
BLKPG: Device or resource busy
error adding partition 4
BLKPG: Device or resource busy
error adding partition 5
[root@node2 drbd.d] #



   第四步:根据上面的描述,我们要给它定义资源,包括资源名,drbd设备,disk以及网络属性,主要是这四个方面;
定义一个资源/etc/drbd.d/,内容如下:    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# cd /etc/drbd.d/
# vim mystore.res
resource mystore {                     #定义一个资源,用关键字resource;
   on node1.tanxw.com {                 #on说明在哪个节点上,跟uname -n保持一致,有多少个节点就定义多少个;
     device     /dev/drbd0 ;             #在磁盘上表现的drbd叫什么名;
     disk       /dev/sda5 ;             #所使用的磁盘设备是哪个;
     address   172.16.27.1:7789;         #在node1这个节点上监听的套接字,默认监听在7789端口上;
     meta-disk internal;                 #保存drbd元数据信息的,表示就放在自己的磁盘区分上,也可以放在外部的磁盘上;
   }
   on node2.tanxw.com {
     device     /dev/drbd0 ;
     disk       /dev/sda5 ;
     address   172.16.27.2:7789;
     meta-disk internal;
   }
}


保存退出,复制一份到别一个节点上,它们的配置文件要保持一致:    

1
2
3
4
5
6
# scp global_common.conf  mystore.res node2.tanxw.com:/etc/drbd.d/
# drdbadm create-md mystore  在各自的节点上初始化资源
# server drbd start   启动drbd
# watch -n 1 'cat /proc/drbd'   实现查看磁盘信息
# drbdadm primary --force mystore   在节点上把其中一个提升为主的
# watch -n 1 'cat /proc/drbd'   提升为主的之后再实现查看磁盘信息


注意:哪个是主节点哪个就可以挂载使用,不是主节点的连挂载都不可以挂载;

OK、看到两个节点上的数据正在同步了,磁盘越大同步时需要时间越久;  

wKioL1Ng8NWg90gnAAGaJJFGrsk231.jpg  wKiom1Ng8LvQHXhOAAFlgvXkdGc315.jpg


   第五步:在其中一个节点上进行格式化:    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# mke2fs -t ext4 /dev/drbd0        格式化drbd0
# mkdir /drbd    创建一个测试目录
# mount /dev/drbd0 /drbd    把创建好的drbd目录挂载到/dev/drbd0上
# cd /drbd  
# cp /etc/fstab .    复制一个文件过来
# vim fstab        编辑这个文件,在里面随便修改修改
# cd
# umount /dev/drbd0        卸载刚编辑的这个节点上的drbd0设备
# drbdadm secondary mystore        降级这个节点
切换到另一个节点上:
# drbdadm primary mystore    提升为主的
# mkdir /drbd    创建目录用来挂载
# mount /dev/drbd0 /drbd    挂载
# cd /drbd
# vim /fstab    再查看刚才编辑的这个文件,内容被修改了


好了,到这里就完成的drbd的工作模式就这么顺利的完成了,我不知道我是否说明白了!


要完成drbd的角色自动切换得要借助于corosync+pacmaker,那接下来我们就来安装配置corosync和pacemaker吧;

为了让高可用的配置顺利,两个节点都不能设置为主的,而且都不能启动,也不能开机自动启动,所以卸载降级:    

1
2
3
4
5
# cd
# umount /dev/drbd0
# drbdadm secondary mystore        哪个是主的就在哪相节点上降级
# service drbd stop        两个节点都需要停止服务
# chkconfig drbd off


第六步:安装corosync + pacemaker,这里直接用yum来安装,两个节点都要安装上;    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# yum -y install corosync pacemaker
# yum -y install crmsh pssh
# cp /etc/corosync.conf.example /etc/corosync/corosync.conf
# vim /etc/corosync/corosync.conf
compatibility: whitetank
totem {
         version: 2
         secauth: on
         threads: 0
         interface {
                 ringnumber: 0
                 bindnetaddr: 172.16.0.0
                 mcastaddr: 226.98.188.188
                 mcastport: 5405
                 ttl: 1
         }
}
logging {
         fileline: off
         to_stderr: no
         to_logfile:  yes
         to_syslog: no
         logfile:  /var/log/cluster/corosync .log
         debug: off
         timestamp: on
         logger_subsys {
                 subsys: AMF
                 debug: off
         }
}
amf {
         mode: disabled
}
service {
         name:   pacemaker
         ver:    0
}
aisexce {
         user:   root
         group:  root
}
# mv /dev/random /dev/m
# ln /dev/urandom /dev/random  如果这把这个随机数墒池改了可以会产生随机数不够用,这个就要敲击键盘给这个墒池一些随机数;生成完这个key后把链接删除,再把墒池改回来;不过这样改可以会有点为安全,不过做测试的应该不要紧;
# corosync-keygen
# rm -rf /dev/random
# mv /dev/m /dev/random
再把改好的配置复制一份到别一个节点上去,也保留一份给另一个节点:
# scp -p authkey corosync.conf node2.tanxw.com:/etc/corosync/

   启动Corosync,每个节点都需要启动;

   wKiom1Ng8ceBCT9QAABh0bWRDhk383.jpg

   wKioL1Ng8aiyy7U_AAB3mbStVUQ376.jpg

   wKiom1Ng8ivgBz8lAAGDY9K91c4290.jpg


  第七步:接下来进入crm命令行接口定义资源:

   # crm status  查看节点的运行状态    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# crm
# configure
# property stonith-enabled=false
# property no-quorum-policy=ignore
# rsc_defaults resource-stickiness=100
# verify
# commit
# show
# meta ocf:linbit:drbd   查看drbd的详细信息
# 定义资源,切换到configure中,mysqlstore定义资源名,drbd_resource=mystore这个是drbd名,后面定义的都是一些监控
# primitive mysqlstore ocf:linbit:drbd params drbd_resource=mystore op monitor role=Master interval=30s timeout=20s op monitor role=Slave interval=60s timeout=20s op start timeout=240s op stop timeout=100s
# verify    检查语法
# 定义主资源
# master ms_mysqlstore mysqlstore meta master-max=1 master-node-max=1 clone-max=2 clone-node-max=1 notify=”True”
# verify
#commit
定义共享文件的资源,并且让服务器切换时可以自动挂载,device= /dev/drbd0 挂载的设备,directory= /drbd 挂载点,两个挂载点的文件名要一致:
# primitive mysqlfs ocf:heartbeat:Filesystem params device=/dev/drbd0 directory=/drbd fstype=ext4 op monitor interval=30s timeout=40s on-fail-restart op start timeout=60s op stop timeout=60s
# verify
定义排列约束:
# collocation mysqlfs_with_ms_mysqlstore_master inf: mysqlfs ms_mysqlstore:Master
# verify
定义顺序约束:
# order mysqlfs_after_ms_mysqlstore_master mandatory: ms_mysqlstore:promote mysqlfs:start
# show
# commit

wKioL1Ng8imi_3ybAAP4WAuO8Ak906.jpg


   OK,再查看一下它们现在的状态,node2是主的,而node1是从的,可以到node2上查看文件是否已经挂载上去的,验证一下,再创建或修改几个文件进去都可以做一下测试的,而后再让node2停掉,看看node1是否会自动切换为主的:

   wKiom1Ng8pjQ2qVpAAItE6aSpo4383.jpg

   wKiom1Ng8ybyASV2AADiCmwq26E699.jpg


   改变节点的主从位置:    

1
2
3
4
crm(live) # node standby node2.tanxw.com   把node2提升为备用的
crm(live) # node noline node2.tanxw.com    让node2上线
crm(live) # node standby node1.tanxw.com   把node1提升为备用的
crm(live) # node noline node1.tanxw.com    让node1上线,都可以随意切换一下再检测一下挂载的效果的;


结束:

   对以上的操作过程可能存在不到之处,如果你发现有什么不对的或做得不到位的可以留言的,一起交流学习,配置到这里基本上可以完成了一个drbd的角色自动切换了,实现高可用。