Mycat 垂直拆分与水平拆分
垂直拆分按业务把不同的表放到不同库;水平拆分把同一张表的数据按规则分散到多个库。Mycat 通过
schema.xml把逻辑表映射到多个dataNode。
一、垂直拆分
1.1 场景
业务系统中,用户与订单每天都会产生大量数据,单台服务器的数据存储及处理能力是有限的,可以对数据库表进行拆分。
| 业务模块 | 表 |
|---|---|
| 省市区 | tb_areas_city、tb_areas_provinces、tb_areas_region |
| 商品 | tb_goods_base、tb_goods_brand、tb_goods_cat、tb_goods_desc、tb_goods_item |
| 订单 | tb_order_item、tb_order_master、tb_order_pay_log |
| 用户 | tb_user、tb_user_address |
拆分后:商品相关表 → dataNode1,订单相关表 → dataNode2,省市区 + 用户相关表 → dataNode3。
schema
└── table
├── dataNode1(商品)
├── dataNode2(订单)
└── dataNode3(省市区 / 用户)
1.2 准备
| 角色 | 地址(示例) |
|---|---|
| Mycat | 1.2.3.4 |
| MySQL | 1.2.3.5、1.2.3.6、1.2.3.7 |
分别在三台 MySQL 中创建数据库 shopping。
1.3 配置 schema.xml
<schema name="SHOPPING" checkSQLschema="true" sqlMaxLimit="100">
<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="dn3" primaryKey="id"/>
<table name="tb_areas_city" dataNode="dn3" primaryKey="id"/>
<table name="tb_areas_region" dataNode="dn3" primaryKey="id"/>
</schema>
<dataNode name="dn1" dataHost="dhost1" database="shopping" />
<dataNode name="dn2" dataHost="dhost2" database="shopping" />
<dataNode name="dn3" dataHost="dhost3" database="shopping" />
同时 server.xml 中该用户的 schemas 要包含 SHOPPING。
primaryKey用于 Mycat 定位分片,避免全节点扫描;表名大小写要与实际库表一致。
1.4 全局表配置
省、市、区 / 县表 tb_areas_provinces、tb_areas_city、tb_areas_region 属于数据字典表,多个业务模块中都可能会遇到,可以将其设置为全局表,利于业务操作。
<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"/>
全局表会在每个数据节点上保留一份完整数据,写操作同步到所有节点,适合数据量小、读取频繁的字典表。
二、水平拆分
2.1 场景
业务系统中有一张日志表 tb_log,每天都会产生大量日志数据,单台服务器的存储及处理能力有限,可以对表进行拆分:同一张表按规则分散到多个节点。
schema → table(tb_log)
├── dataNode1:tb_log
├── dataNode2:tb_log
└── dataNode3:tb_log
2.2 准备
分别在三台 MySQL 中创建数据库 itcast。
2.3 配置 schema.xml
<schema name="ITCAST" checkSQLschema="true" sqlMaxLimit="100">
<table name="tb_log" dataNode="dn4,dn5,dn6" rule="mod-long" />
</schema>
<dataNode name="dn4" dataHost="dhost1" database="itcast" />
<dataNode name="dn5" dataHost="dhost2" database="itcast" />
<dataNode name="dn6" dataHost="dhost3" database="itcast" />
server.xml 中用户可访问的逻辑库要加上 ITCAST:
<property name="schemas">SHOPPING,ITCAST</property>
水平拆分必须指定
rule;dataNode写多个节点,Mycat 按规则路由。
2.4 测试
在 mycat 的命令行中执行如下 SQL 创建表并插入数据,查看数据分布情况:
CREATE TABLE tb_log(
id bigint(20) NOT NULL COMMENT 'ID',
model_name varchar(200) DEFAULT NULL COMMENT '模块名',
model_value varchar(200) DEFAULT NULL COMMENT '模块值',
return_value varchar(200) DEFAULT NULL COMMENT '返回值',
return_class varchar(200) DEFAULT NULL COMMENT '返回值类型',
operate_user varchar(20) DEFAULT NULL COMMENT '操作用户',
operate_time varchar(20) DEFAULT NULL COMMENT '操作时间',
param_and_value varchar(500) DEFAULT NULL COMMENT '请求参数名及参数值',
operate_class varchar(200) DEFAULT NULL COMMENT '操作类',
operate_method varchar(200) DEFAULT NULL COMMENT '操作方法',
cost_time bigint(20) DEFAULT NULL COMMENT '执行方法耗时,单位 ms',
source int(1) DEFAULT NULL COMMENT '来源:1 PC,2 Android,3 IOS',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
建表会在所有分片节点上执行;插入时按
rule="mod-long"对id取模,数据落到不同节点。
三、垂直拆分 vs 水平拆分
| 对比项 | 垂直拆分 | 水平拆分 |
|---|---|---|
| 拆分对象 | 不同的表(按业务) | 同一张表的数据 |
| 解决的问题 | 单库表太多、业务耦合 | 单表数据量过大 |
| 典型配置 | dataNode="dn1" 每表一个节点 | dataNode="dn4,dn5,dn6" + rule |
| 是否需分片规则 | 不需要 | 必须指定 rule |
速查
<!-- schema.xml:垂直拆分,按业务把表分到不同节点 -->
<schema name="SHOPPING" checkSQLschema="true" sqlMaxLimit="100">
<table name="tb_goods_base" dataNode="dn1" primaryKey="id"/>
<table name="tb_order_master" dataNode="dn2" primaryKey="order_id"/>
<table name="tb_user" dataNode="dn3" primaryKey="id"/>
</schema>
<!-- 全局表:每个节点都存一份(字典表) -->
<table name="tb_areas_city" dataNode="dn1,dn2,dn3" primaryKey="id" type="global"/>
<!-- schema.xml:水平拆分,同一张表按规则分散 -->
<schema name="ITCAST" checkSQLschema="true" sqlMaxLimit="100">
<table name="tb_log" dataNode="dn4,dn5,dn6" rule="mod-long" />
</schema>
<!-- 节点与物理库的映射 -->
<dataNode name="dn4" dataHost="dhost1" database="itcast" />
| 要做什么 | 配置 |
|---|---|
| 按业务拆表 | 每张表 dataNode="dnX" |
| 字典表每节点一份 | dataNode="dn1,dn2,dn3" + type="global" |
| 同一张表分片 | 多个 dataNode + rule |
| 让用户能访问新库 | server.xml 的 schemas 加上逻辑库名 |
相关
- Mycat 配置:
schema.xml/rule.xml/server.xml - Mycat 分片规则:水平拆分用的各种
rule - Mycat 管理与监控:查看分片节点与数据分布