文章目录
  1. 1. 安装Mysql主从复制
  2. 2. MyCAT配置主从复制
  3. 3. 测试MyCAT主从复制
  4. 4. MyCAT自动切换
  5. 5. 关于分库和分表

MyCAT的一个典型应用是用于数据库的读写分离,本文以Mysql为例,展示读写分离的MyCAT应用场景。本次操作使用的是Ubuntu14.04。

安装Mysql主从复制

本文仅仅展示最简单的Mysql主从复制配置,实际使用中应该会更加复杂。

先配置主Mysql,先要修改/etc/mysql/my.cnf文件,

1
2
3
[mysqld]
log-bin=mysql-bin
server-id=1

然后重启主Mysql,并登陆,运行以下命令,

1
2
3
4
5
6
7
8
9
10
mysql> GRANT REPLICATION SLAVE ON *.* to 'root'@'%' identified by '111111';
Query OK, 0 rows affected, 1 warning (0.05 sec)
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000007 | 429 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

以上命令表示我们是用root用户镜像主从复制,实际使用中应该会使用其他用户。

主Mysql的配置比较简单,从Mysql的配置稍微麻烦一点。先修改/etc/mysql/my.cnf文件,

1
2
[mysqld]
server-id=10

注意,server-id一定不能与主Mysql相同,这是表示服务器的唯一id。然后重启从Mysql,登陆,运行如下命令,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mysql> change master to master_host='master-1',master_port=3306,master_user='root',master_password='111111',master_log_file='mysql-bin.000007',master_log_pos=429;
Query OK, 0 rows affected, 2 warnings (0.44 sec)
mysql> start slave;
Query OK, 0 rows affected (0.02 sec)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: master-1
Master_User: root
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000007
Read_Master_Log_Pos: 429
Relay_Log_File: 1d508b1aa846-relay-bin.000002
Relay_Log_Pos: 595
......

注意,以上命令中的master_log_file='mysql-bin.000007',master_log_pos=429要与主Mysql中的show master status结果一致。另外,如果配置change master的时候配置错了,需要先运行stop slave停止slave,再运行reset slave清空slave的配置,然后再从头开始配置。

配置完成之后,在主Mysql上进行create database可以同步到从Mysql。按MyCAT测试库的案例,创建db1、db2、db3三个数据库。

MyCAT配置主从复制

MyCAT主从复制的配置主要修改schema.xml文件,修改如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
......
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="2" slaveThreshold="100">
<heartbeat>show slave status</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="workstation:3306" user="root"
password="111111">
<!-- can have multi read hosts -->
<readHost host="hostS" url="workstation:3316" user="root"
password="111111" />
</writeHost>
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
......

对比原文件如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="localhost:3306" user="root"
password="123456">
<!-- can have multi read hosts -->
</writeHost>
<writeHost host="hostS1" url="localhost:3316" user="root"
password="123456" />
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>

修改了以下几个地方,

  1. 删除了writehost hostS1;
  2. 增加了writehost hostM1下的一个readHost hostS;
  3. 修改了dataHost的几个参数, balance="1" writeType="0" switchType="2" slaveThreshold="100"
  4. 修改了检测心跳的方法为show slave status;

(1) 设置 balance="1"与writeType="0"

Balance参数设置:

  1. balance=“0”, 所有读操作都发送到当前可用的writeHost上。
  2. balance=“1”,所有读操作都随机的发送到readHost。
  3. balance=“2”,所有读操作都随机的在writeHost、readhost上分发

WriteType参数设置:

  1. writeType=“0”, 所有写操作都发送到可用的writeHost上。
  2. writeType=“1”,所有写操作都随机的发送到readHost。
  3. writeType=“2”,所有写操作都随机的在writeHost、readhost分上发。

“readHost是从属于writeHost的,即意味着它从那个writeHost获取同步数据,因此,当它所属的writeHost宕机了,则它也不会再参与到读写分离中来,即“不工作了”,这是因为此时,它的数据已经“不可靠”了。基于这个考虑,目前mycat 1.3和1.4版本中,若想支持MySQL一主一从的标准配置,并且在主节点宕机的情况下,从节点还能读取数据,则需要在Mycat里配置为两个writeHost并设置banlance=1。”

(2) 设置 switchType="2" 与slaveThreshold="100"

“Mycat心跳检查语句配置为 show slave status ,dataHost 上定义两个新属性: switchType="2" 与slaveThreshold="100",此时意味着开启MySQL主从复制状态绑定的读写分离与切换机制。Mycat心跳机制通过检测 show slave status 中的 "Seconds_Behind_Master", "Slave_IO_Running", "Slave_SQL_Running" 三个字段来确定当前主从同步的状态以及Seconds_Behind_Master主从复制时延。“

配置好之后,即可运行mycat start启动MyCAT。

测试MyCAT主从复制

在MyCAT上运行建表和插入语句,

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
mysql> explain create table company(id int not null primary key,name varchar(100));
+-----------+---------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+---------------------------------------------------------------------+
| dn1 | create table company(id int not null primary key,name varchar(100)) |
| dn2 | create table company(id int not null primary key,name varchar(100)) |
| dn3 | create table company(id int not null primary key,name varchar(100)) |
+-----------+---------------------------------------------------------------------+
3 rows in set (0.06 sec)
mysql> create table company(id int not null primary key,name varchar(100));
Query OK, 0 rows affected (1.82 sec)
mysql> explain insert into company(id, name) values (100, 'abc');
+-----------+---------------------------------------------------+
| DATA_NODE | SQL |
+-----------+---------------------------------------------------+
| dn1 | insert into company(id, name) values (100, 'abc') |
| dn2 | insert into company(id, name) values (100, 'abc') |
| dn3 | insert into company(id, name) values (100, 'abc') |
+-----------+---------------------------------------------------+
3 rows in set (0.00 sec)
mysql> insert into company(id, name) values (100, 'abc');
Query OK, 1 row affected (0.24 sec)

分别在主从数据库上查看,

可以看到,数据已经在主从Mysql上都存在。

如果想看更多的MyCAT处理细节,需要打开debug级别的log,修改log4j.xml

1
2
3
4
5
<root>
<level value="debug" />
<appender-ref ref="FILE" />
<!--<appender-ref ref="FILE" />-->
</root>

修改后,重启mycat,然后运行sql,select * from company where id = 100;,在mycat/logs/mycat.log中可以看到以下结果,

可以发现mycat实际上是从hostS上读取数据,查看从Mysql的状态,如下,

上图最后一行显示,Seconds_Behind_Master是0,按MyCAT文档中的说法,此时的确是要去读hostS。

MyCAT自动切换

在主Mysql突然断线的时候,MyCAT会自动将连接转到从Mysql上,在从Mysql上读取数据。根据MyCAT文档中的说法,这种情况下不能设置一写一读两个主机,而要设置两个写主机。略微修改schema.xml如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
......
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="2" slaveThreshold="100">
<heartbeat>show slave status</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="workstation:3306" user="root"
password="111111">
<!-- can have multi read hosts -->
</writeHost>
<writeHost host="hostS" url="workstation:3316" user="root"
password="111111" />
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
......

几乎与之前的配置相同,只是将readHost改为writeHost,与原先的hostM1并列。

重启MyCAT,再次运行select * from company where id = 100;,发现log中,仍然是从hostS上查询,与之前相同;运行insert into company(id, name) values (200, 'xyz');,发现log中,也仍然是从hostM1上插入,与之前相同。插入时的log如下,

因此,可以判断,在该配置下,在Mysql没有宕机的时候,与之前一写一读的配置情况一样。此时,模拟Mysql宕机,再次运行查询select * from company where id = 100;,发现log如下,

与之前的查询完全相同,运行insert into company(id, name) values (300, 'def');,log如下,

此时的插入语句已经自动转到hostS上,说明此时的从Mysql已经取代主Mysql。此时,恢复主Mysql,发现所有的查询和插入也仍然是从hostS上走,相当于主Mysql没有在集群中。这种配置虽然简单,但系统的可靠性很差,建议使用多个主Mysql的集群,如Galera。

关于分库和分表

MyCAT主要完成了Mysql集群的水平分库问题。其中水平分库是说,把一个大表按行进行拆分,放在多个数据库中,比如,id为1~100万的在A库,100w~200w的在B库,以此类推。将大表进行水平拆分还有一种方法是水平分表,指的是,仍然按行进行拆分,但是放在一个数据库的多个表中,比如,id为1~100万的在A表,100w~200w的在B表,以此类推。表的水平拆分大致是这两种方法。

水平分表拆分的优点是,仍然是一个数据库,管理成本较低,集群方案等都与单库无差异,而且事务特性支持好,没有跨库的分布式事务问题;缺点是,由于本质上仍然是单个数据库,无法突破单个数据库实例上的CPU、内存、IO等硬件资源限制,性能提升并不会很明显。虽然,Oracle可以通过设置多个表空间来达到突破IO瓶颈的问题,Mysql也逐渐开始支持表空间特性,但是,CPU、内存仍然局限在一台服务器上,无法获得扩展。

水平分库拆分的优点是,引入了多个数据库,这些数据库可以放在多台服务器上,硬件资源扩展性理论上是无限的,性能提升会比较显著。缺点是,由于引入了多个数据库,管理成本提高,需要引入自动化工具,而且,事务特性会比较受限,因为多个数据库之间必然会存在分布式事务问题,这个问题一般都很难解决,也很难做到与单库上完全一致的事务特性,或者限制开发中分布式事务的使用,这对业务实现也不利。

文章目录
  1. 1. 安装Mysql主从复制
  2. 2. MyCAT配置主从复制
  3. 3. 测试MyCAT主从复制
  4. 4. MyCAT自动切换
  5. 5. 关于分库和分表

欢迎来到Valleylord的博客!

本博的文章尽量原创。