MyCat


  

1 MyCat背景

  Mycat的前身是阿里巴巴大名鼎鼎的Cobar,Cobar在开源了一段时间后,就没有再维护了,阿里巴巴放弃了该项目,再加上Cobar在使用过程中也发现存在一些问题;2013年国内一批开源软件爱好者对Cobar这个项目进行了改进,并命名为Mycat,这就是MyCat的诞生。
  MyCat是完全免费开源的,不属于任何商业公司。Mycat于2014年首次在上海的《中华架构师》大会上对外宣讲,随后越来越多的项目采用了Mycat;截至2015年11月,超过300个项目采用Mycat,涵盖银行、电信、电子商务、物流、移动应用、O2O的众多领域和公司;
  Mycat官网:http://www.mycat.io/

2 MyCat是什么

Mycat是一个开源数据库中间件;

什么是中间件?
比如你带了一些家乡的特产打算送给一个朋友,那么怎么送给你的朋友?

第一方式不用中间件:
你亲自坐车到你朋友家,把特产送给你的朋友,或者是你朋友来你家取这些特产;

第二种方式使用中间件:
你叫一个快递,把这些特产同城邮寄给你的朋友,那么这个快递员就充当中间件的角色。

  Mycat是一个实现了MySQL协议的的数据库中间件服务器,我们可以把它看作是一个数据库代理,用MySQL客户端工具和命令行访问Mycat,而Mycat再使用MySQL原生(Native)协议与多个MySQL服务器通信;
  Mycat也可以使用JDBC协议与大多数主流数据库服务器通信,包括SQL Server、Oracle、DB2、PostgreSQL 等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未来还会支持更多类型的存储;
  一般地,Mycat主要用于代理MySQL数据库,虽然它也支持去访问其他类型的数据库;Mycat的默认端口是8066,可以使用常见的对象映射框架比如MyBatis操作Mycat;

3 Mycat主要能做什么

1、数据库的读写分离
  通过Mycat可以自动实现读写分离,写数据时操作主数据库,读数据时操作从数据库,这样能有效地分摊数据库压力;当主数据库出现故障后,Mycat能自动切换到另一个主数据库上,进而提供高可用的数据库服务,当然这需要部署多主多从的模式;

2、数据库分库分表
  分库分表指的是对数据库数据的拆分;
  分库分表分为两种:水平拆分和垂直拆分;
  一种是根据表中数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库服务器上面,这种切分称之为数据的水平切分,也可以称为横向切分;
  一种是按照不同的表来切分到不同的数据库服务器之上,这种切可以称之为数据的垂直切分,也可以称为纵向切分;
  性能有瓶颈了,可以读写分离;
  数据库容量有瓶颈了,可以分库分表

3 Mycat环境搭建

1、下载:

http://dl.mycat.io/1.6-RELEASE/
wget http://dl.mycat.io/1.6-RELEASE/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz

2、下载后解压即可:

tar  –zxvf  Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz  –C  /usr/local

3、解压后即安装完成;

Java语言开发的,直接解压即可使用:
tomcat
maven
zookeeper
activemq
mycat

4 Mycat日常管理

4.1 Mycat启动和关闭

Mycat启动

切换到mycat的bin路径下
./mycat start
mycat安装后需要配置,然后才能启动

Mycat关闭

切换到mycat的bin路径下
./mycat stop

4.2 Mycat命令行

登录mycat,可以使用mysql的命令行工具来操作:
./mysql -umycat -p -P8066 -h127.0.0.1
mycat默认数据访问端口是8066

4.3 MyCat配置文件

1、server.xml

主要用于配置mycat的服务器信息
常用配置:
1、配置序列生成方式(数据库表的主键生成方式)
2、配置mycat逻辑数据库
3、配置mycat的访问账户和密码

2、schema.xml

用于配置逻辑数据库的映射、表、分片规则、数据结点及真实的数据库信息;
常用配置:
1、配置逻辑库映射
2、配置水平切分的表
3、配置垂直切分的表
4、配置真实的数据库
5、配置读写结点

5 Mycat读写分离

1、配置server.xml文件

设置连接mycat时的用户名和密码, 逻辑库:
<user name="mycat">
     <property name="password">123456</property>
     <property name="schemas">mycatdb</property>
</user>

参考配置

<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">

	<system>
		<property name="useSqlStat">0</property>  <!-- 1为开启实时统计、0为关闭 -->
		<property name="useGlobleTableCheck">0</property>  <!-- 1为开启全加班一致性检测、0为关闭 -->
		<property name="sequnceHandlerType">2</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-->
		<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">1m</property>
		<!--
			单位为k
		-->
		<property name="spillsFileBufferSize">1k</property>
		<property name="useStreamOutput">0</property>
		<!--
			单位为m
		-->
		<property name="systemReserveMemorySize">384m</property>
		<!--是否采用zookeeper协调切换  -->
		<property name="useZKSwitch">true</property>
	</system>
	
	<!-- 全局SQL防火墙设置 -->
	<!-- 
	<firewall> 
	   <whitehost>
	      <host host="127.0.0.1" user="mycat"/>
	      <host host="127.0.0.2" user="mycat"/>
	   </whitehost>
       <blacklist check="false">
       </blacklist>
	</firewall>
	-->
	
	<!-- 配置mycat的访问账号 -->
	<user name="mycat">
		<property name="password">123456</property>
		<!-- mycat的逻辑数据库 -->
		<property name="schemas">mycatdb</property>
		
		<!-- 表级 DML 权限设置 -->
		<!-- 		
		<privileges check="false">
			<schema name="mycatdb" dml="0110" >
				<table name="tb01" dml="0000"></table>
				<table name="tb02" dml="1111"></table>
			</schema>
		</privileges>		
		-->
	</user>

	<!-- 配置mycat的访问账号 -->
	<user name="user">
		<property name="password">123456</property>
		<property name="schemas">mycatdb</property>
		<property name="readOnly">true</property>
	</user>

</mycat:server>

2、配置schema.xml文件
2.1、配置schema

作用:schema用于配置逻辑库
只做读写分离,不做分库分表,则schema标签里面不用配置table;
给schema标签加上属性dataNode,配置dataNode的名字(name);
最终配置如下:
<!--schema配置逻辑数据库与真实数据库的映射-->
<schema name="mycatdb" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"/>

2.2、配置dataNode

作用:dataNode定义了MyCat中的数据节点,也就是我们通常说所的数据分片,
一个dataNode标签就是一个独立的数据分片,通俗理解,一个分片就是一个物理数据库;
配置说明:
name 定义数据节点的名字,这个名字需要是唯一的,这个名字在schema里面会使用到;
dataHost用于定义该分片属于哪个数据库实例的,属性值是引用dataHost标签上定义的name属性;
database用于对应真实的数据库名,必须是真实存在的;
最终配置如下:
<dataNode name="dn1" dataHost="localhost1" database="workdb" />

2.3、配置dataHost

作用:定义具体的数据库实例、读写分离配置和心跳语句;
balance属性:
负载均衡类型,目前的取值有4种:
1. balance="0", 不开启读写分离机制,所有读操作都发送到当前可用的writeHost上;
2. balance="1",全部的readHost与stand by writeHost参与select语句的负载均衡,
	简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与 M2互为主备),正常情况下,
	M2,S1,S2都参与select语句的负载均衡。
3.balance="2",所有读操作都随机的在writeHost、readhost上分发;
4.balance="3",所有读请求随机的分发到wiriterHost对应的readhost执行,writerHost
  不负担读压力;
推荐balance设置为1;
switchType属性:
1.用于指定主服务器发生故障后的切换类型:
2.-1 表示不自动切换 1 默认值,自动切换 2 基于MySQL主从同步的状态决定是否切换
	3 基于MySQL galary cluster的切换机制(适合集群)(1.4.1)
通常情况下,我们MySQL采用双主双从的模式下,switchType为1即可。
因为双主从模式下,主从同步关系很复杂,不能根据MySQL的状态来切换。
只需要在一个主出问题后,切换到另外的主。
heartbeat标签
1.用于和后端数据库进行心跳检查的语句
2.当switchType为1时,mysql心跳检查语句是select user()
3.switchType为2时,心跳检查语句是show slave status
writeHost与readHost标签:
1. 这两个标签都指定后端数据库的相关配置给mycat,用于实例化后端连接池。唯一不同的是,
	writeHost指定写实例、readHost指定读实例,组合这些读写实例来满足系统的要求。
2.在一个dataHost内可以定义多个writeHost和readHost。但是,如果writeHost指定的后端
	数据库宕机,那么这个writeHost绑定的所有readHost都将不可用。另一方面,由于这个
	writeHost宕机系统会自动的检测到,并切换到备用的writeHost上去。

一主三从配置参考:

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

	<schema name="mycatdb" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
		<!-- 只实现读写分离,没有涉及到分库分表,那么<schema>标签下不需要配置任何表 -->
	</schema>

	<!--配置真实的数据库名称 test01 -->
	<dataNode name="dn1" dataHost="localhost1" database="test01" />

	<!--配置具体的数据库连接信息、读写分离、心跳语句 -->
	<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="hostM3307" url="localhost:3307" user="root" password="123456">
			<!--配置写数据库下的读数据库(从库)-->
			<readHost host="hostS3308" url="localhost:3308" user="root" password="123456" />
			<readHost host="hostS3309" url="localhost:3309" user="root" password="123456" />
			<readHost host="hostS3310" url="localhost:3310" user="root" password="123456" />
		</writeHost>
		
	</dataHost>
</mycat:schema>

双主双从配置参考

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

	<!--schema配置逻辑数据库与真实数据库的映射-->
	<schema name="mycatdb" checkSQLschema="false" sqlMaxLimit="1000" dataNode="dn1">
		
		<!---3307主、3308主、3309从、3310从-->
		
		<!---读写分离,在schema标签下不需要配置table,当分库分表的时候才需要配置table-->
	</schema>

	<!---3307主、3308主、3309从、3310从-->
	<dataNode name="dn1" dataHost="localhost1" database="test01" />

	<!--
		1、balance="1" 开启读写分离,如果是0表示没有开启读写分离
		2、switchType="1" 故障切换类型,1代表自动切换
	-->
	<dataHost name="localhost1" 
			  maxCon="1000" 
			  minCon="10" 
			  balance="1"
			  writeType="0" 
			  dbType="mysql" 
			  dbDriver="native" 
			  switchType="1"  
			  slaveThreshold="100">
		
		<!--心跳语句 检查服务器有没有故障-->
		<heartbeat>select user()</heartbeat>
		
		<!---主库3307-->
		<writeHost host="hostM3307" url="localhost:3307" user="root" password="123456">
			<!---从库3309-->
			<readHost host="hostS3309" url="localhost:3309" user="root" password="123456" />
			<!---从库3308-->
			<readHost host="hostS3308" url="localhost:3308" user="root" password="123456" />
		</writeHost>
		
		<!---主库3308-->
		<writeHost host="hostM3308" url="localhost:3308" user="root" password="123456">
			<!---从库3310-->
			<readHost host="hostS3310" url="localhost:3310" user="root" password="123456" />
			<!---从库3307-->
			<readHost host="hostS3307" url="localhost:3307" user="root" password="123456" />
		</writeHost>
		
	</dataHost>
	
</mycat:schema>

3 测试读写分离
1、配置好MySQL主从复制并启动主从MySQL;
2、启动Mycat:/usr/local/mycat/bin/mycat start
3、登录Mycat:mysql -uroot -p -P8066 -h 192.168.230.129
4、mycat默认数据访问端口是8066
5、use mycatdb;
6、创建表,插入数据,观察MySQL数据的情况;

 insert into orders (id, money) values (next value for MYCATSEQ_GLOBAL, 105);

7、在从库中创建一个表tables,从库数据不会同步到主库;
8、然后通过mycat往tables中插入数据,观察是否能插入成功,若不能成功,表示已经实现了读写分离;
9、然后,关闭主MySQL3308的服务;
10、在这里再进行数据插入,观察其它MySQL实例数据同步情况。
11、最后,把3308启动,再观察数据能不能同步到3308和它的从节点;
12、主节点的自动切换,会记录在文件dnindex.properties在停掉3306主之前,cat一下该文件的内容;停掉之后,再cat一下;

6 MyCat分库分表(水平)

1、配置server.xml

指定主键生成策略
<property name="sequnceHandlerType">1</property>

指定使用Mycat全局序列的类型:
0为本地文件方式,1为数据库方式,2为时间戳序列方式

2、配置schema.xml
指定逻辑库,分片结点,结点主机等

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

	<!--schema配置逻辑数据库与真实数据库的映射-->
	<schema name="mycatdb" checkSQLschema="false" sqlMaxLimit="1000">
		
		<!---3307主、3308主、3309从、3310从-->
		
		<!---水平切分,需要在schema标签下需要配置需要对哪个table进行水平切分, orders表有1000万数据需要水平切分-->
		
		<!--rule="mod-long"指定切分的规则,取模的规则 表的id % 4 = 余数-->
		<table name="orders" primaryKey="id" dataNode="dn1,dn2,dn3,dn4" rule="mod-long" />
		
	</schema>

	<!---3307主、3308主、3309从、3310从-->
	<dataNode name="dn1" dataHost="localhost1" database="test01" />
	<dataNode name="dn2" dataHost="localhost1" database="test02" />
	<dataNode name="dn3" dataHost="localhost1" database="test03" />
	<dataNode name="dn4" dataHost="localhost1" database="test04" />

	<!--
		1、balance="1" 开启读写分离,如果是0表示没有开启读写分离
		2、switchType="1" 故障切换类型,1代表自动切换
	-->
	<dataHost name="localhost1" 
			  maxCon="1000" 
			  minCon="10" 
			  balance="1"
			  writeType="0" 
			  dbType="mysql" 
			  dbDriver="native" 
			  switchType="1"  
			  slaveThreshold="100">
		
		<!--心跳语句 检查服务器有没有故障-->
		<heartbeat>select user()</heartbeat>
		
		<!---主库3307-->
		<writeHost host="hostM3307" url="localhost:3307" user="root" password="123456">
			<!---从库3309-->
			<readHost host="hostS3309" url="localhost:3309" user="root" password="123456" />
			<!---从库3308-->
			<readHost host="hostS3308" url="localhost:3308" user="root" password="123456" />
		</writeHost>
		
		<!---主库3308-->
		<writeHost host="hostM3308" url="localhost:3308" user="root" password="123456">
			<!---从库3310-->
			<readHost host="hostS3310" url="localhost:3310" user="root" password="123456" />
			<!---从库3307-->
			<readHost host="hostS3307" url="localhost:3307" user="root" password="123456" />
		</writeHost>
		
	</dataHost>
	
</mycat:schema>

3、配置rule.xml

指定分片结点数
改为4

4、插入数据验证

insert into tb11 (id, name) values (next value for MYCATSEQ_GLOBAL,'zhangsan');

不管是何种方式的切分,主键生成必须交给MyCat实现;

7 Mycat分库分表(垂直)

1、修改server.xml

<property name="sequnceHandlerType">0</property>

2、修改schema.xml

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

	<!--schema配置逻辑数据库与真实数据库的映射-->
	<schema name="mycatdb" checkSQLschema="false" sqlMaxLimit="1000">
		<!---3307主、3308主、3309从、3310从-->
		
		<!---垂直切分,需要在schema标签下需要配置需要对哪个table进行垂直切分-->
		
		<!--需求:原来是一个数据库共120张表,现在进行垂直切分,切分成3个数据库,分别是:
			web(前台数据库30张表)、admin(后台数据库45张表)、red(红包数据库45张表)
		-->
		
		<!--web(前台数据库30张表)-->
		<table name="users" primaryKey="id" dataNode="dn1" />
		<table name="auth" primaryKey="id" dataNode="dn1" />
		<!--...省略了下面的28张表...-->
		
		
		<!--admin(后台数据库45张表)-->
		<table name="products" primaryKey="id" dataNode="dn2" />
		<table name="creditors" primaryKey="id" dataNode="dn2" />
		<!--...省略了下面的43张表...-->
		
		
		<!--red(红包数据库45张表)-->
		<table name="redpackage" primaryKey="id" dataNode="dn3" />
		<table name="redpackageType" primaryKey="id" dataNode="dn3" />
		<!--...省略了下面的43张表...-->
		
	</schema>

	<!---3307主、3308主、3309从、3310从-->
	<dataNode name="dn1" dataHost="localhost1" database="web" />
	<dataNode name="dn2" dataHost="localhost1" database="admin" />
	<dataNode name="dn3" dataHost="localhost1" database="red" />

	<!--
		1、balance="1" 开启读写分离,如果是0表示没有开启读写分离
		2、switchType="1" 故障切换类型,1代表自动切换
	-->
	<dataHost name="localhost1" 
			  maxCon="1000" 
			  minCon="10" 
			  balance="1"
			  writeType="0" 
			  dbType="mysql" 
			  dbDriver="native" 
			  switchType="1"  
			  slaveThreshold="100">
		
		<!--心跳语句 检查服务器有没有故障-->
		<heartbeat>select user()</heartbeat>
		
		<!---主库3307-->
		<writeHost host="hostM3307" url="localhost:3307" user="root" password="123456">
			<!---从库3309-->
			<readHost host="hostS3309" url="localhost:3309" user="root" password="123456" />
			<!---从库3308-->
			<readHost host="hostS3308" url="localhost:3308" user="root" password="123456" />
		</writeHost>
		
		<!---主库3308-->
		<writeHost host="hostM3308" url="localhost:3308" user="root" password="123456">
			<!---从库3310-->
			<readHost host="hostS3310" url="localhost:3310" user="root" password="123456" />
			<!---从库3307-->
			<readHost host="hostS3307" url="localhost:3307" user="root" password="123456" />
		</writeHost>
		
	</dataHost>
	
</mycat:schema>

3、插入数据验证

插入数据验证
insert into tb11 (id, name) values (next value for MYCATSEQ_GLOBAL,'zhangsan');

4、垂直切分价值:
垂直切分带来的价值:可以屏蔽掉多数据源的问题,只需要一个统一入口mycat就可以操作下面的多个数据库;不管是何种方式的切分,主键生成必须交给MyCat实现;

8 Mycat全局序列号

8.1 本地文件方式

server.xml配置文件:sequnceHandlerType=0
conf/sequence_conf.properties 

8.2 时间戳方式

server.xml配置文件:sequnceHandlerType=2
使用一个时间戳作为主键

8.3 数据库方式

1、在数据库中执行脚本

DROP TABLE IF EXISTS MYCAT_SEQUENCE;

CREATE TABLE MYCAT_SEQUENCE (name VARCHAR(50) NOT NULL,current_value INT NOT NULL,increment INT NOT NULL DEFAULT 1,
PRIMARY KEY(name)) ENGINE=InnoDB default charset=utf8;

INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ("GLOBAL", 0, 100);

DROP FUNCTION IF EXISTS mycat_seq_currval;
DELIMITER //
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf8
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
SET retval="-999999999,null";
SELECT concat(CAST(current_value AS CHAR),",",CAST(increment AS CHAR)) INTO retval FROM MYCAT_SEQUENCE WHERE name = seq_name;
RETURN retval;
END //
DELIMITER  ;


DROP FUNCTION IF EXISTS mycat_seq_setval;
DELIMITER //
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),value INTEGER) RETURNS varchar(64) CHARSET utf8
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = value
WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END //
DELIMITER ;

DROP FUNCTION IF EXISTS mycat_seq_nextval;
DELIMITER //
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf8
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = current_value + increment WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END //
DELIMITER ;

2、server.xml配置:

<property name="sequnceHandlerType">1</property>

注:sequnceHandlerType 需要配置为1,表示使用数据库方式生成sequence.
3、指定sequence在哪个结点

sequence_db_conf.properties相关配置,指定sequence相关配置在哪个节点上
GLOBAL=dn1,dn2,dn3,dn4

4、插入数据

插入时怎么用
insert into tb1(id,name) values(next value for MYCATSEQ_GLOBAL,"test");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值