经过前面的几篇文章
[MyCat入门篇-使用案例1:读写分离(part1)]
[MyCat入门篇-使用案例1:读写分离(part2)]
[MyCat入门篇-使用案例1:读写分离(part3)]
我们已经把MySQL组从复制的集群环境准备好了,现在才开始结合nycat真正的配置读写分离。
配置读写分离
我们前面已经搭建好MySQL主从同步的集群环境,现在结合mycat来配置读写分离的功能。
mycat根据我们的SQL语句自动去连接对应的MySQL的写节点和读节点,避免了我们在应用程序中自己去增加连接数据源的判断。
我们让M1和M2作为写入节点,S1和S2作为读取节点。这样所有的写操作都分发到M1或者M2上;所有的读操作都分发到S1或S2上。
准备配置文件
我们要使用容器启动部署mycat。
为了方便修改mycat的配置文件,我们把mycat的配置文件目录"mycat/conf"和日志文件目录"mycat/logs"都挂载到本地的"/docker_mycat_conf/mycat1/conf"和"/docker_mycat_conf/mycat1/logs"上。
这在本地修改完成配置文件后,把重启重新启动一下就可以验证我们的修改是否生效,这样很方便。
我们把安装当初构建mycat镜像的时候使用的mycat安装包解压一下,里面有初始化的conf目录,把那个conf目录下面的所有的配置文件都拷贝到本地的“~/docker_mycat_conf/mycat1/conf”目录下面去。这样我们基于这样的初始化配置文件,根据我们的实际需求去修改对应的配置文件,然后就可以启动mycat容器了。
配置server.xml
在server.xml中,我们需要配置两个地方,如下:
- mycat的服务端口
- mycat的管理端口
- 连接mycat的使用的用户名和密码
- useHandshakeV10参数的配置
配置好的server.xml文件如下所示,这里的配合值保留最简配置,把安装包中默认的配置能删除的都删除了。目的只为了测试读写分离,为了避免出现其他异常问题。就使用最简单的配置内容。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<system>
<!--
是否使用HandshakeV10Packet来与client进行通讯, 1:是 , 0:否(使用HandshakePacket)
使用HandshakeV10Packet为的是兼容高版本的jdbc驱动, 后期稳定下来考虑全部采用HandshakeV10Packet来通讯
这里需要配置为1,选择使用V10,否则在登录mycat的时候,提示密码错误。
ERROR 1045 (HY000): Access denied for user 'mycat', because password is error
-->
<property name="useHandshakeV10">1</property>
<property name="serverPort">8066</property><!-- mycat提供访问服务使用的端口 -->
<property name="managerPort">9066</property><!-- mycat管理端使用的端口 -->
</system>
<!-- mycat读写用户的配置 -->
<user name="mycat">
<property name="password">mycat</property>
<property name="schemas">mycat_db</property>
<property name="defaultSchema">mycat_db</property>
</user>
<!-- mycat只读用户的配置 -->
<user name="mycat_ro">
<property name="password">mycat_ro</property>
<property name="schemas">mycat_db</property>
<!-- 指定的该参数,则表示该用户只能读取,不能写入。 -->
<property name="readOnly">true</property>
<property name="defaultSchema">mycat_db</property>
</user>
</mycat:server>
遇到的问题:
登录mycat的时候,提示如下错误:
➜ ~ mysql -umycat -pmycat -P8041 -h127.0.0.1 --default-auth=mysql_native_password
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (HY000): Access denied for user 'mycat', because password is error
仔细排查后发现一个参数配置的问题。useHandshakeV10参数没有配置。关于这个参数看了一下原码中的注释信息如下:
配置后的server.xml文件如下图所示:
配置schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="mycat_db" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"></schema>
<dataNode name="dn1" dataHost="localhost1" database="mysql_db" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0"
dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="172.19.0.11:3306" user="root" password="root">
<readHost host="hostS1" url="172.19.0.12:3306" user="root" password="root" />
</writeHost>
<writeHost host="hostM2" url="172.19.0.21:3306" user="root" password="root">
<readHost host="hostS2" url="172.19.0.22:3306" user="root" password="root" />
</writeHost>
</dataHost>
</mycat:schema>
配置后schema.xml文件截图如下所示:
配置日志文件log4j2.xml
设置mycat日志级别为debug级别,便于验证读写分离。
把level的值由info,改为debug
<asyncRoot level="debug" includeLocation="true">
<!--<AppenderRef ref="Console" />-->
<AppenderRef ref="RollingFile"/>
</asyncRoot>
修改后的日志配置文件如下:
创建MySQL数据库
在动mycat之前,要确保mycat代理的MySQL数据库已经在后面的MySQL数据库实例中创建好,否则在启动mycat之后,mycat会连接不到后面真实的MySQL数据库。
这里我们创建一个数据库名称是:mysql_db在master1节点上。
启动mycat容器
以上配置好后,启动mycat容器,如果启动失败可以在logs/mycat.log和logs/console.log日志文件中查看详细原因。
启动的时候,指定并挂载上mycat的配置文件目录和日志目录。
- 通过如下命令启动mycat容器
docker run --net=mysql-cluster-network --hostname mycat1.mycat --ip 172.19.0.41 --name mycat-mycat1 -d -v /Users/fengwenjian/docker_mycat_conf/mycat1/conf:/usr/local/mycat/conf -v /Users/fengwenjian/docker_mycat_conf/mycat1/logs:/usr/local/mycat/logs -p 8041:8066 -p 9041:9066 mycat:v1.6.7.5
- 查看启动结果
docker ps
- 具体示例如下所示:
➜ ~ docker run --net=mysql-cluster-network --hostname mycat1.mycat --ip 172.19.0.41 --name mycat-mycat1 -d -v /Users/fengwenjian/docker_mycat_conf/mycat1/conf:/usr/local/mycat/conf -v /Users/fengwenjian/docker_mycat_conf/mycat1/logs:/usr/local/mycat/logs -p 8041:8066 -p 9041:9066 mycat:v1.6.7.5
18f0b25e2bf4db59bd7c8dea7c9bd70235483d777ab630d5b8f8ffcc592ef3b8
➜ ~
➜ ~ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
18f0b25e2bf4 mycat:v1.6.7.5 "/usr/local/mycat/bi…" 2 seconds ago Up 2 seconds 0.0.0.0:8041->8066/tcp, 0.0.0.0:9041->9066/tcp mycat-mycat1
87e4940f6e2c mysql:5.7.31 "docker-entrypoint.s…" 22 hours ago Up 14 hours 33060/tcp, 0.0.0.0:3322->3306/tcp mysql-slave2
0756b65f1188 mysql:5.7.31 "docker-entrypoint.s…" 22 hours ago Up 14 hours 33060/tcp, 0.0.0.0:3321->3306/tcp mysql-master2
cb5c2dbb291b mysql:5.7.31 "docker-entrypoint.s…" 22 hours ago Up 14 hours 33060/tcp, 0.0.0.0:3312->3306/tcp mysql-slave1
f3a642b89001 mysql:5.7.31 "docker-entrypoint.s…" 22 hours ago Up 14 hours 33060/tcp, 0.0.0.0:3311->3306/tcp mysql-master1
➜ ~
- 查看mycat的启动日志
➜ mycat1 cat logs/console.log
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=64M; support was removed in 8.0
MyCAT Server startup successfully. see logs in logs/mycat.log
➜ mycat1
验证读写分离的效果
- 使用下面命令登录mycat服务的连接端口
mysql -umycat -pmycat -P8041 -h127.0.0.1 --default-auth=mysql_native_password
当我们想要连接到mycat服务的时候,就是通过上面的命令行去连接上去,mycat正常启动且正常连接后,然后就可以像连接到MySQL的命令行界面一样执行各种SQL语句了。
- 使用下面命令登录mycat服务的管理端口
mysql -umycat -pmycat -P9041 -h127.0.0.1 --default-auth=mysql_native_password
mycat的管理端口,一般情况下面我们不需要连接上去进行任何操作,只有当我们对mycat的配置文件进行了修改,但是想不重启mycat服务的情况下还想让修改的配置文件生效,此时就需要登录到mycat的关联端口9066然后去执行一些reload的命令,使得刚修改的配置文件在不重启mycat的情况下重新加载生效。
注意:并不是对mycat配置文件所有的修改都可以通过登录到9066端口执行reload操作使其生效。有些修改也需要重启mycat服务才可以生效。
具体哪些可以生效哪些不可以生效这个留在以后有时间在给大家分享一下。
我们该如何验证我们的SQL语句被mycat发送到哪个MySQL节点呢?这才是我们最关心的问题。
因为我们在前面已经把mycat的日志级别调整为debug级别,所以可以使用tail -f logs/mycat.log的命令再结合grep命令动态的观察具体每个SQL语句是被发送到哪个节点的。
如果没有打开日志的debug级别,那么则不好从mycat的日志文件中判断它是如何分发SQL语句的。所以建议前面的修改日志级别的步骤不能省略。
当然这是做POC验证,所以打开debug级别的日志,但是到真正的生产环境中,建议不要打开debug日志,保持在info级别的日志就OK。
- 观察写的SQL语句分发到哪个节点使用如下命令:
tail -f logs/mycat.log| grep "select write source"
- 观察读的SQL语句分发到哪个节点使用如下命令:
tail -f logs/mycat.log| grep "select read source"
此时我们可以开启三个命令行窗口:
- 一个用来连接到mycat的8041端口对mycat进行读写操作。
- 一个用来观察mycat日志输出中写操作会连接到哪个节点。
- 一个用来观察mycat日志输出中读操作会连接到哪个节点。
然后再8041端口解密中执行各种读写操作,然后观察另外两个窗口的输出即可。
双主双从,S1是M1的备库,S2是M2的备库;M1和M2互为主备,网络拓扑如下:
经过反复测试验证,基于上述的架构M1->S1;M2->S2; M1<->M2;此种情况下,得到的最后结论如下表所示:
序号 | balance的值 | writeType的值 | 可写节点 | 可读节点 |
---|---|---|---|---|
1 | 0 | 0 | M1 | M1 |
2 | 1 | 0 | M1 | M2、S1、S2 |
3 | 2 | 0 | M1 | M1、M2、S1、S2 |
4 | 3 | 0 | M1 | S1、S2 |
5 | 0 | 1 | M1、M2 | M1、M2 |
6 | 1 | 1 | M1、M2 | M2、S1、S2 |
7 | 2 | 1 | M1、M2 | M1、M2、S1、S2 |
8 | 3 | 1 | M1、M2 | S1、S2 |
下面是balance和writeType各个值的含义:
- balance
- 等于0:不开启读写分离机制,所有读操作都发送到当前可用的writeHost机器上。读都发送到M2上,或者都发送到M1上。哪个是当前可用的writeHost,读就发送到那个writHost上。
- 等于1:全部的readHost和writeHost都参与读的负载,都会分担到查询语句。读都发送到M1、S1、S2三个节点上。哪个是当前可用的writeHost,读就不会发送到那个writHost上。
- 等于2:所有的读操作都随机的分发到writeHost和readHost上。读都发送到M1、M2、S1、S2四个节点上。写节点也会分担读的压力,适合写压力不大的场景。
- 等于3:所有的读操作都发送到writeHost对应的readHost上执行,writeHost不分担读的压力。mycat1.4以后的版本才支持。读都发送到S1、S2两个节点上。写节点不会分担读的压力,适合写压力大的场景。writeType=0写也只会写中活跃的一个writeHost。不会轮询的向两个写的节点写入数据。另外一个只有当活动的writeHost挂掉之后才会承担写的压力。writeType=1的时候会轮询写。
- writeType
- 等于0:所有的写操作都发送到第一个writeHost上,当第一个writeHost挂了之后,才会自动切换第二个writeHost上。第一个writeHost恢复之后,也不会自动的切换回来。
- 等于1,所有的写操作随机的分发到所有的writeHost上。但是mycat1.5以后不再推荐使用这个等于1的配置。这个参数将会被废弃。不过目前1.6.7.5这个版本,该参数仍然有效。
到这里我们已经基于mycat数据库中间件和MySQL主从复制集群,一步步搭建了MySQL读写分离的环境。
接下来我们会继续MySQL集成mycat对数据库进行垂直拆分的实验环境。
敬请期待…
微信搜索“coder-home”或扫一扫下面的二维码,
关注公众号,第一时间了解更多干货分享,还有各类视频教程资源。扫描它,带走我