mycat分片
一、垂直拆分
按照不同的表(或者Schema)来切分到不同的数据库(主机)之上,这种切分可以称之为数据的垂直(纵向)切分。
1.1 准备工作
1).准备三个数据库实例,这里我用docker启动了三个容器
192.168.1.178:3306
192.168.1.178:3307
192.168.1.178:3308
2).准备一个mycat,这里我用的1.6
1.2 插入表
3306节点:
CREATE DATABASE IF NOT EXISTS `user_db` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
use `user_db`;
CREATE TABLE `tb_areas_city` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一ID',
`cityid` varchar(20) NOT NULL COMMENT '城市ID',
`city` varchar(50) NOT NULL COMMENT '城市名称',
`provinceid` varchar(20) NOT NULL COMMENT '省份ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=346 DEFAULT CHARSET=utf8 COMMENT='行政区域地州市信息表';
CREATE TABLE `tb_areas_provinces` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一ID',
`provinceid` varchar(20) NOT NULL COMMENT '省份ID',
`province` varchar(50) NOT NULL COMMENT '省份名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8 COMMENT='省份信息表';
CREATE TABLE `tb_areas_region` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一ID',
`areaid` varchar(20) NOT NULL COMMENT '区域ID',
`area` varchar(50) NOT NULL COMMENT '区域名称',
`cityid` varchar(20) NOT NULL COMMENT '城市ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3145 DEFAULT CHARSET=utf8 COMMENT='行政区域县区信息表';
CREATE TABLE `tb_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(32) NOT NULL COMMENT '密码,加密存储',
`phone` varchar(20) DEFAULT NULL COMMENT '注册手机号',
`email` varchar(50) DEFAULT NULL COMMENT '注册邮箱',
`created` datetime NOT NULL COMMENT '创建时间',
`updated` datetime NOT NULL,
`source_type` varchar(1) DEFAULT NULL COMMENT '会员来源:1:PC,2:H5,3:Android,4:IOS,5:WeChat',
`nick_name` varchar(50) DEFAULT NULL COMMENT '昵称',
`name` varchar(50) DEFAULT NULL COMMENT '真实姓名',
`status` varchar(1) DEFAULT NULL COMMENT '使用状态(Y正常 N非正常)',
`head_pic` varchar(150) DEFAULT NULL COMMENT '头像地址',
`qq` varchar(20) DEFAULT NULL COMMENT 'QQ号码',
`account_balance` decimal(10,0) DEFAULT NULL COMMENT '账户余额',
`is_mobile_check` varchar(1) DEFAULT '0' COMMENT '手机是否验证 (0否 1是)',
`is_email_check` varchar(1) DEFAULT '0' COMMENT '邮箱是否检测(0否 1是)',
`sex` varchar(1) DEFAULT '0' COMMENT '性别,1男,2女',
`user_level` int(11) DEFAULT NULL COMMENT '会员等级',
`points` int(11) DEFAULT NULL COMMENT '积分',
`experience_value` int(11) DEFAULT NULL COMMENT '经验值',
`birthday` datetime DEFAULT NULL COMMENT '生日',
`last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8 COMMENT='用户表';
CREATE TABLE `tb_user_address` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` varchar(50) DEFAULT NULL COMMENT '用户ID',
`province_id` varchar(10) DEFAULT NULL COMMENT '省',
`city_id` varchar(10) DEFAULT NULL COMMENT '市',
`town_id` varchar(10) DEFAULT NULL COMMENT '县/区',
`mobile` varchar(255) DEFAULT NULL COMMENT '手机',
`address` varchar(255) DEFAULT NULL COMMENT '详细地址',
`contact` varchar(255) DEFAULT NULL COMMENT '联系人',
`is_default` varchar(1) DEFAULT NULL COMMENT '是否是默认 1默认 0否',
`notes` varchar(255) DEFAULT NULL COMMENT '备注',
`create_date` datetime DEFAULT NULL COMMENT '创建日期',
`alias` varchar(50) DEFAULT NULL COMMENT '别名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8;
3307节点:
CREATE DATABASE IF NOT EXISTS `goods_db` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
USE `goods_db`;
CREATE TABLE `tb_goods_base` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`seller_id` varchar(20) DEFAULT NULL COMMENT '商家ID',
`goods_name` varchar(100) DEFAULT NULL COMMENT 'SPU名',
`default_item_id` bigint(20) DEFAULT NULL COMMENT '默认SKU',
`audit_status` varchar(2) DEFAULT NULL COMMENT '状态',
`is_marketable` varchar(1) DEFAULT NULL COMMENT '是否上架',
`brand_id` bigint(10) DEFAULT NULL COMMENT '品牌',
`caption` varchar(100) DEFAULT NULL COMMENT '副标题',
`category1_id` bigint(20) DEFAULT NULL COMMENT '一级类目',
`category2_id` bigint(10) DEFAULT NULL COMMENT '二级类目',
`category3_id` bigint(10) DEFAULT NULL COMMENT '三级类目',
`small_pic` varchar(150) DEFAULT NULL COMMENT '小图',
`price` decimal(10,2) DEFAULT NULL COMMENT '商城价',
`type_template_id` bigint(20) DEFAULT NULL COMMENT '分类模板ID',
`is_enable_spec` varchar(1) DEFAULT NULL COMMENT '是否启用规格',
`is_delete` varchar(1) DEFAULT NULL COMMENT '是否删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=149187842867977 DEFAULT CHARSET=utf8;
CREATE TABLE `tb_goods_desc` (
`goods_id` bigint(20) NOT NULL COMMENT 'SPU_ID',
`introduction` text COMMENT '描述',
`specification_items` varchar(3000) DEFAULT NULL COMMENT '规格结果集,所有规格,包含isSelected',
`custom_attribute_items` varchar(3000) DEFAULT NULL COMMENT '自定义属性(参数结果)',
`item_images` varchar(3000) DEFAULT NULL,
`package_list` varchar(3000) DEFAULT NULL COMMENT '包装列表',
`sale_service` varchar(3000) DEFAULT NULL COMMENT '售后服务',
PRIMARY KEY (`goods_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `tb_goods_item` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '商品id,同时也是商品编号',
`title` varchar(100) NOT NULL COMMENT '商品标题',
`sell_point` varchar(500) DEFAULT NULL COMMENT '商品卖点',
`price` decimal(20,2) NOT NULL COMMENT '商品价格,单位为:元',
`stock_count` int(10) DEFAULT NULL,
`num` int(10) NOT NULL COMMENT '库存数量',
`barcode` varchar(30) DEFAULT NULL COMMENT '商品条形码',
`image` varchar(2000) DEFAULT NULL COMMENT '商品图片',
`categoryId` bigint(10) NOT NULL COMMENT '所属类目,叶子类目',
`status` varchar(1) NOT NULL COMMENT '商品状态,1-正常,2-下架,3-删除',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '更新时间',
`item_sn` varchar(30) DEFAULT NULL,
`cost_pirce` decimal(10,2) DEFAULT NULL,
`market_price` decimal(10,2) DEFAULT NULL,
`is_default` varchar(1) DEFAULT NULL,
`goods_id` bigint(20) DEFAULT NULL,
`seller_id` varchar(30) DEFAULT NULL,
`cart_thumbnail` varchar(150) DEFAULT NULL,
`category` varchar(200) DEFAULT NULL,
`brand` varchar(100) DEFAULT NULL,
`spec` varchar(200) DEFAULT NULL,
`seller` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `cid` (`categoryId`),
KEY `status` (`status`),
KEY `updated` (`update_time`)
) ENGINE=InnoDB AUTO_INCREMENT=1369340 DEFAULT CHARSET=utf8 COMMENT='商品表';
CREATE TABLE `tb_goods_item_cat` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '类目ID',
`parent_id` bigint(20) DEFAULT NULL COMMENT '父类目ID=0时,代表的是一级的类目',
`name` varchar(50) DEFAULT NULL COMMENT '类目名称',
`type_id` bigint(11) DEFAULT NULL COMMENT '类型id',
PRIMARY KEY (`id`),
KEY `parent_id` (`parent_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1205 DEFAULT CHARSET=utf8 COMMENT='商品类目';
3308节点:
CREATE DATABASE IF NOT EXISTS `order_db` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
USE `order_db`;
CREATE TABLE `tb_order_item` (
`id` bigint(20) NOT NULL,
`item_id` bigint(20) NOT NULL COMMENT 'SKU_ID',
`goods_id` bigint(20) DEFAULT NULL COMMENT 'SPU_ID',
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`title` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品标题',
`price` decimal(20,2) DEFAULT NULL COMMENT '商品单价',
`num` int(10) DEFAULT NULL COMMENT '商品购买数量',
`total_fee` decimal(20,2) DEFAULT NULL COMMENT '商品总金额',
`pic_path` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品图片地址',
`seller_id` varchar(100) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `item_id` (`item_id`),
KEY `order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `tb_order_master` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`payment` decimal(20,2) DEFAULT NULL COMMENT '实付金额。精确到2位小数;单位:元。如:200.07,表示:200元7分',
`payment_type` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '支付类型,1、在线支付,2、货到付款',
`post_fee` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '邮费。精确到2位小数;单位:元。如:200.07,表示:200元7分',
`status` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '状态:1、未付款,2、已付款,3、未发货,4、已发货,5、交易成功,6、交易关闭,7、待评价',
`create_time` datetime DEFAULT NULL COMMENT '订单创建时间',
`update_time` datetime DEFAULT NULL COMMENT '订单更新时间',
`payment_time` datetime DEFAULT NULL COMMENT '付款时间',
`consign_time` datetime DEFAULT NULL COMMENT '发货时间',
`end_time` datetime DEFAULT NULL COMMENT '交易完成时间',
`close_time` datetime DEFAULT NULL COMMENT '交易关闭时间',
`shipping_name` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流名称',
`shipping_code` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流单号',
`user_id` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '用户id',
`buyer_message` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '买家留言',
`buyer_nick` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '买家昵称',
`buyer_rate` varchar(2) COLLATE utf8_bin DEFAULT NULL COMMENT '买家是否已经评价',
`receiver_province` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人地区名称(省,市,县)街道',
`receiver_city` varchar(12) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人手机',
`receiver_region` varchar(15) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人邮编',
`receiver` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人',
`expire` datetime DEFAULT NULL COMMENT '过期时间,定期清理',
`invoice_type` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '发票类型(普通发票,电子发票,增值税发票)',
`source_type` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '订单来源:1:app端,2:pc端,3:M端,4:微信端,5:手机qq端',
`seller_id` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '商家ID',
PRIMARY KEY (`order_id`),
KEY `create_time` (`create_time`),
KEY `buyer_nick` (`buyer_nick`),
KEY `status` (`status`),
KEY `payment_type` (`payment_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `tb_order_pay_log` (
`out_trade_no` varchar(30) NOT NULL COMMENT '支付订单号',
`create_time` datetime DEFAULT NULL COMMENT '创建日期',
`pay_time` datetime DEFAULT NULL COMMENT '支付完成时间',
`total_fee` bigint(20) DEFAULT NULL COMMENT '支付金额(分)',
`user_id` varchar(50) DEFAULT NULL COMMENT '用户ID',
`transaction_id` varchar(30) DEFAULT NULL COMMENT '交易号码',
`trade_state` varchar(1) DEFAULT NULL COMMENT '交易状态',
`order_list` varchar(200) DEFAULT NULL COMMENT '订单编号列表',
`pay_type` varchar(1) DEFAULT NULL COMMENT '支付类型',
PRIMARY KEY (`out_trade_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1.3 配置mycat
修改schema.xml的配置
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="test_db" checkSQLschema="false" sqlMaxLimit="100">
<table name="tb_areas_city" dataNode="dn1" primaryKey="id" />
<table name="tb_areas_provinces" dataNode="dn1" primaryKey="id" />
<table name="tb_areas_region" dataNode="dn1" primaryKey="id" />
<table name="tb_user" dataNode="dn1" primaryKey="id" />
<table name="tb_user_address" dataNode="dn1" primaryKey="id" />
<table name="tb_goods_base" dataNode="dn2" primaryKey="id" />
<table name="tb_goods_desc" dataNode="dn2" primaryKey="goods_id" />
<table name="tb_goods_item_cat" dataNode="dn2" primaryKey="id" />
<table name="tb_order_item" dataNode="dn3" primaryKey="id" />
<table name="tb_order_master" dataNode="dn3" primaryKey="order_id" />
<table name="tb_order_pay_log" dataNode="dn3" primaryKey="out_trade_no" />
</schema>
<dataNode name="dn1" dataHost="host1" database="user_db" />
<dataNode name="dn2" dataHost="host2" database="goods_db" />
<dataNode name="dn3" dataHost="host3" database="order_db" />
<dataHost name="host1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.1.178:3306" user="root" password="root"></writeHost>
</dataHost>
<dataHost name="host2" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM2" url="192.168.1.178:3307" user="root" password="root"></writeHost>
</dataHost>
<dataHost name="host3" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM3" url="192.168.1.178:3308" user="root" password="root"></writeHost>
</dataHost>
</mycat:schema>
修改server.xml
<user name="mycat">
<property name="password">123456</property>
<property name="schemas">test_db</property>
</user>
1.4 运行mycat
bin目录执行:
./mycat start
二、水平分片
在业务系统中, 有一张表(日志表), 业务系统每天都会产生大量的日志数据 , 单台服务器的数据存储及处理能力是有限的, 可以对数据库表进行拆分, 原有的数据库表拆分成以下表 :
2.1 准备环境
1).准备三个数据库实例,这里我用docker启动了三个容器
192.168.1.178:3306
192.168.1.178:3307
192.168.1.178:3308
2).准备一个mycat,这里我用的1.6
2.2 导入sql
create database log_db DEFAULT CHARACTER SET utf8mb4;
2.3 配置schema.xml的配置
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="LOG_DB" checkSQLschema="false" sqlMaxLimit="100">
<table name="tb_log" dataNode="dn1,dn2,dn3" primaryKey="id" rule="mod-long" />
</schema>
<dataNode name="dn1" dataHost="host1" database="log_db" />
<dataNode name="dn2" dataHost="host2" database="log_db" />
<dataNode name="dn3" dataHost="host3" database="log_db" />
<dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.1.178:3306" user="root" password="root"></writeHost>
</dataHost>
<dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM2" url="192.168.1.178:3307" user="root" password="root"></writeHost>
</dataHost>
<dataHost name="host3" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM3" url="192.168.1.178:3308" user="root" password="root"></writeHost>
</dataHost>
</mycat:schema>
2.4 配置server.xml的配置
<user name="root" defaultAccount="true">
<property name="password">root</property>
<property name="schemas">LOG_DB</property>
</user>
<user name="user">
<property name="password">root</property>
<property name="schemas">LOG_DB</property>
<property name="readOnly">true</property>
</user>
2.5 启动
bin目录下:
./mycat start
2.6 测试
连接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;
INSERT INTO `tb_log` (`id`, `model_name`, `model_value`, `return_value`, `return_class`, `operate_user`, `operate_time`, `param_and_value`, `operate_class`, `operate_method`, `cost_time`,`source`) VALUES('1','user','insert','success','java.lang.String','10001','2020-12-26 18:12:28','{\"age\":\"20\",\"name\":\"Tom\",\"gender\":\"1\"}','com.gitee.iot.DeviceController','insert','10',1);
INSERT INTO `tb_log` (`id`, `model_name`, `model_value`, `return_value`, `return_class`, `operate_user`, `operate_time`, `param_and_value`, `operate_class`, `operate_method`, `cost_time`,`source`) VALUES('2','user','insert','success','java.lang.String','10001','2020-12-26 18:12:27','{\"age\":\"20\",\"name\":\"Tom\",\"gender\":\"1\"}','com.gitee.iot.DeviceController','insert','23',1);
INSERT INTO `tb_log` (`id`, `model_name`, `model_value`, `return_value`, `return_class`, `operate_user`, `operate_time`, `param_and_value`, `operate_class`, `operate_method`, `cost_time`,`source`) VALUES('3','user','update','success','java.lang.String','10001','2020-12-26 18:16:45','{\"age\":\"20\",\"name\":\"Tom\",\"gender\":\"1\"}','com.gitee.iot.DeviceController','update','34',1);
三、分片规则
分片规则在conf目录下的rule.xml文件中定义;
3.1 取模分片
缺点:扩展困难
<tableRule name="mod-long">
<rule>
<columns>id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<property name="count">3</property>
</function>
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段 |
algorithm | 指定分片函数与function的对应关系 |
class | 指定该分片算法对应的类 |
count | 数据节点的数量 |
3.2 范围分片
根据指定的字段及其配置的范围与数据节点的对应情况, 来决定该数据属于哪一个分片
<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>
<property name="defaultNode">0</property>
</function>
autopartition-long.txt 配置如下:
# range start-end ,data node index
# K=1000,M=10000.
0-500M=0
500M-1000M=1
1000M-1500M=2
含义为 : 0 - 500 万之间的值 , 存储在0号数据节点 ; 500万 - 1000万之间的数据存储在1号数据节点 ; 1000万 - 1500 万的数据节点存储在2号节点 ;
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段 |
algorithm | 指定分片函数与function的对应关系 |
class | 指定该分片算法对应的类 |
mapFile | 对应的外部配置文件 |
type | 默认值为0 ; 0 表示Integer , 1 表示String |
defaultNode | 默认节点 默认节点的所用:枚举分片时,如果碰到不识别的枚举值, 就让它路由到默认节点 ; 如果没有默认值,碰到不识别的则报错 。 |
3.3 枚举分片
通过在配置文件中配置可能的枚举值, 指定数据分布到不同数据节点上, 本规则适用于按照省份或状态拆分数据等业务
<tableRule name="sharding-by-intfile">
<rule>
<columns>status</columns>
<algorithm>hash-int</algorithm>
</rule>
</tableRule>
<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-int.txt</property>
<property name="type">0</property>
<property name="defaultNode">0</property>
</function>
partition-hash-int.txt ,内容如下 :
1=0
2=1
3=2
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段 |
algorithm | 指定分片函数与function的对应关系 |
class | 指定该分片算法对应的类 |
mapFile | 对应的外部配置文件 |
type | 默认值为0 ; 0 表示Integer , 1 表示String |
defaultNode | 默认节点 ; 小于0 标识不设置默认节点 , 大于等于0代表设置默认节点 ; 默认节点的所用:枚举分片时,如果碰到不识别的枚举值, 就让它路由到默认节点 ; 如果没有默认值,碰到不识别的则报错 。 |
3.4 范围求模算法
该算法为先进行范围分片, 计算出分片组 , 再进行组内求模。
优点: 综合了范围分片和求模分片的优点。 分片组内使用求模可以保证组内的数据分布比较均匀, 分片组之间采用范围分片可以兼顾范围分片的特点。
缺点: 在数据范围时固定值(非递增值)时,存在不方便扩展的情况,例如将 dataNode Group size 从 2 扩展为 4 时,需要进行数据迁移才能完成 ; 如图所示:
<tableRule name="auto-sharding-rang-mod">
<rule>
<columns>id</columns>
<algorithm>rang-mod</algorithm>
</rule>
</tableRule>
<function name="rang-mod" class="io.mycat.route.function.PartitionByRangeMod">
<property name="mapFile">autopartition-range-mod.txt</property>
<property name="defaultNode">0</property>
</function>
autopartition-range-mod.txt 配置格式 :
#range start-end , data node group size
0-500M=1
500M1-2000M=2
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段名 |
algorithm | 指定分片函数与function的对应关系 |
class | 指定该分片算法对应的类 |
mapFile | 对应的外部配置文件 |
defaultNode | 默认节点 ; 未包含以上规则的数据存储在defaultNode节点中, 节点从0开始 |
3.5 固定分片hash算法
该算法类似于十进制的求模运算,但是为二进制的操作,例如,取 id 的二进制低 10 位 与 1111111111 进行位 & 运算。
最小值:
最大值:
优点: 这种策略比较灵活,可以均匀分配也可以非均匀分配,各节点的分配比例和容量大小由partitionCount和partitionLength两个参数决定
缺点:和取模分片类似。
<tableRule name="sharding-by-long-hash">
<rule>
<columns>id</columns>
<algorithm>func1</algorithm>
</rule>
</tableRule>
<function name="func1" class="org.opencloudb.route.function.PartitionByLong">
<property name="partitionCount">2,1</property>
<property name="partitionLength">256,512</property>
</function>
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段名 |
algorithm | 指定分片函数与function的对应关系 |
class | 指定该分片算法对应的类 |
partitionCount | 分片个数列表 |
partitionLength | 分片范围列表 |
约束 :
1). 分片长度 : 默认最大2^10 , 为 1024 ;
2). count, length的数组长度必须是一致的 ;
3). 两组数据的对应情况: (partitionCount[0]partitionLength[0])=(partitionCount[1]partitionLength[1])
以上分为三个分区:0-255,256-511,512-1023
3.6 取模范围算法
该算法先进行取模,然后根据取模值所属范围进行分片。
优点:可以自主决定取模后数据的节点分布
缺点:dataNode 划分节点是事先建好的,需要扩展时比较麻烦。
<tableRule name="sharding-by-pattern">
<rule>
<columns>id</columns>
<algorithm>sharding-by-pattern</algorithm>
</rule>
</tableRule>
<function name="sharding-by-pattern" class="io.mycat.route.function.PartitionByPattern">
<property name="mapFile">partition-pattern.txt</property>
<property name="defaultNode">0</property>
<property name="patternValue">96</property>
</function>
partition-pattern.txt 配置如下:
0-32=0
33-64=1
65-96=2
在mapFile配置文件中, 1-32即代表id%96后的分布情况。如果在1-32, 则在分片0上 ; 如果在33-64, 则在分片1上 ; 如果在65-96, 则在分片2上。
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段 |
algorithm | 指定分片函数与function的对应关系 |
class | 指定该分片算法对应的类 |
mapFile | 对应的外部配置文件 |
defaultNode | 默认节点 ; 如果id不是数字, 无法求模, 将分配在defaultNode上 |
patternValue | 求模基数 |
3.7 字符串hash求模范围算法
与取模范围算法类似, 该算法支持数值、符号、字母取模,首先截取长度为 prefixLength 的子串,在对子串中每一个字符的 ASCII 码求和,然后对求和值进行取模运算(sum%patternValue),就可以计算出子串的分片数。
优点:可以自主决定取模后数据的节点分布
缺点:dataNode 划分节点是事先建好的,需要扩展时比较麻烦。
<tableRule name="sharding-by-prefixpattern">
<rule>
<columns>id</columns>
<algorithm>sharding-by-prefixpattern</algorithm>
</rule>
</tableRule>
<function name="sharding-by-prefixpattern" class="io.mycat.route.function.PartitionByPrefixPattern">
<property name="mapFile">partition-prefixpattern.txt</property>
<property name="prefixLength">5</property>
<property name="patternValue">96</property>
</function>
partition-prefixpattern.txt 配置如下:
# range start-end ,data node index
# ASCII
# 48-57=0-9
# 64、65-90=@、A-Z
# 97-122=a-z
###### first host configuration
0-32=0
33-64=1
65-96=2
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段 |
algorithm | 指定分片函数与function的对应关系 |
class | 指定该分片算法对应的类 |
mapFile | 对应的外部配置文件 |
prefixLength | 截取的位数; 将该字段获取前prefixLength位所有ASCII码的和, 进行求模sum%patternValue ,获取的值,在通配范围内的即分片数 ; |
patternValue | 求模基数 |
3.8 应用指定算法
由运行阶段由应用自主决定路由到那个分片 , 直接根据字符子串(必须是数字)计算分片号
<tableRule name="sharding-by-substring">
<rule>
<columns>id</columns>
<algorithm>sharding-by-substring</algorithm>
</rule>
</tableRule>
<function name="sharding-by-substring" class="io.mycat.route.function.PartitionDirectBySubString">
<property name="startIndex">0</property> <!-- zero-based -->
<property name="size">2</property>
<property name="partitionCount">3</property>
<property name="defaultPartition">0</property>
</function>
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段 |
algorithm | 指定分片函数与function的对应关系 |
class | 指定该分片算法对应的类 |
startIndex | 字符子串起始索引 |
size | 字符长度 |
partitionCount | 分区(分片)数量 |
defaultPartition | 默认分片(在分片数量定义时, 字符标示的分片编号不在分片数量内时,使用默认分片) |
3.9 字符串hash解析算法
截取字符串中的指定位置的子字符串, 进行hash算法, 算出分片
<tableRule name="sharding-by-stringhash">
<rule>
<columns>user_id</columns>
<algorithm>sharding-by-stringhash</algorithm>
</rule>
</tableRule>
<function name="sharding-by-stringhash" class="io.mycat.route.function.PartitionByString">
<property name="partitionLength">512</property> <!-- zero-based -->
<property name="partitionCount">2</property>
<property name="hashSlice">0:2</property>
</function>
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段 |
algorithm | 指定分片函数与function的对应关系 |
class | 指定该分片算法对应的类 |
partitionLength | hash求模基数 ; length*count=1024 (出于性能考虑) |
partitionCount | 分区数 |
hashSlice | hash运算位 , 根据子字符串的hash运算 ; 0 代表 str.length() , -1 代表 str.length()-1 , 大于0只代表数字自身 ; 可以理解为substring(start,end),start为0则只表示0 |
3.10 一致性hash算法
一致性Hash算法有效的解决了分布式数据的拓容问题
<tableRule name="sharding-by-murmur">
<rule>
<columns>id</columns>
<algorithm>murmur</algorithm>
</rule>
</tableRule>
<function name="murmur" class="io.mycat.route.function.PartitionByMurmurHash">
<property name="seed">0</property>
<property name="count">3</property><!-- -->
<property name="virtualBucketTimes">160</property>
<!-- <property name="weightMapFile">weightMapFile</property> -->
<!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property> -->
</function>
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段 |
algorithm | 指定分片函数与function的对应关系 |
class | 指定该分片算法对应的类 |
seed | 创建murmur_hash对象的种子,默认0 |
count | 要分片的数据库节点数量,必须指定,否则没法分片 |
virtualBucketTimes | 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍;virtualBucketTimes*count就是虚拟结点数量 ; |
weightMapFile | 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替 |
bucketMapPath | 用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西 |
3.11 日期分片算法
按照日期来分片
<tableRule name="sharding-by-date">
<rule>
<columns>create_time</columns>
<algorithm>sharding-by-date</algorithm>
</rule>
</tableRule>
<function name="sharding-by-date" class="io.mycat.route.function.PartitionByDate">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2020-01-01</property>
<property name="sEndDate">2020-12-31</property>
<property name="sPartionDay">10</property>
</function>
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段 |
algorithm | 指定分片函数与function的对应关系 |
class | 指定该分片算法对应的类 |
dateFormat | 日期格式 |
sBeginDate | 开始日期 |
sEndDate | 结束日期,如果配置了结束日期,则代码数据到达了这个日期的分片后,会重复从开始分片插入 |
sPartionDay | 分区天数,默认值 10 ,从开始日期算起,每个10天一个分区 |
注意:配置规则的表的 dataNode 的分片,必须和分片规则数量一致,例如 2020-01-01 到 2020-12-31 ,每10天一个分片,一共需要37个分片。
3.12 单月小时算法
单月内按照小时拆分, 最小粒度是小时 , 一天最多可以有24个分片, 最小1个分片, 下个月从头开始循环, 每个月末需要手动清理数据。
<tableRule name="sharding-by-hour">
<rule>
<columns>create_time</columns>
<algorithm>sharding-by-hour</algorithm>
</rule>
</tableRule>
<function name="sharding-by-hour" class="io.mycat.route.function.LatestMonthPartion">
<property name="splitOneDay">24</property>
</function>
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段 ; 字符串类型(yyyymmddHH), 需要符合JAVA标准 |
algorithm | 指定分片函数与function的对应关系 |
splitOneDay | 一天切分的分片数 |
3.13 自然月分片算法
使用场景为按照月份列分区, 每个自然月为一个分片
<tableRule name="sharding-by-month">
<rule>
<columns>create_time</columns>
<algorithm>sharding-by-month</algorithm>
</rule>
</tableRule>
<function name="sharding-by-month" class="io.mycat.route.function.PartitionByMonth">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2020-01-01</property>
<property name="sEndDate">2020-12-31</property>
</function>
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段 |
algorithm | 指定分片函数与function的对应关系 |
class | 指定该分片算法对应的类 |
dateFormat | 日期格式 |
sBeginDate | 开始日期 |
sEndDate | 结束日期,如果配置了结束日期,则代码数据到达了这个日期的分片后,会重复从开始分片插入 |
3.14 日期范围hash算法
其思想和范围取模分片一样,先根据日期进行范围分片求出分片组,再根据时间hash使得短期内数据分布的更均匀 ;
优点 : 可以避免扩容时的数据迁移,又可以一定程度上避免范围分片的热点问题
注意 : 要求日期格式尽量精确些,不然达不到局部均匀的目的
<tableRule name="range-date-hash">
<rule>
<columns>create_time</columns>
<algorithm>range-date-hash</algorithm>
</rule>
</tableRule>
<function name="range-date-hash" class="io.mycat.route.function.PartitionByRangeDateHash">
<property name="dateFormat">yyyy-MM-dd HH:mm:ss</property>
<property name="sBeginDate">2020-01-01 00:00:00</property>
<property name="groupPartionSize">6</property>
<property name="sPartionDay">10</property>
</function>
属性 | 描述 |
---|---|
columns | 标识将要分片的表字段 |
algorithm | 指定分片函数与function的对应关系 |
class | 指定该分片算法对应的类 |
dateFormat | 日期格式 , 符合Java标准 |
sBeginDate | 开始日期 , 与 dateFormat指定的格式一致 |
groupPartionSize | 每组的分片数量 |
sPartionDay | 代表多少天为一组 |