MyCat 发表于 2021-12-30 | 更新于 2022-07-22
| 字数总计: 5.4k | 阅读时长: 24分钟 | 阅读量:
介绍 Mycat的前身是阿里巴巴大名鼎鼎的Cobar,Cobar在开源了一段时间后,就没有再维护了,阿里巴巴放弃了该项目,再加上Cobar在使用过程中也发现存在一些问题。
2013年国内一批开源软件爱好者对Cobar这个项目进行了改进,并命名为Mycat,这就是MyCat的诞生。
MyCat是完全免费开源的,不属于任何商业公司。
权威指南:https://www.yuque.com/books/share/0576de75-ffc4-4c34-8586-952ae4636944
Mycat是一个开源数据库中间件,是一个实现了MySQL协议的的数据库中间件服务器,我们可以把它看作是一个数据库代理,用MySQL客户端工具和命令行访问Mycat,而Mycat再使用MySQL原生(Native)协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信,包括SQL Server、Oracle、DB2、PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未来还会支持更多类型的存储;
一般地,Mycat主要用于代理MySQL数据库,虽然它也支持去访问其他类型的数据库;
Mycat的默认端口是8066,一般地,我们可以使用常见的对象映射框架比如MyBatis操作Mycat。
主要能做什么
负载均衡
数据库的读写分离 如果有了Mycat,客户端直接连接Mycat,可以实现读写分离,如果主出现问题,会自动切换到从服务器上
数据库分库分表 水平切分(横向切分) 根据表中数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库服务器上面
垂直切分(纵向切分) 按照不同的表来切分到不同的数据库服务器之上
性能有瓶颈了,可以读写分离 数据库容量有瓶颈了,可以分库分表
安装 下载http://dl.mycat.org.cn/
解压后切换到mycat的bin路径下,执行 启动Mycat服务:./mycat start
关闭Mycat服务:./mycat stop
启动后要观察下有没有要运行,错误地运行会掉服务sp -ef | grep mycat
运行Mycat(以Mysql方式运行)./mysql -umycat -p -P8066 -h127.0.0.1
主要修改的配置文件 注意!!文件格式编码为UTF-8
rule.xml 水平分表的时候用到 在原有的rule的xml文件中,设置节点配置的数量
server.xml 主要用于配置mycat需要的服务器信息
Ø 配置序列生成方式
Ø 配置mycat逻辑数据库
Ø 配置mycat的访问账户和密码
sequnceHandlerType属性 指定使用Mycat全局序列的类型:
0为本地文件方式,1为数据库方式,2为时间戳序列方式 对于读写分离而言,是不需要考虑主键生成方式的,也就是不需要配置全局序列号的。
user属性 创建一个用户,使用此用户,登录mysql时需要用到
schema.xml 用于配置的逻辑数据库的映射、表、分片规则、数据结点及真实的数据库信息;
Ø 配置逻辑库映射
Ø 配置垂直切分的表
Ø 配置真实的数据库
Ø 配置读写结点
配置dataNode dataNode定义了Mycat中的数据节点,也就是我们通常说所的数据分片。 一个dataNode标签就是一个独立的数据分片,通俗理解,一个分片就是一个物理数据库
Ø name 定义数据节点的名字,这个名字需要是唯一的,这个名字在schema里面会使用到;
Ø dataHost 用于定义该分片属于哪个数据库实例的,属性值是引用dataHost标签上定义的name属性
Ø database用于对应真实的数据库名,必须是真实存在的;
配置dataHost 定义具体的数据库实例、读写分离配置和心跳语句;
Ø balance属性 负载均衡类型,目前的取值有4种: n balance=”0”, 不开启读写分离机制,所有读操作都发送到当前可用的writeHost上; n balance=”1”,全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与 M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡。 n balance=”2”,所有读操作都随机的在writeHost、readhost上分发 n balance=”3”,所有读请求随机的分发到wiriterHost对应的readhost执行,writerHost不负担读压力
Ø switchType属性 用于指定主服务器发生故障后的切换类型 -1 表示不自动切换 1 默认值,自动切换(推荐) 2 基于MySQL主从同步的状态决定是否切换 3 基于MySQL galary cluster的切换机制(适合集群)(1.4.1) 通常情况下,我们MySQL采用双主双从的模式下,switchType为1即可
。因为双主从模式下,主从同步关系很复杂,不能根据MySQL的状态来切换。只需要在一个主出问题后,切换到另外的主。
Ø heartbeat标签 用于和后端数据库进行心跳检查的语句,检测MySQL数据库是否正常运行 当switchType为1时,mysql心跳检查语句是select user() 当switchType为2时,mysql心跳检查语句是show slave status 当switchType为3时,mysql心跳检查语句是show status like ‘wsrep%’
Ø writeHost与readHost标签 这两个标签都指定后端数据库的相关配置给mycat,用于实例化后端连接池。唯一不同的是,writeHost指定写实例、readHost指定读实例,组合这些读写实例来满足系统的要求。
在一个dataHost内可以定义多个writeHost和readHost。但是,如果writeHost指定的后端数据库宕机,那么这个writeHost绑定的所有readHost都将不可用。另一方面,由于这个writeHost宕机系统会自动的检测到,并切换到备用的writeHost上去。
双主双从读写分离 以下以双主,双从为例子,按端口区分 3307主(3308、3309从) 3308主(3307、3310从) 3307、3308互为从
server 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mycat :server SYSTEM "server.dtd" > <mycat:server xmlns:mycat ="http://io.mycat/" > <system > <property name ="useSqlStat" > 0</property > <property name ="useGlobleTableCheck" > 0</property > <property name ="sequnceHandlerType" > 0</property > <property name ="processorBufferPoolType" > 0</property > <property name ="handleDistributedTransactions" > 0</property > <property name ="useOffHeapForMerge" > 1</property > <property name ="memoryPageSize" > 1m</property > <property name ="spillsFileBufferSize" > 1k</property > <property name ="useStreamOutput" > 0</property > <property name ="systemReserveMemorySize" > 384m</property > <property name ="useZKSwitch" > true</property > </system > <user name ="mycat" > <property name ="password" > Peng@2020google</property > <property name ="schemas" > mycatdb</property > </user > <user name ="user" > <property name ="password" > Peng@2020google</property > <property name ="schemas" > mycatdb</property > <property name ="readOnly" > true</property > </user > </mycat:server >
schema 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mycat :schema SYSTEM "schema.dtd" > <mycat:schema xmlns:mycat ="http://io.mycat/" > <schema name ="mycatdb" checkSQLschema ="false" sqlMaxLimit ="100" dataNode ="dn1" > </schema > <dataNode name ="dn1" dataHost ="localhost1" database ="mycinema" /> <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 ="Peng@2020google" > <readHost host ="hostS3308" url ="localhost:3308" user ="root" password ="Peng@2020google" /> <readHost host ="hostS3309" url ="localhost:3309" user ="root" password ="Peng@2020google" /> </writeHost > <writeHost host ="hostM3308" url ="localhost:3308" user ="root" password ="Peng@2020google" > <readHost host ="hostS3307" url ="localhost:3307" user ="root" password ="Peng@2020google" /> <readHost host ="hostS3310" url ="localhost:3310" user ="root" password ="Peng@2020google" /> </writeHost > </dataHost > </mycat:schema >
测试 启动mycat服务 使用mysql登录mycat./mysql -umycat -p -P8066 -h 192.168.235.128
一主三从读写分离 未测试过,测出省略server.xml表
Schema.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mycat :schema SYSTEM "schema.dtd" > <mycat:schema xmlns:mycat ="http://io.mycat/" > <schema name ="mycatdb" checkSQLschema ="false" sqlMaxLimit ="100" dataNode ="dn1" > </schema > <dataNode name ="dn1" dataHost ="localhost1" database ="mycinema" /> <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 >
水平分表 一张表被拆到n个库中
一主三从 指定逻辑库,分片结点,结点主机等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mycat :schema SYSTEM "schema.dtd" > <mycat:schema xmlns:mycat ="http://io.mycat/" > <schema name ="mycatdb" checkSQLschema ="false" sqlMaxLimit ="100" > <table name ="orders" primaryKey ="id" autoIncrement ="true" dataNode ="dn1,dn2,dn3" rule ="mod-long" /> </schema > <dataNode name ="dn1" dataHost ="localhost1" database ="test01" /> <dataNode name ="dn2" dataHost ="localhost1" database ="test02" /> <dataNode name ="dn3" dataHost ="localhost1" database ="test03" /> <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 >
双主双从 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mycat :schema SYSTEM "schema.dtd" > <mycat:schema xmlns:mycat ="http://io.mycat/" > <schema name ="mycatdb" checkSQLschema ="false" sqlMaxLimit ="100" > <table name ="orders" primaryKey ="id" autoIncrement ="true" dataNode ="dn1,dn2,dn3" rule ="mod-long" /> </schema > <dataNode name ="dn1" dataHost ="localhost1" database ="test01" /> <dataNode name ="dn2" dataHost ="localhost1" database ="test02" /> <dataNode name ="dn3" dataHost ="localhost1" database ="test03" /> <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" /> </writeHost > <writeHost host ="hostM3308" url ="localhost:3308" user ="root" password ="123456" > <readHost host ="hostS3307" url ="localhost:3307" user ="root" password ="123456" /> <readHost host ="hostS3310" url ="localhost:3310" user ="root" password ="123456" /> </writeHost > </dataHost > </mycat:schema >
配置rule.xml 在原有的rule的xml文件中,设置节点配置的数量
1 2 3 4 5 <function name ="mod-long" class ="io.mycat.route.function.PartitionByMod" > <property name ="count" > 3</property > </function >
垂直分库 逻辑数据库与实际数据库的差别双主双从
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mycat :schema SYSTEM "schema.dtd" > <mycat:schema xmlns:mycat ="http://io.mycat/" > <schema name ="mycatdb" checkSQLschema ="false" sqlMaxLimit ="100" > <table name ="orders" primaryKey ="id" autoIncrement ="true" dataNode ="dn1" /> <table name ="users" primaryKey ="id" autoIncrement ="true" dataNode ="dn1" /> <table name ="products" primaryKey ="id" autoIncrement ="true" dataNode ="dn2" /> <table name ="news" primaryKey ="id" autoIncrement ="true" dataNode ="dn2" /> </schema > <dataNode name ="dn1" dataHost ="localhost1" database ="money-web" /> <dataNode name ="dn2" dataHost ="localhost1" database ="money-admin" /> <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" /> </writeHost > <writeHost host ="hostM3308" url ="localhost:3308" user ="root" password ="123456" > <readHost host ="hostS3307" url ="localhost:3307" user ="root" password ="123456" /> <readHost host ="hostS3310" url ="localhost:3310" user ="root" password ="123456" /> </writeHost > </dataHost > </mycat:schema >
一主三从
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mycat :schema SYSTEM "schema.dtd" > <mycat:schema xmlns:mycat ="http://io.mycat/" > <schema name ="mycatdb" checkSQLschema ="false" sqlMaxLimit ="100" > <table name ="orders" primaryKey ="id" autoIncrement ="true" dataNode ="dn1" /> <table name ="users" primaryKey ="id" autoIncrement ="true" dataNode ="dn1" /> <table name ="products" primaryKey ="id" autoIncrement ="true" dataNode ="dn2" /> <table name ="news" primaryKey ="id" autoIncrement ="true" dataNode ="dn2" /> </schema > <dataNode name ="dn1" dataHost ="localhost1" database ="money_web" /> <dataNode name ="dn2" dataHost ="localhost1" database ="money_admin" /> <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:3309" user ="root" password ="123456" /> </writeHost > </dataHost > </mycat:schema >
MyCat的主键生成方式 不管是何种方式的切分,主键生成必须交给MyCat实现,生成方式有四种
本地文件方式
修改conf/server.xml文件中配置sequnceHandlerType=0
在conf/sequence_conf.properties中维护主键信息
如果想要每个表生成的主键连续,可以在sequence_conf.properties配置当前表的生成值,一般将Global替换为自己对应的前缀即可(三个地方),取值的时候通过next value for MYCATSEQ_XXXX获取
1 2 3 INFO.CURID=1256 INFO.MINID=3000 INFO.MAXID=3000000
优点:本地加载,读取速度较快,配置简单
缺点:mycat重新发布时,seq文件需要替换,集群部署无法用此方式,路由到不同的mycat上无法保证id唯一,使mycat变成了有状态的中间件
5.关闭服务,并重启
1 2 /usr/local/mycat/bin/mycat stop /usr/local/mycat/bin/mycat start
6.测试
(1)创建测试表Info
1 2 3 4 CREATE TABLE info(id VARCHAR (64 ) NOT NULL PRIMARY KEY, NAME VARCHAR (50 ) NOT NULL );
(2)插入数据
1 INSERT INTO info (id,NAME) VALUES (NEXT VALUE FOR MYCATSEQ_INFO, '本地文件方式1' );
本地时间戳方式 1.修改conf/server.xml文件中配置sequnceHandlerType=2
2.本地时间戳计算方式:
ID= 64 位二进制 (42(毫秒)+5(机器 ID)+5(业务编码)+12(重复累加) 长度18位,因此表主键字段长度必须大于等于18位
3.优点:不存在mycat重新发布影响seq的问题,
缺点:字段长度是18位,比较占空间
4.关闭服务,并重启
1 2 /usr/local/mycat/bin/mycat stop /usr/local/mycat/bin/mycat start
5.测试
1 INSERT INTO info(NAME) VALUES ('本地时间戳方式1' );
结果如下图:
数据库方式 1.修改conf/server.xml文件中配置sequnceHandlerType=1
2.在3307的money_admin数据库中执行以下代码,用于创建表MyCAT_SEQUENCE,生成序列值
MYCAT_SEQUENCE 的三个字段:
name sequence名称
current_value 当前value
increment 增长步长
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 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 , 10000 );#创建函数,处理当前值 DROP FUNCTION IF EXISTS mycat_seq_currval;DELIMITER / / CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR (50 )) RETURNS VARCHAR (64 ) CHARSET utf8DETERMINISTIC 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 utf8DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCESET 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 utf8DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCESET current_value = current_value + increment WHERE NAME = seq_name;RETURN mycat_seq_currval(seq_name);END / / DELIMITER ;
3.查看表mycat_sequence
1 SELECT * FROM mycat_sequence
4.根据我们在schema.xml文件中的配置,money_admin数据库对应的节点应该是dn2,所以在sequence_db_conf.properties中配置的GLOBAL应该就是dn2
5.关闭mycat服务,并重启
1 2 /usr/local/mycat/bin/mycat stop /usr/local/mycat/bin/mycat start
6.测试
1 2 3 INSERT INTO info(id,NAME) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL,"数据库生成1");INSERT INTO info(id,NAME) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL,"数据库生成2");INSERT INTO info(id,NAME) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL,"数据库生成3");
结果如下图
ZK方式 使用zookeeper服务器提供序列值,优点:无悲观锁,无强竞争,吞吐量更高。缺点:对zookeeper集群的要求增加