• Mycat是开源的、活跃的、基于Java语言编写的MySQL数据库中间件。可以像使用mysql一样来使用mycat,对于开发人员来说根本感觉不到mycat的存在。
  • 开发人员只需要连接MyCat即可,而具体底层用到几台数据库,每一台数据库服务器里面存储了什么数据,都无需关心。
  • 官网地址:http://www.mycat.org.cn/

安装

  • 参看后面github示例。

目录介绍

  1. bin: 存放可执行文件,用于启动停止mycat。
  2. conf:存放mycat的配置文件。
  3. lib:存放mycat的项目依赖包(jar)。
  4. logs:存放mycat的日志文件。

概念

  1. 在MyCat的整体结构中,分为两个部分:上面的逻辑结构、下面的物理结构。
  2. 在MyCat的逻辑结构主要负责逻辑库、逻辑表、分片规则、分片节点等逻辑结构的处理,而具体的数据存储还是在物理结构,也就是数据库服务器中存储的。

其他

  1. 9066 端口,用于查看MyCat监控信息。
  2. 8066 端口,用于与mysql数据交换。
  3. 9066 端口支持命令。(通过:mysql -h localhost -uroot -P9066 -p123456 连接)
  4. 以下介绍部分命令。更多通过:show @@help; 查看。
—————-命令—————- 作用
show @@server 查看服务器状态,包括占用内存等
show @@database 查看数据库
show @@heartbeat 前后端物理库的心跳检测情况,RS_CODE为1表示心跳正常
show @@datanode 查看数据节点
show @@datasource 查看数据源
show @@connection 该命令用于获取 Mycat 的前端连接状态,即应用与 mycat 的连接
show @@backend 查看后端连接状态
show @@cache 查看缓存使用情况,SQLRouteCache:sql路由缓存。TableID2DataNodeCache:缓存表主键与分片对应关系,ER_SQL2PARENTID :缓存 ER 分片中子表与父表关系
reload @@config 重新加载基本配置,使用这个命令时 mycat服务不可用
show @@sysparam 查看参数
show @@sql.high 执行频率高的 SQL
show @@sql.slow 慢 SQL 设置慢 SQL 的命令:reload @@sqlslow=5

MyCat配置

schema.xml

  1. schema.xml作为MyCat中最重要的配置文件之一 , 涵盖了MyCat的逻辑库、逻辑表、分片规则、分片节点及数据源的配置。
  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
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- 逻辑库 -->
    <!-- name: 逻辑库名字 -->
    <!-- checkSQLschema: 
        当设置为true时,比如发送一条sql:select * from mycat_order.t_order,那么MyCat会自动去掉mycat_order逻辑库名字前缀,把sql变为:select * from t_order, 这样有效避免报表或视图不存在错误。
        如果使用select * from test.t_order ,sql语句中所带的逻辑库名字跟schema标签中的name不一致的话,MyCat不会自动去掉逻辑库名字前缀,如果逻辑库不存在,仍然会报错。
    -->
    <!-- sqlMaxLimit:  如果每次执行的sql语句后面没有跟上limit xx关键字的话,MyCat会自动在sql语句的后面拼上limit 100 -->
    <!-- dataNode: 用于指定没有分配分片节点的那些表的默认数据节点 -->
    <schema name="shopping" checkSQLschema="false" sqlMaxLimit="100">
        <!-- 逻辑表,以下都没有配置分片规则rule,因为垂直分表不需要它 -->
        <!-- name: 逻辑表的名字,同一个逻辑库schema中的逻辑表的名称应该唯一 -->
        <!-- dataNode: 配置逻辑表分布的数据节点,名字需要与dataNode标签的name对应上 -->
        <!-- rule: 配置逻辑表的分片规则,需要在rule.xml中声明的规则名字对应上 -->
        <!-- ruleRequired: 指定分片规则是否必须,如果为true,但是没有指定rule,程序会报错 -->
        <!-- primaryKey: 指定逻辑表对应真实表的主键 -->
        <!-- type: 指定该逻辑表是全局表还是普通逻辑表。type="global"表示全局表 -->
        <!-- autoIncrement: 指定是否自增长主键 -->
        <!-- needAddLimit: 指定逻辑表是否在查询的时候自动添加limit去限制返回的结果集记录数,默认为true,如果语句中已经包含了limit关键字,则不会重复添加 -->
        <table name="tb_goods_base" dataNode="dn1" primaryKey="id" />
        <table name="tb_goods_brand" dataNode="dn1" primaryKey="id" />
        <table name="tb_goods_cat" dataNode="dn1" primaryKey="id" />
        <table name="tb_goods_desc" dataNode="dn1" primaryKey="goods_id" />
        <table name="tb_goods_item" dataNode="dn1" primaryKey="id" />

        <table name="tb_order_item" dataNode="dn2" primaryKey="id" />
        <table name="tb_order_master" dataNode="dn2" primaryKey="order_id" />
        <table name="tb_order_pay_log" dataNode="dn2" primaryKey="out_trade_no" />

        <table name="tb_user" dataNode="dn3" primaryKey="id" />
        <table name="tb_user_address" dataNode="dn3" primaryKey="id" />

        <!-- 全局表 -->
        <table name="tb_areas_provinces" dataNode="dn1,dn2,dn3" primaryKey="id" type="global"/>
        <table name="tb_areas_city" dataNode="dn1,dn2,dn3" primaryKey="id" type="global"/>
        <table name="tb_areas_region" dataNode="dn1,dn2,dn3" primaryKey="id" type="global"/>

        <!--
        <table name="t_order"  dataNode="dn1,dn2" rule="mod-long">
            # 定义E-R分片的子表,通过标签上的属性与父表进行关联
            #   name:子表的名称t_order_detail
            #   primaryKey:子表的主键
            #   joinKey:新增子表记录的时候,会根据该值查询父表在哪个分片节点上。(子表中字段的名称order_i
            #   parentKey属性:与父表建立关联关系的列,结合joinKey确定好子表记录存放的分片节点,插入子表记录时直接插入到该分片节点上。(父表中字段名称order_id)
            #   needAddLimit属性: 指定逻辑表是否在查询的时候自动添加limit去限制返回的结果集记录数,默认为true,如果语句中已经包含了limit关键字,则不会重复添加
            <childTable name="t_order_detail" primaryKey="od_id" joinKey="order_id" parentKey="order_id"></childTable>
        </table>
        -->
    </schema>

    <!-- 数据节点 -->
    <!-- name: 指定分片节点的名称,与声明逻辑表table标签中的dataNode名字对应上 -->
    <!-- dataHost: 指定分片节点所在的节点主机(数据库实例),与dataHost标签声明的name对应 -->
    <!-- database: 真实数据库名称 -->
    <dataNode name="dn1" dataHost="dhost1" database="shopping" />
    <dataNode name="dn2" dataHost="dhost2" database="shopping" />
    <dataNode name="dn3" dataHost="dhost3" database="shopping" />

    <!-- 具体数据库实例 -->
    <dataHost name="dhost1" maxCon="1000" minCon="10" balance="0"
        writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <!--心跳检测 -->
        <heartbeat>select user()</heartbeat>
        <!-- 写服务器,如果要配置读写,添加readHost标签即可 -->
        <writeHost host="M1" url="172.16.0.101:3306" user="root" password="123456">
        </writeHost>
    </dataHost>

    <dataHost name="dhost2" maxCon="1000" minCon="10" balance="0"
        writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <!--心跳检测 -->
        <heartbeat>select user()</heartbeat>
        <!-- 写服务器,如果要配置读写,添加readHost标签即可 -->
        <writeHost host="M2" url="172.16.0.102:3306" user="root" password="123456">
        </writeHost>
    </dataHost>

    <!-- name: 指定分片主机的名称,供dataNode标签使用 -->
    <!-- maxCon: 指定读写实例的连接池的最大连接数量 -->
    <!-- minCon: 指定读写实例的连接池的最小连接数量,初始化连接池的大小 -->
    <!-- balance: 指定负载均衡的类型
            balance = “0” : 不开启读写分离,所有的读请求都发送到可用的writeHost写节点上(不会发readHost)
            balance = “1” : 全部的readHost与stand by writeHost参与select语句的负载均衡,
            balance = “2” : 读操作会随机发往writeHost以及 readHost,理论上实现的是负载均衡
            balance = “3” : 配置了readHost时读操作会随机发往readHost(不会发writeHost),而没有配置readHost时读操作会发往第一个writeHost。
    -->
    <!-- writeType:  
            writeType="0": 所有写操作发送到配置的第一个writeHost,当第一个writeHost宕机时,切换到第二个writeHost,重新启动后以切换后的为准,切换记录在配置文件:dnindex.properties中
            writeType="1": 所有写操作都随发送到配置的writeHost
    -->
    <!-- dbType: 指定后端数据库类型,支持mysql、oracle等 -->
    <!-- dbDriver: 指定后端数据库连接驱动信息,支持native和jdbc -->
    <!-- switchType: 指定切换方式 
            switchType = -1:不自动切换
            switchType = 1:自动切换(默认)
            switchType = 2:基于MySql主从同步的状态来决定是否切换,心跳语句: show slave status
            switchType = 3: 基于mysql galary cluster的切换机制,心跳语句: show status like 'wsrep%'
    -->
    <!-- slaveThreshold:  -->
    <dataHost name="dhost3" maxCon="1000" minCon="10" balance="0"
        writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <!--心跳检测,指定后端数据库进行心跳检查的语句 -->
        <heartbeat>select user()</heartbeat>
        <!-- 写服务器,如果要配置读写,添加readHost标签即可 -->
        <!-- host: 用于标识不同实例,一般 writeHost 我们使用M1,readHost 我们用S1 -->
        <!-- url: 后端实例连接地址,如果是使用 native 的 dbDriver,则一般为 address:port 这种形式,用 JDBC 或其他的 dbDriver,则需要特殊指定,使用 JDBC 时则可以这么写:jdbc:mysql://localhost:3306/ -->
        <!-- user: 后端存储实例需要的用户名 -->
        <!-- password: 后端存储实例需要的密码 -->
        <!-- weight: 权重 配置在 readhost 中作为读节点的权重 -->
        <!-- usingDecrypt: 是否对密码加密默认 0 否 如需要开启配置 1,同时使用加密程序对密码加密 -->
        <writeHost host="M3" url="172.16.0.103:3306" user="root" password="123456">
        </writeHost>
    </dataHost>
</mycat:schema>

schema标签

  1. schema标签用于定义MyCat实例中的逻辑库, 一个MyCat实例中, 可以有多个逻辑库, 可以通过schema标签来划分不同的逻辑库。
  2. MyCat中的逻辑库的概念,等同于MySQL中的database概念,需要操作某个逻辑库下的表时,也需要切换逻辑库(use xxx)。
1
2
3
4
5
<!-- 定义逻辑库 -->
<schema name="DB01" checkSQLschema="true" sqlMaxLimit="100">
    <!-- 定义逻辑表 -->
    <table name="TB_ORDER" dataNode="dn1,dn2,dn3" rule="auto-sharding-long"/>
</schema>
  1. schema 属性:
    • name:指定自定义的逻辑库库名。
    • checkSQLschema:在SQL语句操作时指定了数据库名称,执行时是否自动去除;true:自动去除,false:不自动去除。
    • sqlMaxLimit:如果未指定limit进行查询,列表查询模式查询多少条记录。
  2. table标签定义了MyCat中逻辑库schema下的逻辑表,所有需要拆分的表都需要在table标签中定义。
  3. schema.table 属性:
    • name:定义逻辑表表名,在该逻辑库下唯一。
    • dataNode:定义逻辑表所属的dataNode,该属性需要与dataNode标签中name对应;多个dataNode逗号分隔。
    • rule:分片规则的名字,分片规则名字是在rule.xml中定义的。
    • primaryKey:逻辑表对应真实表的主键。
    • type:逻辑表的类型,目前逻辑表只有全局表和普通表,如果未配置就是普通表;全局表配置为global。

datanode标签

  1. 该标签用于定义节点。
1
2
3
<dataNode name="dn1" dataHost="dhost1" database="db01" />
<dataNode name="dn2" dataHost="dhost2" database="db01" />
<dataNode name="dn3" dataHost="dhost3" database="db01" />
  1. dataNode 属性:
    • name:定义数据节点名称。
    • dataHost:数据库实例主机名称,引用自dataHost标签中name属性。
    • database:定义分片所属数据库。

datahost标签

  1. 该标签在MyCat逻辑库中作为底层标签存在, 直接定义了具体的数据库实例、读写分离、心跳语句。
1
2
3
4
5
6
7
8
9
<dataHost name="dhost1" maxCon="1000" minCon="10" balance="0"
    writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"
    slaveThreshold="100">
    <heartbeat>select user()</heartbeat>

    <writeHost host="master" url="jdbc:mysql://192.168.200.210:3306?
        useSSL=false&amp;serverTimezone=Asia/Shanghai&amp;characterEncoding=utf8"
        user="root" password="1234" />
</dataHost>
  1. dataNode 属性:
    • name:唯一标识,供上层标签使用。
    • maxCon/minCon:最大连接数/最小连接数。
    • balance:负载均衡策略,取值 0,1,2,3。
    • writeType:写操作分发方式(0:写操作转发到第一个writeHost,第一个挂了,切换到第二个;1:写操作随机分发到配置的writeHost)。
    • dbDriver:数据库驱动,支持 native、jdbc。

rule.xml

  1. rule.xml中定义所有拆分表的规则, 在使用过程中可以灵活的使用分片算法, 或者对同一个分片算法使用不同的参数, 它让分片过程可配置化。主要包含两类标签:tableRule、Function。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<tableRule name="auto-sharding-long">
    <rule>
        <columns>id</columns>
        <algorithm>rang-long</algorithm>
    </rule>
</tableRule>

<function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
    <property name="mapFile">autopartition-long.txt</property>
</function>
  1. autopartition-long.txt
# range start-end, data node index
# K=1000,M=10000
0-500M=0
500M-1000M=1
1000M-1500M=2

server.xml

  1. server.xml配置文件包含了MyCat的系统配置信息,主要有两个重要的标签:system、user。
 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
<user name="root" defaultAccount="true">
    <!-- 用户密码 -->
    <property name="password">123456</property>
    <!-- 用户可访问的逻辑数据库有,多个逻辑库使用英文逗号分隔开 -->
    <property name="schemas">DB01</property>
    <!-- 表级 DML 权限设置 -->
    <!--
    <privileges check="true">
        <schema name="DB01" dml="0110" >
            <table name="TB_ORDER" dml="1110"></table>
        </schema>
    </privileges>
    -->
</user>

<user name="user">
    <!-- 用户密码 -->
    <property name="password">123456</property>
    <!-- 用户可访问的逻辑数据库有,多个逻辑库使用英文逗号分隔开 -->
    <property name="schemas">DB01</property>
    <!-- 用户的读写权限 -->
    <property name="readOnly">true</property>
    <!-- 限制前端的连接数量,如果为0或者没有配置表示不限制 -->
    <property name="benchmark">1000</property>
    <!-- 开启密码加密功能 默认值为0,表示不进行加密 -->
    <property name="usingDecrypt">1</property>
</user>
  1. 主要配置MyCat中的系统配置(system)信息,对应的系统配置项及其含义,如下:
属性 取值 含义
charset utf8 设置Mycat的字符集, 字符集需要与MySQL的字符集保持一致
nonePasswordLogin 0,1 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户
useHandshakeV10 0,1 使用该选项主要的目的是为了能够兼容高版本的jdbc驱动, 是否采用HandshakeV10Packet来与client进行通信, 1:是, 0:否
useSqlStat 0,1 开启SQL实时统计, 1 为开启 , 0 为关闭 ;开启之后, MyCat会自动统计SQL语句的执行情况 ; mysql -h 127.0.0.1 -P 9066-u root -p 查看MyCat执行的SQL, 执行效率比较低的SQL , SQL的整体执行情况、读写比例等 ; show @@sql ; show @@sql.slow ; show @@sql.sum
useGlobleTableCheck 0,1 是否开启全局表的一致性检测。1为开启 ,0为关闭
sqlExecuteTimeout 1000 SQL语句执行的超时时间 , 单位为 s
sequnceHandlerType 0,1,2 用来指定Mycat全局序列类型,0 为本地文件,1 为数据库方式,2 为时间戳列方式,默认使用本地文件方式,文件方式主要用于测试
sequnceHandlerPattern 正则表达式 必须带有MYCATSEQ或者 mycatseq进入序列匹配流程 注意MYCATSEQ_有空格的情况
subqueryRelationshipCheck true,false 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false
useCompression 0,1 开启mysql压缩协议 , 0 : 关闭, 1 : 开启
fakeMySQLVersion 5.5,5.6 设置模拟的MySQL版本号
defaultSqlParser 由于MyCat的最初版本使用了FoundationDB的SQL解析器, 在MyCat1.3后增加了Druid解析器, 所以要设置defaultSqlParser属性来指定默认的解析器; 解析器有两个 :druidparser 和 fdbparser, 在MyCat1.4之后,默认是druidparser,fdbparser已经废除了
processors 1,2…. 指定系统可用的线程数量, 默认值为CPU核心x 每个核心运行线程数量; processors 会影响processorBufferPool,processorBufferLocalPercent,processorExecutor属性, 所有, 在性能调优时, 可以适当地修改processors值
processorBufferChunk 指定每次分配Socket Direct Buffer默认值为4096字节, 也会影响BufferPool长度,如果一次性获取字节过多而导致buffer不够用, 则会出现警告, 可以调大该值
processorExecutor 指定NIOProcessor上共享businessExecutor固定线程池的大小;MyCat把异步任务交给 businessExecutor线程池中, 在新版本的MyCat中这个连接池使用频次不高, 可以适当地把该值调小
packetHeaderSize 指定MySQL协议中的报文头长度, 默认4个字节
maxPacketSize 指定MySQL协议可以携带的数据最大大小, 默认值为16M
idleTimeout 30 指定连接的空闲时间的超时长度;如果超时,将关闭资源并回收, 默认30分钟
txIsolation 1,2,3,4 初始化前端连接的事务隔离级别,默认为REPEATED_READ , 对应数字为3READ_UNCOMMITED=1;READ_COMMITTED=2; REPEATED_READ=3;SERIALIZABLE=4
sqlExecuteTimeout 300 执行SQL的超时时间, 如果SQL语句执行超时,将关闭连接; 默认300秒;
serverPort 8066 定义MyCat的使用端口, 默认8066
managerPort 9066 定义MyCat的管理端口, 默认9066

MyCat分片

垂直拆分

  1. 在业务系统中,涉及以下表结构,但是由于用户与订单每天都会产生大量的数据,单台服务器的数据存储及处理能力是有限的,可以对数据库表进行拆分,原有的数据库表如下。
  2. 现在考虑将其进行垂直分库操作,将商品相关的表拆分到一个数据库服务器,订单表拆分的一个数据库服务器,用户及省市区表拆分到一个服务器。

名称 IP 端口
MyCat 172.16.0.10 8066,9066
mysql1 172.16.0.101 3306
mysql2 172.16.0.102 3307
mysql3 172.16.0.103 3308

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
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- 逻辑库 -->
    <!-- name: 逻辑库名字 -->
    <!-- checkSQLschema: 
        当设置为true时,比如发送一条sql:select * from mycat_order.t_order,那么MyCat会自动去掉mycat_order逻辑库名字前缀,把sql变为:select * from t_order, 这样有效避免报表或视图不存在错误。
        如果使用select * from test.t_order ,sql语句中所带的逻辑库名字跟schema标签中的name不一致的话,MyCat不会自动去掉逻辑库名字前缀,如果逻辑库不存在,仍然会报错。
    -->
    <!-- sqlMaxLimit:  如果每次执行的sql语句后面没有跟上limit xx关键字的话,MyCat会自动在sql语句的后面拼上limit 100 -->
    <!-- dataNode: 用于指定没有分配分片节点的那些表的默认数据节点 -->
    <schema name="shopping" checkSQLschema="false" sqlMaxLimit="100">
        <!-- 逻辑表,以下都没有配置分片规则rule,因为垂直分表不需要它 -->
        <!-- name: 逻辑表的名字,同一个逻辑库schema中的逻辑表的名称应该唯一 -->
        <!-- dataNode: 配置逻辑表分布的数据节点,名字需要与dataNode标签的name对应上 -->
        <!-- rule: 配置逻辑表的分片规则,需要在rule.xml中声明的规则名字对应上 -->
        <!-- ruleRequired: 指定分片规则是否必须,如果为true,但是没有指定rule,程序会报错 -->
        <!-- primaryKey: 指定逻辑表对应真实表的主键 -->
        <!-- type: 指定该逻辑表是全局表还是普通逻辑表。type="global"表示全局表 -->
        <!-- autoIncrement: 指定是否自增长主键 -->
        <!-- needAddLimit: 指定逻辑表是否在查询的时候自动添加limit去限制返回的结果集记录数,默认为true,如果语句中已经包含了limit关键字,则不会重复添加 -->
        <table name="tb_goods_base" dataNode="dn1" primaryKey="id" />
        <table name="tb_goods_brand" dataNode="dn1" primaryKey="id" />
        <table name="tb_goods_cat" dataNode="dn1" primaryKey="id" />
        <table name="tb_goods_desc" dataNode="dn1" primaryKey="goods_id" />
        <table name="tb_goods_item" dataNode="dn1" primaryKey="id" />

        <table name="tb_order_item" dataNode="dn2" primaryKey="id" />
        <table name="tb_order_master" dataNode="dn2" primaryKey="order_id" />
        <table name="tb_order_pay_log" dataNode="dn2" primaryKey="out_trade_no" />

        <table name="tb_user" dataNode="dn3" primaryKey="id" />
        <table name="tb_user_address" dataNode="dn3" primaryKey="id" />

        <!-- 全局表 -->
        <table name="tb_areas_provinces" dataNode="dn1,dn2,dn3" primaryKey="id" type="global"/>
        <table name="tb_areas_city" dataNode="dn1,dn2,dn3" primaryKey="id" type="global"/>
        <table name="tb_areas_region" dataNode="dn1,dn2,dn3" primaryKey="id" type="global"/>

        <!--
        <table name="t_order"  dataNode="dn1,dn2" rule="mod-long">
            # 定义E-R分片的子表,通过标签上的属性与父表进行关联
            #   name:子表的名称t_order_detail
            #   primaryKey:子表的主键
            #   joinKey:新增子表记录的时候,会根据该值查询父表在哪个分片节点上。(子表中字段的名称order_i
            #   parentKey属性:与父表建立关联关系的列,结合joinKey确定好子表记录存放的分片节点,插入子表记录时直接插入到该分片节点上。(父表中字段名称order_id)
            #   needAddLimit属性: 指定逻辑表是否在查询的时候自动添加limit去限制返回的结果集记录数,默认为true,如果语句中已经包含了limit关键字,则不会重复添加
            <childTable name="t_order_detail" primaryKey="od_id" joinKey="order_id" parentKey="order_id"></childTable>
        </table>
        -->
    </schema>

    <!-- 数据节点 -->
    <!-- name: 指定分片节点的名称,与声明逻辑表table标签中的dataNode名字对应上 -->
    <!-- dataHost: 指定分片节点所在的节点主机(数据库实例),与dataHost标签声明的name对应 -->
    <!-- database: 真实数据库名称 -->
    <dataNode name="dn1" dataHost="dhost1" database="shopping" />
    <dataNode name="dn2" dataHost="dhost2" database="shopping" />
    <dataNode name="dn3" dataHost="dhost3" database="shopping" />

    <!-- 具体数据库实例 -->
    <dataHost name="dhost1" maxCon="1000" minCon="10" balance="0"
        writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <!--心跳检测 -->
        <heartbeat>select user()</heartbeat>
        <!-- 写服务器,如果要配置读写,添加readHost标签即可 -->
        <writeHost host="M1" url="172.16.0.101:3306" user="root" password="123456">
        </writeHost>
    </dataHost>

    <dataHost name="dhost2" maxCon="1000" minCon="10" balance="0"
        writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <!--心跳检测 -->
        <heartbeat>select user()</heartbeat>
        <!-- 写服务器,如果要配置读写,添加readHost标签即可 -->
        <writeHost host="M2" url="172.16.0.102:3306" user="root" password="123456">
        </writeHost>
    </dataHost>

    <!-- name: 指定分片主机的名称,供dataNode标签使用 -->
    <!-- maxCon: 指定读写实例的连接池的最大连接数量 -->
    <!-- minCon: 指定读写实例的连接池的最小连接数量,初始化连接池的大小 -->
    <!-- balance: 指定负载均衡的类型
            balance = “0” : 不开启读写分离,所有的读请求都发送到可用的writeHost写节点上(不会发readHost)
            balance = “1” : 全部的readHost与stand by writeHost参与select语句的负载均衡,
            balance = “2” : 读操作会随机发往writeHost以及 readHost,理论上实现的是负载均衡
            balance = “3” : 配置了readHost时读操作会随机发往readHost(不会发writeHost),而没有配置readHost时读操作会发往第一个writeHost。
    -->
    <!-- writeType:  
            writeType="0": 所有写操作发送到配置的第一个writeHost,当第一个writeHost宕机时,切换到第二个writeHost,重新启动后以切换后的为准,切换记录在配置文件:dnindex.properties中
            writeType="1": 所有写操作都随发送到配置的writeHost
    -->
    <!-- dbType: 指定后端数据库类型,支持mysql、oracle等 -->
    <!-- dbDriver: 指定后端数据库连接驱动信息,支持native和jdbc -->
    <!-- switchType: 指定切换方式 
            switchType = -1:不自动切换
            switchType = 1:自动切换(默认)
            switchType = 2:基于MySql主从同步的状态来决定是否切换,心跳语句: show slave status
            switchType = 3: 基于mysql galary cluster的切换机制,心跳语句: show status like 'wsrep%'
    -->
    <!-- slaveThreshold:  -->
    <dataHost name="dhost3" maxCon="1000" minCon="10" balance="0"
        writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <!--心跳检测,指定后端数据库进行心跳检查的语句 -->
        <heartbeat>select user()</heartbeat>
        <!-- 写服务器,如果要配置读写,添加readHost标签即可 -->
        <!-- host: 用于标识不同实例,一般 writeHost 我们使用M1,readHost 我们用S1 -->
        <!-- url: 后端实例连接地址,如果是使用 native 的 dbDriver,则一般为 address:port 这种形式,用 JDBC 或其他的 dbDriver,则需要特殊指定,使用 JDBC 时则可以这么写:jdbc:mysql://localhost:3306/ -->
        <!-- user: 后端存储实例需要的用户名 -->
        <!-- password: 后端存储实例需要的密码 -->
        <!-- weight: 权重 配置在 readhost 中作为读节点的权重 -->
        <!-- usingDecrypt: 是否对密码加密默认 0 否 如需要开启配置 1,同时使用加密程序对密码加密 -->
        <writeHost host="M3" url="172.16.0.103:3306" user="root" password="123456">
        </writeHost>
    </dataHost>
</mycat:schema>

server.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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
    <system>
        <!-- 字符集,需要保证MyCat字符集与数据库字符集一致 -->
        <property name="charset">utf8mb4</property>
        <!-- SQL解析器 -->
        <property name="defaultSqlParser">druidparser</property>
        <!-- MyCat系统可用的线程数量 -->
        <property name="processors">1</property>
        <!-- 指定MyCat全局序列的类型,0表示本地文件方式 1表示数据库方式 2表示时间戳方式  -->
        <property name="sequenceHandlerType">0</property>
        <!-- 1为开启实时统计、0为关闭 -->
        <property name="useSqlStat">0</property>
        <!-- 1为开启全局表一致性检测、0为关闭 --> 
        <property name="useGlobleTableCheck">0</property>
        <!-- MyCat的端口,默认为8066 --> 
        <property name="serverPort">8066</property>
        <!-- MyCat管理端口,默认为9066  --> 
        <property name="managerPort">9066</property>
        <!-- 服务监听的IP地址,默认为0.0.0.0 --> 
        <property name="bindIp">0.0.0.0</property>
        <!-- 指定连接的空闲时间的超时长度,如果某个连接的空闲时间超时长度大于idleTimeout,则该连接会被回收,默认30分钟 -->
        <property name="idleTimeout">300000</property>
        <!--分布式事务开关,0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但是记录分布式事务日志-->
        <property name="handleDistributedTransactions">0</property>
        <!-- 配置是否启用非堆内存处理跨分片结果集。 1开启   0关闭 -->
        <property name="useOffHeapForMerge">1</property>
        <!--是否采用zookeeper协调切换  -->
        <property name="useZKSwitch">true</property>
    </system>

    <user name="root" defaultAccount="true">
        <!-- 用户密码 -->
        <property name="password">123456</property>
        <!-- 用户可访问的逻辑数据库有,多个逻辑库使用英文逗号分隔开 -->
        <property name="schemas">shopping</property>
        <!-- 表级 DML 权限设置 -->
        <privileges check="false">
            <schema name="shopping" dml="0110" >
                <table name="tb_goods_base" dml="1111"></table>
            </schema>
        </privileges>
    </user>

    <user name="user">
        <!-- 用户密码 -->
        <property name="password">123456</property>
        <!-- 用户可访问的逻辑数据库有,多个逻辑库使用英文逗号分隔开 -->
        <property name="schemas">shopping</property>
        <!-- 用户的读写权限 -->
        <property name="readOnly">true</property>
    </user>
</mycat:server>

github

  1. 完整代码参看github。https://github.com/helium-chain/mycat-vertical

水平拆分

  1. 在业务系统中,有一张表(日志表),业务系统每天都会产生大量的日志数据,单台服务器的数据存储及处理能力是有限的,可以对数据库表进行拆分。

名称 IP 端口
MyCat 172.16.0.10 8066,9066
mysql1 172.16.0.101 3306
mysql2 172.16.0.102 3307
mysql3 172.16.0.103 3308

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
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- 逻辑库 -->
    <!-- name: 逻辑库名字 -->
    <!-- checkSQLschema: 
        当设置为true时,比如发送一条sql:select * from mycat_order.t_order,那么MyCat会自动去掉mycat_order逻辑库名字前缀,把sql变为:select * from t_order, 这样有效避免报表或视图不存在错误。
        如果使用select * from test.t_order ,sql语句中所带的逻辑库名字跟schema标签中的name不一致的话,MyCat不会自动去掉逻辑库名字前缀,如果逻辑库不存在,仍然会报错。
    -->
    <!-- sqlMaxLimit:  如果每次执行的sql语句后面没有跟上limit xx关键字的话,MyCat会自动在sql语句的后面拼上limit 100 -->
    <!-- dataNode: 用于指定没有分配分片节点的那些表的默认数据节点 -->
    <schema name="shopping" checkSQLschema="false" sqlMaxLimit="100">
        <!-- 逻辑表,以下都没有配置分片规则rule,因为垂直分表不需要它 -->
        <!-- name: 逻辑表的名字,同一个逻辑库schema中的逻辑表的名称应该唯一 -->
        <!-- dataNode: 配置逻辑表分布的数据节点,名字需要与dataNode标签的name对应上 -->
        <!-- rule: 配置逻辑表的分片规则,需要在rule.xml中声明的规则名字对应上 -->
        <!-- ruleRequired: 指定分片规则是否必须,如果为true,但是没有指定rule,程序会报错 -->
        <!-- primaryKey: 指定逻辑表对应真实表的主键 -->
        <!-- type: 指定该逻辑表是全局表还是普通逻辑表。type="global"表示全局表 -->
        <!-- autoIncrement: 指定是否自增长主键 -->
        <!-- needAddLimit: 指定逻辑表是否在查询的时候自动添加limit去限制返回的结果集记录数,默认为true,如果语句中已经包含了limit关键字,则不会重复添加 -->
        <table name="tb_goods_base" dataNode="dn1" primaryKey="id" />
        <table name="tb_goods_brand" dataNode="dn1" primaryKey="id" />
        <table name="tb_goods_cat" dataNode="dn1" primaryKey="id" />
        <table name="tb_goods_desc" dataNode="dn1" primaryKey="goods_id" />
        <table name="tb_goods_item" dataNode="dn1" primaryKey="id" />

        <table name="tb_order_item" dataNode="dn2" primaryKey="id" />
        <table name="tb_order_master" dataNode="dn2" primaryKey="order_id" />
        <table name="tb_order_pay_log" dataNode="dn2" primaryKey="out_trade_no" />

        <table name="tb_user" dataNode="dn3" primaryKey="id" />
        <table name="tb_user_address" dataNode="dn3" primaryKey="id" />

        <!-- 全局表 -->
        <table name="tb_areas_provinces" dataNode="dn1,dn2,dn3" primaryKey="id" type="global"/>
        <table name="tb_areas_city" dataNode="dn1,dn2,dn3" primaryKey="id" type="global"/>
        <table name="tb_areas_region" dataNode="dn1,dn2,dn3" primaryKey="id" type="global"/>

        <!--
        <table name="t_order"  dataNode="dn1,dn2" rule="mod-long">
            # 定义E-R分片的子表,通过标签上的属性与父表进行关联
            #   name:子表的名称t_order_detail
            #   primaryKey:子表的主键
            #   joinKey:新增子表记录的时候,会根据该值查询父表在哪个分片节点上。(子表中字段的名称order_i
            #   parentKey属性:与父表建立关联关系的列,结合joinKey确定好子表记录存放的分片节点,插入子表记录时直接插入到该分片节点上。(父表中字段名称order_id)
            #   needAddLimit属性: 指定逻辑表是否在查询的时候自动添加limit去限制返回的结果集记录数,默认为true,如果语句中已经包含了limit关键字,则不会重复添加
            <childTable name="t_order_detail" primaryKey="od_id" joinKey="order_id" parentKey="order_id"></childTable>
        </table>
        -->
    </schema>

    <schema name="logs" checkSQLschema="false" sqlMaxLimit="100">
        <!-- 水平分片 -->
        <!-- rule:分片规则 -->
        <table name="tb_log" dataNode="dn4,dn5,dn6" primaryKey="id" rule="mod-long" />
    </schema>

    <!-- 数据节点 -->
    <!-- name: 指定分片节点的名称,与声明逻辑表table标签中的dataNode名字对应上 -->
    <!-- dataHost: 指定分片节点所在的节点主机(数据库实例),与dataHost标签声明的name对应 -->
    <!-- database: 真实数据库名称 -->
    <dataNode name="dn1" dataHost="dhost1" database="shopping" />
    <dataNode name="dn2" dataHost="dhost2" database="shopping" />
    <dataNode name="dn3" dataHost="dhost3" database="shopping" />

    <dataNode name="dn4" dataHost="dhost1" database="logs" />
    <dataNode name="dn5" dataHost="dhost2" database="logs" />
    <dataNode name="dn6" dataHost="dhost3" database="logs" />


    <!-- 具体数据库实例 -->
    <dataHost name="dhost1" maxCon="1000" minCon="10" balance="0"
        writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <!--心跳检测 -->
        <heartbeat>select user()</heartbeat>
        <!-- 写服务器,如果要配置读写,添加readHost标签即可 -->
        <writeHost host="M1" url="172.16.0.101:3306" user="root" password="123456">
        </writeHost>
    </dataHost>

    <dataHost name="dhost2" maxCon="1000" minCon="10" balance="0"
        writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <!--心跳检测 -->
        <heartbeat>select user()</heartbeat>
        <!-- 写服务器,如果要配置读写,添加readHost标签即可 -->
        <writeHost host="M2" url="172.16.0.102:3306" user="root" password="123456">
        </writeHost>
    </dataHost>

    <!-- name: 指定分片主机的名称,供dataNode标签使用 -->
    <!-- maxCon: 指定读写实例的连接池的最大连接数量 -->
    <!-- minCon: 指定读写实例的连接池的最小连接数量,初始化连接池的大小 -->
    <!-- balance: 指定负载均衡的类型
            balance = “0” : 不开启读写分离,所有的读请求都发送到可用的writeHost写节点上(不会发readHost)
            balance = “1” : 全部的readHost与stand by writeHost参与select语句的负载均衡,
            balance = “2” : 读操作会随机发往writeHost以及 readHost,理论上实现的是负载均衡
            balance = “3” : 配置了readHost时读操作会随机发往readHost(不会发writeHost),而没有配置readHost时读操作会发往第一个writeHost。
    -->
    <!-- writeType:  
            writeType="0": 所有写操作发送到配置的第一个writeHost,当第一个writeHost宕机时,切换到第二个writeHost,重新启动后以切换后的为准,切换记录在配置文件:dnindex.properties中
            writeType="1": 所有写操作都随发送到配置的writeHost
    -->
    <!-- dbType: 指定后端数据库类型,支持mysql、oracle等 -->
    <!-- dbDriver: 指定后端数据库连接驱动信息,支持native和jdbc -->
    <!-- switchType: 指定切换方式 
            switchType = -1:不自动切换
            switchType = 1:自动切换(默认)
            switchType = 2:基于MySql主从同步的状态来决定是否切换,心跳语句: show slave status
            switchType = 3: 基于mysql galary cluster的切换机制,心跳语句: show status like 'wsrep%'
    -->
    <!-- slaveThreshold:  -->
    <dataHost name="dhost3" maxCon="1000" minCon="10" balance="0"
        writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <!--心跳检测,指定后端数据库进行心跳检查的语句 -->
        <heartbeat>select user()</heartbeat>
        <!-- 写服务器,如果要配置读写,添加readHost标签即可 -->
        <!-- host: 用于标识不同实例,一般 writeHost 我们使用M1,readHost 我们用S1 -->
        <!-- url: 后端实例连接地址,如果是使用 native 的 dbDriver,则一般为 address:port 这种形式,用 JDBC 或其他的 dbDriver,则需要特殊指定,使用 JDBC 时则可以这么写:jdbc:mysql://localhost:3306/ -->
        <!-- user: 后端存储实例需要的用户名 -->
        <!-- password: 后端存储实例需要的密码 -->
        <!-- weight: 权重 配置在 readhost 中作为读节点的权重 -->
        <!-- usingDecrypt: 是否对密码加密默认 0 否 如需要开启配置 1,同时使用加密程序对密码加密 -->
        <writeHost host="M3" url="172.16.0.103:3306" user="root" password="123456">
        </writeHost>
    </dataHost>
</mycat:schema>

server.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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
    <system>
        <!-- 字符集,需要保证MyCat字符集与数据库字符集一致 -->
        <property name="charset">utf8mb4</property>
        <!-- SQL解析器 -->
        <property name="defaultSqlParser">druidparser</property>
        <!-- MyCat系统可用的线程数量 -->
        <property name="processors">1</property>
        <!-- 指定MyCat全局序列的类型,0表示本地文件方式 1表示数据库方式 2表示时间戳方式  -->
        <property name="sequenceHandlerType">0</property>
        <!-- 1为开启实时统计、0为关闭 -->
        <property name="useSqlStat">0</property>
        <!-- 1为开启全局表一致性检测、0为关闭 --> 
        <property name="useGlobleTableCheck">0</property>
        <!-- MyCat的端口,默认为8066 --> 
        <property name="serverPort">8066</property>
        <!-- MyCat管理端口,默认为9066  --> 
        <property name="managerPort">9066</property>
        <!-- 服务监听的IP地址,默认为0.0.0.0 --> 
        <property name="bindIp">0.0.0.0</property>
        <!-- 指定连接的空闲时间的超时长度,如果某个连接的空闲时间超时长度大于idleTimeout,则该连接会被回收,默认30分钟 -->
        <property name="idleTimeout">300000</property>
        <!--分布式事务开关,0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但是记录分布式事务日志-->
        <property name="handleDistributedTransactions">0</property>
        <!-- 配置是否启用非堆内存处理跨分片结果集。 1开启   0关闭 -->
        <property name="useOffHeapForMerge">1</property>
        <!--是否采用zookeeper协调切换  -->
        <property name="useZKSwitch">true</property>
    </system>

    <user name="root" defaultAccount="true">
        <!-- 用户密码 -->
        <property name="password">123456</property>
        <!-- 用户可访问的逻辑数据库有,多个逻辑库使用英文逗号分隔开 -->
        <property name="schemas">shopping,logs</property>
        <!-- 表级 DML 权限设置 -->
        <privileges check="false">
            <schema name="shopping" dml="0110" >
                <table name="tb_goods_base" dml="1111"></table>
            </schema>
        </privileges>
    </user>

    <user name="user">
        <!-- 用户密码 -->
        <property name="password">123456</property>
        <!-- 用户可访问的逻辑数据库有,多个逻辑库使用英文逗号分隔开 -->
        <property name="schemas">shopping,logs</property>
        <!-- 用户的读写权限 -->
        <property name="readOnly">true</property>
    </user>
</mycat:server>

rule.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <!-- name: 规则名称 -->
    <tableRule name="mod-long">
        <rule>
            <!-- columns: 标识将要分片的表字段 -->
            <columns>id</columns>
            <!-- algorithm: 指定分片函数与function的对应关系 -->
            <algorithm>mod-long</algorithm>
        </rule>
    </tableRule>

    <!-- 分片对应函数 -->
    <!-- name: 对应tableRule的algorithm标签 -->
    <!-- class: 指定该分片算法对应的类 -->
    <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
        <!-- count: 数据节点的数量 -->
        <property name="count">3</property>
    </function>
</mycat:rule>

github

  1. 完整代码参看github。https://github.com/helium-chain/mycat-vertical-horizontal

分片规则

范围分片

  1. 根据指定的字段及其配置的范围与数据节点的对应情况,来决定该数据属于哪一个分片。

  1. schema.xml逻辑表配置:
1
<table name="TB_ORDER" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
  1. rule.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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <!-- name: 规则名称 -->
    <tableRule name="auto-sharding-long">
        <rule>
            <!-- columns: 标识将要分片的表字段 -->
            <columns>id</columns>
            <!-- 指定分片函数与function的对应关系 -->
            <algorithm>rang-long</algorithm>
        </rule>
    </tableRule>

    <!-- 分片对应函数 -->
    <!-- name: 对应tableRule的algorithm标签 -->
    <!-- class: 指定该分片算法对应的类 -->
    <function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
        <!-- mapFile: 对应的外部配置文件 -->
        <property name="mapFile">autopartition-long.txt</property>
        <!-- type: 默认值为0 ; 0 表示Integer , 1 表示String -->
        <property name="type">0</property>
        <!-- defaultNode: 默认节点 默认节点的所用:枚举分片时,如果碰到不识别的枚举值, 就让它路由到默认节点, 如果没有默认值,碰到不识别的则报错 -->
        <property name="defaultNode">0</property>
    </function>
</mycat:rule>
  1. 在rule.xml中配置分片规则时,关联了一个映射配置文件 autopartition-long.txt,该配置文件的配置如下:
# range start-end ,data node index
# K=1000,M=10000.

# 0-500万之间的值,存储在0号数据节点
0-500M=0
# 500万-1000万之间的数据存储在1号数据节点
500M-1000M=1
# 1000万-1500万的数据节点存储在2号节点
1000M-1500M=2
  1. 该分片规则,主要是针对于数字类型的字段适用。

取模分片

  1. 根据指定的字段值与节点数量进行求模运算,根据运算结果, 来决定该数据属于哪一个分片。

  1. schema.xml逻辑表配置:
1
<table name="tb_log" dataNode="dn4,dn5,dn6" primaryKey="id" rule="mod-long" />
  1. rule.xml分片规则配置:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <!-- name: 规则名称 -->
    <tableRule name="mod-long">
        <rule>
            <!-- columns: 标识将要分片的表字段 -->
            <columns>id</columns>
            <!-- algorithm: 指定分片函数与function的对应关系 -->
            <algorithm>mod-long</algorithm>
        </rule>
    </tableRule>

    
    <!-- 分片对应函数 -->
    <!-- name: 对应tableRule的algorithm标签 -->
    <!-- class: 指定该分片算法对应的类 -->
    <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
        <!-- count: 数据节点的数量 -->
        <property name="count">3</property>
    </function>
</mycat:rule>
  1. 该分片规则,主要是针对于数字类型的字段适用。

一致性hash分片

  1. 所谓一致性哈希,相同的哈希因子计算值总是被划分到相同的分区表中,不会因为分区节点的增加而改变原来数据的分区位置,有效的解决了分布式数据的拓容问题。

  1. schema.xml中逻辑表配置:
1
<table name="tb_order" dataNode="dn4,dn5,dn6" rule="sharding-by-murmur" />
  1. rule.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
30
31
32
33
34
35
36
37
38
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <!-- name: 规则名称 -->
    <tableRule name="sharding-by-murmur">
        <rule>
            <!-- columns: 标识将要分片的表字段 -->
            <columns>id</columns>
            <!-- algorithm: 指定分片函数与function的对应关系 -->
            <algorithm>murmur</algorithm>
        </rule>
    </tableRule>

    <!-- 分片对应函数 -->
    <!-- name: 对应tableRule的algorithm标签 -->
    <!-- class: 指定该分片算法对应的类 -->
    <function name="murmur" class="io.mycat.route.function.PartitionByMurmurHash">
        <!-- seed: 创建murmur_hash对象的种子,默认0 -->
        <property name="seed">0</property><!-- 默认是0 -->
        <!-- count: 要分片的数据库节点数量,必须指定,否则没法分片 -->
        <property name="count">3</property>
        <!-- virtualBucketTimes: 
            一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160
            倍;virtualBucketTimes*count就是虚拟结点数量 ;
        -->
        <property name="virtualBucketTimes">160</property>
        <!-- weightMapFile: 
            节点的权重,没有指定权重的节点默认是1。以properties文件的
            格式填写,以从0开始到count-1的整数值也就是节点索引为key,
            以节点权重值为值。所有权重值必须是正整数,否则以1代替
        -->
        <!-- bucketMapPath: 
            用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个
            属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出
            到这个文件,没有默认值,如果不指定,就不会输出任何东西
        -->
    </function>
</mycat:rule>

枚举分类

  1. 通过在配置文件中配置可能的枚举值, 指定数据分布到不同数据节点上, 本规则适用于按照省份、性别、状态拆分数据等业务。

  1. schema.xml中逻辑表配置:
1
<table name="tb_user" dataNode="dn4,dn5,dn6" rule="sharding-by-intfile-enumstatus"/>
  1. rule.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
30
31
32
33
34
35
36
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <!-- name: 规则名称 -->
    <tableRule name="sharding-by-intfile">
        <rule>
            <!-- columns: 标识将要分片的表字段 -->
            <columns>sharding_id</columns>
            <!-- algorithm: 指定分片函数与function的对应关系 -->
            <algorithm>hash-int</algorithm>
        </rule>
    </tableRule>

    <!-- 自己增加 tableRule -->
    <tableRule name="sharding-by-intfile-enumstatus">
        <rule>
            <columns>status</columns>
            <algorithm>hash-int</algorithm>
        </rule>
    </tableRule>

    <!-- 分片对应函数 -->
    <!-- name: 对应tableRule的algorithm标签 -->
    <!-- class: 指定该分片算法对应的类 -->
    <function name="mod-long" class="io.mycat.route.function.PartitionByFileMap">
        <!-- defaultNode:
            默认节点; 小于0 标识不设置默认节点, 大于等于0代表设置默认节点;
            默认节点的所用:枚举分片时,如果碰到不识别的枚举值, 就让它路由到默认节点; 
            如果没有默认值,碰到不识别的则报错 
        -->
        <property name="defaultNode">2</property>
        <!-- mapFile: 对应的外部文件 -->
        <property name="mapFile">partition-hash-int.txt</property>
        <!-- type: 默认值为0 ; 0 表示Integer , 1 表示String -->
    </function>
</mycat:rule>
  1. partition-hash-int.txt,内容如下:
1=0
2=1
3=2

应用指定算法

  1. 运行阶段由应用自主决定路由到那个分片 , 直接根据字符子串(必须是数字)计算分片号。

  1. schema.xml中逻辑表配置:
1
<table name="tb_app" dataNode="dn4,dn5,dn6" rule="sharding-by-substring" />
  1. rule.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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <!-- name: 规则名称 -->
    <tableRule name="sharding-by-substrin">
        <rule>
            <!-- columns: 标识将要分片的表字段 -->
            <columns>id</columns>
            <!-- algorithm: 指定分片函数与function的对应关系 -->
            <algorithm>sharding-by-substring</algorithm>
        </rule>
    </tableRule>

    <!-- 分片对应函数 -->
    <!-- name: 对应tableRule的algorithm标签 -->
    <!-- class: 指定该分片算法对应的类 -->
    <function name="sharding-by-substring" class="io.mycat.route.function.PartitionDirectBySubString">
        <!-- startIndex: 字符子串起始索引 -->
        <property name="startIndex">0</property> <!-- zero-based -->
        <!-- size: 字符长度 -->
        <property name="size">2</property>
        <!-- partitionCount: 分区(分片)数量 -->
        <property name="partitionCount">3</property>
        <!-- defaultPartition: 默认分片(在分片数量定义时, 字符标示的分片编号不在分片数量内时,使用默认分片)  -->
        <property name="defaultPartition">0</property>
    </function>
</mycat:rule>
  1. 示例说明:
    • id=05-100000002 , 在此配置中代表根据id中从 startIndex=0,开始,截取siz=2位数字即 05,05就是获取的分区。
    • 如果没找到对应的分片则默认分配到defaultPartition。

固定分片hash算法

  1. 该算法类似于十进制的求模运算,但是为二进制的操作,例如取 id 的二进制低 10 位 与 1111111111 进行位 & 运算,位与运算最小值为 0000000000,最大值为1111111111,转换为十进制,也就是位于0-1023之间。

  1. 特点:
    • 如果是求模,连续的值,分别分配到各个不同的分片;但是此算法会将连续的值可能分配到相同的分片,降低事务处理的难度。
    • 可以均匀分配,也可以非均匀分配。
    • 分片字段必须为数字类型。
  2. schema.xml中逻辑表配置:
1
<table name="tb_longhash" dataNode="dn4,dn5,dn6" rule="sharding-by-long-hash" />
  1. rule.xml中分片规则配置:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <!-- name: 规则名称 -->
    <tableRule name="sharding-by-long-hash">
        <rule>
            <!-- columns: 标识将要分片的表字段 -->
            <columns>id</columns>
            <!-- algorithm: 指定分片函数与function的对应关系 -->
            <algorithm>sharding-by-long-hash</algorithm>
        </rule>
    </tableRule>

    <!-- 分片对应函数 -->
    <!-- name: 对应tableRule的algorithm标签 -->
    <!-- class: 指定该分片算法对应的类 -->
    <function name="sharding-by-long-hash" class="io.mycat.route.function.PartitionByLong">
        <!-- partitionCount: 分片个数列表 -->
        <property name="partitionCount">2,1</property>
        <!-- partitionLength: 分片范围列表 -->
        <property name="partitionLength">256,512</property>
    </function>
</mycat:rule>
  1. 约束:
    • 分片长度 : 默认最大2^10,为 1024 ;
    • count, length的数组长度必须是一致的;

字符串hash解析算法

  1. 截取字符串中的指定位置的子字符串, 进行hash算法,算出分片。

  1. schema.xml中逻辑表配置:
1
<table name="tb_strhash" dataNode="dn4,dn5" rule="sharding-by-stringhash" />
  1. rule.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
30
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <!-- name: 规则名称 -->
    <tableRule name="sharding-by-stringhash">
        <rule>
            <!-- columns: 标识将要分片的表字段 -->
            <columns>name</columns>
            <!-- algorithm: 指定分片函数与function的对应关系 -->
            <algorithm>sharding-by-stringhash</algorithm>
        </rule>
    </tableRule>

    <!-- 分片对应函数 -->
    <!-- name: 对应tableRule的algorithm标签 -->
    <!-- class: 指定该分片算法对应的类 -->
    <function name="sharding-by-stringhash" class="io.mycat.route.function.PartitionByString">
        <!-- partitionLength: hash求模基数 ; length*count=1024 (出于性能考虑) -->
        <property name="partitionLength">512</property> <!-- zero-based -->
        <!-- partitionCount: 分区数 -->
        <property name="partitionCount">2</property>
        <!-- hashSlice: hash运算位 , 根据子字符串的hash运算
                0 代表 str.length()
                -1 代表 str.length()-1 
                大于0只代表数字自身
            可以理解为substring(start,end),start为0则只表示0
        -->
        <property name="hashSlice">0:2</property>
    </function>
</mycat:rule>

按天分片算法

  1. 按照日期及对应的时间周期来分片。

  1. schema.xml中逻辑表配置:
1
<table name="tb_datepart" dataNode="dn4,dn5,dn6" rule="sharding-by-date" />
  1. rule.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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <!-- name: 规则名称 -->
    <tableRule name="sharding-by-date">
        <rule>
            <!-- columns: 标识将要分片的表字段 -->
            <columns>create_time</columns>
            <!-- algorithm: 指定分片函数与function的对应关系 -->
            <algorithm>sharding-by-dat</algorithm>
        </rule>
    </tableRule>

    <!-- 分片对应函数 -->
    <!-- name: 对应tableRule的algorithm标签 -->
    <!-- class: 指定该分片算法对应的类 -->
    <function name="sharding-by-dat" class="io.mycat.route.function.PartitionByDate">
        <!-- dateFormat: 日期格式 -->
        <property name="dateFormat">yyyy-MM-dd</property>
        <!-- sBeginDate: 开始日期 -->
        <property name="sBeginDate">2022-01-01</property>
        <!-- sEndDate: 结束日期,如果配置了结束日期,则代码数据到达了这个日期的分片后,会重复从开始分片插入 -->
        <property name="sEndDate">2022-01-30</property>
        <!-- sPartionDay: 分区天数,默认值 10 ,从开始日期算起,每个10天一个分区 -->
        <property name="sPartionDay">10</property>
    </function>
</mycat:rule>

自然月分片

  1. 使用场景为按照月份来分片, 每个自然月为一个分片。

  1. schema.xml中逻辑表配置:
1
<table name="tb_monthpart" dataNode="dn4,dn5,dn6" rule="sharding-by-month" />
  1. rule.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
30
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <!-- name: 规则名称 -->
    <tableRule name="sharding-by-month">
        <rule>
            <!-- columns: 标识将要分片的表字段 -->
            <columns>create_time</columns>
            <!-- algorithm: 指定分片函数与function的对应关系 -->
            <algorithm>partbymonth</algorithm>
        </rule>
    </tableRule>

    <!-- 分片对应函数 -->
    <!-- name: 对应tableRule的algorithm标签 -->
    <!-- class: 指定该分片算法对应的类 -->
    <function name="partbymonth" class="io.mycat.route.function.PartitionByMonth">
        <!-- dateFormat: 日期格式 -->
        <property name="dateFormat">yyyy-MM-dd</property>
        <!-- sBeginDate: 开始日期 -->
        <property name="sBeginDate">2022-01-01</property>
        <!-- sEndDate: 结束日期,如果配置了结束日期,则代码数据到达了这个日期的分片后,会重复从开始分片插入 -->
        <property name="sEndDate">2022-03-31</property>
    </function>

    <!--
        从开始时间开始,一个月为一个分片,到达结束时间之后,会重复开始分片插入
        配置表的 dataNode 的分片,必须和分片规则数量一致,例如 2022-01-01 到 2022-12-31 ,一共需要12个分片。
    -->
</mycat:rule>

双主双丛读写分离

  1. 一个主机 Master1 用于处理所有写请求,它的从机 Slave1 和另一台主机 Master2 还有它的从机 Slave2 负责所有读请求。
  2. 当 Master1 主机宕机后,Master2 主机负责写请求,Master1、Master2 互为备机。

名称 IP 端口
MyCat 172.16.0.10 8066,9066
M1 172.16.0.101 3306
M2 172.16.0.102 3307
S1 172.16.0.103 3308
S2 172.16.0.104 3309

master01

  1. 修改配置文件 /etc/my.cnf。
1
2
3
4
5
6
7
8
#mysql 服务ID,保证整个集群环境中唯一,取值范围:1 – 2^32-1,默认为1
server-id=1
#指定同步的数据库
binlog-do-db=db01
binlog-do-db=db02
binlog-do-db=db03
# 在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates
  1. 创建账户并授权。
1
2
3
4
5
-- 创建itcast用户,并设置密码,该用户可在任意主机连接该MySQL服务
CREATE USER 'masterSlave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

-- 为 'master'@'%' 用户分配主从复制权限
GRANT REPLICATION SLAVE ON *.* TO 'masterSlave'@'%';
  1. 查看二进制日志坐标:
1
show master status;

master02

  1. 修改配置文件 /etc/my.cnf。
1
2
3
4
5
6
7
8
#mysql 服务ID,保证整个集群环境中唯一,取值范围:1 – 2^32-1,默认为1
server-id=2
#指定同步的数据库
binlog-do-db=db01
binlog-do-db=db02
binlog-do-db=db03
# 在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates
  1. 创建账户并授权。
1
2
3
4
5
-- 创建itcast用户,并设置密码,该用户可在任意主机连接该MySQL服务
CREATE USER 'masterSlave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

-- 为 'master'@'%' 用户分配主从复制权限
GRANT REPLICATION SLAVE ON *.* TO 'masterSlave'@'%';
  1. 查看二进制日志坐标:
1
show master status;

salve01

  1. 修改配置文件 /etc/my.cnf。
1
2
#mysql 服务ID,保证整个集群环境中唯一,取值范围:1 – 2^32-1,默认为1
server-id=3

salve02

  1. 修改配置文件 /etc/my.cnf。
1
2
#mysql 服务ID,保证整个集群环境中唯一,取值范围:1 – 2^32-1,默认为1
server-id=4

从库关联主库

  1. 在 slave01/slave02上执行:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
CHANGE MASTER TO MASTER_HOST='mysql-master01', MASTER_USER='masterSlave',
MASTER_PASSWORD='Root@123456', MASTER_LOG_FILE='binlog.000002',
MASTER_LOG_POS=663;

-- 开启主从复制
start slave;

-- 查看同步状态,主库S1/S2中查看。
show slave status \G;
    -- Slave_IO_Running: Yes
    -- Slave_SQL_Running: Yes

两主库相互复制

  1. M2 复制 M1,M1 复制 M2。
  2. 在M1/M2上执行:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
-- M1上执行
CHANGE MASTER TO MASTER_HOST='mysql-master02', MASTER_USER='masterSlave',
MASTER_PASSWORD='123456', MASTER_LOG_FILE='mysql-bin.000003',
MASTER_LOG_POS=194;

start slave;
show slave status \G;

-- M2上执行
CHANGE MASTER TO MASTER_HOST='mysql-master01', MASTER_USER='masterSlave',
MASTER_PASSWORD='123456', MASTER_LOG_FILE='mysql-bin.000003',
MASTER_LOG_POS=194;

start slave;
show slave status \G;

测试

  1. 分别在两台主库M1、M2上执行DDL、DML语句,查看涉及到的数据库服务器的数据同步情况。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
-- M1执行

create table tb_user(
    id int(11) not null primary key ,
    name varchar(50) not null,
    sex varchar(1)
)engine=innodb default charset=utf8mb4;

insert into tb_user(id,name,sex) values(1,'Tom','1');
insert into tb_user(id,name,sex) values(2,'Trigger','0');
insert into tb_user(id,name,sex) values(3,'Dawn','1');
insert into tb_user(id,name,sex) values(4,'Jack Ma','1');
insert into tb_user(id,name,sex) values(5,'Coco','0');
insert into tb_user(id,name,sex) values(6,'Jerry','1');

配置读写分离

 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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- 逻辑库 -->
    <!-- name: 逻辑库名字 -->
    <!-- checkSQLschema: 
        当设置为true时,比如发送一条sql:select * from mycat_order.t_order,那么MyCat会自动去掉mycat_order逻辑库名字前缀,把sql变为:select * from t_order, 这样有效避免报表或视图不存在错误。
        如果使用select * from test.t_order ,sql语句中所带的逻辑库名字跟schema标签中的name不一致的话,MyCat不会自动去掉逻辑库名字前缀,如果逻辑库不存在,仍然会报错。
    -->
    <!-- sqlMaxLimit:  如果每次执行的sql语句后面没有跟上limit xx关键字的话,MyCat会自动在sql语句的后面拼上limit 100 -->
    <!-- dataNode: 用于指定没有分配分片节点的那些表的默认数据节点 -->
    <schema name="shopping" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
        <!-- 逻辑表,以下都没有配置分片规则rule,因为垂直分表不需要它 -->
        <!-- name: 逻辑表的名字,同一个逻辑库schema中的逻辑表的名称应该唯一 -->
        <!-- dataNode: 配置逻辑表分布的数据节点,名字需要与dataNode标签的name对应上 -->
        <!-- rule: 配置逻辑表的分片规则,需要在rule.xml中声明的规则名字对应上 -->
        <!-- ruleRequired: 指定分片规则是否必须,如果为true,但是没有指定rule,程序会报错 -->
        <!-- primaryKey: 指定逻辑表对应真实表的主键 -->
        <!-- type: 指定该逻辑表是全局表还是普通逻辑表。type="global"表示全局表 -->
        <!-- autoIncrement: 指定是否自增长主键 -->
        <!-- needAddLimit: 指定逻辑表是否在查询的时候自动添加limit去限制返回的结果集记录数,默认为true,如果语句中已经包含了limit关键字,则不会重复添加 -->
        <table name="tb_user" primaryKey="id" />

        <!--
        <table name="t_order"  dataNode="dn1,dn2" rule="mod-long">
            # 定义E-R分片的子表,通过标签上的属性与父表进行关联
            #   name:子表的名称t_order_detail
            #   primaryKey:子表的主键
            #   joinKey:新增子表记录的时候,会根据该值查询父表在哪个分片节点上。(子表中字段的名称order_i
            #   parentKey属性:与父表建立关联关系的列,结合joinKey确定好子表记录存放的分片节点,插入子表记录时直接插入到该分片节点上。(父表中字段名称order_id)
            #   needAddLimit属性: 指定逻辑表是否在查询的时候自动添加limit去限制返回的结果集记录数,默认为true,如果语句中已经包含了limit关键字,则不会重复添加
            <childTable name="t_order_detail" primaryKey="od_id" joinKey="order_id" parentKey="order_id"></childTable>
        </table>
        -->
    </schema>

    <!-- 数据节点 -->
    <!-- name: 指定分片节点的名称,与声明逻辑表table标签中的dataNode名字对应上 -->
    <!-- dataHost: 指定分片节点所在的节点主机(数据库实例),与dataHost标签声明的name对应 -->
    <!-- database: 真实数据库名称 -->
    <dataNode name="dn1" dataHost="dhost1" database="shopping" />


    <!-- 具体数据库实例 -->
    <dataHost name="dhost1" maxCon="1000" minCon="10" balance="1"
        writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <!--心跳检测 -->
        <heartbeat>select user()</heartbeat>
        <!-- 写服务器,如果要配置读写,添加readHost标签即可 -->
        <writeHost host="M1" url="172.16.0.101:3306" user="root" password="123456">
            <!-- 读服务器 -->
            <readhost host="S1" url="172.16.0.103:3308" user="root" password="123456" />
        </writeHost>

        <!-- 写服务器,如果要配置读写,添加readHost标签即可 -->
        <writeHost host="M2" url="172.16.0.102:3306" user="root" password="123456">
            <!-- 读服务器 -->
            <readhost host="S2" url="172.16.0.104:3309" user="root" password="123456" />
        </writeHost>
    </dataHost>

    <!-- name: 指定分片主机的名称,供dataNode标签使用 -->
    <!-- maxCon: 指定读写实例的连接池的最大连接数量 -->
    <!-- minCon: 指定读写实例的连接池的最小连接数量,初始化连接池的大小 -->
    <!-- balance: 指定负载均衡的类型
            balance = “0” : 不开启读写分离,所有的读请求都发送到可用的writeHost写节点上(不会发readHost)
            balance = “1” : 全部的readHost与stand by writeHost参与select语句的负载均衡,
            balance = “2” : 读操作会随机发往writeHost以及 readHost,理论上实现的是负载均衡
            balance = “3” : 配置了readHost时读操作会随机发往readHost(不会发writeHost),而没有配置readHost时读操作会发往第一个writeHost。
    -->
    <!-- writeType:  
            writeType="0": 所有写操作发送到配置的第一个writeHost,当第一个writeHost宕机时,切换到第二个writeHost,重新启动后以切换后的为准,切换记录在配置文件:dnindex.properties中
            writeType="1": 所有写操作都随发送到配置的writeHost
    -->
    <!-- dbType: 指定后端数据库类型,支持mysql、oracle等 -->
    <!-- dbDriver: 指定后端数据库连接驱动信息,支持native和jdbc -->
    <!-- switchType: 指定切换方式 
            switchType = -1:不自动切换
            switchType = 1:自动切换(默认)
            switchType = 2:基于MySql主从同步的状态来决定是否切换,心跳语句: show slave status
            switchType = 3: 基于mysql galary cluster的切换机制,心跳语句: show status like 'wsrep%'
    -->
    <!-- slaveThreshold:  -->
    <!--<dataHost name="dhost3" maxCon="1000" minCon="10" balance="0"
        writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">-->
        <!--心跳检测,指定后端数据库进行心跳检查的语句 -->
        <!--<heartbeat>select user()</heartbeat>-->
        <!-- 写服务器,如果要配置读写,添加readHost标签即可 -->
        <!-- host: 用于标识不同实例,一般 writeHost 我们使用M1,readHost 我们用S1 -->
        <!-- url: 后端实例连接地址,如果是使用 native 的 dbDriver,则一般为 address:port 这种形式,用 JDBC 或其他的 dbDriver,则需要特殊指定,使用 JDBC 时则可以这么写:jdbc:mysql://localhost:3306/ -->
        <!-- user: 后端存储实例需要的用户名 -->
        <!-- password: 后端存储实例需要的密码 -->
        <!-- weight: 权重 配置在 readhost 中作为读节点的权重 -->
        <!-- usingDecrypt: 是否对密码加密默认 0 否 如需要开启配置 1,同时使用加密程序对密码加密 -->
        <!--<writeHost host="M3" url="172.16.0.103:3306" user="root" password="123456">
        </writeHost>-->
    </dataHost>
</mycat:schema>

github

  1. 完整代码参看 github。https://github.com/helium-chain/mycat-tow
  2. 参看其他:https://github.com/baojingyu/docker-mycat-mysql