Mycat中间件案例

wen java案例 6

本文目录导读:

Mycat中间件案例

  1. 案例一:基础读写分离(一主一从)
  2. 案例二:垂直分库(业务拆分)
  3. 案例三:水平分表(分库分表核心)
  4. 案例四:全局表(字典表冗余)
  5. 案例五:分片 + 读写分离组合(生产高可用)
  6. 高级案例:多租户(按租户 ID 分片)
  7. MyCat 常见注意点与性能陷阱

MyCat 作为经典的数据库中间件,主要用于分库分表读写分离多租户隔离,下面提供几个从入门到进阶的真实案例,涵盖核心配置和业务场景。


基础读写分离(一主一从)

场景:单库压力大,读多写少,需要将查询请求分发到从库。

核心配置 schema.xml

<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- 逻辑库 -->
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
        <!-- 逻辑表:指向 dataNode -->
        <table name="user" primaryKey="id" dataNode="dn_user" />
    </schema>
    <!-- 数据节点:指向具体主机 -->
    <dataNode name="dn_user" dataHost="host1" database="user_db" />
    <dataHost name="host1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native">
        <!-- writeHost 为主库,readHost 为从库 -->
        <writeHost host="192.168.1.100" url="192.168.1.100:3306" user="root" password="123456">
            <readHost host="192.168.1.101" url="192.168.1.101:3306" user="root" password="123456" />
        </writeHost>
    </dataHost>
</mycat:schema>

使用效果

  • 执行 INSERT/UPDATE/DELETE 时,MyCat 会将 SQL 路由到 168.1.100(主库)。
  • 执行 SELECT 时,MyCat 会根据 balance="1" 的负载均衡算法,将请求分发到 168.1.100168.1.101,有效降低主库读压力。

垂直分库(业务拆分)

场景:将订单和用户业务拆分为独立的数据库,降低单一数据库的表数量。

核心配置 schema.xml

<schema name="SHOP" checkSQLschema="false" sqlMaxLimit="100">
    <!-- 订单表 -> 订单库 -->
    <table name="orders" primaryKey="id" dataNode="dn_order" />
    <!-- 用户表 -> 用户库 -->
    <table name="users" primaryKey="id" dataNode="dn_user" />
    <!-- 关联表:跨库查询(需全局表或ER Join) -->
    <table name="order_items" primaryKey="id" dataNode="dn_order,dn_user" rule="sharding-by-intfile" />
</schema>
<dataNode name="dn_order" dataHost="host1" database="order_db" />
<dataNode name="dn_user" dataHost="host2" database="user_db" />
<dataHost name="host1" ...>...</dataHost>
<dataHost name="host2" ...>...</dataHost>

使用效果

  • 订单相关的 SQL 自动发往 host1order_db
  • 用户相关的 SQL 自动发往 host2user_db
  • 注意SELECT * FROM orders o JOIN users u ON o.user_id = u.id 这种跨库关联查询在分库后无法直接执行,通常需要修改为应用层拼接,或者在 MyCat 中配置 全局表ER Join

水平分表(分库分表核心)

场景:订单表数据量极大(亿级),需要按规则将数据分散到多个 MySQL 实例中。

核心配置 schema.xml

<schema name="BIGDATA" checkSQLschema="false" sqlMaxLimit="100">
    <!-- 水平拆分:订单表按 id 取模 3,数据分布到 3 个数据节点 -->
    <table name="order_info" primaryKey="id" dataNode="dn1,dn2,dn3" rule="mod-long" />
</schema>
<dataNode name="dn1" dataHost="host1" database="db1" />
<dataNode name="dn2" dataHost="host2" database="db2" />
<dataNode name="dn3" dataHost="host3" database="db3" />

核心配置 rule.xml

<!-- 取模分片规则:按 id % 3 分配 -->
<rule name="mod-long">
    <columns>id</columns>
    <algorithm>mod-long</algorithm>
</rule>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
    <property name="count">3</property> <!-- 分片数量 -->
</function>

使用效果

  • INSERT INTO order_info (id, name) VALUES (1, 'a') -> 数据写入 dn1(因为 1%3=1)。
  • SELECT * FROM order_info WHERE id = 5 -> MyCat 直接路由到 dn2,查询速度极快。
  • SELECT * FROM order_info WHERE name = 'x'(无分片键)-> MyCat 会广播到所有 3 个节点进行查询(全表扫描),然后合并结果。

全局表(字典表冗余)

场景:分库后,每个分片数据库都有自己的 dict(字典表),避免跨库 JOIN。status_name 表。

核心配置 schema.xml

<schema name="BIGDATA" checkSQLschema="false" sqlMaxLimit="100">
    <table name="order_info" primaryKey="id" dataNode="dn1,dn2,dn3" rule="mod-long" />
    <!-- type="global" 表示全局表,数据自动冗余到所有分片 -->
    <table name="dict" primaryKey="code" dataNode="dn1,dn2,dn3" type="global" />
</schema>

使用效果

  • 当执行 INSERT INTO dict (code, name) VALUES ('01', '待支付') 时,MyCat 会将这条数据同时插入到 dn1dn2dn3 三个库中。
  • 查询时,SELECT * FROM order_info o JOIN dict d ON o.status = d.code 无需跨库,因为每个分片库中都有完整的 dict 表,Join 操作可以直接在本地完成。

分片 + 读写分离组合(生产高可用)

场景:每个分片再有主从同步,实现水平扩展 + 高可用。

核心配置 schema.xml

<!-- 分片1:使用 host1(主)和 host2(从) -->
<dataNode name="dn1" dataHost="shard1" database="db1" />
<!-- 分片2:使用 host3(主)和 host4(从) -->
<dataNode name="dn2" dataHost="shard2" database="db2" />
<dataNode name="dn3" dataHost="shard3" database="db3" />
<dataHost name="shard1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native">
    <writeHost host="host1" url="host1:3306" user="root" password="123">
        <readHost host="host2" url="host2:3306" user="root" password="123" />
    </writeHost>
</dataHost>
<dataHost name="shard2" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native">
    <writeHost host="host3" url="host3:3306" user="root" password="123">
        <readHost host="host4" url="host4:3306" user="root" password="123" />
    </writeHost>
</dataHost>
<!-- shard3 配置类似... -->

使用效果

  • 写入 dn1 分片时,只写 host1,从库 host2 自动复制。
  • 读取 dn1 分片时,可以在 host1host2 之间负载均衡。
  • host1 宕机,MyCat 自动将写操作切到 host2(如果开启了故障切换),保证高可用。

高级案例:多租户(按租户 ID 分片)

场景:SaaS 系统,不同租户的数据隔离,且租户间数据量差异大。

配置 schema.xmlrule.xml

  • 规则:使用 PartitionByStringPartitionByPrefixPattern,根据 tenant_id 字符串的特征(如首字符或哈希)进行分片。
  • 所有 SQL 必须强制携带 tenant_id,否则 MyCat 会广播所有分片,导致性能问题。
<table name="biz_data" primaryKey="id" dataNode="dn1,dn2,dn3,dn4" rule="hash-tenancy" />
<function name="hash-tenancy" class="io.mycat.route.function.PartitionByHash">
    <property name="partitionCount">4</property> <!-- 4 个分区 -->
</function>

使用效果

  • 查询时:WHERE tenant_id = 'T001',MyCat 秒速定位到特定分片。
  • 查询时:WHERE name = 'x'(缺少租户条件),MyCat 需要扫描 4 个分片,性能极差(在这个场景下需要业务层强制限制)。

MyCat 常见注意点与性能陷阱

  1. 分片键必须出现在 WHERE 中SELECT * FROM order WHERE id = 100 很快(直接路由);SELECT * FROM order WHERE name = 'xx' 会全分片扫描(慢)。
  2. 跨分片 JOIN 限制:MyCat 支持跨分片 JOIN(如 orderorder_item 使用 ER Join),但如果跨分片且无关联关系,必须使用全局表或应用层处理。
  3. 分布式事务弱化:MyCat 默认 SET AUTOCOMMIT=0 的分布式事务有性能开销(XA 协议),通常建议业务尽量使用本地事务。
  4. 计数限制COUNT(*) 在大数据分片下,MyCat 需要聚合所有分片结果,数据量巨大时建议在应用层通过 Redis 维护计数。

如果需要针对上述某个具体案例提供 具体的 server.xml(账号权限)配置启动/连接测试命令,可以随时告诉我,我可以继续补充。

抱歉,评论功能暂时关闭!