利用docker实现mysql主从同步读写分离,附赠docker搭建mycat读写分离
下载mysql镜像。
1 | docker pull mysql5.7 |
1 | ps:如果下载太慢,请添加腾讯源,依次执行 |
下载完输入
1 | docker images |
第二种:创建 MySQL 容器
创建主数据库容器
1 | docker run --name mysql-master -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 |
创建从数据库容器
1 | docker run --name mysql-slave -p 3308:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 |
配置主数据库
首先,进入容器:
1 | docker exec -it mysql-master /bin/bash |
连接mysql
1 | mysql -u root -p123456 |
修改 root 可以通过任何客户端连接
1 | ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456'; |
修改 MySQL 配置文档 ==/etc/mysql/mysql.conf.d/mysqld.cnf==,在 [mysqld] 段添加以下配置:
1 | log-bin=mysql-bin //[必须]启用二进制日志 |
配置从服务器
首先,进入容器:
1 | docker exec -it mysql-master /bin/bash |
连接mysql
1 | mysql -u root -p123456 |
修改 root 可以通过任何客户端连接
1 | ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456'; |
修改 MySQL 配置文档 ==/etc/mysql/mysql.conf.d/mysqld.cnf==,在 [mysqld] 段添加以下配置:
1 | log-bin=mysql-bin //[必须]启用二进制日志 |
重启容器
配置 MySQL 主从复制
首先连接 master 服务器,查看数据库状态:
1 | mysql> show master status; |
记录 File 的值和 Position 的值,等会配置 slave 服务器的时候要用。
接下来连接 slave 服务器,配置主从复制:
1 | mysql>change master to |
解释下配置参数
1 | master_host='x.x.x.x' // 这里填 master 主机 ip |
如果不小心配置错, 输入 mysql> stop slave; 然后重新录入一遍就可以了。
检查主从连接状态
1 | mysql> show slave status\G |
这两个必须是Yes 为No 或者connect说明没有连接上
1 | Slave_IO_Running: Yes |
测试主从连接
注意设置主从后,操作只能在master终端上,slave上的操作不会同步到master上。
登陆master终端,
1 | mysql> create database sunhao; |
登陆slave服务器
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sunhao |
| sys |
+--------------------+
5 rows in set (0.00 sec)
mysql> use sunhao
mysql> select * from user;
+---------+-----------+-----------+
| user_id | username | password |
+---------+-----------+-----------+
| 1 | test_user | test_pass |
+---------+-----------+-----------+
1 row in set (0.00 sec)
如果主服务器已经存在应用数据,则在进行主从复制时,需要单独复制处理(注意此操作,如果对从服务器单独录入的数据,会被覆盖掉。):
这里我们做一次完整的测试
(1)在主服务器数据库插入新的数据,并进行锁表操作,不让数据再进行写入动作
mysql> insert into sunhao values(2,'xiaoshuai');
Query OK, 1 row affected (0.01 sec)
mysql> select * from sunhao;
+------+-----------+
| id | name |
+------+-----------+
| 1 | xiaoshuai |
| 2 | xiaoshuai |
+------+-----------+
2 rows in set (0.00 sec)
mysql> FLUSH TABLES WITH READ LOCK;
mysql> show full processlist;
`
(2)退出mysql,用mysqldump备份数据文件到/var/lib,然后顺便多余的用tar打包一下玩。哈哈。
mysql> exit
Bye
root@980e5ea48152:/var/lib/mysql# mysqldump -u root -p sunhao > /var/lib/sunhao.dump
Enter password:
root@980e5ea48152:/var/lib# tar -zcvf ./sunhao.dump .tar ./sunhao.dump
(3)打开宿主服务器,复制mysql主服务器文件sunhao.dump.tar。到宿主服务器
[root]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8d1e3b87d499 slave/mysql "docker-entrypoint.sh" 4 hours ago Up 4 hours 0.0.0.0:32769->3306/tcp mysql-slave
980e5ea48152 master/mysql "docker-entrypoint.sh" 4 hours ago Up 4 hours 0.0.0.0:32768->3306/tcp mysql-master
mkdir -p /var/mydata
docker cp 980e:/var/lib/sunhao.dump.tar /var/mydata/
cd /var/mydata
[root@VM_128_230_centos mydata]# ls
sunhao.dump.tar
解释:docker cp 980e:/var/lib/sunhao.dump.tar /var/mydata/
980e是980e5ea48152的缩写。保证不重复简写就可以
980e:/var/lib/sunhao.dump.tar 意思就是选中的容器下面你的文件下的sunhao.dump.tar文件
/var/mydata/ 目标文件
(4)在宿主主机上输入
[root]# docker cp /var/mydata/sunhao.dump.tar 8d1e3b87d49936414c0e91ffdc60a054e7f4ef8b15baee295350565519abba0e:/var/lib/
(5)在从服务器上输入
root@8d1e3b87d499:/# cd /var/lib/
root@8d1e3b87d499:/var/lib# tar -zcvf sunhao.dump.tar
(6)在从服务器上输入
tar -zxvpf /var/lib/mysqlbak.sql.tar
mysql -uroot -pmysql sunhao < /var/lib/sunhao.dump;
如果写入成功,这个时候就可以用select查询到数据。
(2)取消主服务器数据库锁定
mysql> UNLOCK TABLES;
docker搭建mycat读写分离
制作mycat容器,并运行
首先在本地新建个文件夹/usr/mycat。然后去mycat官网下载最新版本,这里我下载的是1.6版本。安装完解压到这里。
http://dl.mycat.io/
[http://dl.mycat.io/1.6-RELEASE/](http://dl.mycat.io/1.6-RELEASE/ "http://dl.mycat.io/1.6-RELEASE/")
编写Dockerfile,内容为
# 来源镜像,因为mycat依赖java,所以这里直接选的java环境。
FROM java
RUN mkdir -p /var/local/mycat/
# Add复制Mycat到容器
ADD mycat/ /var/local/mycat/
ENTRYPOINT ["/var/local/mycat/bin/mycat","console","&"]
# 对外端口
EXPOSE 8066 9066
# 启动控制台
CMD ["/var/local/mycat/bin/mycat","console","&"]
先别急着构建镜像,我们先修改下mycat的配置文件。
[root@centos mycat]# ll
total 15324
-rw-r--r-- 1 root root 357 Jul 5 15:26 Dockerfile
-rw-r--r-- 1 root root 15662280 Jul 3 15:07 Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
drwxr-xr-x 7 root root 4096 Jul 5 15:27 mycat
在我用的1.6版本。mycat对外端口是注释掉的。我们要打开下。我们编辑/usr/mycat/mycat/conf/server.xml.找到第32-35行。去掉注释符号。
<!--
<property name="serverPort">8066</property> <property name="managerPort">9066</property>
<property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property>
<property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
我们往下看 有这么几句。这里分别默认两个用户。 name为root的管理员,可以进行读写。和普通用户只能进行读。我们也可以手动创建修改,另外password是密码 schemas是用户所能操作的库。 在这里我什么都没有改。下面都是默认。
<user name="root">
<property name="password">123456</property>
<property name="schemas">TESTDB</property>
<!-- 表级 DML 权限设置 -->
<!--
<privileges check="false">
<schema name="TESTDB" dml="0110" >
<table name="tb01" dml="0000"></table>
<table name="tb02" dml="1111"></table>
</schema>
</privileges>
-->
</user>
<user name="user">
<property name="password">user</property>
<property name="schemas">TESTDB</property>
<property name="readOnly">true</property>
</user>
我们编辑/usr/mycat/mycat/conf/schema.xml,这个是我们配置分片和逻辑库表,规则的地方,数据节点,和数据源。其中schema是我们所操作的逻辑库。默认为TESTDB。下面分别是各个逻辑表。在这里直接默认。我只是为了区分dh和db两个字的区别,把db1-3改了data1-3你们可以不用管。
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<!-- auto sharding by id (long) -->
<table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
<!-- global table is auto cloned to all defined data nodes ,so can join
with any table whose sharding node is in the same data node -->
<table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />
<table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2" />
<!-- random sharding using mod sharind rule -->
<table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3"
rule="mod-long" />
<!-- <table name="dual" primaryKey="ID" dataNode="dnx,dnoracle2" type="global"
needAddLimit="false"/> <table name="worker" primaryKey="ID" dataNode="jdbc_dn1,jdbc_dn2,jdbc_dn3"
rule="mod-long" /> -->
<table name="employee" primaryKey="ID" dataNode="dn1,dn2"
rule="sharding-by-intfile" />
<table name="customer" primaryKey="ID" dataNode="dn1,dn2"
rule="sharding-by-intfile">
<childTable name="orders" primaryKey="ID" joinKey="customer_id"
parentKey="id">
<childTable name="order_items" joinKey="order_id"
parentKey="id" />
</childTable>
<childTable name="customer_addr" primaryKey="ID" joinKey="customer_id"
parentKey="id" />
</table>
<!-- <table name="oc_call" primaryKey="ID" dataNode="dn1$0-743" rule="latest-month-calldate"
/> -->
</schema>
修改37-45行 /usr/mycat/mycat/conf/wrapper.conf。设置java虚拟机内存。
# Initial Java Heap Size (in MB)
wrapper.java.initmemory=3
# Maximum Java Heap Size (in MB)
wrapper.java.maxmemory=64
在schema.xml往下修改。43-55行。数据源地址dataHost。这些就是我们的数据源,mycat把逻辑表的数据,读写都来源于我们配置地址。其中
writeHost写入源。设置多个,默认也只用第一个。readHost是读服务器。heartbeat是我们检测数据库是否正常运行的。
在这里 mycat 有两种配置方式。
分别是两个writeHost和一个writeHost一个readHost
第一种如果写入失败,还是可读。
第二种如果写入失败,不可读。
我们采用安全稳妥的方式。一个writeHost一个readHost
我的配置为
<dataHost name="localhost1" maxCon="1000" minCon="20" 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="115.159.124.18:32768" user="root" password="mysql">
<!-- can have multi read hosts -->
<readHost host="hostS1" url="115.159.124.18:32769" user="root" password="mysql" />
</writeHost>
</dataHost>
hostM1和hostS1分别对应我们创建的两个docker容器的对外端口。
修改/usr/mycat/mycat/conf/log4j2.xml 这个是配置日志文件的,我们打开debug方便我们学习。修改第25行info为debug
<asyncRoot level="debug" includeLocation="true">
<AppenderRef ref="Console" />
<AppenderRef ref="RollingFile"/>
</asyncRoot>
构建镜像
docker build -t sunhao/mycat:1.6 . 别忘了最后面的圆点
运行创建容器
docker run --name sunhaomycat -d -p 8066:8066 -p 9066:9066 sunhao/mycat:1.6
就那么简单。我们的mycat已经搭建成功了。测试下吧打开4个终端
1个宿主,1个mysql主,1个mysql从,1个用来看mycat日志。
宿主环境操作
在宿主终端上,安装mysql。并且连接我们的mycat。
[root@VM_128_230_centos mycat]# mysql -uroot -p123456 -h115.159.124.18 -P8066
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (OpenCloundDB)
Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]>
完美,Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server 出现这,说明mycat运行了。
进行简单的操作。
Database changed
MySQL [TESTDB]> show databases;
+----------+
| DATABASE |
+----------+
| TESTDB |
+----------+
1 row in set (0.00 sec)
MySQL [TESTDB]> show tables;
+------------------+
| Tables in TESTDB |
+------------------+
| company |
| customer |
| customer_addr |
| employee |
| goods |
| hotnews |
| orders |
| order_items |
| travelrecord |
+------------------+
9 rows in set (0.00 sec)
MySQL [TESTDB]>
测试下写入
MySQL [TESTDB]> create table travelrecord (id bigint not null primary key,user_id varchar(100),traveldate DATE, fee decimal,days int);
ERROR 1105 (HY000): Table 'travelrecord' already exists
MySQL [TESTDB]> insert into travelrecord(id,user_id,traveldate,fee,days) values(1,@@hostname,20170707,100,10);
Query OK, 1 row affected (0.01 sec)
MySQL [TESTDB]>
MySQL [TESTDB]> insert into travelrecord(id,user_id,traveldate,fee,days) values(10000001,@@hostname,20170707,100,10);
Query OK, 1 row affected (0.00 sec)
分别进入mysql主和mysql从可以看到。
MySQL [data2]> use data3
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MySQL [data3]> select * from travelrecord;
+----------+--------------+------------+------+------+
| id | user_id | traveldate | fee | days |
+----------+--------------+------------+------+------+
| 10000001 | 980e5ea48152 | 2017-07-07 | 100 | 10 |
+----------+--------------+------------+------+------+
1 row in set (0.00 sec)
MySQL [data3]> use data1;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MySQL [data1]> select * from travelrecord;
+----+--------------+------------+------+------+
| id | user_id | traveldate | fee | days |
+----+--------------+------------+------+------+
| 1 | 980e5ea48152 | 2017-07-07 | 100 | 10 |
+----+--------------+------------+------+------+
1 row in set (0.00 sec)
MySQL [data1]>
测试读取分离
打开一个终端,用
docker exec -it 61e74eee274d9d0f0404a572dec1d14c8b03dfd480e13d3c96fa04c534df0556 bash
进入我们的mycat容器
其中61e74为你的mycat容器
这个就是我们的日志终端
root@61e74eee274d:/var/local/mycat/logs# ls
2017-07 mycat.log mycat.pid wrapper.log
root@61e74eee274d:/var/local/mycat/logs# tail -f mycat.log
在宿主环境mycat下
输入
MySQL [TESTDB]> select * from travelrecord ;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id: 9
Current database: TESTDB
+----------+--------------+------------+------+------+
| id | user_id | traveldate | fee | days |
+----------+--------------+------------+------+------+
| 1 | 980e5ea48152 | 2017-07-07 | 100 | 10 |
| 10000001 | 980e5ea48152 | 2017-07-07 | 100 | 10 |
+----------+--------------+------------+------+------+
2 rows in set (0.02 sec)
然后切回我们的日志终端,按ctrl+c中断。
然后输入cat tail 进行查看,很长在最后面找个空白的大坑(自己体会)慢慢找。
017-07-07 06:28:16.863 DEBUG [$_NIOREACTOR-5-RW] (io.mycat.backend.datasource.PhysicalDatasource.releaseChannel(PhysicalDatasource.java:442)) - release channel MySQLConnection [id=5, lastTime=1499408896859, user=root, schema=data3, old shema=data3, borrowed=true, fromSlaveDB=false, threadId=527, charset=latin1, txIsolation=3, autocommit=true, attachment=null, respHandler=null, host=115.159.184.18, port=32774, statusSync=null, writeQueue=0, modifiedSQLExecuted=false]
2017-07-07 06:28:16.864 DEBUG [$_NIOREACTOR-3-RW] (io.mycat.backend.datasource.PhysicalDatasource.releaseChannel(PhysicalDatasource.java:442)) - release channel MySQLConnection [id=33, lastTime=1499408896859, user=root, schema=data3, old shema=data3, borrowed=true, fromSlaveDB=true, threadId=108, charset=latin1, txIsolation=3, autocommit=true, attachment=null, respHandler=null, host=115.159.184.18, port=32770, statusSync=null, writeQueue=0, modifiedSQLExecuted=false]
2017-07-07 06:28:24.473 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.net.FrontendConnection.query(FrontendConnection.java:288)) - ServerConnection [id=2, schema=TESTDB, host=115.159.184.18, user=root,txIsolation=3, autocommit=true, schema=TESTDB] select * from travelrecord
2017-07-07 06:28:24.474 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.server.ServerQueryHandler.query(ServerQueryHandler.java:57)) - ServerConnection [id=2, schema=TESTDB, host=115.159.184.18, user=root,txIsolation=3, autocommit=true, schema=TESTDB]select * from travelrecord
2017-07-07 06:28:24.474 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.cache.impl.EnchachePool.get(EnchachePool.java:71)) - SQLRouteCache hit cache ,key:TESTDBselect * from travelrecord
2017-07-07 06:28:24.474 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.server.NonBlockingSession.execute(NonBlockingSession.java:110)) - ServerConnection [id=2, schema=TESTDB, host=115.159.184.18, user=root,txIsolation=3, autocommit=true, schema=TESTDB]select * from travelrecord, route={
1 -> dn1{SELECT *
FROM travelrecord
LIMIT 100}
2 -> dn2{SELECT *
FROM travelrecord
LIMIT 100}
3 -> dn3{SELECT *
FROM travelrecord
LIMIT 100}
} rrs
2017-07-07 06:28:24.474 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.mysql.nio.handler.MultiNodeQueryHandler.<init>(MultiNodeQueryHandler.java:101)) - execute mutinode query select * from travelrecord
2017-07-07 06:28:24.474 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.mysql.nio.handler.MultiNodeQueryHandler.<init>(MultiNodeQueryHandler.java:137)) - has data merge logic
2017-07-07 06:28:24.474 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.mysql.nio.handler.MultiNodeQueryHandler.execute(MultiNodeQueryHandler.java:170)) - rrs.getRunOnSlave()-null
2017-07-07 06:28:24.474 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.mysql.nio.handler.MultiNodeQueryHandler.execute(MultiNodeQueryHandler.java:180)) - node.getRunOnSlave()1-null
2017-07-07 06:28:24.474 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.mysql.nio.handler.MultiNodeQueryHandler.execute(MultiNodeQueryHandler.java:182)) - node.getRunOnSlave()2-null
2017-07-07 06:28:24.474 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.datasource.PhysicalDBNode.getConnection(PhysicalDBNode.java:96)) - rrs.getRunOnSlave() null
2017-07-07 06:28:24.475 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.datasource.PhysicalDBNode.getConnection(PhysicalDBNode.java:127)) - rrs.getRunOnSlave() null
2017-07-07 06:28:24.475 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.datasource.PhysicalDBPool.getRWBanlanceCon(PhysicalDBPool.java:456)) - select read source hostS1 for dataHost:localhost1
2017-07-07 06:28:24.475 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.mysql.nio.handler.MultiNodeQueryHandler.execute(MultiNodeQueryHandler.java:180)) - node.getRunOnSlave()1-null
2017-07-07 06:28:24.475 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.mysql.nio.handler.MultiNodeQueryHandler.execute(MultiNodeQueryHandler.java:182)) - node.getRunOnSlave()2-null
2017-07-07 06:28:24.475 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.datasource.PhysicalDBNode.getConnection(PhysicalDBNode.java:96)) - rrs.getRunOnSlave() null
2017-07-07 06:28:24.475 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.datasource.PhysicalDBNode.getConnection(PhysicalDBNode.java:127)) - rrs.getRunOnSlave() null
就是这了我们可以看到select read source hostS1 for dataHost:localhost1来至哪个服务器
2017-07-07 06:28:24.475 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.datasource.PhysicalDBPool.getRWBanlanceCon(PhysicalDBPool.java:456)) - select read source hostS1 for dataHost:localhost1
2017-07-07 06:28:24.475 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.mysql.nio.handler.MultiNodeQueryHandler.execute(MultiNodeQueryHandler.java:180)) - node.getRunOnSlave()1-null
2017-07-07 06:28:24.475 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.mysql.nio.handler.MultiNodeQueryHandler.execute(MultiNodeQueryHandler.java:182)) - node.getRunOnSlave()2-null
2017-07-07 06:28:24.475 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.datasource.PhysicalDBNode.getConnection(PhysicalDBNode.java:96)) - rrs.getRunOnSlave() null
2017-07-07 06:28:24.476 DEBUG [$_NIOREACTOR-29-RW] (io.mycat.backend.datasource.PhysicalDBNode.getConnection
如果配置不小心错了,可以用docker cp 复制到镜像里,然后重启镜像
docker cp /usr/mycat/mycat/conf 61e74eee274d9d0f0404a572dec1d14c8b03dfd480e13d3c96fa04c534df0556:/var/local/mycat/conf
docker restart 61e74eee274
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Navi!
评论