最近在看一些关于数据库的资料,从最开始的mysql的主从复制到mysql的双主+heartbeat实现mysql的高可用再到mysql+drbd+heartbeat实现底层数据同步的双主高可用再到mysql_mmm+amoeba实现双主多从的高可用和负载均衡以及读写分离,再到后来发现mysql自从被Oracle收购后已经越来越走向了封闭,更新也不如以前频繁,并且新版的mysql已经不支持GPL协议了。。。感觉mysql已经在Oracle手中渐渐没落了。。。后来发现了一个更好的替代方案那就是mariadb的galera实现多主负载均衡,于是动手实验搭建了一把mariadb galbra实验环境,发现效果确实不错,果断以后要慢慢退出mysql,使用mariadb来做存储了。

    关于mariadb的产生,由于08年sun收购了mysql之后,mysql中的一批高管就离开了mysql项目出来创业,而09年sun被oracle收购后又有一批mysql老员工离开了,这两批人后来就创立了一个新的公司,继续开发开源的关系数据库,于是mariadb就这样诞生了。并且这两年mariadb的发展越来越迅猛,很多大公司都开始抛弃mysql转向mariadb了。包括Redheat 7以及Centos 7都抛弃了mysql转而投奔了mariadb。好了闲扯了这么多废话,给各位看官们大概讲解了一下mariadb的前世今生,具体的各位可以百度一下更详细的资料,下面来分析一下以上各种数据库集群的优缺点已经我为何选择mariadb galera来实现数据库集群。

    首先,mysql主从复制由于是使用的binlog日志实现同步的,主和从之间的数据同步是异步的,在面对大并发量的数据读写时存在时延性的问题,可能导致数据不同步现象。但是该场景可以适用于少量写入数据,大量查询数据场景中,使用mysql的主+多从还是个不错的方案。

    接着是mysql+heartbeat实现双主复制,其原理也是使用mysql的binlog来实现数据同步的,只不过在配置中设置了两台数据库服务器互为对方的主,然后通过heartbeat来实现双主的高可用,但是这个存在一个问题就是永远只有一个mysql服务器在工作,另一个一直处于热备状态,浪费了服务器资源,适用于对核心数据提供高可用的场景中,并且能提供的并发量也不是很大,况且还有可能存在脑裂的问题。

    再然后就是mysql+drbd+heartbeat实现双主数据库的高可用了,其数据同步的原理是使用drbd在磁盘上面划取一块磁盘专门用来做数据存储,通过DRBD来实现两台服务器的数据同步,该同步过程是在底层数据块实现的,效率比使用mysql的binlog日志同步更加高效,个人感觉比mysql的binlog同步数据要更好,但是假如随着数据量的越来越大,预先划定的DRBD同步磁盘区域不够用怎么办?这也是一个问题,而且这个方案也存在脑裂的问题。

    然后发现了一个比较好的数据库集群高可用方案,那就是mysql_mmm+amoeba实现双主多从的高可用和负载均衡以及读写分离。mysql_mmm是mysql的一套组件,通过使用虚拟IP的方式,动态的将读写分离到不同的服务器上面去执行,并且假如某台服务器挂掉了,虚拟IP将自动跳转到其他正常服务器上面继续提供服务。而amoeba提供的服务是将所有mysql_mmm产生的虚拟IP转换成一个IP,对前端业务提供服务接口,从而在前端业务看来,mysql集群是透明的,不需要对前端程序进行修改就能实现数据库的负载均衡,读写分离。这里既然提到了amoeba就不得不提mysql的一个组件mysql_HAproxy,mysql_HAproxy这套组件是mysql官方退出的一套实现mysql集群的读写分离套件,但是mysql官方都不建议企业中使用该套件,因为该套件还不稳定,其实现读写分离的功能是通过一个配置文件balance.lua来实现的,在面对大并发量数据的时候不稳定,并且假如后端某台数据库服务器挂掉了,HAproxy无法检测到,从而出现将数据转发到挂掉的数据库上面,相对比来讲mysql_mmm+amoeba的组合方式比HAproxy的方式要好。但是在看mysql_mmm+amoeba的资料的时候发现其salve是和其中的某一台maste同步数据的,这样就产生了一个问题,那就是假如这台master服务器挂掉了,slave将无法继续同步数据了,需要手动将slave同步的master服务器切换到另外一台,这样就产生了时延性,影响业务的正常应用。

    最后,mariadb galera实现数据库的多主模式,该模式是通过在写数据的时候,确保数据写入到所有服务器中之后才认为该写入操作成功,所以其能够基本保持数据的一致性以及数据操作的原子性。并且其不存在mysql主从中的不能在从上面写入数据的原则,在所有服务器上面都可以写入数据,其会自动同步到所有服务器中。当然,不能只谈mariadb galera的好处不谈它的缺点,它的缺点就是其写入数据的性能是由集群中最差的一台服务器来决定的,所以在生产环境中需要尽量保持集群中的所有服务器软硬件配置一样,从而避免所谓的木桶原理影响性能。还有就是mariadb galera只能使用innodb存储引擎,而不能使用其他存储引擎,并且不支持锁表操作。对于mariadb galera的局限性可以参考以下连接:官网解释

    好了,以上就是我对于数据库集群的一些理解,里面的一些不对之处还请各位大神轻喷,前面说了一大堆文字理论,下面我们要进入正题了,那就是怎样搭建mariadb galera环境。

    最开始,我本来想直接去官网下载mariadb galera的源码包来安装的,但是不知道为什么,最近官网的所有包都不能下载,于是在网上找资料,发现可以使用yum安装,于是找到了yum安装的源地址:http://yum.mariadb.org/ 配置如下

[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.0.20/centos6-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1

但是,因为这是一个境外站点,yum下载速度好慢,老是失败,于是逼得没办法,只能把这个站中的10.0.20/centos6-amd64/目录整个下载下来,放到本地做成本地源来使用了,下面贴出我做的本地源的配置

[root@test3 my.cnf.d]# tail -15 /etc/yum.repos.d/Centos-Local.repo 
name=CentOS-6 - Local
baseurl=http://192.168.1.160/base/
gpgcheck=0
enabled=1
failovermethod=priority
[c6-epel]
name=CentOS-6 - Local
baseurl=http://192.168.1.160/epel/$basearch/
gpgcheck=0
enabled=1
[mariadb]
name=mariadb_galera
baseurl=http://192.168.1.160/mariadb_galera/centos6X86_64/
gpgcheck=0
enabled=1

其中的192.168.1.160是我的局域网yum源服务器。

好了,配置好yum源后开始安装了,我这里准备了4台服务器,分别是:

192.168.1.161 nd1

192.168.1.162 nd2

192.168.1.163 nd3

192.168.1.164 nd4

分别在四台服务器上面使用命令安装套件:

yum -y install MariaDB-Galera-server MariaDB-client rsync galera

安装好后,启动数据库,使用命令service mysql start启动,启动之后需要对数据库进行安全加固,删除一些不需要的账户,这里就不进行赘述了。然后需要添加一个同步数据的用户,在四台服务器上进入数据库中实行下面的命令:

grant all privileges on *.* to 'wsrep_sst-user'@'192.168.1.%' identified by 'password';
flush privileges;

之后退出数据库,创建配置文件:

[root@test2 ~]# cat /etc/my.cnf.d/galera.cnf
[server]
query_cache_size=0
binlog_format=ROW
default_storage_engine=innodb
innodb_autoinc_lock_mode=2
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
#wsrep_cluster_address="gcomm://192.168.1.162,192.168.1.163,192.168.1.164"
wsrep_cluster_address=gcomm://
wsrep_cluster_name='example_cluster'
wsrep_node_address='192.168.1.161'
wsrep_node_name='nd1'
wsrep_sst_method=rsync
#wsrep_sst_method=xtrabackup
wsrep_sst_auth=wsrep_sst-user:password

上面是nd1的配置文件,其中需要注意的地方有wsrep_cluster_address=gcomm://这条命令,gcomm://是一个特殊的参数,在启动第一台数据库时需要使用这个参数来启动,否则会启动失败,后面的节点使用wsrep_cluster_address="gcomm://192.168.1.162,192.168.1.163,192.168.1.164"这个参数来启动数据库。当第一台数据库需要重启时需要切换到wsrep_cluster_address="gcomm://192.168.1.162,192.168.1.163,192.168.1.164"这个参数来启动才能加入到集群中。这样讲有点抽象,换一种方式来讲就是最开始启动集群的第一台服务器时将wsrep_cluster_address="gcomm://192.168.1.162,192.168.1.163,192.168.1.164"这一行注释掉,使用下面那个参数来启动,后面的节点注释掉wsrep_cluster_address=gcomm://这个参数启动数据库,加入到集群中来。当集群全部起来以后万一第一台数据库要重启时将下面那条参数注释掉,开启上面那条参数。这样就能加入集群中来。至于wsrep_sst_auth=wsrep_sst-user:password这个参数就是我们之前设定的用来同步的用户名和密码。

另外,需要注意的是防火墙需要开启TCP的3306端口和TCP4567端口开启,否则集群将不能实现,这里为了方便直接清空了防火墙iptables -F,也可以使用下面的命令来使防火墙开启相应端口

iptables -A INPUT -i eth0 -p tcp --dport 3306 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 4567 -j ACCEPT

配置好了参数之后,最先重启nd1节点service mysql restart,接下来重启nd2-4节点,之后就可以进数据库中查询同步状态了,可以使用下面的命令查询数据库同步状态:

MariaDB [(none)]> show global status like  'wsrep%';
+------------------------------+-----------------------------------------------------------------------------+
| Variable_name                | Value                                                                       |
+------------------------------+-----------------------------------------------------------------------------+
| wsrep_local_state_uuid       | 0381ab0f-a3aa-11e4-9737-be607495053f                                        |
| wsrep_protocol_version       | 7                                                                           |
| wsrep_last_committed         | 2                                                                           |
| wsrep_replicated             | 0                                                                           |
| wsrep_replicated_bytes       | 0                                                                           |
| wsrep_repl_keys              | 0                                                                           |
| wsrep_repl_keys_bytes        | 0                                                                           |
| wsrep_repl_data_bytes        | 0                                                                           |
| wsrep_repl_other_bytes       | 0                                                                           |
| wsrep_received               | 4                                                                           |
| wsrep_received_bytes         | 948                                                                         |
| wsrep_local_commits          | 0                                                                           |
| wsrep_local_cert_failures    | 0                                                                           |
| wsrep_local_replays          | 0                                                                           |
| wsrep_local_send_queue       | 0                                                                           |
| wsrep_local_send_queue_max   | 1                                                                           |
| wsrep_local_send_queue_min   | 0                                                                           |
| wsrep_local_send_queue_avg   | 0.000000                                                                    |
| wsrep_local_recv_queue       | 0                                                                           |
| wsrep_local_recv_queue_max   | 1                                                                           |
| wsrep_local_recv_queue_min   | 0                                                                           |
| wsrep_local_recv_queue_avg   | 0.000000                                                                    |
| wsrep_local_cached_downto    | 18446744073709551615                                                        |
| wsrep_flow_control_paused_ns | 0                                                                           |
| wsrep_flow_control_paused    | 0.000000                                                                    |
| wsrep_flow_control_sent      | 0                                                                           |
| wsrep_flow_control_recv      | 0                                                                           |
| wsrep_cert_deps_distance     | 0.000000                                                                    |
| wsrep_apply_oooe             | 0.000000                                                                    |
| wsrep_apply_oool             | 0.000000                                                                    |
| wsrep_apply_window           | 0.000000                                                                    |
| wsrep_commit_oooe            | 0.000000                                                                    |
| wsrep_commit_oool            | 0.000000                                                                    |
| wsrep_commit_window          | 0.000000                                                                    |
| wsrep_local_state            | 4                                                                           |
| wsrep_local_state_comment    | Synced                                                                      |
| wsrep_cert_index_size        | 0                                                                           |
| wsrep_causal_reads           | 0                                                                           |
| wsrep_cert_interval          | 0.000000                                                                    |
| wsrep_incoming_addresses     | 192.168.1.164:3306,192.168.1.162:3306,192.168.1.161:3306,192.168.1.163:3306 |
| wsrep_evs_delayed            |                                                                             |
| wsrep_evs_evict_list         |                                                                             |
| wsrep_evs_repl_latency       | 0/0/0/0/0                                                                   |
| wsrep_evs_state              | OPERATIONAL                                                                 |
| wsrep_gcomm_uuid             | c009d89b-a3b6-11e4-9e41-a2518f032b8a                                        |
| wsrep_cluster_conf_id        | 6                                                                           |
| wsrep_cluster_size           | 4                                                                           |
| wsrep_cluster_state_uuid     | 0381ab0f-a3aa-11e4-9737-be607495053f                                        |
| wsrep_cluster_status         | Primary                                                                     |
| wsrep_connected              | ON                                                                          |
| wsrep_local_bf_aborts        | 0                                                                           |
| wsrep_local_index            | 2                                                                           |
| wsrep_provider_name          | Galera                                                                      |
| wsrep_provider_vendor        | Codership Oy                                            |
| wsrep_provider_version       | 25.3.9(r3385)                                                               |
| wsrep_ready                  | ON                                                                          |
| wsrep_thread_count           | 2                                                                           |
+------------------------------+-----------------------------------------------------------------------------+
57 rows in set (0.00 sec)

其中可以看到wsrep_incoming_addresses中已经列出来了所有的四台服务器都同步了,还有wsrep_connected和wsrep_ready都是ON状态。这样就可以确定数据库已经同步了,接下来创建一个数据库测试是否真的能同步数据。

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.01 sec)
MariaDB [(none)]> create database huxianglin;
Query OK, 1 row affected (0.00 sec)

这是在节点1上面进行的操作

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)
MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| huxianglin         |
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.00 sec)

这是在节点2上面前后查询结果的对比,从中我们可以看出数据已经同步到节点2了。至此mariadb galera集群实验完成了,至于mariadb galera的仲裁人节点配置可以使用命令来实现

garbd -a gcomm://192.168.1.100:4567 -g my_wsrep_cluster -d

# 注释:参数说明: -d:以daemon模式运行 -a:集群地址 -g: 集群名称

具体使用方法可以自行百度,这里我就不再赘述了,将近凌晨4点了,这是第一次写博客写到这么晚,干净写完收工,睡觉了。。。祝各位都能有个好梦^-^