MyCat入门配置详解和常见九种数据分片算法

5 篇文章 0 订阅
1 篇文章 0 订阅

MyCat入门配置详解和常见九种数据分片算法

第一节 分库分表概述

1、为什么要拆分?

①MySQL 实例内部结构

[1]单一架构

images

[2]复制架构

尽管搭建了复制架构,但是实际上从逻辑上来说仍然只有一个 db_hr 数据库。

images

②性能瓶颈

MySQL 工作过程中的性能瓶颈主要来自于下面三个方面(同等硬件条件下):

  • 数据存储量:单表 1000 万条数据达到极限;500 万条开始性能明显下降;300 万条开始就应该考虑拆分。
  • I/O 瓶颈:关系型数据库以硬盘作为主要存储介质,所以必然存在 I/O 瓶颈。
  • 访问量瓶颈:通常 MySQL 的最大连接数默认是100,最大可以达到 16384。

由此我们可以看出,对数据库进行拆分主要是出于数据量不断增加的挑战。

2、拆分方式

①垂直拆分

垂直拆分是最容易想到的拆分方式。它按照项目的业务功能模块,把从属于不同模块的数据库表分散到对应的不同数据库中。

images

这种拆分方式的优缺点是:

  • 优点
    • 拆分规则明确,按照不同的功能模块或服务分配不同数据库
    • 数据维护与定位简单
  • 缺点
    • 并没有解决单表数据量太大的问题
    • 会出现跨库 join
    • 需要对上层应用系统的代码进行重构,修改原有的事务操作

②水平拆分

针对一张数据量很大的表,把它拆分为多张表,数据分流保存到各个拆分后的数据库表中。

如果数据量继续增加,超过一个单库能够容纳的极限则需要继续分库:

images

这种拆分方式的优缺点评价:

  • 只分表不分库:
    • 同库无分布式事务问题,事务处理相对简单
    • 同库无跨库 join 问题
    • 表拆分后不存在超大型表的性能问题
    • 只要拆分规则定义好,很难出现扩展性的限制,但拆分规则设定并不简单,规则一定会和业务挂钩,如根据 id、根据时间等。
  • 既分表又分库:
    • 异库存在分布式事务问题
    • 异库存在跨库 join 问题
    • 多数据源管理难度加大,代码复杂度增加

3、MyCat 简介

尽管拆分后必然要面对很多问题,但是随着数据量的增加又不得不拆分。所以我们开发的上层应用系统必须有能力对接拆分后的多个数据库。MyCat 就是帮助我们实现这一功能的数据库中间件。

images

MyCat 是一款数据库中间件。

对于应用程序来说完全透明:不管底层的数据如何拆分,应用只需要连接 MyCat 即可完成对数据的操作。

支持 MySQL、SQL Server、Oracle、DB2、PostgreSQL 等主流数据库。

MyCat 不存储数据,它只是数据的路由

底层拦截用户发送过来的 SQL 语句并进行分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此 SQL 发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。

Mycat的特性如下:

  • 支持SQL92标准
  • 遵守Mysql原生协议,跨语言,跨平台,跨数据库的通用中间件代理
  • 基于心跳的自动故障切换,支持读写分离,支持MySQL主从,以及galera cluster集群
  • 支持Galera for MySQL集群,Percona Cluster或者MariaDB cluster
  • 基于Nio实现,有效管理线程,高并发问题
  • 支持数据的多片自动路由与聚合,支持sum,count,max等常用的聚合函数
  • 支持单库内部任意join,支持跨库2表join
  • 支持通过全局表,ER关系的分片策略,实现了高效的多表join查询
  • 支持多租户方案
  • 支持分布式事务
  • 支持全局序列号,解决分布式下的主键生成问题
  • 分片规则丰富,插件化开发,易于扩展
  • 强大的web,命令行监控
  • 支持前端作为mysq通用代理,后端JDBC方式支持Oracle、DB2、SQL Server 、 mongodb
  • 支持密码加密
  • 支持服务降级
  • 支持IP白名单
  • 支持SQL黑名单、sql注入攻击拦截
  • 支持分表(1.6以后版本)
  • 集群基于ZooKeeper管理,在线升级,扩容,智能优化,大数据处理(2.0以后版本)

第二节 安装与配置

1、获取 MyCat 程序

①方式一

访问这个地址下载:https://codeload.github.com/MyCATApache/Mycat-Server/zip/Mycat-server-1675-release

②方式二

由老师发给你。

2、解压 MyCat 压缩包

images

3、使用 IDEA 打开

images

4、配置 schema.xml

从这里开始,我们就是在初步搭建 MyCat 服务器。我们想要初步实现的目标:

  • MyCat 中配置虚拟数据库、虚拟数据库表,物理库和物理表暂时不拆分
  • 启动 MyCat
  • 使用客户端连接到 MyCat

而让 MyCat 连接物理库、配置虚拟库、虚拟表都需要在 schema.xml 中配置。

①配置文件位置

images

②告诉 MyCat 如何连接物理库

<!--
	dataHost 标签:配置物理库的连接方式。可以配置多个。本质上是连接到数据库服务器。
	name 属性:给当前 dataHost 标签命名,便于其它地方引用。
 -->
<dataHost name="virtual-host-hello"
		  maxCon="1000"
		  minCon="10"
		  balance="0"
		  writeType="0"
		  dbType="mysql"
		  dbDriver="jdbc"
		  switchType="1"
		  slaveThreshold="100">

	<!--
		heartbeat 标签:设置做心跳检查时使用的 SQL 语句。
	-->
	<heartbeat>select user()</heartbeat>
	<!--
		writeHost 标签:具体配置连接物理库的信息,可以有多个。
		host 属性:命名 一般writeHost用M1 readHost用S1。
		url 属性:物理库的 URL 地址
		user 属性:连接物理库使用的用户名
		password 属性:连接物理库使用的密码
	 -->
	<writeHost host="hostM1"
			   url="jdbc:mysql://localhost:3306"
			   user="root"
			   password="root"/>

</dataHost>

③配置 dataNode

<!--
	dataNode 标签:配置数据节点。本质上是连接到数据库服务器上的一个具体物理数据库。
	name 属性:给当前 dataNode 标签命名,便于其它地方引用。
	dataHost 属性:引用一个已经配置好的 dataHost。
	database 属性:指定一个具体的物理库的名称。
-->
<dataNode name="data-node-hello" dataHost="virtual-host-hello" database="db_hr" />

④创建虚拟库和虚拟表

<!--
	schema 标签:配置虚拟库,里面子标签配置虚拟表。
	name 属性:给当前 schema 标签命名,便于其它地方引用。同时也是指定虚拟数据库的名称。
 -->
<schema name="virtual-db-hello" checkSQLschema="true" sqlMaxLimit="100">

	<!-- table 标签:配置虚拟表。 -->
	<!-- name 属性:指定虚拟表的名称。 -->
	<!-- dataNode 属性:通过指定 dataNode 指定当前虚拟表要连接的物理库。如果有多个,可以使用逗号分开,也可以使用 dn$1-3 这样的表达式。 -->
	<!-- subTables 属性:指定虚拟表对应的物理表。 -->
	<table name="virtual_t_emp"
		   primaryKey="emp_id"
		   dataNode="data-node-hello"
		   autoIncrement="true"
		   fetchStoreNodeByJdbc="true"
		   subTables="t_emp"
	/>
</schema>

5、配置 server.xml

①配置文件位置

images

②配置 MyCat 自身的连接信息

<!-- user 标签:配置外界连接 MyCat 时使用的连接信息 -->
<!-- name 属性:指定用户名。 -->
<user name="myCat">
	<!-- password 属性:指定密码。 -->
	<property name="password">hello</property>

	<!-- schemas 属性:要连接的虚拟库的名称。
	请到 schema.xml 配置文件中找到 schema 标签,复制过来 schema 标签的 name 属性。 -->
	<property name="schemas">virtual-db-hello</property>
</user>

6、启动 MyCat

①找到 MyCat 启动类

images

②配置 JVM 参数

  • 指定 MYCAT_HOME:这个参数是需要指定 MyCat 工程的 src/main 目录的完整路径。
  • 指定直接内存大小:如果 512M 不够,那就指定 1024M。

-DMYCAT_HOME=D:\idea2019workspace\mycat210722\src\main
-XX:MaxDirectMemorySize=512M

③运行程序

images

7、两个坑

①第一个

如果 schema 标签的配置是从官方提供的配置中复制过来的,那么可能会带有 randomDataNode 属性,此时会有下面问题:

images

如果尝试连接 MyCat 时,没有指定一个具体的数据库名称,MyCat 会访问 randomDataNode 属性指定的数据节点。而如果这个数据节点不存在,那么就会访问失败。

②第二个

images

调整 JDK 版本操作如下:

images

images

第三节 数据分片

1、数据分片概念

从虚拟库、虚拟表看到的数据,逻辑上是一个整体。而实际上数据的物理存储是分散在不同物理库、物理表中。每个实际的物理表可以看成是一个数据分片。

数据进入数据库时,经过不同拆分规则的分流进入了不同的数据分片。我们对拆分规则有两点期望:

  • 数据存储的过程中:执行 insert 语句后将数据准确插入到对应分片
  • 数据提取的过程中:能够准确的从指定分片查询到我们需要的数据

2、数据分片的具体算法使用详解(见末尾附录)

[取模分片](# ①取模分片)

[全局 id 分片](# ②全局 id 分片)

[枚举分片](# ③枚举分片)

[固定 hash 分片](# ④固定 hash 分片)

[固定范围分片](# ⑤固定范围分片)

[取模范围分片](# ⑥取模范围分片)

[字符串 hash 分片](# ⑦字符串 hash 分片)

[时间分片](# ⑧时间分片)

[一致性 hash 分片](# ⑨一致性 hash 分片)

第四节 跨库 join

概念:A 表和 B 表做关联查询,但是 A 表和 B 表不在同一个数据库中。

1、全局表

系统中基本都会存在数据字典信息,如数据分类信息、项目的配置信息等。这些字典数据最大的特点就是数据量不大并且很少会被改变。同时绝大多数的业务场景都会涉及到字典表的操作。 因此为了避免频繁的跨库join操作,结合冗余数据思想,可以考虑把这些字典信息在每一个分库中都存在一份。

mycat在进行join操作时,当业务表与全局表进行聚合会优先选择相同分片的全局表,从而避免跨库join操作。在进行数据插入时,会把数据同时插入到所有分片的全局表中。

修改 schema.xml

<table name="tb_global" dataNode="dn142,dn145" primaryKey="global_id" type="global"/>

2、ER表

ER 表也是一种为了避免跨库join的手段,在业务开发时,经常会使用到主从表关系的查询,如商品表与商品详情表。

ER 表的出现就是为了让有关系的表数据存储于同一个分片中,从而避免跨库 join 的出现。

修改 schema.xml

<table name="tb_goods" dataNode="dn129,dn130" primaryKey="goods_id" rule="sharding-by-murmur-goods">
    <childTable name="tb_goods_detail" primaryKey="goods_detail_id" joinKey="goods_id" parentKey="goods_id"></childTable>
</table>

再次添加 goods 数据的时候,有关系的表数据存储于同一个分片中

附:分片算法

①取模分片

[点击返回](# 2、数据分片的具体算法)

1、理解

根据 id 值进行模运算,然后根据取模的计算结果决定数据分流后存入的目标物理表。这里涉及到的用于取模计算的数据库表字段值,不能指望由数据库自增来得到——因为这个数据是在决定分流到哪个物理表时用到的,此时还没有执行 insert 语句。所以这个数据必须由程序员指定,在 Java 代码中生成

images

2、操作

①创建用于测试的物理表

CREATE TABLE `db_hr`.`t_emp1` ( `emp_id` INT NOT NULL AUTO_INCREMENT, `emp_name` CHAR(100), PRIMARY KEY (`emp_id`) ); 
CREATE TABLE `db_hr`.`t_emp2` ( `emp_id` INT NOT NULL AUTO_INCREMENT, `emp_name` CHAR(100), PRIMARY KEY (`emp_id`) ); 
CREATE TABLE `db_hr`.`t_emp3` ( `emp_id` INT NOT NULL AUTO_INCREMENT, `emp_name` CHAR(100), PRIMARY KEY (`emp_id`) ); 

②配置 subTables 属性

  • 所在位置:schema.xml 配置文件中 schema 标签的子标签 table 的 subTables 属性。
  • 属性值设置方式:
    • 单个值:t_user
    • 多个值:
      • 将多个物理表名称用逗号隔开:t_user1,t_user2,t_user3
      • 使用正则表达式格式指定数值区间:t_user$1-5
      • 将多个用区间表示的物理表名称用逗号隔开:t_user$1-5,t_user$7-10

③配置拆分规则

  • 在 schema.xml 中配置 rule 属性

在 table 标签中通过 rule 属性指定规则名称即可。当前取模分片的名称是 mod-lang,这些规则名称是在 rule.xml 中定义的。

<!-- 取模分片 -->
<!-- 配置 1:通过 subTables 属性指定物理表 -->
<!-- 配置 2:通过 rule 属性指定拆分规则 -->
<table name="virtual_t_emp"
	   primaryKey="emp_id"
	   dataNode="data-node-hello"
	   autoIncrement="true"
	   fetchStoreNodeByJdbc="true"
	   subTables="t_emp$1-3"
	   rule="mod-long"
/>
  • 在 rule.xml 中配置 mod-long 规则

    • 配置 tableRule 标签
    <tableRule name="mod-long">
    	<rule>
    		<!-- 指定用于执行取模分片的字段 -->
    		<columns>emp_id</columns>
    		
    		<!-- 具体规则名称 -->
    		<algorithm>mod-long</algorithm>
    	</rule>
    </tableRule>
    
    • 配置 function 标签
    <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
    	<!-- 物理表的数量,需要正好就是取模的数值 -->
    	<property name="count">3</property>
    </function>
    

④重启 MyCat

MyCat 配置文件修改后重启 MyCat 程序才能够生效。

3、测试

①数据存储操作

INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES(1, 'tom01');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES(2, 'tom02');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES(3, 'tom03');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES(4, 'tom04');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES(5, 'tom05');

数据插入后,请打开物理表查看是否分流到了三个物理表。

  • t_emp1

    emp_id emp_name

    3 tom03

  • t_emp2

    emp_id emp_name

    1 tom01
    4 tom04

  • t_emp3

    emp_id emp_name

    2 tom02
    5 tom05

②数据查询操作

SELECT emp_id,emp_name FROM virtual_t_emp WHERE emp_id=4;

效果:

emp_id emp_name

   4      tom04     

4、注意

如果在 insert 语句中没有指定 emp_id 字段,则有下面的报错:

images

②全局 id 分片

[点击返回](# 2、数据分片的具体算法)

1、理解

全局 id 分片和上面的取模分片就一个区别:id 的来源不同。

  • 取模分片:由程序员提供 id 值。
  • 全局 id 分片:由 MyCat 提供 id 值。

images

具体来说,MyCat 提供 id 值有下面这些办法:

  • 基于本地文件
  • 基于数据库
  • 基于 zookeeper
  • 基于时间戳

2、操作

①基于本地文件

第一步:配置 sequence_conf.properties

文件位置:

images

配置内容:

# 使用过的历史分段,可不配置
USER.HISIDS=

# ID 的起始值,从这个值开始生成 ID
USER.MINID=1

# 最大ID值
USER.MAXID=200000

# 当前ID值
USER.CURID=1000

配置中属性名前缀的作用:

images

第二步:配置 server.xml

指定全局 id 分片具体使用的 id 生成方式。

<!--设置全局序号生成方式
   0:文件
   1:数据库
   2:时间戳
   3:zookeeper
  -->
<!--必须带有MYCATSEQ_或者 mycatseq_进入序列匹配流程 注意MYCATSEQ_有空格的情况-->
<property name="sequenceHandlerType">0</property>
第三步:测试

别忘记重启 MyCat。

INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_EMP', 'jerry01');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_EMP', 'jerry02');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_EMP', 'jerry03');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_EMP', 'jerry04');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_EMP', 'jerry05');

②基于数据库

第一步:在物理库建表

使用 MyCat 提供的一个 SQL 文件:

images

执行的效果:

images

第二步:在 MYCAT_SEQUENCE 表中增加一条记录

images

第三步:配置 sequence_db_conf.properties

文件位置:

images

配置内容:

EMP_INCR=data-node-hello

属性名和其他配置的关系:

images

第四步:配置 server.xml
<!-- 指定全局 id 分片方式 -->
<!-- 	0 表示基于文件 -->
<!-- 	1 表示基于数据库 -->
<property name="sequenceHandlerType">1</property>
第五步:重启 MyCat

略。

第六步:测试
USE virtual-db-hello;

INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_EMP_INCR', 'kate01');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_EMP_INCR', 'kate02');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_EMP_INCR', 'kate03');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_EMP_INCR', 'kate04');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_EMP_INCR', 'kate05');

SELECT emp_id,emp_name FROM virtual_t_emp;

③基于时间戳

第一步:配置 server.xml
<!-- 指定全局 id 分片方式 -->
<!-- 	0 表示基于文件 -->
<!-- 	1 表示基于数据库 -->
<!-- 	2 表示基于时间戳 -->
<property name="sequenceHandlerType">2</property>
第二步:配置 sequence_time_conf.properties

WORKID 与 DATAACENTERID 都是 0-31 任意整数。多 mycat 节点下,每个节点的 WORKID、DATAACENTERID 不能重复,组成唯一标识,总共支持 32*32=1024 种组合。

images

第三步:修改物理表 emp_id 字段宽度

基于时间戳的方式将使用时间戳数值作为 emp_id 值,必须使用 bigint 类型。

images

第四步:重启 MyCat

略。

第五步:测试

next value for MYCATSEQ_ 后面可以随便写。

USE virtual-db-hello;

INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_FOO', 'BOB01');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_FOO', 'BOB02');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_FOO', 'BOB03');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_FOO', 'BOB04');
INSERT INTO virtual_t_emp(emp_id, emp_name) VALUES('next value for MYCATSEQ_FOO', 'BOB05');

SELECT emp_id,emp_name FROM virtual_t_emp;

③枚举分片

[点击返回](# 2、数据分片的具体算法)

1、理解

images

2、操作

第一步:创建数据库和表

在物理库所在的服务器上执行下面的 SQL 语句:

CREATE DATABASE `db_hr_male`;
CREATE DATABASE `db_hr_female`; 
CREATE TABLE `db_hr_female`.`t_emp` ( `emp_id` INT NOT NULL AUTO_INCREMENT, `emp_name` CHAR(100), `emp_gender` CHAR(100), PRIMARY KEY (`emp_id`) );
CREATE TABLE `db_hr_male`.`t_emp` ( `emp_id` INT NOT NULL AUTO_INCREMENT, `emp_name` CHAR(100), `emp_gender` CHAR(100), PRIMARY KEY (`emp_id`) );

第二步:创建新的 dataNode

在 schema.xml 配置文件中增加配置:

<dataNode name="data-node-male" dataHost="virtual-host-hello" database="db_hr_male" />
<dataNode name="data-node-female" dataHost="virtual-host-hello" database="db_hr_female" />

第三步:配置 table 标签

在 schema.xml 配置文件中修改配置:

<!-- 枚举分片 -->
<!-- 配置 1:将虚拟表名称设置为和物理表一样(物理表是分别放在不同物理库中的同名的表)。 -->
<!-- 配置 2:让 dataNode 属性指向枚举分片涉及到的多个数据节点 -->
<!-- 配置 3:去掉 subTables 属性 -->
<!-- 配置 4:拆分规则改成 sharding-by-intfile -->
<table name="t_emp"
	   primaryKey="emp_id"
	   dataNode="data-node-male,data-node-female"
	   autoIncrement="true"
	   fetchStoreNodeByJdbc="true"
	   rule="sharding-by-intfile"
/>

第四步:配置 rule.xml

  • 先配置 tableRule 标签
<tableRule name="sharding-by-intfile">
	<rule>
		<!-- 指定提供枚举值的字段 -->
		<columns>emp_gender</columns>
		
		<!-- 具体算法 -->
		<algorithm>hash-int</algorithm>
	</rule>
</tableRule>
  • 再配置 function 标签
<function name="hash-int"
		  class="io.mycat.route.function.PartitionByFileMap">

	<!-- 指定另外一个配置文件,配置枚举值和数据节点之间的对应关系 -->
	<property name="mapFile">partition-hash-int.txt</property>

	<!--type 属性:指定枚举值类型。默认值为0,0表示Integer,非零表示String -->
	<property name="type">1</property>

	<!--defaultNode 当有一些特殊数据信息可以存放于默认节点中,如即不是male也不是female。默认节点:小于0表示不设置默认节点,大于等于0表示设置默认节点,不能解析的枚举就存到默认节点-->
	<property name="defaultNode">0</property>
</function>

第五步:配置 partition-hash-int.txt

#代表第一个datanode
male=0

#代表第二个datanode
female=1

3、测试

USE virtualDB;

INSERT INTO t_emp(emp_id, emp_name,emp_gender) VALUES (1, 'tom','male');
INSERT INTO t_emp(emp_id, emp_name,emp_gender) VALUES (2, 'kate','female');

4、注意点

  • table 标签中不写 subTables 属性,原因是对照枚举规则之后,不同的数据进入了不同数据库中。在各自数据库中的表名是相同的。
  • 在 partition-hash-int.txt 文件中,0 和 1 这些值表示序号,这个序号对应 table 标签中 dataNode 属性值中 dataNode 名称的顺序。比如:dataNode=“dn-docker-female,dn-docker-male” 这个例子中,dn-docker-female 的序号是 0,dn-docker-male 的序号是 1。

④固定 hash 分片

[点击返回](# 2、数据分片的具体算法)

1、理解

images

2、操作

第一步:配置 schema.xml

<!-- 固定 hash 分配 -->
<!-- 配置 rule 属性:partition-by-fixed-hash -->
<table name="t_emp"
	   primaryKey="emp_id"
	   dataNode="data-node-male,data-node-female"
	   autoIncrement="true"
	   fetchStoreNodeByJdbc="true"
	   rule="partition-by-fixed-hash"
/>

第二步:配置 rule.xml

<tableRule name="partition-by-fixed-hash">
	<rule>
		<!-- 指定执行 hash 运算的字段 -->
		<columns>emp_id</columns>
		
		<!-- 具体算法 -->
		<algorithm>partition-by-fixed-hash</algorithm>
	</rule>
</tableRule>

<!--
  partitionCount: 各分片空间中节点的数量。格式是:m,n
  partitionLength: 每个分片空间中分配的范围大小。格式是:x,y
	计算公式是:m * x + n * y = 1024
	当前配置:1 * 256 + 1 * 768 = 1024
 -->
<function name="partition-by-fixed-hash" class="io.mycat.route.function.PartitionByLong">
	<property name="partitionCount">1,1</property>
	<property name="partitionLength">256,768</property>
</function>

3、测试

USE virtual-db-hello;

INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(50,'harry07','male');
INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(80,'harry08','male');
INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(120,'harry09','male');
INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(360,'rose05','female');
INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(1780,'rose06','female');

⑤固定范围分片

[点击返回](# 2、数据分片的具体算法)

1、理解

images

2、操作

①配置 schema.xml

<!-- 固定范围分片 -->
<!-- 配置 rule 属性:auto-sharding-long -->
<table name="t_emp"
	   primaryKey="emp_id"
	   dataNode="data-node-male,data-node-female"
	   autoIncrement="true"
	   fetchStoreNodeByJdbc="true"
	   rule="auto-sharding-long"
/>

②配置 rule.xml

<tableRule name="auto-sharding-long">
	<rule>
		<!-- 指定用于做 hash 运算的字段 -->
		<columns>emp_id</columns>
		<algorithm>rang-long</algorithm>
	</rule>
</tableRule>

③配置 autopartition-long.txt

images

# range start-end ,data node index
# K=1000,M=10000.
# 0-500M=0
# 500M-1000M=1
# 1000M-1500M=2

0-20=0
21-50=1

3、测试

USE virtual-db-hello;

INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(2,'jack13','male');
INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(4,'jack14','male');
INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(6,'jack15','male');
INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(35,'rose09','female');
INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(44,'rose10','female');

SELECT emp_id,emp_name,emp_gender FROM t_emp;

⑥取模范围分片

[点击返回](# 2、数据分片的具体算法)

1、理解

取模后,根据范围决定数据节点。

2、操作

①配置 schema.xml

指定分片规则:sharding-by-partition

②配置 rule.xml

<tableRule name="sharding-by-partition">
    <rule>
        <!-- 指定用于取模的字段 -->
        <columns>emp_id</columns>
        <algorithm>sharding-by-partition</algorithm>
    </rule>
</tableRule>

<function name="sharding-by-partition" class="io.mycat.route.function.PartitionByPattern">
    <!-- 求模基数 -->
    <property name="patternValue">256</property>
    
    <!-- 默认节点 -->
    <property name="defaultNode">0</property>
    
    <!-- 指定规则配置文件 -->
    <property name="mapFile">partition-pattern.txt</property>
</function>

③配置 partition-pattern.txt

这个文件没有,需要我们自己建:

#0-128表示id%256后的数据范围。
0-128=0
129-256=1

3、测试

USE virtual-db-hello;

INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(90,'peter01','male');
INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(150,'peter02','male');

⑦字符串 hash 分片

[点击返回](# 2、数据分片的具体算法)

1、理解

在业务场景下,有时可能会根据某个分片字段的前几个值来进行取模。如地址信息只取省份、姓名只取前一个字的姓等。此时则可以使用该种方式。

其工作方式与取模范围分片类似,该分片方式支持数值、符号、字母取模。

执行流程大致是:字符串截取→hash操作→取模→根据指定范围选择 DataNode

2、操作

[1]配置 schema.xml

指定分片规则:sharding-by-string-hash

[2]配置 rule.xml
<tableRule name="sharding-by-string-hash">
    <rule>
        <columns>emp_name</columns>
        <algorithm>sharding-by-string-hash-function</algorithm>
    </rule>
</tableRule>

<function name="sharding-by-string-hash-function" class="io.mycat.route.function.PartitionByPrefixPattern">
    <!-- 求模基数 -->
    <property name="patternValue">256</property>
    
    <!-- 截取的位数 -->
    <property name="prefixLength">1</property>
    
    <!-- 细节配置文件 -->
    <property name="mapFile">partition-pattern-string-hash.txt</property>
</function>
[3]配置 partition-pattern-string-hash.txt
0-128=0
129-256=1

3、测试

USE virtual-db-hello;

INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(88,'ccccccc','male');
INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(99,'uvwxyz','male');

⑧时间分片

[点击返回](# 2、数据分片的具体算法)

1、理解

根据时间、日期信息分片。

2、操作

①修改数据库表

给 t_emp 表增加 emp_birthday 字段。

ALTER TABLE `db_hr_male`.`t_emp` ADD COLUMN `emp_birthday` CHAR(100) NULL AFTER `emp_gender`;
ALTER TABLE `db_hr_female`.`t_emp` ADD COLUMN `emp_birthday` CHAR(100) NULL AFTER `emp_gender`;

②配置 schema.xml

指定拆分规则:sharding-by-date

③配置 rule.xml

<tableRule name="sharding-by-date">
    <rule>
        <!-- 指定用于分片的字段 -->
        <columns>emp_birthday</columns>
        <algorithm>partbyday</algorithm>
    </rule>
</tableRule>

<function name="partbyday"
          class="io.mycat.route.function.PartitionByDate">

    <!-- 日期格式 -->
    <property name="dateFormat">yyyy-MM-dd</property>

    <!-- 支持自然日分区属性 -->
    <property name="sNaturalDay">0</property>

	<!-- 开始日期 -->
	<property name="sBeginDate">2014-06-01</property>

	<!-- 结束日期 -->
	<property name="sEndDate">2014-06-30</property>

	<!-- 每隔几天算一个分片 -->
	<property name="sPartionDay">15</property>
</function>

3、测试

USE virtual-db-hello;

INSERT INTO t_emp(emp_id,emp_birthday) VALUES(666, '2014-06-10');
INSERT INTO t_emp(emp_id,emp_birthday) VALUES(777, '2014-06-25');

⑨一致性 hash 分片

[点击返回](# 2、数据分片的具体算法)

1、理解

①目的

最大限度的让数据均匀分布

②原理

一致性 hash 算法引入了 hash 环的概念。环的大小是 0~2^32-1。首先通过 crc16 算法计算出数据节点在 hash 环中的位置。

images

当存储数据时,也会采用同样的算法,计算出数据key的hash值,映射到hash环上。

images

然后从数据映射的位置开始,以顺时针的方式找出距离最近的数据节点,接着将数据存入到该节点中。

images

此时可以发现,数据并没有达到预期的数据均匀,可以发现如果两个数据节点在环上的距离,决定有大量数据存入了dataNode2,而仅有少量数据存入dataNode1。

为了解决数据不均匀的问题,在mycat中可以设置虚拟数据映射节点。同时这些虚拟节点会映射到实际数据节点。

images

数据仍然以顺时针方式寻找数据节点,当找到最近的数据节点无论是实际还是虚拟,都会进行存储,如果是虚拟数据节点的话,最终会将数据保存到实际数据节点中。 从而尽量的使数据均匀分布。

2、操作

①配置 schema.xml

指定拆分规则:sharding-by-murmur

②配置 rule.xml

<tableRule name="sharding-by-murmur">
    <rule>
        <columns>emp_id</columns>
        <algorithm>murmur</algorithm>
    </rule>
</tableRule>

<function name="murmur"
          class="io.mycat.route.function.PartitionByMurmurHash">
	<!-- 默认是0即可 -->
    <property name="seed">0</property>
    
    <!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
    <property name="count">2</property>
    
    <!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
    <property name="virtualBucketTimes">160</property>
</function>

3、测试

USE virtual-db-hello;

INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(111,'eeeeeeeeeee','male');
INSERT INTO t_emp(emp_id,emp_name,emp_gender) VALUES(888,'ttttttttttt','male');
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙龙龙呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值