写在前面
因为最近要用到MySQL的分库分表,所以自己尝试在测试机器里搭建一套分库分表的MySQL数据库,我这里是通过Docker运行了3台MySQL 5.7 ,然后官方下载MyCat的程序包进行部署的,分库分表做的是水平拆分
构建MySQL
首先拉取MySQL镜像
docker pull mysql:5.7
然后创建数据库数据的持久化目录
mkdir -p /data/mysqlone/log /data/mysqlone/data /data/mysqlone/conf
mkdir -p /data/mysqltwo/log /data/mysqltwo/data /data/mysqltwo/conf
mkdir -p /data/mysqlthree/log /data/mysqlthree/data /data/mysqlthree/conf
运行第一个容器然后查看是否能正常运行
docker run -p 3307:3306 --name mysqlone -v /data/mysqlone/log:/var/log/mysql -v /data/mysqlone/data:/var/lib/mysql -v /data/mysqlone/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=123456 -e TZ=Asia/Shanghai -d mysql:5.7
#端口我改为了3307,因为本机也有mysql,为了防止端口冲突导致容器运行失败就改了一下,也是为了区分
#root密码为123456,可以根据需求更改,这里为了测试方便就弄成了简单的
#通过命令查看容器状态,如果运行正常就可以进行自定义配置文件了
docker ps -a
#自定义配置文件,因为已经把配置文件目录挂载出来了,所以直接在宿主机创建即可
vim /data/mysqlone/conf/my.conf
[mysqld]
port = 3306
socket = /var/lib/mysql/mysql.sock
#basedir = /var/lib/mysql
datadir = /var/lib/mysql
pid-file = /var/run/mysqld/mysqld.pid
user = mysql
bind-address = 0.0.0.0
server-id = 1 #另外两台数据库可以考虑改成不一样的,方便以后做主从复制和读写分离
default-time-zone = '+8:00'
character-set-server = utf8mb4
skip-name-resolve
#skip-networking
back_log = 300
max_connections = 1000
max_connect_errors = 6000
open_files_limit = 65535
table_open_cache = 128
max_allowed_packet = 500M
binlog_cache_size = 1M
max_heap_table_size = 8M
tmp_table_size = 16M
read_buffer_size = 2M
read_rnd_buffer_size = 8M
sort_buffer_size = 8M
join_buffer_size = 8M
key_buffer_size = 4M
thread_cache_size = 8
query_cache_type = 1
query_cache_size = 8M
query_cache_limit = 2M
ft_min_word_len = 4
log_bin = mysql-bin
binlog_format = mixed
expire_logs_days = 7
log_error = /var/log/mysql/mysqld.log
slow_query_log = 1
long_query_time = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
performance_schema = 0
explicit_defaults_for_timestamp
skip-external-locking
default_storage_engine = InnoDB
innodb_file_per_table = 1
innodb_open_files = 500
innodb_buffer_pool_size = 64M
innodb_write_io_threads = 4
innodb_read_io_threads = 4
innodb_thread_concurrency = 0
innodb_purge_threads = 1
innodb_flush_log_at_trx_commit = 2
innodb_log_buffer_size = 2M
innodb_log_file_size = 32M
innodb_log_files_in_group = 3
innodb_max_dirty_pages_pct = 90
innodb_lock_wait_timeout = 120
bulk_insert_buffer_size = 8M
myisam_sort_buffer_size = 8M
myisam_max_sort_file_size = 10G
myisam_repair_threads = 1
interactive_timeout = 28800
wait_timeout = 28800
sql_mode =
[mysqldump]
quick
然后重启容器查看是否正常
#重启容器
docker restart mysqlone
#查看状态
docker inspect mysqlone
#如果运行正常,表示配置文件可用,复制到其他两个目录
cp /data/mysqlone/conf/my.conf /data/mysqltwo/conf/
cp /data/mysqlone/conf/my.conf /data/mysqlthree/conf/
启动另外两台数据库
docker run -p 3308:3306 --name mysqltwo -v /data/mysqltwo/log:/var/log/mysql -v /data/mysqltwo/data:/var/lib/mysql -v /data/mysqltwo/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=123456 -e TZ=Asia/Shanghai -d mysql:5.7
docker run -p 3309:3306 --name mysqlthree -v /data/mysqlthree/log:/var/log/mysql -v /data/mysqlthree/data:/var/lib/mysql -v /data/mysqlthree/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=123456 -e TZ=Asia/Shanghai -d mysql:5.7
运行成功后MySQL就部署完成了
部署MyCat
下载并部署MyCat
#下载程序包,为这里下载到是1.6.6,最高版本好像到了2.0,根据需求下载即可
wget http://dl.mycat.org.cn/1.6.6/Mycat-server-1.6.6.1-test-20180709095126-linux.tar.gz
#解压
tar zxvf Mycat-server-1.6.6.1-test-20180709095126-linux.tar.gz -C /usr/local/
编辑配置文件
#这里只需求修改server和schema两个文件就可以,其他文件用的到到时候不多,首先修改server
cd /usr/local/mycat/conf
vim server.xml
#上面其实不用修改直接到最下面修改账户名密码
<?xml version="1.0" encoding="UTF-8"?>
<!-- - - Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License. - You
may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0
- - Unless required by applicable law or agreed to in writing, software -
distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the
License for the specific language governing permissions and - limitations
under the License. -->
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<system>
<property name="nonePasswordLogin">0</property> <!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户-->
<property name="useHandshakeV10">1</property>
<property name="useSqlStat">0</property> <!-- 1为开启实时统计、0为关闭 -->
<property name="useGlobleTableCheck">0</property> <!-- 1为开启全加班一致性检测、0为关闭 -->
<property name="sequnceHandlerType">0</property>
<property name="subqueryRelationshipCheck">false</property> <!-- 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false -->
<!-- <property name="useCompression">1</property>--> <!--1为开启mysql压缩协议-->
<!-- <property name="fakeMySQLVersion">5.6.20</property>--> <!--设置模拟的MySQL版本号-->
<!-- <property name="processorBufferChunk">40960</property> -->
<!--
<property name="processors">1</property>
<property name="processorExecutor">32</property>
-->
<!--默认为type 0: DirectByteBufferPool | type 1 ByteBufferArena | type 2 NettyBufferPool -->
<property name="processorBufferPoolType">0</property>
<!--默认是65535 64K 用于sql解析时最大文本长度 -->
<!--<property name="maxStringLiteralLength">65535</property>-->
<!--<property name="sequnceHandlerType">0</property>-->
<!--<property name="backSocketNoDelay">1</property>-->
<!--<property name="frontSocketNoDelay">1</property>-->
<!--<property name="processorExecutor">16</property>-->
<!--
<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> -->
<!--分布式事务开关,0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但是记录分布式事务日志-->
<property name="handleDistributedTransactions">0</property>
<!--
off heap for merge/order/group/limit 1开启 0关闭
-->
<property name="useOffHeapForMerge">1</property>
<!--
单位为m
-->
<property name="memoryPageSize">64k</property>
<!--
单位为k
-->
<property name="spillsFileBufferSize">1k</property>
<property name="useStreamOutput">0</property>
<!--
单位为m
-->
<property name="systemReserveMemorySize">384m</property>
<!--是否采用zookeeper协调切换 -->
<property name="useZKSwitch">false</property>
<!-- XA Recovery Log日志路径 -->
<!--<property name="XARecoveryLogBaseDir">./</property>-->
<!-- XA Recovery Log日志名称 -->
<!--<property name="XARecoveryLogBaseName">tmlog</property>-->
<!--如果为 true的话 严格遵守隔离级别,不会在仅仅只有select语句的时候在事务中切换连接-->
<property name="strictTxIsolation">false</property>
<property name="useZKSwitch">true</property>
</system>
<!-- 全局SQL防火墙设置 -->
<!--白名单可以使用通配符%或着*-->
<!--例如<host host="127.0.0.*" user="root"/>-->
<!--例如<host host="127.0.*" user="root"/>-->
<!--例如<host host="127.*" user="root"/>-->
<!--例如<host host="1*7.*" user="root"/>-->
<!--这些配置情况下对于127.0.0.1都能以root账户登录-->
<!--
<firewall>
<whitehost>
<host host="1*7.0.0.*" user="root"/>
</whitehost>
<blacklist check="false">
</blacklist>
</firewall>
-->
<!-- ** 修改这里就可以了 ** -->
<user name="sheep" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">sheepdb</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">sheepdb</property>
<property name="readOnly">true</property>
</user>
</mycat:server>
#user 中name为连接MyCat的用户名,password为密码,schemas后面的数据库如果修改,一定要和schemas文件中的数据库对应,并且也要修改下面user用户的数据库
接着修改schemas文件
vim schemas.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- ** 这里的name名字要和server里数据库名一致 ** -->
<schema name="sheepdb" checkSQLschema="false" sqlMaxLimit="100">
<!-- auto sharding by id (long) -->
<!-- ** 这里表的名字要在库里存在 ** -->
<table name="user" primaryKey="id" dataNode="dn1,dn2,dn3" rule="mod-long" autoIncrement="true" />
</schema>
<!-- ** 后面database的名字的库要在数据库里存在 ** -->
<dataNode name="dn1" dataHost="localhost1" database="sheepdb" />
<dataNode name="dn2" dataHost="localhost2" database="sheepdb" />
<dataNode name="dn3" dataHost="localhost3" database="sheepdb" />
<!-- ** balance要改为0不做负载均衡 ** -->
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100" maxRetryCount="4">
<heartbeat>select user()</heartbeat>
<!-- ** 填写数据库地址、用户名和密码,注意host名字不要都一样 ** -->
<writeHost host="hostM1" url="192.168.1.212:3307" user="root" password="123456">
<!--<readHost host="hostS1" url="192.168.1.212:3306" user="sheep" password="Ming456!" />-->
</writeHost>
</dataHost>
<dataHost name="localhost2" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100" maxRetryCount="4">
<heartbeat>select user()</heartbeat>
<!-- ** 注意host名字 ** -->
<writeHost host="hostM2" url="192.168.1.212:3308" user="root" password="123456">
<!--<readHost host="hostS1" url="192.168.1.212:3306" user="sheep" password="Ming456!" />-->
</writeHost>
</dataHost>
<dataHost name="localhost3" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100" maxRetryCount="4">
<heartbeat>select user()</heartbeat>
<!-- ** 注意host名字 ** -->
<writeHost host="hostM3" url="192.168.1.212:3309" user="root" password="123456">
<!--<readHost host="hostS1" url="192.168.1.212:3306" user="sheep" password="Ming456!" />-->
</writeHost>
</dataHost>
</mycat:schema>
修改完成就可以启动MyCat了
#启动
/usr/local/mycat/bin/mycat start
#查看日志
cd /usr/local/mycat/logs
tail -f wrapper.log

日志没有报错的话服务就已经启动了,如果启动有报错会在这个日志中体现,再去查看运行日志
tail -f mycat.log
如果没有任何报错信息,MyCat就已经启动完成,可以通过命令或者工具连接了,用户名密码为server文件中的信息,默认端口8066

配置读写分离
可以直接使用前面的库,先开启MySQL的主从复制功能
#把mysqlone作为主库,修改配置文件
vim /data/mysqlone/conf/my.cnf
#在[mysqld]模块内增加以下配置
#开启二进制日志功能
log-bin=mysql-bin
#复制过滤:不需要备份的数据库,不输出(mysql库一般不同步)
binlog-ignore-db=mysql
#日志保留时间(天)
expire-logs-days=10
#跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断
#如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
然后重启mysqlone容器
docker restart mysqlone
接着修改从库
#同样在[mysqld]模块内增加下面的配置
binlog-ignore-db=mysql
log-bin=mysql-slave1-bin
slave_skip_errors=1062
log_slave_updates=1
# relay_log配置中继日志
relay-log=relay-log-bin
relay-log-index=slave-relay-bin.index
配置完成后重启mysqltwo
docker restart mysqltwo
到这里配置文件就已经修改完成了,然后登陆mysql进行配置
#如果本机安装了mysql客户端程序可以在本机登陆,如果没有就要进到容器内登陆
#本机登陆主库,一定要加-h 不然是以localhost登陆,会提示无法登陆
mysql -h127.0.0.1 -uroot -p123456 -P3307
#增加一个用于同步的账户(可不创建,直接使用root)
GRANT REPLICATION SLAVE ON *.* to 'slave'@'%' identified by '123456';
FLUSH PRIVILEGES;
#查看binlog日志是否已经开启
show variables like '%log_bin%';

#查看当前binlog日志的信息
show master status;

我们要的是binlong文件名和偏移,让从库一会通过这个两个信息开启主从复制功能
#登陆从库mysqltwo
mysql -h 127.0.0.1 -uroot -p123456 -P3308
#绑定主库(如果数据库有人使用,偏移可能变化很快,建议使用量少或者无人使用时配置)
change master to master_host='192.168.1.212', master_user='root', master_password='123456', master_port=3307, master_log_file='mysql-bin.000001',master_log_pos=35861;
#解释
#master_host为主库的IP地址
#master_user为连接主库用的用户名,可以是之前创建的,也可以用root
#master_password对应用户的密码
#master_port主库的端口
#master_log_file主库binlog日志文件名,就是上面截图中的file
#master_log_pos为偏移数,上面截图中Position

然后开启主从复制功能(从库操作)
start slave;
#查看主从复制状态
show slave status\G;

两个位置均为Yes表示已经开启成功,如果没有成功可以重置以后再开启
#先停掉主从复制
stop slave;
#重置
reset slave;
#重新配置绑定,查看新的偏移数后进行配置,再次启动查看信息,直到成功
到这里主从复制就已经配置完成,接着去配MyCat开启读写分离(读写分离和水平拆分可同时使用)
先修改server文件,这里为了演示所以修改了之前的配置,读写分离和分库分表可在一个配置内
cd /usr/local/mycat/conf/
#修改配置,只需要修改user部分
vim server.xml
<user name="mycat" defaultAccount="true">
<property name="password">123456</property>
<!-- 我这里添加了2个库做读写分离,多个库可以用逗号隔开 -->
<property name="schemas">account,money_record</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">account,money_record</property>
<property name="readOnly">true</property>
</user>
然后修改schema.xml
#我这里做了精简,如果想让读写分离和分库分表同时使用,添加多个schema模块即可
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="account" dataNode="dn1" checkSQLschema="false" sqlMaxLimit="100"></schema>
<schema name="money_record" dataNode="dn2" checkSQLschema="false" sqlMaxLimit="100"></schema>
<dataNode name="dn1" dataHost="localhost1" database="account" />
<dataNode name="dn2" dataHost="localhost1" database="money_record" />
<!-- balance配置为1 性能相对更好一些 -->
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100" maxRetryCount="4">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.1.212:3307" user="root" password="123456">
<readHost host="hostS1" url="192.168.1.212:3308" user="root" password="123456" />
</writeHost>
</dataHost>
</mycat:schema>
文档顺序一定是schema —> dataNode —> dataHost 顺序错误会无法启动,读写分离因为没有配置table,所以一定要在schema中配置dataNode,而且必须添加写节点和读节点,写节点内添加读节点,写为主库读为从库,不然数据会不一致
接着开启MyCat
/usr/local/mycat/bin/mycat start
查看启动日志状态
tail -f /usr/local/mycat/logs/wrapper.log

没有错误就已经启动成功了,到此读写分离配置完成
示例
#读写分离和分库分表同时使用示例
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<! -- 分库分表 -->
<schema name="sheepdb" dataNode="dn1" checkSQLschema="false" sqlMaxLimit="100"></schema>
<table name="user" primaryKey="id" dataNode="dn1,dn2" rule="mod-long" autoIncrement="true" />
</schema>
<!-- 读写分离 -->
<schema name="Mingdb" dataNode="dn3" checkSQLschema="false" sqlMaxLimit="100"></schema>
<dataNode name="dn1" dataHost="localhost1" database="sheepdb" />
<dataNode name="dn2" dataHost="localhost2" database="sheepdb" />
<dataNode name="dn3" dataHost="localhost3" database="Mingdb" />
<!-- 分库分表 -->
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100" maxRetryCount="4">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.1.212:3307" user="root" password="123456">
</writeHost>
</dataHost>
<dataHost name="localhost2" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100" maxRetryCount="4">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM2" url="192.168.1.212:3308" user="root" password="123456">
</writeHost>
</dataHost>
<!-- 读写分离 -->
<dataHost name="localhost3" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100" maxRetryCount="4">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM3" url="192.168.1.212:3307" user="root" password="123456">
<readHost host="hostS3" url="192.168.1.212:3308" user="root" password="123456" />
</writeHost>
</dataHost>
</mycat:schema>