Mycat

简洁

一、Mycat是什么 : 减轻数据库压力 实现 主从 分库分表

MyCat是一个开源的分布式数据库系统,是一个实现了MySQL协议的服务器,前端用户可以把它看作是一个数据库代理,用MySQL客户端工具和命令行访问,而其后端可以用MySQL原生协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信,其核心功能是分表分库,即将一个大表水平分割为N个小表,存储在后端MySQL服务器里或者其他数据库里。

MyCat发展到目前的版本,已经不是一个单纯的MySQL代理了,它的后端可以支持MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未来还会支持更多类型的存储。而在最终用户看来,无论是那种存储方式,在MyCat里,都是一个传统的数据库表,支持标准的SQL语句进行数据的操作,这样一来,对前端业务系统来说,可以大幅降低开发难度,提升开发速度。

我们的应用只需要一台数据库服务器的时候我们并不需要Mycat,而如果你需要分库甚至分表,这时候应用要面对很多个数据库的时候,这个时候就需要对数据库层做一个抽象,来管理这些数据库,而最上面的应用只需要面对一个数据库层的抽象或者说数据库中间件就好了,这就是Mycat的核心作用

mycat 可以理解为一个中间件 用来连接java java程序直接操作mycat 不需要操作后台的实际数据库

安装 默认端口号时8066

[地址](MyCATApache/Mycat-Server (github.com))

mycat命令

mycat install1

启动:

mycat start1

停止:

mycat stop1

重启:

mycat restart

配置文件的简洁

在conf目录下面有:我们主要使用前三个

  1. server.xml :

  2. 简单配置

    <!-- mycat对外提供服务的端口-->
    		<property name="serverPort">8066</property>
    		<!-- 主键生成策略
    			0、本地文件方式
    			1、数据库方式
    			2、时间戳序列方式
    			-->
    		<property name="sequnceHandlerType">2</property>
    		<!--分布式事务开关
    			0、为不过滤分布式事务
    			1、为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤)
    			2、为不过滤分布式事务,但是记录分布式事务日志
    			-->
    		<property name="handleDistributedTransactions">0</property>
    		<--登录名--/>
    	<user name="mycat" defaultAccount="true">
    		<property name="password">333</property>
    		<!-- 可以配置多个,逗号分割 ,schema配置文件要与之对应-->
    		<property name="schemas">mycatdb</property>逻辑库与schema文件对应
    
  3. 详细配置介绍

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
	<system>
		<!-- mycat对外提供服务的端口-->
		<property name="serverPort">8066</property>
		<!-- mycat管理端口-->
		<property name="managerPort">9066</property>
		<!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户-->
		<property name="nonePasswordLogin">0</property> 
		<property name="useHandshakeV10">1</property>
		<!-- 服务器有多个网卡,多个ip,指定要绑定的ip,0.0.0.0表示绑定所有-->
		<property name="bindIp">0.0.0.0</property>
		<!-- 前端写队列的大小 -->
		<property name="frontWriteQueueSize">4096</property>

		<!-- mycat默认字符集 -->
		<property name="charset">utf8</property>
		<!-- 连接mysql使用的隔离级别1、2、3、4,分别代表读未提交、读已提交、可重复读、串行化 -->
		<property name="txIsolation">3</property>
		<!-- mycat进程的数量,通常等于服务器CPU核数 -->
		<property name="processors">8</property>
		<!-- 前台应用访问mycat最大空闲时间,单位是毫秒 -->
		<property name="idleTimeout">300000</property>
		<!-- SQL执行超时时间,单位是秒 -->
		<property name="sqlExecuteTimeout">300</property>
		<!-- 如果SQL中没有指定limit,则会使用该参数来限制返回的结果集行数 -->
		<property name="defaultMaxLimit">100</property>
		<!-- mycat允许的最大packet大小 -->
		<property name="maxPacketSize">104857600</property>
		<!-- 1为开启实时统计、0为关闭 -->
		<property name="useSqlStat">0</property>  
		<!-- 1为开启全局表一致性检测、0为关闭 -->
		<property name="useGlobleTableCheck">0</property>
		<!-- 主键生成策略
			0、本地文件方式
			1、数据库方式
			2、时间戳序列方式
			-->
		<property name="sequnceHandlerType">2</property>
		
		<!-- 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false -->
		<property name="subqueryRelationshipCheck">false</property> 
		<!--1为开启mysql压缩协议-->
	    <property name="useCompression">1</property>
	    <!--设置模拟的MySQL版本号-->
	    <property name="fakeMySQLVersion">5.7.30</property>
		<property name="processorBufferChunk">40960</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>
		
		<!--分布式事务开关
			0、为不过滤分布式事务
			1、为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤)
			2、为不过滤分布式事务,但是记录分布式事务日志
			-->
		<property name="handleDistributedTransactions">0</property>
		<!-- off heap for merge/order/group/limit  1开启 0关闭-->
		<property name="useOffHeapForMerge">1</property>
        <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>
	</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="mycat" defaultAccount="true">
		<property name="password">333</property>
		<!-- 可以配置多个,逗号分割 ,schema配置文件要与之对应-->
		<property name="schemas">mycat</property>
		
		<!-- 表级 DML 权限设置 -->
		<!-- check表示是否启用权限控制-->	
		<privileges check="false">
			<!-- dml四个bit位分别代表insert、update、select、delete-->	
			<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>

</mycat:server>
  1. schema.xml :
  • 配置逻辑库逻辑表
  • 配置逻辑表所存储的数据节点
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

	<!-- 定义逻辑库
		name属性定义逻辑库的名称;
		checkSQLschema设置是否检查SQL语法
		sqlMaxLimit用于SQL语句未使用Limit时,限制返回的结果数量
	-->
	<schema name="mycatdb" checkSQLschema="false" sqlMaxLimit="1000">
		<!-- 定义逻辑表
			name属性定义逻辑表的名称,名称必须和物理数据库中的表名一致;
			primaryKey定义逻辑表的主键
			dataNode 水平分表
			rule定义使用哪种分片规则,对应rule.xml中<tableRule>节点的name
		-->
		<table name="goods" primaryKey="ID" type="global" dataNode="dn1"  rule="auto-sharding-long"/></table>
		<table name="user" primaryKey="ID" type="global" dataNode="dn2"  rule="auto-sharding-long"/></table>
		<table name="order" primaryKey="ID" type="global" dataNode="dn3"  rule="auto-sharding-long"/></table>
		<table name="money" primaryKey="ID" type="global" dataNode="dn4"  rule="auto-sharding-long"/></table>
	</schema>

	<!-- name属性定义数据节点的名称,必须唯一
		dataHost属性定义分片所在的物理主机(可能是一组集群)
		database表示后台真实存在的数据库名
	-->
	<dataNode name="dn1" dataHost="localhost1" database="goods" />
	<dataNode name="dn2" dataHost="localhost1" database="user" />
	<dataNode name="dn3" dataHost="localhost1" database="order" />
	<dataNode name="dn4" dataHost="localhost1" database="money" />
	
	<!-- 定义后端数据库主机信息:
		name属性必须唯一
		maxCon、minCon定义MyCAT连接数的最大值和最小值
		balance定义负载均衡策略,可选值为0、1、2、3
			* 0表示不读写分离机制(适合单机)
			* 1表示所有的readHost与stand by writeHost参与select语句的负载均衡(适用于多主多从模式)
			* 2表示所有的readHost和writeHost都参与select语句的负载均衡(适用于写请求压力不大时,让写节点参与读负载)
			* 3表示所有的readHost参与select语句的负载均衡(适用于一主多从模式)
		dbType定于数据库类型
		dbDriver可选值为native、jdbc
			* native表示mysql原生的通信协议
			* jdbc表示连接其他的关系型数据库或者非关系型数据库
			*switchType 配合心跳机制
			*slaveThreshold 从节点数量
	-->
	<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
	
		<!-- mycat对后端数据库进行心跳检测-->
		<heartbeat>select user()</heartbeat>
		
		<!-- 主从复制中的master节点 host 取值随意 唯一值  读节点-->
		<writeHost host="hostM1" url="localhost:3306" user="root" password="123456">
			<!-- 主从复制中的slave节点,必须定义在writeHost内部 写节点-->
			<readHost host="hostS2" url="localhost:3307" user="root" password="xxx" />
		</writeHost>
		
		<writeHost host="hostM1" url="localhost:3308" user="root" password="123456">
			<readHost host="hostS2" url="localhost:3309" user="root" password="xxx" />
		</writeHost>
	</dataHost>

</mycat:schema>
  1. rule.xml : 和schema 文件中的rule属性相匹配 表示 mycat拥有的
  2. ehcache.xml
  3. log4j2.xml

读写分离

  1. server文件同上
  2. schema文件

dataNode 表示数据库名 要和标签匹配 是映射到实际库中 值建议为dn1 唯一值

balance表示读写的策略

switchType 表示主服务器故障之后的操作

-1 不切换

1 默认值 (推荐)

2 基于msql主从同步的状态来决定是否切换

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

	<schema name="mycatdb" dataNode="dn1" checkSQLschema="false" sqlMaxLimit="1000">
		
	</schema>

	<dataNode name="dn1" dataHost="localhost1" database="goods" />
	
	<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="localhost:3306" user="root" password="123456">
			<readHost host="hostS2" url="localhost:3307" user="root" password="xxx" />
		</writeHost>
		<writeHost host="hostM1" url="localhost:3308" user="root" password="123456">
			<readHost host="hostS2" url="localhost:3309" user="root" password="xxx" />
		</writeHost>
	</dataHost>

</mycat:schema>

测试

在navicat中新建一个连接 用户名为mycat (你自己定义的名) 密码 地址

读写分离成功

水平拆分 : 一张表中的数据太多分散到不同的数据库中

1 配置server 文件 同上

2 修改schema文件

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

	<schema name="mycatdb" dataNode="dn1" checkSQLschema="false" sqlMaxLimit="1000">
	<--	name 表名 
		primaryKey 主键字段 
		autoIncrement 自动递增 
		dataNode 表示goods表将出现在那些物理库中
		rule 水平拆分的算法
		--/>
		<table name="goods" primaryKey="ID" type="global" autoIncrement="true" dataNode="dn1,dn2,dn3"  rule="auto-sharding-long"/>
	</schema>

	<dataNode name="dn1" dataHost="localhost1" database="goods1" />  database 表示实际物理库名 
	<dataNode name="dn2" dataHost="localhost1" database="goods2" />
	<dataNode name="dn3" dataHost="localhost1" database="goods3" />
	
	<--注意这里的dataHost 只是读写分离 水平拆分在前面已经完成了 --/>
	<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="localhost:3306" user="root" password="123456">
			<readHost host="hostS2" url="localhost:3307" user="root" password="xxx" />
		</writeHost>
		<writeHost host="hostM1" url="localhost:3308" user="root" password="123456">
			<readHost host="hostS2" url="localhost:3309" user="root" password="xxx" />
		</writeHost>
	</dataHost>

</mycat:schema>

垂直拆分 指的是本来应该放在一个库中的表放到不同的数据库中 以便于减轻数据库的压力

注 : 表示一张表的请求过高 另一张表的请求不高 但是 会导致 请求不高的表也会收到影响

1 server 文件同上

2 schame文件修改

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

	<schema name="mycatdb" dataNode="dn1" checkSQLschema="false" sqlMaxLimit="1000">
	<--	name 表名 
		primaryKey 主键字段 
		autoIncrement 自动递增 
		dataNode 表示goods表将出现在那些物理库中
		这里不需要水平拆分所以rule删除 如果需要 则加上 
		dataNode 对应的只是一个数据库
		--/>
		<table name="goods" primaryKey="ID" autoIncrement="true" dataNode="dn1"  />
		<table name="user" primaryKey="ID" autoIncrement="true" dataNode="dn2"  />
		<table name="order" primaryKey="ID" autoIncrement="true" dataNode="dn3"  />
	</schema>

	<dataNode name="dn1" dataHost="localhost1" database="goods" />  database 表示实际物理库名 
	<dataNode name="dn2" dataHost="localhost1" database="user" />
	<dataNode name="dn3" dataHost="localhost1" database="order" />
	
	<--注意这里的dataHost 只是读写分离 水平拆分在前面已经完成了 --/>
	<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="localhost:3306" user="root" password="123456">
			<readHost host="hostS2" url="localhost:3307" user="root" password="xxx" />
		</writeHost>
		<writeHost host="hostM1" url="localhost:3308" user="root" password="123456">
			<readHost host="hostS2" url="localhost:3309" user="root" password="xxx" />
		</writeHost>
	</dataHost>

</mycat:schema>

3 测试

成功之后所有的表会在逻辑库中显示 之后只要正常的面的mycat 操作就可以了

主键生成策略

本地文件方式

  1. 在server 文件中修改0
  2. 在conf/sequence_conf.properties 文件中维护信息
  3. 在sql语句中 添加next value for MYCATSEQ_xxxx
<insert id = "insert" parameterType="xxx">
	insert into user (id,name)values(next value for MYCATSEQ_GLOBAL,'zzy')
</insert>
  1. next value for MYCATSEQ_xxxx : xxxx 是从本地conf/sequence_conf.properties 文件中获取的

时间戳方式

  1. 在server 文件中修改2

这种方式 需要将主键设置为varchar类型 长度一般20 不推荐 第一浪费磁盘空间 第二 varchar 不能排序 索引收到影响