软件界有只猫,不用我说,各位看官肯定知道是哪只,那就是大名鼎鼎的Tomcat,现在又来了一只猫,据说是位东方萌妹子,暂且认作Tom猫的表妹,

本来叫OpencloudDB,后又改名为Mycat,或许Cat更亲切?那现在就来认识下这只小猫吧。

数据库的核心地位就不说了,但现在的问题是,各种RDB,各种NoSQL交织,又是分布式、多租户的场景下,心里有没有十足的把握能稳住如此局面呢。

有需求,就有市场!自然,相应的技术也应运而生,Mycat作为一款DB中间件,可以作为应用和DB间的“桥梁”,让后台DB的复杂组成对应用透明,处理

分库分表、多租户架构和大数据实时查询等都不在话下!

( 作者原创文章,谢绝任何形式转载,否则追究法律责任。)

工具:

Idea201902/JDK11/ZK3.5.5/Gradle5.4.1/RabbitMQ3.7.13/Lombok0.26/Erlang21.2/RocketMQ4.5.2/Sentinel1.6.3/SpringBoot2.1.6/RHEL7.6/

VMware15.0.4/Mysql8.0.17/Mycat1.6.7.3/MysqlWorkbench6.3

难度: 新手--战士--老兵--大师

目标:

1.Linux下使用Mycat连接Mysql集群(两主一从),读写分离式应用


步骤:

1.建立Mysql集群,步骤参考往期文章(Linux下Mysql集群使用)。

2.下载Mycat,放到Linux中/usr/mycat下,记得先建立此目录。

3.进入该目录,解压:

[root@localhost mycat]# tar -zxvf Mycat-server-1.6.7.3-release-20190828135747-linux.tar.gz

4.可以看到目录结构如下,两猫确实略像:

bin—Mycat的各种管理命令;

  • catlet—扩展功能;
  • conf—配置信息,这个也是本期重点使用的;
  • lib—jar包库,因为Mycat是Java开发的;
  • logs—日志文件;

5.Mycat融合应用的架构,即本次目标架构:

如果需要做扩展高可用,即可变成这样的:

就是这么简单!

6.其实Mycat从应用上讲,就是做配置,源码可按喜好研究,据说很复杂!

主要是三个文件核心文件rule.xml、schema.xml、server.xml的配置:

  • server.xml:Mycat的配置文件,可以将Mycat视为DBServer的代理,
  • schema.xml:逻辑表与物理DB/分片分库的映射配置,
  • rule.xml:分库分表规则,

7.挨个看看长啥样,参数的含义注释上基本有说明,这里都是全局配置参数:

  • <system>中设置Mycat全局属性;

  • <firewall>设置黑白名单;

  • <user>设置用户登录Mycat的账号信息;

  • <privileges>单独设置表的DML权限;

server.xml原版样例:

 1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE mycat:server SYSTEM "server.dtd">
3 <mycat:server xmlns:mycat="http://io.mycat/">
4 <system>
5 <property name="nonePasswordLogin">0</property> <!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户-->
6 <property name="useHandshakeV10">1</property>
7 <property name="useSqlStat">0</property> <!-- 1为开启实时统计、0为关闭 -->
8 <property name="useGlobleTableCheck">0</property> <!-- 1为开启全加班一致性检测、0为关闭 -->
9 <property name="sqlExecuteTimeout">300</property> <!-- SQL 执行超时 单位:秒-->
10 <property name="sequnceHandlerType">2</property>
11 <!--<property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>-->
12 <!--必须带有MYCATSEQ_或者 mycatseq_进入序列匹配流程 注意MYCATSEQ_有空格的情况-->
13 <property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>
14 <property name="subqueryRelationshipCheck">false</property> <!-- 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false -->
15 <!-- <property name="useCompression">1</property>--> <!--1为开启mysql压缩协议-->
16 <!-- <property name="fakeMySQLVersion">5.6.20</property>--> <!--设置模拟的MySQL版本号-->
17 <!-- <property name="processorBufferChunk">40960</property> -->
18 <!--
19 <property name="processors">1</property>
20 <property name="processorExecutor">32</property>
21 -->
22 <!--默认为type 0: DirectByteBufferPool | type 1 ByteBufferArena | type 2 NettyBufferPool -->
23 <property name="processorBufferPoolType">0</property>
24 <!--默认是65535 64K 用于sql解析时最大文本长度 -->
25 <!--<property name="maxStringLiteralLength">65535</property>-->
26 <!--<property name="sequnceHandlerType">0</property>-->
27 <!--<property name="backSocketNoDelay">1</property>-->
28 <!--<property name="frontSocketNoDelay">1</property>-->
29 <!--<property name="processorExecutor">16</property>-->
30 <!--
31 <property name="serverPort">8066</property> <property name="managerPort">9066</property>
32 <property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property>
33 <property name="dataNodeIdleCheckPeriod">300000</property> 5 * 60 * 1000L; //连接空闲检查
34 <property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
35 <!--分布式事务开关,0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但是记录分布式事务日志-->
36 <property name="handleDistributedTransactions">0</property>
37 <!--off heap for merge/order/group/limit 1开启 0关闭-->
38 <property name="useOffHeapForMerge">0</property>
39 <!--单位为m-->
40 <property name="memoryPageSize">64k</property>
41 <!--单位为k-->
42 <property name="spillsFileBufferSize">1k</property>
43 <property name="useStreamOutput">0</property>
44 <!--单位为m-->
45 <property name="systemReserveMemorySize">384m</property>
46 <!--是否采用zookeeper协调切换 -->
47 <property name="useZKSwitch">false</property>
48 <!-- XA Recovery Log日志路径 -->
49 <!--<property name="XARecoveryLogBaseDir">./</property>-->
50 <!-- XA Recovery Log日志名称 -->
51 <!--<property name="XARecoveryLogBaseName">tmlog</property>-->
52 <!--如果为 true的话 严格遵守隔离级别,不会在仅仅只有select语句的时候在事务中切换连接-->
53 <property name="strictTxIsolation">false</property>
54 <property name="useZKSwitch">true</property>
55 </system>
56
57 <!-- 全局SQL防火墙设置 -->
58 <!--白名单可以使用通配符%或着*-->
59 <!--例如<host host="127.0.0.*" user="root"/>-->
60 <!--例如<host host="127.0.*" user="root"/>-->
61 <!--例如<host host="127.*" user="root"/>-->
62 <!--例如<host host="1*7.*" user="root"/>-->
63 <!--这些配置情况下对于127.0.0.1都能以root账户登录-->
64 <!--
65 <firewall>
66 <whitehost>
67 <host host="1*7.0.0.*" user="root"/>
68 </whitehost>
69 <blacklist check="false">
70 </blacklist>
71 </firewall>
72 -->
73 <user name="root" defaultAccount="true">
74 <property name="password">123456</property>
75 <property name="schemas">TESTDB</property>
76 <!-- 表级 DML 权限设置 -->
77 <!--
78 <privileges check="false">
79 <schema name="TESTDB" dml="0110" >
80 <table name="tb01" dml="0000"></table>
81 <table name="tb02" dml="1111"></table>
82 </schema>
83 </privileges>
84 -->
85 </user>
86 <user name="user">
87 <property name="password">user</property>
88 <property name="schemas">TESTDB</property>
89 <property name="readOnly">true</property>
90 </user>
91 </mycat:server>

8.schema.xml,配置schema下各个table的分片/分库,以及物理DB:

  • <schema>+<table>租户和子表配置,

  • <dataNode>分片,

  • <dataHost>物理DB,

原版样例:

 1 <?xml version="1.0"?>
2 <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
3 <mycat:schema xmlns:mycat="http://io.mycat/">
4 <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100">
5 <!-- auto sharding by id (long) -->
6 <table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
7 <!-- global table is auto cloned to all defined data nodes ,so can join
8 with any table whose sharding node is in the same data node -->
9 <table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />
10 <table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2" />
11 <!-- random sharding using mod sharind rule -->
12 <table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3"
13 rule="mod-long" />
14 <!-- <table name="dual" primaryKey="ID" dataNode="dnx,dnoracle2" type="global"
15 needAddLimit="false"/> <table name="worker" primaryKey="ID" dataNode="jdbc_dn1,jdbc_dn2,jdbc_dn3"
16 rule="mod-long" /> -->
17 <table name="employee" primaryKey="ID" dataNode="dn1,dn2"
18 rule="sharding-by-intfile" />
19 <table name="customer" primaryKey="ID" dataNode="dn1,dn2"
20 rule="sharding-by-intfile">
21 <childTable name="orders" primaryKey="ID" joinKey="customer_id"
22 parentKey="id">
23 <childTable name="order_items" joinKey="order_id"
24 parentKey="id" />
25 </childTable>
26 <childTable name="customer_addr" primaryKey="ID" joinKey="customer_id"
27 parentKey="id" />
28 </table>
29 <!-- <table name="oc_call" primaryKey="ID" dataNode="dn1$0-743" rule="latest-month-calldate"
30 /> -->
31 </schema>
32 <!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
33 /> -->
34 <dataNode name="dn1" dataHost="localhost1" database="db1" />
35 <dataNode name="dn2" dataHost="localhost1" database="db2" />
36 <dataNode name="dn3" dataHost="localhost1" database="db3" />
37 <!--<dataNode name="dn4" dataHost="sequoiadb1" database="SAMPLE" />
38 <dataNode name="jdbc_dn1" dataHost="jdbchost" database="db1" />
39 <dataNode name="jdbc_dn2" dataHost="jdbchost" database="db2" />
40 <dataNode name="jdbc_dn3" dataHost="jdbchost" database="db3" /> -->
41 <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
42 writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
43 <heartbeat>select user()</heartbeat>
44 <!-- can have multi write hosts -->
45 <writeHost host="hostM1" url="localhost:3306" user="root"
46 password="123456">
47 <!-- can have multi read hosts -->
48 <readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" />
49 </writeHost>
50 <writeHost host="hostS1" url="localhost:3316" user="root"
51 password="123456" />
52 <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
53 </dataHost>
54 <!--
55 <dataHost name="sequoiadb1" maxCon="1000" minCon="1" balance="0" dbType="sequoiadb" dbDriver="jdbc">
56 <heartbeat> </heartbeat>
57 <writeHost host="hostM1" url="sequoiadb://1426587161.dbaas.sequoialab.net:11920/SAMPLE" user="jifeng" password="jifeng"></writeHost>
58 </dataHost>
59 ​
60 <dataHost name="oracle1" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="oracle" dbDriver="jdbc"> <heartbeat>select 1 from dual</heartbeat>
61 <connectionInitSql>alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'</connectionInitSql>
62 <writeHost host="hostM1" url="jdbc:oracle:thin:@127.0.0.1:1521:nange" user="base" password="123456" > </writeHost> </dataHost>
63 ​
64 <dataHost name="jdbchost" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="mongodb" dbDriver="jdbc">
65 <heartbeat>select user()</heartbeat>
66 <writeHost host="hostM" url="mongodb://192.168.0.99/test" user="admin" password="123456" ></writeHost> </dataHost>
67 ​
68 <dataHost name="sparksql" maxCon="1000" minCon="1" balance="0" dbType="spark" dbDriver="jdbc">
69 <heartbeat> </heartbeat>
70 <writeHost host="hostM1" url="jdbc:hive2://feng01:10000" user="jifeng" password="jifeng"></writeHost> </dataHost> -->
71 ​
72 <!-- <dataHost name="jdbchost" maxCon="1000" minCon="10" balance="0" dbType="mysql"
73 dbDriver="jdbc"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1"
74 url="jdbc:mysql://localhost:3306" user="root" password="123456"> </writeHost>
75 </dataHost> -->
76 </mycat:schema>

9.rule.xml详细描述表的分片规则,格式如下:

1   <tableRule name="分片规则名">
2 <rule>
3 <columns>分片的列</columns>
4 <algorithm>分片算法名</algorithm>
5 </rule>
6 </tableRule>
7 <function name="分片算法名" class="算法实现类">
8 <property name="算法参数">参数值</property>
9 </function>

原版样例:

  1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE mycat:rule SYSTEM "rule.dtd">
3 <mycat:rule xmlns:mycat="http://io.mycat/">
4 <tableRule name="rule1">
5 <rule>
6 <columns>id</columns>
7 <algorithm>func1</algorithm>
8 </rule>
9 </tableRule>
10 <tableRule name="rule2">
11 <rule>
12 <columns>user_id</columns>
13 <algorithm>func1</algorithm>
14 </rule>
15 </tableRule>
16 <tableRule name="sharding-by-intfile">
17 <rule>
18 <columns>sharding_id</columns>
19 <algorithm>hash-int</algorithm>
20 </rule>
21 </tableRule>
22 <tableRule name="auto-sharding-long">
23 <rule>
24 <columns>id</columns>
25 <algorithm>rang-long</algorithm>
26 </rule>
27 </tableRule>
28 <tableRule name="mod-long">
29 <rule>
30 <columns>id</columns>
31 <algorithm>mod-long</algorithm>
32 </rule>
33 </tableRule>
34 <tableRule name="sharding-by-murmur">
35 <rule>
36 <columns>id</columns>
37 <algorithm>murmur</algorithm>
38 </rule>
39 </tableRule>
40 <tableRule name="crc32slot">
41 <rule>
42 <columns>id</columns>
43 <algorithm>crc32slot</algorithm>
44 </rule>
45 </tableRule>
46 <tableRule name="sharding-by-month">
47 <rule>
48 <columns>create_time</columns>
49 <algorithm>partbymonth</algorithm>
50 </rule>
51 </tableRule>
52 <tableRule name="latest-month-calldate">
53 <rule>
54 <columns>calldate</columns>
55 <algorithm>latestMonth</algorithm>
56 </rule>
57 </tableRule>
58 <tableRule name="auto-sharding-rang-mod">
59 <rule>
60 <columns>id</columns>
61 <algorithm>rang-mod</algorithm>
62 </rule>
63 </tableRule>
64 <tableRule name="jch">
65 <rule>
66 <columns>id</columns>
67 <algorithm>jump-consistent-hash</algorithm>
68 </rule>
69 </tableRule>
70 <function name="murmur"
71 class="io.mycat.route.function.PartitionByMurmurHash">
72 <property name="seed">0</property><!-- 默认是0 -->
73 <property name="count">2</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
74 <property name="virtualBucketTimes">160</property><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
75 <!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替 -->
76 <!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property>
77 用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西 -->
78 </function>
79 <function name="crc32slot"
80 class="io.mycat.route.function.PartitionByCRC32PreSlot">
81 </function>
82 <function name="hash-int"
83 class="io.mycat.route.function.PartitionByFileMap">
84 <property name="mapFile">partition-hash-int.txt</property>
85 </function>
86 <function name="rang-long"
87 class="io.mycat.route.function.AutoPartitionByLong">
88 <property name="mapFile">autopartition-long.txt</property>
89 </function>
90 <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
91 <!-- how many data nodes -->
92 <property name="count">3</property>
93 </function>
94 ​
95 <function name="func1" class="io.mycat.route.function.PartitionByLong">
96 <property name="partitionCount">8</property>
97 <property name="partitionLength">128</property>
98 </function>
99 <function name="latestMonth"
100 class="io.mycat.route.function.LatestMonthPartion">
101 <property name="splitOneDay">24</property>
102 </function>
103 <function name="partbymonth"
104 class="io.mycat.route.function.PartitionByMonth">
105 <property name="dateFormat">yyyy-MM-dd</property>
106 <property name="sBeginDate">2015-01-01</property>
107 </function>
108 <function name="rang-mod" class="io.mycat.route.function.PartitionByRangeMod">
109 <property name="mapFile">partition-range-mod.txt</property>
110 </function>
111 <function name="jump-consistent-hash" class="io.mycat.route.function.PartitionByJumpConsistentHash">
112 <property name="totalBuckets">3</property>
113 </function>
114 </mycat:rule>

部分常用的分片规则算法说明:

  • PartitionByMurmurHash(一致性hash):将物理节点虚拟并映射为一个“一致性hash环”;

  • PartitionByCRC32PreSlot(crc32slot 算法):crc32(key)%102400=slot,slot 按照范围均匀分布在 dataNode 上;

  • LatestMonthPartion(单月小时拆分):单月内按照小时拆分,最小粒度是小时,可以一天最多 24 个分片,最少 1 个分片,一个月完后下月 从头开始循环;

  • PartitionByMonth(自然月):按自然月分片;

  • PartitionByRangeMod(范围求模):先进行范围分片计算出分片组,组内再求模;

  • PartitionByJumpConsistentHash(一致性hash):另一种一致性hash算法;

  • PartitionByFileMap(枚举):通过在配置文件中配置可能的枚举 id,自己配置分片,本规则适用于特定的场景,比如有些业务需要按照省份或区县来做保存,而全国省份区县是固定的;

  • PartitionByLong(固定分片 hash 算法):取 id 的二进制低 10 位取模运算,即( id 二进制) &1111111111,partitionCount分片个数,partitionLength分片长度,默认这两个参数的向量积为1024;

  • AutoPartitionByLong(范围约定):按照提前规划好分片字段范围计算属于哪个分片,start <= range <= end;

  • PartitionByMod(求模):即根据 id 进行十进制求模预算,相比固定分片 hash,此种在批量插入时可能存在批量插入单事务插入多数据分片,增大事务一致性难度;

  • PartitionByDate(按天分片):即根据指定的格式,起止日期,按日期划分,如果配置了 sEndDate 则代表数据达到了这个日期的分片后后循环从开始分片插入;

10.情况一:如果DB是一主一从:需注意这里的主从复制由Mysql实现,Mycat不负责数据复制功能。只需配置server.xml和schema.xml即可: 本次server.xml实例:

 1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE mycat:server SYSTEM "server.dtd">
3 <mycat:server xmlns:mycat="http://io.mycat/">
4 <system>
5 <property name="nonePasswordLogin">0</property>
6 <property name="useHandshakeV10">1</property>
7 <property name="useSqlStat">0</property>
8 <property name="useGlobleTableCheck">0</property>
9 <property name="sqlExecuteTimeout">300</property>
10 <property name="sequnceHandlerType">2</property>
11 <property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>
12 <property name="subqueryRelationshipCheck">false</property>
13 <property name="processorBufferPoolType">0</property>
14 <property name="handleDistributedTransactions">0</property>
15 <property name="useOffHeapForMerge">0</property>
16 <property name="memoryPageSize">64k</property>
17 <property name="spillsFileBufferSize">1k</property>
18 <property name="useStreamOutput">0</property>
19 <property name="systemReserveMemorySize">384m</property>
20 <property name="useZKSwitch">false</property>
21 <property name="strictTxIsolation">false</property>
22 <property name="useZKSwitch">true</property>
23 </system>
24 <user name="mycat" defaultAccount="true">
25 <property name="password">12345678</property>
26 <property name="schemas">dubbo_db</property>
27 </user>
28 </mycat:server>

schema.xml示例:

 1 <?xml version="1.0"?>
2 <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
3 <!-- 数据库配置,与server.xml中的数据库对应 -->
4 <mycat:schema xmlns:mycat="http://io.mycat/">
5 <schema name="dubbo_db" checkSQLschema="true" sqlMaxLimit="100">
6 <table name="dubbo_delivery" primaryKey="ID" dataNode="dn1"/>
7 <table name="dubbo_finance" primaryKey="ID" dataNode="dn1 "/>
8 <table name="dubbo_item" primaryKey="ID" dataNode="dn1 " />
9 <table name="dubbo_order" primaryKey="ID" dataNode="dn1"/>
10 <table name="dubbo_order_detail" primaryKey="ID" dataNode="dn1 "/>
11 <table name="dubbo_stock" primaryKey="ID" dataNode="dn1 " />
12 </schema>
13 <!-- 分片配置 -->
14 <dataNode name="dn1" dataHost="localhost1" database="dubbo_db" />
15 <!-- 物理数据库配置 -->
16 <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
17 writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
18 <heartbeat>select user()</heartbeat>
19 <writeHost host="hostM1" url="192.168.1.204:3306" user="root" password="abcd@1234">
20 <readHost host="hostS2" url="192.168.1.205:3306" user="root" password="abcd@1234" />
21 </writeHost>
22 </dataHost>
23 </mycat:schema>

11.情况二,即本期目标架构,DB是两主一从:server.xml不变, 本次schema.xml实例:

 1 <?xml version="1.0"?>
2 <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
3 <!-- 数据库配置,与server.xml中的数据库对应 -->
4 <mycat:schema xmlns:mycat="http://io.mycat/">
5 <schema name="dubbo_db" checkSQLschema="true" sqlMaxLimit="100">
6 <table name="dubbo_delivery" primaryKey="ID" dataNode="dn1"/>
7 <table name="dubbo_finance" primaryKey="ID" dataNode="dn1,dn2" rule="rule1"/>
8 <table name="dubbo_item" primaryKey="ID" dataNode="dn1,dn2" rule="rule2"/>
9 <table name="dubbo_order" primaryKey="ID" dataNode="dn1,dn2" rule="sharding-by-murmur"/>
10 <table name="dubbo_order_detail" primaryKey="ID" dataNode="dn1,dn2" rule="sharding-by-month"/>
11 <table name="dubbo_stock" primaryKey="ID" dataNode="dn1" />
12 </schema>
13 <!-- 分片配置 -->
14 <dataNode name="dn1" dataHost="localhost1" database="dubbo_db" />
15 <dataNode name="dn2" dataHost="localhost2" database="dubbo_db" />
16 <!-- 物理数据库配置 -->
17 <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
18 writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
19 <heartbeat>select user()</heartbeat>
20 <writeHost host="hostM1" url="192.168.1.204:3306" user="root" password="abcd@1234">
21 <readHost host="hostS2" url="192.168.1.205:3306" user="root" password="abcd@1234" />
22 </writeHost>
23 </dataHost>
24 <dataHost name="localhost2" maxCon="1000" minCon="10" balance="0"
25 writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
26 <heartbeat>select user()</heartbeat>
27 <writeHost host="hostM2" url="192.168.1.206:3306" user="root" password="abcd@1234" />
28 </dataHost>
29 </mycat:schema>

本次rule.xml实例:只有使用了分片模式时,才需要配置rule规则,这里写了三种rule,其实也没全部用上:

 1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE mycat:rule SYSTEM "rule.dtd">
3 <mycat:rule xmlns:mycat="http://io.mycat/">
4 <!--规则定义-->
5 <tableRule name="sharding-by-murmur">
6 <rule>
7 <columns>id</columns>
8 <algorithm>murmur</algorithm>
9 </rule>
10 </tableRule>
11 <!--自定义规则-->
12 <tableRule name="rule1">
13 <rule>
14 <columns>userr_id</columns>
15 <algorithm>func1</algorithm>
16 </rule>
17 </tableRule>
18 <tableRule name="rule2">
19 <rule>
20 <columns>id</columns>
21 <algorithm>func2</algorithm>
22 </rule>
23 </tableRule>
24 <tableRule name="sharding-by-month">
25 <rule>
26 <columns>create_time</columns>
27 <algorithm>partbymonth</algorithm>
28 </rule>
29 </tableRule>
30 <!--规则算法实现-->
31 <function name="murmur"
32 class="io.mycat.route.function.PartitionByMurmurHash">
33 <property name="seed">0</property><!-- 默认是0 -->
34 <property name="count">2</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
35 <property name="virtualBucketTimes">160</property><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
36 <!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替 -->
37 <!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property>
38 用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西 -->
39 </function>
40 <function name="func1" class="io.mycat.route.function.PartitionByLong">
41 <!--分片数量,partitionCount*partitionLength=1024-->
42 <property name="partitionCount">2</property>
43 <property name="partitionLength">512</property>
44 </function>
45 <function name="func2" class="io.mycat.route.function.PartitionByLong">
46 <property name="partitionCount">8</property>
47 <property name="partitionLength">128</property>
48 </function>
49 <function name="partbymonth"
50 class="io.mycat.route.function.PartitionByMonth">
51 <property name="dateFormat">yyyy-MM-dd</property>
52 <property name="sBeginDate">2015-01-01</property>
53 </function>
54 </mycat:rule>

12.测试:配置好mycat/conf/下的3个xml文件,即配置好了Mycat与物理DB的连接,应用端连接仅需修改连接串端口为Mycat的IP+端口,

账号为server.xml中user信息,注意:要写上默认schema,否则启动应用报Mycat no chose错,

13.此处有坑!如果Mysql是独立安装在linux上,需要对远程访问打开,否则访问默认仅限本地,导致远程连接一直报错,以开放root用户远程连接为例:

mysql> use mysql;
mysql> update user set Host='%' where User='root';
mysql> quit;

再重启mysql:

[root@localhost ~]# systemctl restart mysqld

启动Mycat:

[root@localhost ~]# cd /usr/mycat/mycat/bin
[root@localhost bin]# ./mycat start

mycat启动成功:

如果启动有问题,使用以下命令查看log:

[root@localhost conf]# tail -F  /usr/mycat/mycat/logs/wrapper.log
[root@localhost conf]# tail -F /usr/mycat/mycat/logs/mycat.log

然后可以在window上使用如MysqlWorkbench,Navicat测试下是否连接正常,并测试下Mycat连接:

为了集中测试代码,我只改写了finance模块,写个service方法:com.biao.mall.service.DubboFinanceServiceImpl中:

 1  //插入1000条数据,看data分布
2 @Override
3 public void testMycat(){
4 DubboFinanceEntity financeEntity = new DubboFinanceEntity();
5 for (int i = 0; i < 1000; i++) {
6 financeEntity.setUserId(String.valueOf(i+100));
7 financeDao.insert(financeEntity);
8 }
9 return "testMycat successfully";
10 }

写个controller方法跑一跑:

@RestController
@RequestMapping("/finance")
public class DubboFinanceController {
private DubboFinanceServiceImpl financeService;
@Autowired
public DubboFinanceController(DubboFinanceServiceImpl financeService) {
this.financeService = financeService;
} @RequestMapping("/mycat")
public void testMycat(){
return financeService.testMycat();
}
}

启动:ZK---> business -->  finance, URI来一个!

DB情况如下,请看数量和ID(DB主键)分布,红色数字是IP,user_id分布分为两部分488+512=1000,ID(DB主键)为自增型,

所以都从1开始,204和205为主从,故保持一致:

这里只测试了两主一从和一种分片规则,其他请君自测!

13.代码地址:其中的day16,https://github.com/xiexiaobiao/dubbo-project.git


后记:

1.认识Mycat的关键特性:

  • 支持Mysql原生协议,跨语言,跨平台,跨数据库的通用中间件代理;
  • 基于心跳的自动故障切换,支持读写分离,支持MySQL主从;
  • 基于Nio实现,有效管理线程,高并发问题;
  • 支持数据的多片自动路由与聚合,支持sum,count,max等常用的聚合函数,支持跨库分页;
  • 支持通过全局表,ER关系的分片策略,实现了高效的单库多表join查询;
  • 支持多租户方案,即同DB下多schema模式;
  • 支持全局序列号,解决分布式下的主键生成问题;
  • 分片规则丰富,插件化开发,易于扩展,可自定义;
  • 集群基于ZooKeeper管理,在线升级,扩容,智能优化,大数据处理(V2.0dev);
  • 引入Mycat的无痕切换,我觉得这是最大的优势;

2.认清Mycat的局限性

  • 目前只支持跨库join2个表,不支持3 表及其以上跨库 join ;

  • Mycat并没有根据二阶段提交协议实现 XA事务,而是只保证 prepare 阶段数据一致性的弱XA事务,分布式事务场景下,强一致性无法保证;

  • 分页排序场景下,会一次查询所有分片,再集中排序分页,有性能瓶颈;

  • 不同类型DB适配一般,如Oracle/SQLServer等,由于SQL语法差异,须做彻底的语句兼容测试;

  • 没有API配置方法,只有XML方式配置,十分过时;

3.Mycat作为DB上一层的重量级中间件,统一了入口,实际上也破坏了分布式的定义,未能充分发挥DB层的效能,所以也有很多不看好的声音,DB独立使用,

更能发挥灵活自由配置,直接对接应用层更为高效。

4.总结:Mycat框架的使用,需持谨慎态度,至少目前来看如此。

本人原创,谢绝任何形式转载,否则追究法律责任。


推荐阅读:

最新文章

  1. [Tex学习笔记]开方
  2. java利用透明的图片轮廓抠图
  3. MySQL 时间戳(Timestamp)函数
  4. CSS3-旋转齿轮
  5. php中des加密解密&#160;匹配C#des加密解密&#160;对称加密
  6. Swift Array copy 的线程安全问题
  7. iOS 横竖屏适配 笔记
  8. activiti工作流框架简介
  9. JVM回收算法
  10. NLP入门(六)pyltp的介绍与使用
  11. vue开发目录
  12. Linux配置虚拟内存
  13. java、asp.net 通用分页码函数
  14. 阿里开源项目 druid 相关资料汇总
  15. android linux 休眠 深度睡眠 查看 方法 调试【转】
  16. POJ 2570 线段树
  17. [wx]自然数学规律
  18. 数据库中查询json 样式的值的sql语句
  19. jqGrid随窗口大小变化自适应宽度
  20. DevExpress 15.1.sln

热门文章

  1. 实战jmeter入门压测接口性能
  2. [转]Android中设置TextView的颜色setTextColor
  3. String类的intern()方法,随常量池发生的变化
  4. WebApi使用OAuth2认证
  5. 2019 ICPC南京网络预选赛 I Washing clothes 李超线段树
  6. Gym 100956 A Random Points on the Circle
  7. 修改,编译,GDB调试openjdk8源码(docker环境下)
  8. HDU 1010 temp of the bone 解题报告 (DFS)
  9. YUM简单入门
  10. 从零开始入门 K8s| 详解 Pod 及容器设计模式