#################################################################

  • 开篇引题

  • Distributed Replicated Block Device

  • 部署MFS

  • 部署Corosync+Pacemaker

  • 故障模拟测试

  • 补充和总结

#################################################################


开篇引题

实现MooseFS的高可用_第1张图片


   直接上图,有图有真相啊!此图是MFS网络组成和运行原理,先不说图中每种角色的作用(下文会有详细说明),直观信息告诉我们客户端无论是读写请求都需要与MasterServer通信,而图中MasterServer角色只有一个,因此单点故障的因素就显而易见了。解决MFS的单点故障正是本文的初衷,接下来就介绍如何利用多种技术解决MFS的单点故障,实现MasterServer的高可用。


Distributed Replicated Block Device

实现MooseFS的高可用_第2张图片

   分布式复制块设备是Linux内核的存储层中的一个分布式存储系统,可利用DRBD在两台Linux服务器之间共享块设备、文件系统和数据,类似于一个网络RAID1的功能,内核中的DRBD模块监听特定套接字上,复制系统调用产生的写数据为副本并通过TCP协议发送至DRBD从节点,因为节点间磁盘设备每一个数据位都是相同的,所以DRBD可以实现廉价块级别的数据共享。

   DRBD工作模型

       主从模型(primary/secondary),同一时刻只能有一个节点提供服务(否则会产生脑裂),从节点无法使用磁盘分区(挂载也不可以)。

       主主模型(primary/primary),需要借助于集群文件系统并启用分布式文件锁功能,而且写性能不会有提升.

   DRBD管理

       内核模块:drbd用户空间

       管理工具:drbdadm,drbdsetup,drbdmeta

   工作流程(默认模型是Sync)

       Async:副本交于本地TCP/IP协议栈就返回(性能最高)

       SemiSync:副本交对方TCP/IP协议栈就返回(折中方案)

       Sync:副本被secondary存储到磁盘中就返回(性能差)

   安装配置DRBD(drbd内核模块必须和内核版本完全匹配)

rpm -ivh drbd-8.4.3-33.el6.x86_64.rpm drbd-kmdl-2.6.32-358.el6-8.4.3-33.el6.x86_64.rpm

   主配置文件

[root@one packages]# 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";

   全局配置文件

cat /etc/drbd.d/global_common.conf
global {
    usage-count yes;
    # minor-count dialog-refresh disable-ip-verification
}
common {
    handlers {
        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;
    }
    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 {
        cram-hmac-alg "sha1";
        shared-secret "soulboy";
        # 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;
    }
}

   定义资源mfs

[root@one packages]# cat /etc/drbd.d/mydata.res
resource mydata {
    on one.soulboy.com {
        device  /dev/drbd0;
        disk    /dev/sdb2;     #大小要一致
        address 192.168.1.61:7789;
        meta-disk internal;
    }
    on two.soulboy.com {
        device  /dev/drbd0;
        disk    /dev/sdb1;     #大小要一致
        address 192.168.1.62:7789;
        meta-disk internal;
    }
}
resource mfs {
    on one.soulboy.com {
        device  /dev/drbd1;
        disk    /dev/sdb3;
        address 192.168.1.61:7788;
        meta-disk internal;
    }
    on two.soulboy.com {
        device  /dev/drbd1;
        disk    /dev/sdb2;
        address 192.168.1.62:7788;
        meta-disk internal;
    }
}

   同步配置文件到从节点

scp /etc/drbd.d/* two.soulboy.com:/etc/drbd.d/

   初始化资源(分别在两个节点上执行)

drbdadm create-md mfs

   启动资源(分别在两个节点上执行)

service drbd start

   将某节点变为主节点(192.168.1.61为主节点)

drbdadm primary --force mydata

   查看状态确定同步完毕

[root@one packages]# service drbd status
1:mfs     Connected  Primary/Secondary  UpToDate/UpToDate  C  /mfs     ext4

   格式化文件系统(在主节点)

mke2fs -t ext4 /dev/drbd1

   允许对方抢占(分别在两节点上执行)

drbdadm primary mfs

   开机不要自动启动

chkconfig drbd off

部署MFS

   MFS工作原理

       MFS文件系统能够实现RAID功能,节约成本,不逊色于专业的存储系统,可以实现在线扩容。

   MFS的四种角色

       MasterServer(元数据服务器):负责管理各个ChunkServer及调度文件读写,回收文件空间及恢复多节点拷贝。

       Metalogger(元数据日志服务器):负责备份管理服务器的变化日志文件。

       ChunkServer(数据存储服务器):真正存储用户数据的服务器,将文件切块相互同步,听从MasterServer的调度为Client提供数据传输,Chunk节点数量越多,可靠性和MFS可用的磁盘空间就会越大。

       Client(客户端):客户端通过fuse内核接口远程管理服务器上所管理的数据存储服务器,和使用本地文件系统一样。

   安装配置元数据服务

mount /dev/drbd1 /mfs               #挂载drbd设备
groupadd -g 1000 mfs                #两边节点的uid要统一
useradd -u 1000 -g mfs -s /sbin/nologin mfs  #两边节点都需要创建
mkdir -pv /mfs                      #主节点创建数据目录即可
chown -R mfs.mfs /mfs               #两个节点修改目录属主和属组为mfs
tar xf mfs-1.6.26.tar.gz
cd mfs-1.6.26
./configure --prefix=/mfs --with-default-user=mfs --with-default-group=mfs
make && make install
cp /mfs/etc/mfsmaster.cfg.dist  /mfs/etc/mfsmaster.cfg
cp /mfs/etc/mfsexports.cfg.dist  /mfs/etc/mfsexports.cfg
cp /mfs/var/mfs/metadata.mfs.empty  /mfs/var/mfs/metadata.mfs

   主配置文件

vim /mfs/etc/mfsmaster.cfg
    # WORKING_USER = mfs            #运行用户
    # WORKING_GROUP = mfs           #运行组
    # SYSLOG_IDENT = mfsmaster      #在syslog中标识自己
    # LOCK_MEMORY = 0               #是否执行mlockall()以避免mfsmaster进程溢出(默认为0)
    # NICE_LEVEL = -19              #运行的优先级
    # EXPORTS_FILENAME = /usr/local/mfs/etc/mfsexports.cfg   #目录控制文件路径
    # TOPOLOGY_FILENAME = /usr/local/mfs/etc/mfstopology.cfg #拓扑类型文件路径
    # DATA_PATH = /usr/local/mfs/var/mfs    #数据存放路径(changelog,sessions,stats)
    # BACK_LOGS = 50                        #元数据的改变日志文件数量
    # BACK_META_KEEP_PREVIOUS = 1           #
    # REPLICATIONS_DELAY_INIT = 300         #延迟复制时间(300秒)
    # REPLICATIONS_DELAY_DISCONNECT = 3600  #ChunkServer断开复制的延迟
    # MATOML_LISTEN_HOST = *                #元数据日志服务器监听的IP地址(*代表任何IP)
    # MATOML_LISTEN_PORT = 9419             #元数据日志服务器监听的端口地址(9419)
    # MATOCS_LISTEN_HOST = *                #用于ChunkServer连接的IP地址(*代表任何IP)
    # MATOCS_LISTEN_PORT = 9420             #用于ChunkServer连接的端口(9420)
    # MATOCL_LISTEN_HOST = *                #用于客户端连接的地址
    # MATOCL_LISTEN_PORT = 9421             #用于客户端连接的端口
    # CHUNKS_LOOP_CPS = 100000       
    # CHUNKS_LOOP_TIME = 300                #Chunks回环频率
    # CHUNKS_SOFT_DEL_LIMIT = 10     
    # CHUNKS_HARD_DEL_LIMIT = 25
    # CHUNKS_WRITE_REP_LIMIT = 2            #在一个循环里复制到一个ChunkServer的最大Chunks数目
    # CHUNKS_READ_REP_LIMIT = 10
    # REJECT_OLD_CLIENTS = 0                #弹出低于1.6.0客户端的连接

   目录挂载控制文件

vim /mfs/etc/mfsexports.cfg #分为三个部分,无需修改
*                       .           rw
*                       /           rw,alldirs,maproot=0
客户端IP         被挂载目录       客户端拥有的权限

   为MasterServer提供lsb格式启动脚本

cat /etc/init.d/mfsmaster
# chkconfig: 345 91 10
# description: mfs start.
. /etc/rc.d/init.d/functions
. /etc/sysconfig/network
path="/mfs/sbin"
[ "${NETWORKING}" = "no" ] && exit 0
start() {
$path/mfsmaster start
$path/mfscgiserv start
}
stop() {
$path/mfsmaster stop
$path/mfscgiserv start
}
restart() {
$path/mfsmaster restart
$path/mfscgiserv restart
}
status() {
$path/mfsmaster test
$path/mfscgiserv test
}
case "$1" in
 start)
     start
     ;;
 stop)
     stop
     ;;
 restart)
     restart
     ;;
 status)
     status
     ;;
 *)
     echo $"Usage: $0 start|stop|restart|status"
     exit 1
     esac
     exit 0

   修改权限

chmod 755 /etc/init.d/mfsmaster

   导出命令

echo 'export PATH=$PATH:/mfs/sbin' > /etc/profile.d/mfs.sh
. /etc/profile.d/mfs.sh

   同步启动脚本至从节点

scp -p /etc/init.d/mfsmaster two:/etc/init.d/

   关闭服务卸载drbd设备

service mfsmaster stop
umount /dev/drbd1


部署Corosync+Pacemaker

实现MooseFS的高可用_第3张图片

   Corosync是集群管理套件的一部分,它在传递信息的时候可以通过一个简单的配置文件来定义信息传递的方式和协议等,RHCS集群套件就是基于corosync实现。但corosync只提供了message layer的能力。集群的资源管理则需要Pacemaker,其管理接口有两个分别是crmsh和pcs。

   环境准备

       service NetworkManager stop

       时间同

       主机名称解析的结果等于uname -n

   安装(pacemaker作为corosync的插件运行)

yum install -y corosync pacemaker

   资源管理器配置接口基于crmsh

yum install -y crmsh-1.2.6-4.el6.x86_64.rpm pssh-2.3.1-2.el6.x86_64.rpm

   生成密钥

corosync-keygen
cp /etc/corosync/corosync.conf.example /etc/corosync/corosync.conf

   配置文件

vim /etc/corosync/corosync.conf #添加pacemaker插件
            compatibility: whitetank    #是否兼容0.8版本的corosync
            totem {                     #用来定义集群节点心跳信息传递
                version: 2              #版本号
                secauth: on             #启用安全认证机制
                threads: 0              #启用多少线程完成心跳信息传递
                interface {                   #定义心跳信息传递的接口
                    ringnumber: 0             #避免循环转发心跳信息
                    bindnetaddr: 192.168.2.0  #指定网卡的网络地址
                    mcastaddr: 226.194.61.21   #心跳信息使用的组播地址
                    mcastport: 5405            #组播监听端口
                    ttl: 1
                }
            }
            logging {               #心跳信息层日志
                fileline: off       #
                to_stderr: no       #是否把错误信息发往屏幕
                to_logfile: yes     #使用自定义日志文件logfile
                to_syslog: no       #是否记录到系统日志
                logfile: /var/log/cluster/corosync.log
                debug: off          #调试功能
                timestamp: on       #每次记录心跳信息是否记录时间戳
                logger_subsys {
                    subsys: AMF
                    debug: off
                }
            }
            amf {
                mode: disabled
            }
            service {       #添加pacemaker插件
                ver: 0
                name: pacemaker
            }
            aisexec {       #可省略
                user: root
                group: root
            }

   复制配置文件到其他节点

scp -p /etc/corosync/corosync.conf /etc/corosync/authkey two.soulboy.com:/etc/corosync/

  分别在两节点启动corosync服务

service corosync start

   使用crmsh接口定义drbd资源(忽略法定票数、禁用stonith设备)

crm(live)configure# property no-quorum-policy=ignore
crm(live)configure# property stonith-enabled=false

   定义原始资源

crm(live)configure# primitive mfs_drbd ocf:linbit:drbd params drbd_resource=mfs op monitor role=Master interval=10 timeout=20 op monitor role=Slave interval=20 timeout=20 op start timeout=240 op stop timeout=100   #定义drbd资源
crm(live)configure# ms ms_mfs_drbd mfs_drbd meta master-max="1" master-node-max="1" clone-max="2" clone-node-max="1" notify="true"   #定义drbd的克隆资源、克隆属性
crm(live)configure# primitive mfsstore ocf:heartbeat:Filesystem params device="/dev/drbd1" directory="/mfs" fstype="ext4" op monitor interval=40 timeout=40 op start timeout=60 op stop timeout=60   #定义本地挂载资源
crm(live)configure# primitive mfsip ocf:heartbeat:IPaddr params ip="192.168.1.40" op monitor interval=20 timeout=20 on-fail=restart   #定义vip
crm(live)configure# primitive mfsserver lsb:mfsmaster   #定义mfs服务

   定义colocation约束(资源运行在同一个节点上的偏好)

crm(live)configure# colocation mfsstore_with_ms_mfs_drbd_master inf: mfsstore ms_mfs_drbd:Master   #挂载资源追随drbd主资源在一起
crm(live)configure# colocation mfsserver_with_mfsstore inf: mfsserver mfsstore   #mfs服务追随挂载资源
crm(live)configure# colocation mfsip_with_mfsserver inf: mfsip mfsserver   #vip追随mfs服务

 定义资源组(如果定义了资源组就没有必要定义colocation约束了)

crm(live)configure# group ha_mfsservice mfsstore mfsserver mfsip   #本文没有这样做,但特此说明这样做也是可以的

   定义order约束(资源启动和关闭的次序)  

crm(live)configure# order ms_mfs_drbd_before_mfsstore mandatory: ms_mfs_drbd:promote mfsstore:start   #节点上存在drbdMaster才能启动mystore服务
crm(live)configure# order mfsstore_before_mfsserver mandatory: mfsstore:start mfsserver:start   #mystore服务启动才能启动mfs服务
crm(live)configure# order mfsip_before_mfsserver mandatory: mfsip mfsserver   #vip启动才能启动mfs服务   

 定义location约束(资源对节点的倾向性)

location mfsservice_prefer_one ha_mfsservice 500: one.soulboy.com   #主节点从故障中回复是否可以将资源抢夺回来,本文没有这样做,特此说明这样做是可以完成资源抢占的。

   检查语法并保存

crm(live)configure# verify
crm(live)configure# commit

   查看集群状态(发现资源都运行在主节点上)

[root@one packages]# crm
crm(live)# status
Online: [ one.soulboy.com two.soulboy.com ]
Master/Slave Set: ms_mfs_drbd [mfs_drbd]
     Masters: [ one.soulboy.com ]
     Slaves:  [ two.soulboy.com ]
 mfsstore   (ocf::heartbeat:Filesystem):    Started one.soulboy.com
 mfsserver  (lsb:mfsmaster):                Started one.soulboy.com
 mfsip      (ocf::heartbeat:IPaddr):        Started one.soulboy.com

  查看验证

[root@one ~]# drbd-overview               #drbd资源正常
  1:mfs/0     Connected Primary/Secondary UpToDate/UpToDate C r----- /mfs    ext4 5.0G 142M 4.6G 3%
[root@one ~]# service mfsmaster status       #mfs资源正常
mfsmaster pid: 13966
mfscgiserv pid:14158
[root@one ~]# ip addr show  | grep 192.168.1.40  #vip资源正常
    inet 192.168.1.40/24 brd 192.168.1.255 scope global secondary eth0
[root@one ~]# ls /mfs               #挂载资源正常
etc  lost+found  sbin  share  var

故障模拟测试

   安装ChunkServer

useradd mfs -s /sbin/nologin
tar xf mfs-1.6.26.tar.gz
cd mfs-1.6.26
./configure --prefix=/usr/local/mfs --with-default-user=mfs --with-default-group=mfs
make && make install
cp /usr/local/mfs/etc/mfschunkserver.cfg.dist /usr/local/mfs/etc/mfschunkserver.cfg
cp /usr/local/mfs/etc/mfshdd.cfg.dist /usr/local/mfs/etc/mfshdd.cfg

   主配置文件

vim /usr/local/mfs/etc/mfschunkserver.cfg
# WORKING_USER = mfs
# WORKING_GROUP = mfs
# SYSLOG_IDENT = mfschunkserver
# LOCK_MEMORY = 0
# NICE_LEVEL = -19
# DATA_PATH = /usr/local/mfs/var/mfs
# MASTER_RECONNECTION_DELAY = 5
# BIND_HOST = *
MASTER_HOST = 192.168.1.40         #元数据服务器的地址
MASTER_PORT = 9420                 #元数据服务器监听端口
# MASTER_TIMEOUT = 60
# CSSERV_LISTEN_HOST = *
# CSSERV_LISTEN_PORT = 9422       #此端口用户和其他ChunkServer间复制数据
# HDD_CONF_FILENAME = /usr/local/mfs/etc/mfshdd.cfg   #分配给MFS磁盘使用空间配置文件路径
# HDD_TEST_FREQ = 10
# LOCK_FILE = /var/run/mfs/mfschunkserver.lock
# BACK_LOGS = 50
# CSSERV_TIMEOUT = 5

   磁盘空间配置文件

vim /usr/local/mfs/etc/mfshdd.cfg
/data      #/data是一个MFS的分区,实例化为本机一个独立的磁盘挂载分区。

   修改权限并启动服务

chown -R mfs:mfs /data
mfschunkserver start

   Client编译安装

   MFS客户端依赖于fuse

tar xf fuse-2.9.2.tar.gz
cd fuse-2.9.2
./configure
make && make install
vim /etc/profile     #在最后添加
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
source /etc/profile   #即时生效
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH

   安装MFS客户端

useradd mfs -s /sbin/nologin
tar xf mfs-1.6.26.tar.gz
cd mfs-1.6.26
./configure --prefix=/usr/local/mfs --with-default-user=mfs --with-default-group=mfs --enable-mfsmount
make && make install
modprobe fuse    #加载fuse到内核

   挂载MFS文件系统

mkdir /webdata       #创建本地目录作为挂载点
/usr/local/mfs/bin/mfsmount /webdata -H 192.168.1.40   #挂载MFS到本地/webdata目录

   挂载MFSMeta文件系统

mkdir /webdatameta   #创建本地MFSMeta目录
/usr/local/mfs/bin/mfsmount -m /webdatameta -H 192.168.1.40   #挂载MFSMeta文件系统

   client创建文件并查看信息(正常)

[root@five /]# echo "123" > /webdata/one   #创建文件
[root@five /]# mfsfileinfo  /webdata/one  #查看副本和存储节点
/webdata/one:
    chunk 0: 0000000000000006_00000001 / (id:6 ver:1)
        copy 1: 192.168.1.50:9422
        copy 2: 192.168.1.64:9422

   登录web管理控制台(正常)

实现MooseFS的高可用_第4张图片

   模拟主节点故障

crm(live)node# standby    #离线,等待几秒钟
crm(live)node# online     #上线
crm(live)node# cd         #回退
crm(live)# status         #查看集群资源状态
Online: [ one.soulboy.com two.soulboy.com ]
 Master/Slave Set: ms_mfs_drbd [mfs_drbd]
     Masters: [ two.soulboy.com ]
     Slaves: [ one.soulboy.com ]
 mfsstore   (ocf::heartbeat:Filesystem):    Started two.soulboy.com
 mfsserver  (lsb:mfsmaster):                Started two.soulboy.com
 mfsip      (ocf::heartbeat:IPaddr):        Started two.soulboy.com

   client再次创建文件并查看副本数(正常)

[root@five /]# echo "123" > /webdata/two
[root@five /]# mfsfileinfo  /webdata/two
/webdata/two:
    chunk 0: 0000000000000007_00000001 / (id:7 ver:1)
        copy 1: 192.168.1.50:9422
        copy 2: 192.168.1.64:9422

   再次登录web管理控制台(正常)

实现MooseFS的高可用_第5张图片


补充和总结

   解决MFS单点故障的主要思路是将MasterServer安装在drbd设备目录中,通过corosync+pacemaker将drbd、vip、mount、mfsmaster资源粘合在一起,并通过colocation和order的约束保证了资源间依赖关系和启动次序,此外mfsmaster的启动在pacemaker中定义为lsb风格RA,也就是形如/etc/init.d/目录下的sysv风格的脚本。值得一提的是pacemaker的管理接口,本文中使用的是crmsh,而pcs接口有着比crmsh更强大的功能,可以实现管理集群整个生命周期,支持节点的添加、移除、启动、关闭等操作。

   实现mysql的高可用也可以通过本文这种思路实现,具体步骤可参考本文,这里补充下pcs接口的用法,方便读者做对比。

pcs resource create myvip ocf:heartbeat:IPaddr params ip=192.168.1.70 op monitor interval=20 timeout=20 on-fail=restart   #定义vip
pcs resource create mystore ocf:heartbeat:Filesystem params device="192.168.1.50:/mysqldata" directory="/mydata" fstype="nfs" op monitor interval=40 timeout=40 on-fail=restart op start timeout=60 op stop timeout=60   #定义nfs
pcs resource create mysqlserver lsb:mysqld op monitor interval=20 timeout=20 on-fail=restart   #定义httpd
pcs resource group add mysqlservice myvip mystore mysqlserver   #定义webservice资源组
pcs constraint location mysqlservice prefers two.soulboy.com=500   #定义资源倾向性,资源组webservice对节点二的倾向性为500
pcs constraint order start myvip then start mystore   #定义资源的order执行次序,这个貌似不能一下子定义三个资源月约束
pcs constraint order start mystore then start mysqlserver   #定义资源的order执行次序
pcs constraint colocation add myvip mystore   #定义colocation,如果有资源组可以省略。这个貌似不能一次定义三个资源月约束
pcs constraint colocation add mystore mysqlserver   #定义colocation

   实现mfs的高可用也可以通过heartbeat+drbd来实现,思路和本文类似,已经大牛撰写,文章内容优质,请参考:  qzhijun的BLOG