部署目标:本次需要开启五台服务器,主机及ip如下图所示。master1部署1主2从,master2省略从服务器,但理论上讲master2也是主服务器,只是这里省略了从服务器。Mycat的读写分离是建立在Mysql的主从复制的基础上的,所以前提是要配置好主从复制。
部署主从复制
前提条件,修改my.cof文件,master1、master2开启二进制日志和server_id,从节点开启server_id,最后重启mysqld服务。
1. [root@master1 ~]# cat /etc/my.cnf 2. [mysqld] 3. user=mysql 4. basedir=/usr/local/mysql 5. datadir=/usr/local/mysql/data 6. socket=/tmp/mysql.sock 7. server_id=1 8. log_bin=mysql-bin
mastr1登录mysql,创建主从复制用户,查看二进制文件
1. mysql> grant replication slave on *.* to rep@'192.168.8.%' identified by '123'; 2. Query OK, 0 rows affected, 1 warning (0.00 sec) 3. 4. mysql> show master status\G 5. *************************** 1. row *************************** 6. File: mysql-bin.000006 7. Position: 446 8. Binlog_Do_DB: 9. Binlog_Ignore_DB: 10. Executed_Gtid_Set: 11. 1 row in set (0.00 sec)
登录slave1,指定主服务器。
1. mysql> change master to 2. -> master_host='192.168.8.20', 3. -> master_port=3306, 4. -> master_user='rep', 5. -> master_password='123', 6. -> master_log_file='mysql-bin.000007', 7. -> master_log_pos=655; 8. Query OK, 0 rows affected, 2 warnings (0.01 sec) 9. 10. mysql> start slave; 11. Query OK, 0 rows affected (0.01 sec) 12. 13. mysql> show slave status\G 14. *************************** 1. row *************************** 15. Slave_IO_State: Waiting for master to send event 16. Master_Host: 192.168.8.20 17. Master_User: rep 18. Master_Port: 3306 19. Connect_Retry: 60 20. Master_Log_File: mysql-bin.000007 21. Read_Master_Log_Pos: 655 22. Relay_Log_File: slave-relay-bin.000002 23. Relay_Log_Pos: 320 24. Relay_Master_Log_File: mysql-bin.000007 25. Slave_IO_Running: Yes 26. Slave_SQL_Running: Yes
登录slave2,指定主服务器。
1. mysql> change master to 2. -> master_host='192.168.8.20', 3. -> master_port=3306, 4. -> master_user='rep', 5. -> master_password='123', 6. -> master_log_file='mysql-bin.000007', 7. -> master_log_pos=655; 8. Query OK, 0 rows affected, 2 warnings (0.02 sec) 9. 10. mysql> start slave; 11. Query OK, 0 rows affected (0.01 sec) 12. 13. mysql> show slave status\G 14. *************************** 1. row *************************** 15. Slave_IO_State: Waiting for master to send event 16. Master_Host: 192.168.8.20 17. Master_User: rep 18. Master_Port: 3306 19. Connect_Retry: 60 20. Master_Log_File: mysql-bin.000007 21. Read_Master_Log_Pos: 655 22. Relay_Log_File: slave2-relay-bin.000002 23. Relay_Log_Pos: 320 24. Relay_Master_Log_File: mysql-bin.000007 25. Slave_IO_Running: Yes 26. Slave_SQL_Running: Yes
master2因为省略了两个从节点,所以目前还不需要配置。
mycat读写分离
修改配置文件
重点修改的是baliance=“3”和主机。
1. [root@mycat ~]# cat /usr/local/mycat/conf/schema.xml 2. <?xml version="1.0"?> 3. <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> 4. <mycat:schema xmlns:mycat="http://io.mycat/"> 5. 6. <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1"> 7. </schema> 8. <dataNode name="dn1" dataHost="localhost1" database="mytest" /> 9. <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3" 10. writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100"> 11. <heartbeat>select user()</heartbeat> 12. <!-- can have multi write hosts --> 13. <writeHost host="hostM1" url="jdbc:mysql://192.168.8.20:3306" user="root" 14. password="123"> 15. <readHost host="hostS1" url="jdbc:mysql://192.168.8.30:3306" user="root" 16. password="123"></readHost> 17. <readHost host="hostS2" url="jdbc:mysql://192.168.8.40:3306" user="root" 18. password="123"></readHost> 19. </writeHost> 20. 21. </dataHost> 22. </mycat:schema>
可以看到远程的主机用户都是root,所以需要在所有mysql主机都创建一个远程root用户。注意:master1、master2、slave1、slave2都需要创建。
1. mysql> grant all on *.* to root@'192.168.8.%' identified by '123'; 2. Query OK, 0 rows affected, 1 warning (0.00 sec)
设置balance与writeType
Balance参数设置:
修改的balance属性,通过此属性配置读写分离的类型,负载均衡类型,目前的取值有4 种:
- balance="0",不开启读写分离机制, 所有读操作都发送到当前可用的 writeHost 上。
- balance="1",全部的 readHost与 stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从 模式(M1->S1, M2->S2,并且M1 与 M2 互为主备),正常情况下, M2,S1,S2 都参与 select 语句的负载均衡。
- balance="2",所有读操作都随机的在 writeHost、 readhost 上分发。
- balance="3",所有读请求随机的分发到 readhost 执行,writerHost 不负担读压力
WriteType参数设置:
- writeType=“0”, 所有写操作都发送到可用的writeHost上。
- writeType=“1”,所有写操作都随机的发送到readHost。
- writeType=“2”,所有写操作都随机的在writeHost、readhost分上发。
“readHost是从属于writeHost的,即意味着它从那个writeHost获取同步数据,因此,当它所属的writeHost宕机了,则它也不会再参与到读写分离中来,即“不工作了”,这是因为此时,它的数据已经“不可靠”了。基于这个考虑,目前mycat 1.3和1.4版本中,若想支持MySQL一主一从的标准配置,并且在主节点宕机的情况下,从节点还能读取数据,则需要在Mycat里配置为两个writeHost并设置banlance=1。”
设置switchType与slaveThreshold
switchType 目前有三种选择:
-1:表示不自动切换
1 :默认值,自动切换
2 :基于MySQL主从同步的状态决定是否切换
“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/bin 目录下执行 ./mycat console
- 后台启动 :去mycat/bin 目录下./mycat start 为了能第一时间看到启动日志,方便定位问题,这里我们选择控制台启动。
1. [root@mycat ~]# mycat console 2. Running Mycat-server... 3. Removed stale pid file: /usr/local/mycat/logs/mycat.pid 4. wrapper | --> Wrapper Started as Console 5. wrapper | Launching a JVM... 6. jvm 1 | Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org 7. jvm 1 | Copyright 1999-2006 Tanuki Software, Inc. All Rights Reserved. 8. jvm 1 | 9. jvm 1 | Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
验证读写分离
登录master1修改my.cnf文件,添加binlog_format参数。创建mytest库、tb1表。
1. [root@master1 ~]# vim /etc/my.cnf 2. #添加下面参数 3. binlog_format=STATEMENT 4. [root@master1 ~]# systemctl restart mysql #重启后稍等查看slave两个线程yes 5. [root@master1 ~]# mysql -uroot -p123 6. #省略部分内容 7. mysql> create database mytest character set utf8; 8. Query OK, 1 row affected (0.01 sec) 9. 10. mysql> use mytest; 11. Database changed 12. mysql> create table tb1( 13. -> id int, 14. -> name varchar(20)); 15. Query OK, 0 rows affected (0.02 sec)
1. 在master1主机插入下列数据,就可以测试主从主机数据不一致了。 (@@hostname表示插入的变量为主机名)
1. mysql> insert into tb1 values(1,@@hostname); 2. Query OK, 1 row affected, 1 warning (0.02 sec)
2. 登录mycat里查询tb1表,刷新两次可以看到两个name列不同,因为读的是从表,但是主机名不一样。所以可以分析出,读写分离成功。
1. [root@master2 ~]# mysql -umycat -p123456 -P8066 -h 192.168.8.10 2. #省略部分内容 3. mysql> use TESTDB; 4. 5. mysql> select * from tb1; 6. +----+-------+ 7. | id | name | 8. +----+-------+ 9. | 1 | slave | 10. +----+-------+ 11. 1 row in set (0.01 sec) 12. 13. mysql> select * from tb1; 14. +----+--------+ 15. | id | name | 16. +----+--------+ 17. | 1 | slave2 | 18. +----+--------+ 19. 1 row in set (0.01 sec)
垂直拆分-分库
一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类, 分布到不同 的数据库上面,这样也就将数据或者说压力分担到不同的库上面, 如何划分表 分库的原则: 有紧密关联关系的表应该在一个库里,相互没有关联关系的表可以分到不同的库里。
1. #客户表 rows:20万 2. CREATE TABLE customer( 3. id INT AUTO_INCREMENT, 4. NAME VARCHAR(200), 5. PRIMARY KEY(id) 6. ); 7. 8. #订单表 rows:600万 9. CREATE TABLE orders( 10. id INT AUTO_INCREMENT, 11. order_type INT, 12. customer_id INT, 13. amount DECIMAL(10,2), 14. PRIMARY KEY(id) 15. ); 16. 17. #订单详细表 rows:600万 18. CREATE TABLE orders_detail( 19. id INT AUTO_INCREMENT, 20. detail VARCHAR(2000), 21. order_id INT, 22. PRIMARY KEY(id) 23. ); 24. 25. #订单状态字典表 rows:20 26. CREATE TABLE dict_order_type( 27. id INT AUTO_INCREMENT, 28. order_type VARCHAR(200), 29. PRIMARY KEY(id) 30. );
上面有四个表如何分库?客户表分在一个数据库,另外三张都需要关联查询,分在另外一个数据库。
实现分库
因为master2没有mytest库,所以提前需要登录master2,创建该库(生产环境中,会直接备份,然后导入)。
1. [root@master2 ~]# mysql -uroot -p123 2. #省略部分内容 3. mysql> create database mytest character set utf8; 4. Query OK, 1 row affected (0.00 sec)
修改配置文件
登录mycat,修改schema.xml 配置文件
1. [root@mycat conf]# cd /usr/local/mycat/conf/ 2. [root@mycat conf]# cat schema.xml 3. <?xml version="1.0"?> 4. <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> 5. <mycat:schema xmlns:mycat="http://io.mycat/"> 6. 7. <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1"> 8. <table name="customer" dataNode="dn2"></table> #添加 9. </schema> 10. <dataNode name="dn1" dataHost="localhost1" database="mytest" /> 11. <dataNode name="dn2" dataHost="localhost2" database="mytest" /> 12. <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3" 13. writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100"> 14. <heartbeat>select user()</heartbeat> 15. <!-- can have multi write hosts --> 16. <writeHost host="hostM1" url="jdbc:mysql://192.168.8.20:3306" user="root" 17. password="123"> 18. <readHost host="hostS1" url="jdbc:mysql://192.168.8.30:3306" user="root" 19. password="123"></readHost> 20. <readHost host="hostS2" url="jdbc:mysql://192.168.8.40:3306" user="root" 21. password="123"></readHost> 22. </writeHost> 23. 24. </dataHost> 25. <dataHost name="localhost2" maxCon="1000" minCon="10" balance="0" #下面七行添加 26. writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100"> 27. <heartbeat>select user()</heartbeat> 28. <!-- can have multi write hosts --> 29. <writeHost host="hostM2" url="jdbc:mysql://192.168.8.50:3306" user="root" 30. password="123"> 31. </writeHost> 32. 33. </dataHost> 34. </mycat:schema> 35. [root@mycat conf]# mycat console 36. Running Mycat-server... 37. wrapper | --> Wrapper Started as Console 38. wrapper | Launching a JVM... 39. jvm 1 | Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org 40. jvm 1 | Copyright 1999-2006 Tanuki Software, Inc. All Rights Reserved. 41. jvm 1 | 42. jvm 1 | Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.