corosync+heartbeat+mysql+nfs实现mysql高可用          


简单介绍

随着互联网络应用的发展,大规模海量级数据存储对于一个企业越来越重要,组织机构依赖于数据库来运行各种重要的业务,几小时甚至几分钟的宕机,都会造成不可估量的损失,因此保证数据库的高可用是所有组织机构优先考虑的事情,对于想要在竞争中立于不败之地的企业来说,构建高可用的数据存储至关重要。

这里提供了一种在中小型企业应用中数据库搭建的廉价解决方案,在不购买高额的高性能的服务器前提下,利用现有的资源,进行整合配置以完成。用于为企业提供数据库的高效率、高安全、低故障的服务。总体说来,实现MySQL的高可用集群,在后台创建多个MySQL服务器节点,当某一个节点遇到故障后,能在最短时间内定位,并自动切换到别的正常节点上,从而不影响用户的使用,也使企业自己内部数据存取和修改等操作能够正常的进行,将损失降到最低,也给后期的维护提供了很大方便。

至于数据库前端的APP这里就不再介绍了。

通过创建一个NFS服务器,来实现数据的共享存储。用户可以用同一个IP地址来访问数据库,这个IP地址被称为VIP,多个MySQL节点利用这个VIP向用户提供服务,用户自己并不知道是具体的哪一个MySQL节点提供的服务,各个MySQL节点将用户操作所产生的数据存放到NFS服务器上。当其中的一个MySQL节点出现故障后,别的节点会使自己成为主节点,并抢占VIP,且将NFS服务器的共享目录挂载至自己的某个目录下,继续向用户提供服务,而这个过程对于用户来说是透明的,从而实现MySQL的高可用功能。

corosync+heartbeat+mysql+nfs实现mysql高可用_mysql

   用户远程访问MySQL服务,在访问时使用VIP:172.16.100.6进行访问,用户的访问操作被分配到MySQL1或者MySQL2上,操作所产生的数据存储在NFS Server,NFS Server服务器上创建一个共享存储,用于存储数据,并且挂载在对外提供服务的MySQL服务器上。两个MySQL服务器都有自己的实际的IP地址,MySQL1IP地址为172.16.100.11MySQL2主机的IP地址为172.16.100.12。向外提供服务的服务器向用户显示的则是VIP,如果这个服务器出现宕机等故障时,另外一台服务器会争夺VIP,且将NFS Server的共享存储挂载在自己的目录下,继续对外提供服务,这一过程对用户来说是透明的,此过程通过corosync来实现。上面过程中一台服务器出现故障后,另一台服务器会自动检测到,而这个检测个过程是通过heartbeat来实现,在两台服务器之间使用一根心跳线连接起来,它们时时刻刻传递心跳信息,当一台服务器出现故障后,另一台服务器能够马上检测到,然后切换状态,使自己成为对外提供服务的服务器。


实现过程


1:配置主机名和IP地址


为NFS Server服务器和两台MySQL服务器配置主机名和IP地址,以便对外提供服务,本项目中NFS Server的IP地址为172.16.100.1,主机名为NFS。主机一的IP地址为172.16.100.11,主机名为node1.sange.com。主机二的IP地址为172.16.100.12,主机名为node2.sange.com。现在进行如下配置:

1.在NFS Server上配置主机名和IP地址:

[root@NFS ~]# hsotname NFS
[root@NFS ~]# vim/etc/sysconfig/network
NETWORKING=yes
HOSTNAME=NFS
[root@NFS ~]# vim /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
IPADDR=172.16.100.1
ONBOOT=yes

2.在MySQL1上配置主机名和IP地址:

[root@node1 ~]# hostname node1.sange.com
[root@node1 ~]#vim/etc/sysconfig/network
NETWORKING=yes
HOSTNAME=node1.sange.com
[root@node1 ~]# vim/etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=static
ONBOOT=yes
IPADDR=172.16.100.11

3.在MySQL2上配置主机名和IP地址:

[root@node2 ~]# hostnamenode2.sange.com
[root@node2 ~]# vim/etc/sysconfig/network
NETWORKING=yes
HOSTNAME=node2.sange.com
[root@node2 ~]#vim/etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=static
IPADDR=172.16.100.12
ONBOOT=yes

2:MySQL1MySQL2上实现双机互信

在MySQL1和MySQL2之间建立双机互信,在一台主机上生成公钥和私钥,并将产生的公钥和私钥送到另一台主机上即可。建立双机互信后,在两台机器之间进行文件备份、执行命令等操作时,省去输入密码的过程,为后面的安装程序、配置服务提供很多方便。

在MySQL1上配置IP地址所对应的主机名和别名,其中node1为node1.sange.com的别名,node2为node2.sange.com的别名,在项目实现的过程中,可以直接使用node1和node2来代替主机名,这样会提供很多方便。


在MySQL1上配置IP地址所对应的主机名和别名:

[root@node1 ~]# vim/etc/hosts

#Do not remove the following line, or various programs
#that require network functionality will fail.
127.0.0.1               localhost.localdomain localhost
172.16.100.11   node1.sange.com   node1
172.16.100.12   node2.sange.com   node2                                      

在MySQL2上配置IP地址所对应的主机名和别名:

[root@node2 ~]#vim/etc/hosts
#Do not remove the following line, or various programs
#that require network functionality will fail.
127.0.0.1               localhost.localdomain localhost
172.16.100.11   node1.sange.com   node1
172.16.100.12   node2.sange.com   node2

实现双机互信:

node1上生成密钥:

[root@node1~]# ssh-keygen -t rsa

将密钥复制到node2上去:

[root@node1 ~]#ssh-copy-id-i .ssh/id_rsa.pub root@172.16.100.12

node2上生成密钥:

[root@node2~]#ssh-keygen -t rsa

将密钥复制到node1上去:

[root@node2 ~]#ssh-copy-id-i .ssh/id_rsa.pub root@172.16.100.11


3:NFS Server上通过建立逻辑卷共享数

NFS Server提供共享存储的功能,将用户操作所产生的数据存储下来,然后挂载至对外提供MySQL的主机上(node1或node2)。而提供共享存储的介质有很多种,可以是一块硬盘,也可以是一个磁盘。这里建立一个逻辑卷来存储数据,方便以后的管理和扩充,先建立一个大小为20G的磁盘分区,用于建立逻辑卷,然后再建立一个大小为10G的逻辑卷。

[root@NFS ~]# fdisk /dev/sda      //对磁盘分区
The number of cylinders for this disk is set to 15665.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
   (e.g., DOS FDISK, OS/2 FDISK)
Command (m for help): n      //新建一个磁盘
Command action
   e   extended
   p   primary partition (1-4)
e          //扩展分区
Selected partition 4
First cylinder (5359-15665, default 5359):
Using default value 5359
Last cylinder or +size or +sizeM or +sizeK (5359-15665, default 15665):
Using default value 15665
Command (m for help): n
First cylinder (5359-15665, default 5359):
Using default value 5359
Last cylinder or +size or +sizeM or +sizeK (5359-15665, default 15665): +20G        //大小为20G
Command (m for help): P       // 显示磁盘分区
Disk /dev/sda: 128.8 GB, 128849018880 bytes
255 heads, 63 sectors/track, 15665 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1          13      104391   83  Linux
/dev/sda2              14        5235    41945715   8e  Linux LVM
/dev/sda3            5236        5358      987997+  83  Linux
/dev/sda4            5359       15665    82790977+   5  Extended
/dev/sda5            5359        7791    19543041   83  Linux
Command (m for help): T      //设定磁盘类型
Partition number (1-5): 5
Hex code (type L to list codes): 8e    //创建LVM时的专用格式
Changed system type of partition 5 to 8e (Linux LVM)
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.
Syncing disks.
[root@NFS ~]# partprobe /dev/sda    //重新格式化一下
要建立逻辑卷,先要建立物理卷,然后建立卷组,最后才能建立逻辑卷。
[root@NFS ~]# pvcreate /dev/sda5     //创建物理卷
[root@NFS ~]# vgcreate myvg /dev/sda5     //创建卷组
[root@NFS ~]# vgs    //显示新建的卷组
  VG   #PV #LV #SN Attr   VSize  VFree
  myvg   1   0   0 wz--n- 18.64G 18.64G
  vg0    1   4   0 wz--n- 40.00G     0
[root@NFS ~]# lvcreate -L 10G -n mydata myvg   //创建逻辑卷
[root@NFS ~]# lvs    //显示新建的卷组
  LV     VG   Attr   LSize  Origin Snap%  Move Log Copy%  Convert
  mydata myvg -wi-a- 10.00G                                     
[root@NFS ~]#mke2fs –j –L MYDATA /dev/myvg/mydata
[root@NFS ~]# mkdir /mydata
[root@NFS ~]#vim /etc/fstab  //添加如下内容
LABEL=MYDATA            /mydata                 ext3    defaults        0 0
[root@NFS ~]#mount –a   //重新挂载一下


将/mydata目录通过nfs服务导出出去,由于nfs服务不识别主机名,只识别ID号,所以必须先建立用户,ID号要和mysql服务器上的mysql用户(后面创建)的ID号保持一致,这里设定ID号都为306。

先创建mysql用户:

[root@NFS ~]# groupadd -g 306 -r mysql
[root@NFS ~]# useradd -g mysql -r -u 306 -s /sbin/nologin mysql
将/mydata的属主和属组改为mysql:
[root@NFS ~]# chown -R mysql:mysql /mydata/
[root@NFS ~]# vim /etc/exports   //将/mydata目录导出出去,172.16.0.0网段内的用户可以读写/mydata目录中的文件。
/mydata         172.16.0.0/16(rw,no_root_squash)

启动nfs服务:

[root@NFS ~]# service nfs start

让nfs服务开机自动启动:

[root@NFS ~]# chkconfig nfs on


在node1和node2上测试nfs服务提供的共享文件是否能成功应用:

在node1先创建mysql用户:

[root@node1 ~]# groupadd -r -g 306 mysql
[root@node1 ~]# useradd -g mysql -u 306 -r mysql
[root@node1 ~]# mkdir /mydata

将NFS Server上的/mydata目录挂载至node1的/mydata目录上

[root@node1 ~]# mount -t nfs 172.16.100.1:/mydata/mydata/

试一下能否在共享目录中创建文件:

corosync+heartbeat+mysql+nfs实现mysql高可用_nfs_02

a文件创建成功,则说明node1能够使用NFS Server共享的目录。

node2上的测试方法与node1相同,方法同上。


4:在节点node1和节点node2上安装mysql


Mysql的安装方式可以分为rpm包安装和编译安装,编译安装可以定制自己所需要的各种服务,非常有用,这里我们使用源码编译安装的方式安装mysql。

安装的mysql版本为mysql-5.5.22-linux2.6-i686.tar.gz,可以在网站上搜索并下载。

在node1上安装mysql:

[root@node1~]# tar xf mysql-5.5.22-linux2.6-i686.tar.gz -C /usr/local  
[root@node1 ~]# cd /usr/local
[root@node1 local]# ln -sv mysql-5.5.22-linux2.6-i686 mysql 
[root@node1 local]# cd mysql
[root@node1 mysql]# chown -R mysql:mysql .  
[root@node1 mysql]# scripts/mysql_install_db --user=mysql --datadir=/mydata/data  
[root@node1 mysql]# cp support-files/my-large.cnf /etc/my.cnf   //为mysql提供主配置文件
[root@node1 mysql]# vim /etc/my.cnf      //修改mysqld的主配置文件,添加如下两行:
thread_concurrency = 2       
datadir = /mydata/data      
[root@node1mysql]#cp support-files/mysql.server /etc/init.d/mysqld //  为mysql提供sysv服务脚本
[root@node1 mysql]# vim /etc/profile   //修改PATH环境变量,让系统可以直接使用mysql的相关命令,添加如下行
PATH=$PATH:/usr/local/mysql/bin
[root@node1 mysql]# chown -R root .    //将属主重新改为root
[root@node1 mysql]# chkconfig --add mysqld     //将mysqld添加至服务列表
[root@node1 mysql]# service mysqld start     //启动mysqld服务

由于node1和node2上的mysqld服务为高可用服务,当一台服务器出现故障后,另一台mysql服务器会自动启动mysqld服务,所以应将mysqld服务关闭,且不让它开机自动启动,这一点非常重要。

[root@node1 ~]# service mysqld stop
[root@node1 ~]# chkconfig mysqld off

node1配置完成,node2的配置方法同node1,这里不再重复。


5:验证NFS Server的共享存储

由于用户创建的数据都是存放在NFSServer上,所以在一台mysql服务器上创建的文件在另一台服务器上也应改能够看到,以实现数据同步,这里验证一下。

在节点node1上打开mysql服务并创建数据库,查看在节点node2上是否能够看到:

在节点node1上创建数据库db1:

corosync+heartbeat+mysql+nfs实现mysql高可用_corosync_03


在节点node2上查看db1是否已经存在:

corosync+heartbeat+mysql+nfs实现mysql高可用_corosync_04

数据库db1存在,说明数据库共享存储成功。

同样,在node2上创建数据库,在node1上也应该能够看到,方法同上。


6:安装集群软件

前面都是一些准备工作,要使mysql集群具有高可用的功能,必须安装heartbeat用于时刻检验mysql服务器的心跳信息,当一台服务器宕机时,通知其它服务器启动mysql服务;还要安装核心软件corosync为服务配置几个资源,第一个资源是IP资源,使各个mysql服务器都通过同一个VIP对外提供服务,第二个资源是nfs资源,使多个mysql服务器能够使用NFS Server提供的共享存储,且NFS Server共享的目录只挂载在提供mysql服务的主机上,第三个资源是mysqld服务资源,用于对外提供mysql服务。Corosync同时还定义了这三个资源的启动次序,mysqld资源必须在IP资源和nfs资源之后启动。

由于软件之间有依赖关系,需要安装一些具有依赖关系的软件,可以在互联网上搜索并下载安装:

cluster-glue-1.0.6-1.6.el5.i386.rpm      
libesmtp-1.0.4-5.el5.i386.rpm
cluster-glue-libs-1.0.6-1.6.el5.i386.rpm 
corosync-1.2.7-1.1.el5.i386.rpm           
corosynclib-1.2.7-1.1.el5.i386.rpm      
pacemaker-libs-1.0.11-1.2.el5.i386.rpm                                  perl-TimeDate-1.16-5.el5.noarch.rpm
heartbeat-3.0.3-2.3.el5.i386.rpm         
resource-agents-1.0.4-1.1.el5.i386.rpm
heartbeat-libs-3.0.3-2.3.el5.i386.rpm


在node1上直接在本地安装上述所有软件:

[root@node1 ~]# yum -y --nogpgcheck localinstall *.rpm


在node2上也直接在本地安装:

[root@node2 ~]# yum -y --nogpgcheck localinstall *.rpm


安装完成之后,需要对corosync作如下配置,在node1上:

[root@node1 ~]# cd/etc/corosync/
[root@node1 corosync]# cp corosync.conf.example corosync.conf
[root@node1 corosync]# vim corosync.conf//  修改以下内容
secauth: on
bindnetaddr: 172.16.0.0
to_syslog: no
// 添加如下内容
service {
        ver:   0
        name: pacemaker
        use_mgmtd: yes
}
aisexec {
        user: root
        group: root
}
[root@node1 corosync]#corosync-keygen   // 生成认证文件 


由于node1和node2上安装的软件一样,配置方式也一样。两台机器之间建立了双机互信,可以直接将在node1上生成的认证文件authkey和配置好的corosync.conf 文件自己接复制到节点2上:

[root@node1 corosync]#scp -p authkey corosync.conf node2:/etc/corosync/
[root@node1 corosync]#mkdir /var/log/cluster
[root@node1 corosync]#ssh node2 'mkdir /var/log/cluster'


启动node1上的corosync服务:

[root@node1 corosync]#service corosync start


启动node2上的corosync服务:

[root@node1 corosync]# ssh node2 '/etc/init.d/corosync start'


7:配置corosync

   

使用corosync配置mysql的高可用功能,主要定义三个资源,第一个资源是ip资源,第二个资源是nfs资源,第三个资源是mysql资源。下面的内容非常关键,可以说是整个项目的核心内容,必须保证配置的正确性:

[root@node1 corosync]# crm
crm(live)# configure
INFO: building help index
crm(live)configure# property stonith-enabled=false  //配置stonith
crm(live)configure# verify    //验证一下是否有错误
crm(live)configure# property no-quorum-policy=ignore //设定没有quorum时怎么办
crm(live)configure# verify
crm(live)configure# rsc_defaults resource-stickiness=100  //配置资源粘性
crm(live)configure# verify
crm(live)configure# commit   //提交
//下面配置ip资源,VIP为172.16.100.6
crm(live)configure# primitive myip ocf:heartbeat:IPaddr params ip="172.16.100.6"  //生成IP资源myip,使用的是VIP
crm(live)configure# show     //使用show查看上面的配置
node node1.sange.com
node node2.sange.com
primitive myip ocf:heartbeat:IPaddr \
params ip="172.16.100.6"       //说名VIP配置成功
property $id="cib-bootstrap-options" \
dc-version="1.0.11-1554a83db0d3c3e546cfd3aaff6af1184f79ee87" \
cluster-infrastructure="openais" \
expected-quorum-votes="2" \
stonith-enabled="false" \
no-quorum-policy="ignore"
rsc_defaults $id="rsc-options" \
resource-stickiness="100"
crm(live)configure# commit

[root@node1 ~]#ifconfig    //下面多了eth0:0网卡,VIP设置成功


对MySQL而言,它在哪个节点上启动,就应该让哪个节点过载/mydata目录,下面把NFS也配置成一个高可用资源

crm(live)# configure
crm(live)configure# primitive mynfs ocf:heartbeat:Filesystem params device="172.16.100.1:/mydata" directory="/mydata" fstype="nfs" op start timeout=60s op stop timeout=60s      //配置nfs资源

corosync+heartbeat+mysql+nfs实现mysql高可用_corosync_05


三个资源定义完成,corosync配置结束。



测试

   

测试主要测试的是mysql各个服务器之间的数据是否同步,也就是当用户在一个mysql服务器上写入数据后,在另外一台mysql服务器上能否查看得到。以及mysql的高可用是否配置成功,也就是当一台mysql服务器出现故障后,另外一台mysql服务器能否自动启动,并对外提供服务。


1:测试共享目录的自动转换

测试当node2为standby(宕机)时,/mydata目录能否自动挂载到node1上。

[root@node2 ~]# crm status

此时会看到nfs服务在node2上启动。

[root@node2 ~]# ls /mydata/

corosync+heartbeat+mysql+nfs实现mysql高可用_corosync_06

让节点2变成被动节点:

[root@node2 ~]# crm node standby

在节点1上查看一下/mydata目录:

[root@node1 ~]# crm status

此时nfs服务共享的目录自动挂载到了node1上:

[root@node1 ~]# ls /mydata/

corosync+heartbeat+mysql+nfs实现mysql高可用_高可用_07

2:通过远程连接进行高可用测试

在节点1上建立一个远程连接的用户,使用GRANT命令建立用户:

[root@node1 ~]# mysql
mysql> GRANT ALL ON *.*TO root@'%' IDENTIFIED BY 'redhat';
mysql>mysql> FLUSHPRIVILEGES;


下面在windows使用远程连接(先在windows上安装mysql的客户端)通过VIP连接进行检,并删除数据库db1:

corosync+heartbeat+mysql+nfs实现mysql高可用_corosync_08

在节点1上查看db1是否还存在:

corosync+heartbeat+mysql+nfs实现mysql高可用_nfs_09


数据库db1已经删除。


在让node1出现故障,看看mysql服务能否自动转移到node2上,使用crm node standby命令,将服务器处于宕机状态:

[root@node1 ~]# crm node standby
[root@node1 ~]# crm status   //查看状态

   此时会看到服务自动转移到node2上了

   在通过windows远程连接试一下:

corosync+heartbeat+mysql+nfs实现mysql高可用_corosync_10

说明当正在提供服务的node1出现故障后,mysql服务能够自动转移到node2上,不影响远程用户的访问。

在让node2出现故障,重新启用node1,此时mysql服务又应该自动转移到node1上,测方法同上。


远程用户一样能正常连接,且能够进行各种操作,说明mysql的高可用功能实现了,至此mysql的高可用服务配置完成


总结:

部署与实现具有负载均衡功能的服务器集群是一项非常复杂的系统工程,需要多方面良好的协同合作才能做好它。应用系统程序的开发都要紧紧围绕着实现MySQL服务器集群负载均衡功能这个目标。必须对主服务器的运行状态进行动态监控,如果发生故障,立即执行角色转换过程,确保为终端用户提供可靠、不间断的服务。可以针对具体系统环境写出监控脚本或程序,确保系统的可靠性与稳定性。这里只使用一台NFS server,当它出现故障时,整个服务也会变成不可用。另外配置mysql主从可以实现数据复制到从服务器上,还能实现读写分离来提高mysql性能。在mysql前端可以添加memcache服务器实现缓存,以减轻mysql负担,这次就不再介绍了。