本篇来实现mysql在程序中的读写分离

使用到数据库中间件myCat,实现读写库的自动路由

服务器环境:
linux Centos 7
mysql8.0.21
服务器三台(一主一从)   
192.168.121.10 (主库)、
192.168.121.20 (从库)
192.168.121.30(mycat中间件)

三台机器均需安装同一版本mysql

数据库安装步骤参考linux安装mysql详细教程(远程连接)

下面主要讲myCat的安装部署

1、安装java环境(mycat基于java,已有则忽略)

#安装Java环境(mycat基于java)  已有则忽略
wget http://dl.mycat.io/jdk-8u20-linux-x64.tar.gz

# 解压到/usr/local
tar -zxcf jdk-8u20-linux-x64.tar.gz /usr/local
mv jdk-8u20-linux-x64 jdk

sudo vim /etc/profile
export JDK_HOME=/usr/local/jdk
export PATH=%PATH:$JDK_HOME/bin

# 保存退出
source /etc/profile

2、下载安装mycat(我mysql 8.0    下载的mycat 1.6.6)

#下载安装包
wget http://dl.mycat.io/1.6.6.1/Mycat-server-1.6.6.1-release-20181031195535-linux.tar.gz

#解压
tar -xvf Mycat-server-1.6.6.1-release-20181031195535-linux.tar.gz -C /usr/local

#配置环境变量
sudo vim /etc/profile
export MYCAT_HOME=/usr/local/mycat
export PATH=%PATH:$MYCAT_HOME/bin

#保存退出
source /etc/profile

3、开始修改配置文件

主要两个(schema.xml、server.xml)

server.xml:定义用户以及系统相关变量,如端口等

schema.xml:定义逻辑库,表、分片节点等内容

rule.xml:定义分片规则

server.xml:

主要修改下面两个<user>内的用户名、密码、库名

还有<property name="useOffHeapForMerge">0</property>   为0   默认是1开启

[root@centos7 conf]# cat 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">2</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">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>
		
	</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"/>
	     <host host="172.*" user="root"/>
	   </whitehost>
       <blacklist check="false">
       </blacklist>
	</firewall>


<!-- 登陆用户名, 即MyCat连接用户名 -->

<!-- 写入帐号的配置 -->
	<user name="用户1" defaultAccount="true">
        <!-- 登陆密码, 即MyCat连接密码 -->
		<property name="password">密码</property>
        <!-- 数据库名, 即MyCat的逻辑库, 此处会与schema.xml的配置存在关联 -->
		<property name="schemas">库名</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="用户2">
		<property name="password">密码</property>
		<property name="schemas">库名</property>
		<property name="readOnly">true</property>
	</user>

</mycat:server>

schema.xml

修改逻辑库名,mycat访问地址ip、主库、从库ip、访问库的用户名密码

[root@centos7 conf]# cat schema.xml 
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

    <!-- 数据库设置,此数据库为逻辑数据库,name与server.xml中schemas对应 -->
    <!-- schema : 定义mycat实例中的逻辑库,也就是mycat服务中有数据库,mycat可以有多个逻辑库,每个逻辑库都有自己的相关配置 -->
    <!-- name : 逻辑数据库名,与server.xml中的schemas对应-->
    <!-- checkSQLschema : 数据库前缀相关设置,当该值为true时,例如我们执行语句select * from db_store.company 。mycat会把语句修改为 select * from company 去掉db_store -->
    <!-- sqlMaxLimit : 当该值设置为某个数值时,每条执行的sql语句,如果没有加上limit语句,Mycat会自动加上对应的值。不写的话,默认返回所有的值。
* 需要注意的是,如果运行的schema为非拆分库的,那么该属性不会生效。需要自己sql语句加limit -->
    <!-- 如果schema中没有table配置,需要指定dataNode属性 -->

	<schema name="库名" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"></schema>
	
    <!-- 节点配置 : 分片信息,也就是分库相关配置-->
    <!-- dataNode : 定义了mycat中的数据节点,也就是我们所说的数据分片。一个datanode标签就是一个独立的数据分片
    * 如下表述的意思为,使用名字为db_storeHOST数据库实例上的db_store物理数据库,这就组成一个数据分片,最后我们用db_store_dataNode来标示这个分片-->
    <!-- name : 定义数据节点的唯一名称, 在table标签上用这个名字建立表与分片对应的关系 -->
    <!-- dataHost : 用于定义该分片属于哪个数据库实例,属性与datahost标签上定义的name对应 -->
    <!-- database : 用于定义该分片属于数据库实例上的物理库,也就是真实的数据库名 -->

    <dataNode name="dn1" dataHost="mycatip地址" database="真实数据库名" />


    <!-- 节点主机配置 : 物理数据库,真正存储数据的数据库 -->
    <!-- 这个标签直接定义了具体数据库实例,读写分离配置和心跳语句 -->
    <!-- name : 唯一标示dataHost标签,供上层dataNode使用 -->
    <!-- maxCon : 指定每个读写实例连接池的最大连接 -->
    <!-- minCon : 指定每个读写实例连接池的最小连接 -->
    <!-- balance : 负载均称类型
    * 0 : 不开启读写分离机制,所有读操作都发送到当前可用的writeHost上
    * 1 : 全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1-S1,M2-S2 并且M1 M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡
    * 2 : 所有读操作都随机的在writeHost、readHost上分发
    * 3 : 所有读请求随机的分发到writeHst对应的readHost执行,writeHost不负担读写压力 -->
    <!-- writeType : 负载均衡类型
    * 0 : 所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个writeHost,重新启动后已切换后的为准,切换记录在配置文件中:dnindex.properties
    * 1 : 所有写操作都随机的发送到配置的 writeHost。1.5以后版本废弃不推荐 -->
    <!-- switchType : 节点切换方式
    * -1 : 不自动切换
    *  1 : 默认值 自动切换
    *  2 : 基于MySql主从同步的状态决定是否切换心跳语句为 show slave status
    *  3 :  基于mysql galary cluster 的切换机制(适合集群)1.4.1 心跳语句为 show status like 'wsrep%'-->
    <!-- dbType : 指定后端链接的数据库类型目前支持二进制的mysql协议,还有其他使用jdbc链接的数据库,例如:mongodb,oracle,spark等 -->
    <!-- dbDriver : 指定连接后段数据库使用的driver,目前可选的值有native和JDBC。使用native的话,因为这个值执行的是二进制的mysql协议,所以可以使用mysql和maridb,其他类型的则需要使用JDBC驱动来支持; 如果使用JDBC的话需要符合JDBC4标准的驱动jar 放到mycat\lib目录下 -->
    <!-- tempReadHostAvailable : 如果配置了这个属性 writeHost 下面的 readHost 仍旧可用,默认 0 可配置(0、1) -->
	<dataHost name="mycatip地址" maxCon="1000" minCon="10" balance="1" writeType="0"
            dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        
        <!-- 指明用于和后端数据库进行心跳检查的语句 -->
        <!-- mysql : 可以用select user()-->
        <!-- oracle : 可以用select 1 from dual-->
		
        <heartbeat>select user()</heartbeat>
		
        <!-- readHost/writeHost : 这两个标签都指定后端数据库的相关配置,用于实例化后端连接池。唯一不同的是,writeHost 指定写实例、readHost 指定读实例 -->
        <!-- host : 标识不同的示例, 一般 writeHost 我们使用*M1,readHost 我们用*S1 -->
        <!-- url : 后端实例连接地址。
        * Native:地址:端口
        * JDBC:jdbc的url -->
        <!-- user : 后端存储实例需要的用户名称 -->
        <!-- password : 后端存储实例需要的密码 -->
        <!-- weight : 权重, 配置在 readhost 中作为读节点的权重 -->
        <!-- usingDecrypt : 是否对密码加密,默认0(不加密)。具体加密方法看官方文档 -->
        <writeHost host="主库hostname" url="主库ip:3306" user="" password="">
			<!-- can have multi read hosts -->
			<readHost host="从库hostname" url="从库ip:3306" user="" password="" />
		</writeHost>
	
	</dataHost>
</mycat:schema>

修改完成

启动,bin目录下 ./mycat start

日志可查看 cat /usr/local/mycat/logs/wrapper.log

STATUS | wrapper  | 2021/11/29 12:40:06 | --> Wrapper Started as Daemon
STATUS | wrapper  | 2021/11/29 12:40:06 | Launching a JVM...
INFO   | jvm 1    | 2021/11/29 12:40:06 | Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=64M; support was removed in 8.0
INFO   | jvm 1    | 2021/11/29 12:40:07 | Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org
INFO   | jvm 1    | 2021/11/29 12:40:07 |   Copyright 1999-2006 Tanuki Software, Inc.  All Rights Reserved.
INFO   | jvm 1    | 2021/11/29 12:40:07 | 
INFO   | jvm 1    | 2021/11/29 12:40:09 | MyCAT Server startup successfully. see logs in logs/mycat.log

cat /usr/local/mycat/logs/mycat.log 查看正常输出

bin目录下 ./mycat status查看运行状态

其他问题

1.启动正常,mycat.log显示访问不通

set Error 1 DBHostConfig [hostName=centos20, url=*.*.*.*:3306]

2021-11-29 11:37:24.072 ERROR [$_NIOREACTOR-11-RW] (io.mycat.backend.heartbeat.MySQLHeartbeat.nextDector(MySQLHeartbeat.java:215)) - set Error 1  DBHostConfig [hostName=centos20, url=ip:3306]

查看是否主从库主机名hostname是否正确

[root@centos20 bin]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4 centos20
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6 centos20

2.查看使用的主从数据库用户权限是否开启

目前我安装部署遇见的两个问题,其他暂时没遇见,遇见再补充。。。。