安装docker
- sudo apt-get update
- sudo apt-get install
apt-transport-https
ca-certificates
curl
software-properties-common - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
- sudo apt-key fingerprint 0EBFCD88
- sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
- sudo apt-get update
- sudo apt-get install docker-ce
- 启动
sudo systemctl enable docker
sudo systemctl start docker
解决docker需要sudo的问题
#如果还没有 docker group 就添加一个:
$sudo groupadd docker
#将用户加入该 group 内。然后退出并重新登录就生效啦。
$sudo gpasswd -a ${USER} docker
#重启 docker 服务
$systemctl restart docker
#切换当前会话到新 group 或者重启 X 会话
$newgrp - docker
#注意:最后一步是必须的,否则因为 groups 命令获取到的是缓存的组信息,刚添加的组信息未能生效,
#所以 docker images 执行时同样有错。
安装mysql
- pull mysql镜像
docker pull daocloud.io/library/mysql:5.7.31
- 启动 mysql docker(为了映射目录,后续就删除掉这个容器)
docker run -p 3306:3306 -d -e MYSQL_ROOT_PASSWORD=root 42cdba9f1b08
- 复制映射conf,log,data目录
docker cp 0f2e67c6930f:/etc/mysql/my.cnf /home/mysql/conf/ (不copy,直接在/home/mysql/conf/ 下建立目录和文件)
- my.cnf文件内容如下:
master:
[mysqld]
# 主机ID,唯一
server-id=107
# 开启及其设置二进制文件名称
log_bin=mysql-bin
# 要同步的库
binlog-do-db=guanjia
# 不需要同步的库
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
binlog-ignore-db=sys
# 设置logbin格式
binlog_format=MIXED # binlog日志格式,mysql默认采用statement,建议使用mixed
# 在作为从数据库的时候,有写入操作也要更新二进制文件
#log-slave-updates
# 表示自增字段的步长,默认值1,最大值65535
#auto-increment-increment=1 # 步长视情况需要修改
# 表示自增字段从哪个数开始
#auto-increment-offset=1
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
secure-file-priv= NULL
symbolic-links=0
!includedir /etc/mysql/conf.d/
slaver:
[mysqld]
# 主机ID,唯一
server-id=109
# 设置中继日志文件名称
relay-log=mysql-relay
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
secure-file-priv= NULL
symbolic-links=0
!includedir /etc/mysql/conf.d/
只复制目录,不能复制文件,否则会docker run可能会失败
docker cp c2ddffaaf905:/var/log/mysql /home/mysql/log
docker cp c2ddffaaf905:/var/lib/mysql /home/mysql/data
删除第2步mysql容器
启动mysql docker
# 启动mysql master
docker run -d -p 13306:3306 --name mysql_107 -e TZ="Asia/Shanghai" -e MYSQL_ROOT_PASSWORD=root \
-v /data/mysql/conf/my.cnf:/etc/mysql/my.cnf \
-v /data/mysql/log:/var/log/mysql \
-v /data/mysql/data:/var/lib/mysql \
42cdba9f1b08
# slaver
# -m 4096MB --memory-swap 0 限制内存。mysql设置了内存大小,这个设置就似乎不需要了!
docker run -d -p 13306:3306 --name mysql_109 -e TZ="Asia/Shanghai" -e MYSQL_ROOT_PASSWORD=root \
-v /data/mysql/conf/my.cnf:/etc/mysql/my.cnf \
-v /data/mysql/log:/var/log/mysql \
-v /data/mysql/data:/var/lib/mysql \
42cdba9f1b08
启动时可能会报错如下:
➜ mysql docker logs -f -t --tail -100f 3533435c2e8d
2021-04-06T03:18:08.231624560Z Initializing database
2021-04-06T03:18:08.237879949Z 2021-04-06T03:18:08.237775Z 0 [ERROR] --initialize specified but the data directory has files in it. Aborting.
2021-04-06T03:18:08.237896681Z 2021-04-06T03:18:08.237798Z 0 [ERROR] Aborting
2021-04-06T03:18:08.237900584Z
解决方法:将宿主机映射的/data/mysql/data目录的用户改成当前用户- 从库的root需要开放外部访问权限
use mysql;
create user 'root'@'%' identified by 'root';
grant all privileges on *.* to 'root'@'%' identified by 'root' ;
grant all privileges on *.* to 'root'@'%' identified by 'root' WITH GRANT OPTION;
FLUSH PRIVILEGES;
- 设置master
show master status;
create user 'slave1'@'%' identified by '123456';
grant replication slave on *.* to 'slave1'@'%';
flush privileges;
- 设置slave
change master to master_host='172.16.0.107', master_port=13306, master_user='slave1', master_password='123456', master_log_file='mysql-bin.000001', master_log_pos=154;
安装mycat
docker build -f mycat.dockfile -t ysmmycat/mycat:1.0 .
docker run -p 8066:8066 -it 2402236ef96c
docker cp 5ffa66d2ed76:/home/mycat/logs/ /data/mycat/
docker cp 5ffa66d2ed76:/home/mycat/conf/ /data/mycat/
最终启动
docker run -d -p 3306:8066 --name mycat_002 -e TZ="Asia/Shanghai" \
-v /home/mycat/conf:/home/mycat/conf \
-v /home/mycat/logs:/home/mycat/logs \
2402236ef96c
下面这2个文件,一定要注意了,搞不好就会导致select只读主库,不读从库
schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!--
name: 逻辑库名称
checkSQLschema: 当执行select * from guanjia.user;时,表名前制定了mycat逻辑库的名称
取值为true: mycat会把语句转换成 select * from user;
取值为false: 不会转换,可能会报错
sqlMaxLimit: sql语句中不指定limit时的最大查询数
dataNode: 配置数据库节点,用于配置该逻辑库默认的分片。
没有通过table标签配置的表,就会走到默认的分片上。
这里注意没有配置在table标签的表,用工具查看时无法显示的,但是可以正常使用。
如果没有配置dataNode属性,则没有配置在table标签的表是无法使用的。
-->
<schema name="guanjia" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
<!-- auto sharding by id (long) -->
<!--splitTableNames 启用<table name 属性使用逗号分割配置多个表,即多个表使用这个配置-->
<!-- <table name="travelrecord,address" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" splitTableNames ="true"/> -->
<!-- <table name="oc_call" primaryKey="ID" dataNode="dn1$0-743" rule="latest-month-calldate"
/> -->
</schema>
<!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
/> -->
<!--
数据分片节点
dataHost: 定义该数据分片节点属于哪个数据库主机
database: 定义该数据库分片节点属于哪个具体数据库实例上的具体库(即,对应mysql中实际的db)
-->
<dataNode name="dn1" dataHost="localhost1" database="guanjia" />
<!-- <dataNode name="dn2" dataHost="localhost1" database="db2" />
<dataNode name="dn3" dataHost="localhost1" database="db3" /> -->
<!--<dataNode name="dn4" dataHost="sequoiadb1" database="SAMPLE" />
<dataNode name="jdbc_dn1" dataHost="jdbchost" database="db1" />
<dataNode name="jdbc_dn2" dataHost="jdbchost" database="db2" />
<dataNode name="jdbc_dn3" dataHost="jdbchost" database="db3" /> -->
<!--
maxCon: 最大连接数
minCon: 最小连接数
balance: 负载均衡类型
0: 不开启读写分离,所有读操作都发送到当前可用的writeHost上
1: 全部的readHost与stand by的writeHost参与select语句的负载均衡
即,双主双从的情况下,备用writeHost参与select语句的负载均衡
2: 所有select语句都随机的分配到writeHost与readHost
3: 所有select语句都随机负载到writeHost对应的readHost,writeHost不负担select压力。(只在1.4及其之后的版本才有)
writeType:
0: 所有的写操作都发送到第一个writeHost,第一个宕机会切到下一个writeHost,重启之后以切换后的为准,切换记录在配置文件:dnindex.properties里
1: 所有写操作都随机发送到配置的writeHost,1.5后不推荐。
dbType: 指定后端连接的数据库类型,目前支持二进制的mysql协议,还有其他使用jdbc连接的数据库。例如mongodb,oracle,spark等。
dbDriver: 指定连接后端数据库使用的Driver,目前可选的值有native和JDBC。
使用native时,因为这个值执行的是二进制的mysql协议,所以可以使用mysql和maridb。
其他类型的数据库则需要使用JDBC驱动来支持
switchType:
-1: 表示不自动切换
1: 默认值,自动切换
2: 基于MySQL主从同步的状态决定是否切换,心跳语句为show slave status
3: 基于MySQL galary cluster的切换机制(适合集群)
slaveThreshold: 配置的MySQL与MyCat心跳
-->
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostMaster1" url="172.16.0.107:13306" user="guanjia"
password="guanjia_aoyuan#$">
<!-- readHost里的user要用root,如果用demo的话,会导致从writeHost读数据 -->
<readHost host="hostSlave1" url="172.16.0.109:13306" user="root"
password="root">
</readHost>
</writeHost>
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
<!--
<dataHost name="sequoiadb1" maxCon="1000" minCon="1" balance="0" dbType="sequoiadb" dbDriver="jdbc">
<heartbeat> </heartbeat>
<writeHost host="hostM1" url="sequoiadb://1426587161.dbaas.sequoialab.net:11920/SAMPLE" user="jifeng" password="jifeng"></writeHost>
</dataHost>
<dataHost name="oracle1" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="oracle" dbDriver="jdbc"> <heartbeat>select 1 from dual</heartbeat>
<connectionInitSql>alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'</connectionInitSql>
<writeHost host="hostM1" url="jdbc:oracle:thin:@127.0.0.1:1521:nange" user="base" password="123456" > </writeHost> </dataHost>
<dataHost name="jdbchost" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="mongodb" dbDriver="jdbc">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM" url="mongodb://192.168.0.99/test" user="admin" password="123456" ></writeHost> </dataHost>
<dataHost name="sparksql" maxCon="1000" minCon="1" balance="0" dbType="spark" dbDriver="jdbc">
<heartbeat> </heartbeat>
<writeHost host="hostM1" url="jdbc:hive2://feng01:10000" user="jifeng" password="jifeng"></writeHost> </dataHost> -->
<!-- <dataHost name="jdbchost" maxCon="1000" minCon="10" balance="0" dbType="mysql"
dbDriver="jdbc"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1"
url="jdbc:mysql://localhost:3306" user="root" password="123456"> </writeHost>
</dataHost> -->
</mycat:schema>
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="ignoreUnknownCommand">0</property><!-- 0遇上没有实现的报文(Unknown command:),就会报错、1为忽略该报文,返回ok报文。
在某些mysql客户端存在客户端已经登录的时候还会继续发送登录报文,mycat会报错,该设置可以绕过这个错误-->
<property name="useHandshakeV10">1</property>
<property name="removeGraveAccent">1</property>
<property name="useSqlStat">0</property> <!-- 1为开启实时统计、0为关闭 -->
<property name="useGlobleTableCheck">0</property> <!-- 1为开启全加班一致性检测、0为关闭 -->
<property name="sqlExecuteTimeout">300</property> <!-- SQL 执行超时 单位:秒-->
<property name="sequnceHandlerType">1</property>
<!--<property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>
INSERT INTO `travelrecord` (`id`,user_id) VALUES ('next value for MYCATSEQ_GLOBAL',"xxx");
-->
<!--必须带有MYCATSEQ_或者 mycatseq_进入序列匹配流程 注意MYCATSEQ_有空格的情况-->
<property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>
<property name="subqueryRelationshipCheck">false</property> <!-- 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false -->
<property name="sequenceHanlderClass">io.mycat.route.sequence.handler.HttpIncrSequenceHandler</property>
<!-- <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="dataNodeIdleCheckPeriod">300000</property> 5 * 60 * 1000L; //连接空闲检查
<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">0</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>
<!--如果为0的话,涉及多个DataNode的catlet任务不会跨线程执行-->
<property name="parallExecute">0</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="root" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">guanjia</property>
<property name="defaultSchema">guanjia</property>
<!--No MyCAT Database selected 错误前会尝试使用该schema作为schema,不设置则为null,报错 -->
<!-- 表级 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>
<property name="defaultSchema">TESTDB</property>
</user>
</mycat:server>
1主1从在不停机的前提下,增加1从
master: 107
slaver: 109
新增slaver: 103
- 锁107的表:
mysql> flush tables with read lock;
- dump数据库
mysqldump -udemo -pdemo --routines --databases guanjia > /var/log/mysql/sqldump_guanjia_107.sql
--routines:导出存储过程和函数
--single_transaction:导出开始时设置事务隔离状态,并使用一致性快照开始事务,然后unlock tables;而lock-tables是锁住一张表不能写操作,直到dump完毕。
--master-data:默认等于1,将dump起始(change master to)binlog点和pos值写到结果中,等于2是将change master to写到结果中并注释。
导入从库数据,测试从库表是否可用
注意:宿主机上mysql的data目录的用户是999,否则会导入失败。查看master状态,show master status; 看master_log_file与master_log_pos
设置slave103, 注意master_log_file与master_log_pos的值与master的一致
change master to master_host='172.16.0.107', master_port=13306, master_user='slave1', master_password='123456', master_log_file='mysql-bin.000001', master_log_pos=800503194;
- 测试同步状态
- 解锁master107
# 解锁:
unlock tables;
- 修改mycat的schema.xml文件,在<writerHost>节点下增加一个<readHost>节点
- 测试mycat是否读第二个个从库103