mysql性能优化系列9-分库分表mycat

1. 分库分表

如果在数据库中表的数量达到了一定的量级, 则需要进行分表, 分解单表的大数据量对索引查询带来的压力,方便对索引和表结构的变更 。
如果数据库的吞吐量达到了瓶颈,就需要增加数据库实例,利用多个数据库实例来分解大量的数据库请求带来的系统压力。
分库分表就是将一个表分为多个表, 这些表可以放在同一个库里, 也可以放到不同的库里, 甚至可以放在不同的数据库实例上。
(1)单实例单库
单库单表是最常见的数据库设计,目前大部分的系统都是单库单表。
(2)多实例单库
多实例单库常用于读写分离和主备。多个实例之间启用了复制功能。
(3)多库(单实例/多实例)
这里的多库是将原来单库的部分表放在一个数据库,另外一部分放在另外一个数据库。这些数据库可以在一个实例,也可以在多个实例上。
(4)多库多表
多库多表就是在将不同数据表分部在不同的数据库基础上,对同一个表的数据也会拆分放在不同的数据库。

2. 分库分表的数据访问

2.1 客户端分片

客户端分片有三种:应用层直接实现、定制JDBC协议实现、定制ORM框架实现。
(1)应用层直接实现
应用层直接决定每次操作应该使用哪个数据库实例、数据库及哪个数据库的表等。这种实现方式会让数据库保持的连接比较多。
(2)定制JDBC协议
通过定制JDBC协议来实现,也就是对业务层提供统一的JDBC接口,JDBC内部实现分库分表。这种需要开发人员理解JDBC协议,Sharding JDBC便采用了这种方案。
(3)定制ORM框架
把分片规则实现放到ORM框架中。

2.2 代理分片

代理分片就是在应用层和数据库层之间增加一个代理层。代理层对外提供与JDBC兼容的接口,实现JDBC协议的解析,并通过分片的路由规则来路由请求。不过增加了代理层增加了一层网络传输,对性能是有影响的。
代理分片实现的主要框架有Cobar、Mycat、ShardingSphere等。

3. 数据切分方式

3.1 垂直切分

直切分是将单一库中的表按业务拆分到多个库或者多个表,甚至分散到不同的实例上。垂直切分除了可以分解单库单表的压力, 也可以实现冷热分离, 因为对拥有不同活跃度的数据的处理方式不同。对于冷数据查询较多, 更新较少,这种可以用MyISAM引擎。对于冷数据可以构建多个从库分解查询压力。而热数据更新比较频繁,适合使用InnoDB存储引擎。对于热数据使用分库分表分解压力。
优点:
拆分后业务清晰,拆分规则明确。系统之间进行整合或扩展很容易。便于实现动静分离、冷热分离的数据库表的设计模式。数据维护简单。
缺点:
无法关联查询,只能程序自行解决,提高了系统的复杂度,事务处理复杂。

3.2 水平切分

根据表中数据逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库。每个表中包含一部分数据, 所有表加起来就是全量的数据。
优点:
单库单表的数据保持在一定的量级,有助于性能的提高。
切分的表的结构相同,应用层改造较少,只需要增加路由规则即可。
提高了系统的稳定性和负载能力 。
缺点:
无法关联查询。事务处理复杂,数据扩容的难度和维护量极大。
通常两种切分方式会同时使用, 垂直切分更偏向于业务拆分, 在技术上我们更关注水平切分的方案。

3.3 分库分表的问题

(1)扩容
在分库分表后, 如果需要对集群进行扩容,这时候 扩容是很麻烦的,因为路由规则可能发生变化,原有数据需要按照新规则迁移。
(2)查询间题
分库分表后,查询的条件不是分库分片的键值,这时候需要全库扫描。
(3)跨库事务
同时更新多个数据库数据的事务

4. Mycat

Mycat是一个开源的分布式数据库系统,实现了MySQL协议,也就是前面说的代理分片,其后端可以用MySQL原生协议或者JDBC和多个MySQL服务器通信,其核心功能是分表分库下如何和数据库通信。Mycat目前可以支持MySQL、SQLServer、Oracle、DB2、PostgreSQL、MongoDB等数据库。
Mycat通过拦截用户发的SQL语句,对SQL语句进行分析,如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。

4.1 常见概念

(1)逻辑库(schema)
数据库中间件可以被看做是一个或多个数据库集群构成的逻辑库。
(2)逻辑表(table)
分布式数据库中,对应用来说读写数据的表就是逻辑表。
(3)分片表
分片表就是由于表数据过大进行水平切分到不同数据库的表。
(4)非分片表
没有进行数据切分的表
(5)ER表
关系型数据库是基于实体关系模型(Entity-Relationship Model),通过其描述了真实世界中事物与关系。Mycat中基于此提出了基于E-R关系的数据分片策略,将子表的记录与所关联的父表记录存放在同一个数据分片上,保证数据Join不会跨库操作。
(6)全局表
一个真实的业务系统中,有些表变动不频繁,数据量也不大。有时候需要将分片表和这些表进行关联,Mycat 通过数据冗余来解决这类表的join,将这些表定义为全局表,即所有的分片都有一份数据的拷贝。
(7)分片节点(dataNode)
一个大表被分到不同的分片数据库上面,每个表分片所在的数据库就是分片节点(dataNode)。
(8)节点主机(dataHost)
每个分片节点(dataNode)不一定都会独占一台机器,同一机器上面可以有多个分片数据库,这样一个或多个分片节点(dataNode)所在的机器就是节点主机(dataHost),量将读写压力高的分片节点(dataNode)均衡的放在不同的节点主机(dataHost)。
(9)分片规则(rule)
按照某种业务规则把数据分到某个分片的规则就是分片规则。
(10)全局序列号(sequence)
数据切分后,原有的关系数据库中的主键约束在分布式条件下将无法使用,因此需要引入外部机制保证数据唯一性标识,这种保证全局性的数据唯一标识的机制就是全局序列号(sequence)

4.2 mycat目录

(1)bin目录
存放了启动脚本,mycat支持命令{console|start|stop|restart|status|dump}。
mycat可通过9066端口进行连接管理。登陆命令:mysql -h主机 -u用户名 -p密码 -P9066 [-d逻辑库]。

  • -h:后面是主机ip
  • -u:后面是server.xml中配置的逻辑库用户
  • -p:后面是server.xml中配置的逻辑库密码
  • -P:后面是端口默认9066
  • -d:后面是server.xml 中配置的逻辑库

管理命令:

  • reload @@config:用于不重启更新配置文件
  • show @@database:显示MyCAT的数据库的列表,对应schema.xml配置文件的schema子节点
  • show @@datanode:显示MyCAT的数据节点的列表,对应schema.xml配置文件的dataNode节点,其中NAME表示dataNode 的名称,dataHost表示对应dataHost属性的值即数据主机,ACTIVE表示活跃连接数,IDLE表示闲置连接数,SIZE对应总连接数量
    查找schema下面的dataNode列表命令:
  • show @@datanode where schema = ?
  • show @@version:获取MyCAT 的版本
  • show @@connection:获取Mycat的前端连接状态
  • kill @@connection id:用于杀掉连接。
  • show @@backend:查看后端连接状态。
  • show @@sql:记录用户通过本地8066端口向Mycat-Server发送的SQL
  • show @@sql.slow:慢SQL时间阈值的

(2)conf目录
conf目录下存放配置文件,server.xml是Mycat服务器参数调整和用户授权的配置文件,schema.xml 是逻辑库定义和表以及分片定义的配置文件,rule.xml是分片规则的配置文件,配置文件修改,需要重启Mycat 或者通过9066端口reload。
(3)lib目录
存放mycat依赖的一些jar文件.
(4)log目录
日志存放在logs/mycat.log中,每天一个文件,日志的配置是在conf/log4j.xml中。

4.3 配置文件

4.3.1 schema.xml

Schema.xml管理着MyCat的逻辑库、表、分片规则、DataNode 以及DataSource。schema 标签用于定义MyCat 实例中的逻辑库,MyCat 可以有多个逻辑库,每个逻辑库都有自己的相关配置。
(1)schema标签
schema标签来划分不同的逻辑库。如果不配置schema标签,所有的表属于同一个默认的逻辑库。在查询不同的逻辑库中表的时候需要切换到该逻辑库下才可以查询到所需要的表。

	<schema name="USERDB" checkSQLschema="false" sqlMaxLimit="100">
		<table name="post" dataNode="dnUser1" ruleRequired="false" primaryKey="post_code" />
		<table name="user_list" dataNode="dnUser1,dnUser2,dnUser3" rule="user-mod-long" />
		<table name="user_login" dataNode="dnUser1,dnUser2,dnUser3" rule="prefix-pattern" />
		<table name="area" primaryKey="area_code" type="global" dataNode="dnUser1,dnUser2,dnUser3" />
	</schema>
	<schema name="ORDERDB" checkSQLschema="false" sqlMaxLimit="100">
		<table name="orderlist_buyer" primaryKey="id" dataNode="dnOrder1,dnOrder2"
			   rule="buyer-sharding-by-pattern">
			<childTable name="order_item_buyer" primaryKey="id" joinKey="order_id"
						parentKey="id">
			</childTable>
		</table>
		<table name="orderlist_merchant" primaryKey="id" dataNode="dnOrder1,dnOrder2"
			   rule="merchant-sharding-by-pattern">
			<childTable name="order_item_merchant" primaryKey="id" joinKey="order_id"
						parentKey="id">
			</childTable>
		</table>		
	</schema>

schema标签属性:

  • dataNode:逻辑库所在具体的数据库
  • checkSQLschema:该值为true 时,如果我们执行语句select * from USERDB.post;则MyCat会把语句修改为select * from post。即把表示schema 的字符去掉。但是如果SQL所带的是并非是schema指定的名字,MyCat并不会删除改字符,所以SQL语句的最好是不带这个字段
  • sqlMaxLimit:SQL如果没有limit,MyCat会自动的加上对应的值

(2)table标签
Table标签定义了逻辑表,所有需要拆分的表都需要在这个标签中定义。同个schema标签中定义的名称必须唯一。
table标签的相关属性:

  • dataNode:定义这个逻辑表所属的dataNode, 该属性的值需要和dataNode标签中name属性的值一样,多个以逗号隔开
  • rule:指定逻辑表要使用的规则,规则名字在rule.xml中定义,必须与tableRule标签中name属性一样
  • ruleRequired:表是否一定要绑定分片规则,如果配置为true,没有配置规则程序会报错
  • primaryKey:逻辑表对应真实表的主键。如果分片的规则使用非主键,那么在使用主键查询的时候,就会发送查询语句到所有配置的DN 上,如果使用该属性配置真实表的主键。MyCat会缓存主键与具体DN的信息,那么再次使用非主键进行查询就会直接发送语句给具体的DN,不会广播、如果缓存并没有命中的话,还是会发送语句给具体的DN来获得数据
  • type:逻辑表的类型,目前逻辑表只有全局表(global)和普通表(不指定)两种类型
  • autoIncrement:为true 指定这个表有使用自增长主键。mysql对非自增长主键,使用last_insert_id()只会返回0。只有定义了自增长主键的表才可以用last_insert_id()返回主键值。
    由于insert 操作的时候没有带入分片键,mycat会先取下这个表对应的全局序列,然后赋值给分片键。这样才能正常的插入到数据库。如果要使用这个功能最好配合使用数据库模式的全局序列
  • subTables:分表功能,使用方式添加subTables=“表$1-3”。目前分表1.6 以后开始支持并且dataNode 在分表条件下只能配置一个,分表条件下不支持各种条件的join语句
  • needAddLimit:指定表是否需要自动的在每个语句后面加上limit限制

(3)childTable标签
用于定义E-R 分片的子表。通过标签上的属性与父表进行关联。配在table标签里。

  • name:子表的表名
  • joinKey:插入子表的时候会使用这个列的值查找父表存储的数据节点。
  • parentKey:关联父表的列名。程序首先获取joinkey 的值,再通过parentKey属性指定的列名产生查询语句,通过执行该语句得到父表存储在哪个分片上。从而确定子表存储的位置。
  • primaryKey:同table标签
  • needAddLimit:同table标签

(4)dataNode标签
定义了MyCat的数据节点,也就是数据分片。一个dataNode标签就是一个独立的数据分片。
dataNode标签属性:

  • name:定数据节点的名字,必须唯一,在table标签上使用来建立表与分片对应的关系
  • dataHost:用于定义该分片属于哪个数据库实例的,属性值是引用dataHost 标签上定义的name属性
  • database:用于定义该分片上的哪个库

(5)dataHost标签
定义了具体的数据库实例、读写分离配置和心跳语句。

  • name:dataHost 标签名称,必须唯一
  • maxCon:每个读写实例连接池的最大连接。标签内嵌套的writeHost、readHost 标签都会使用这个属性实例化出连接池的最大连接数。
  • minCon:每个读写实例连接池的最小连接,初始化连接池的大小。
  • balance:负载均衡类型,0代表不开启读写分离机制,所有读操作都发送到当前可用的writeHost上。1代表全部的readHost和备用的writeHost参与select语句的负载均衡。2代表所有读操作随机的在writeHost、readhost上分发。3代表所有读请求随机的分发到wiriterHost对应的readhost 执行,writerHost不负担读压力,这个只在1.4 及其以后版本有
  • writeType:负载均衡类型,0代表写操作发送到配置的第一个writeHost,第一个宕机后切换到生存的第二个writeHost,重新启动后以切换后的为准,切换记录在配置文件中dnindex.properties中。1代表所有写操作都随机的发送到配置的writeHost,1.5 以后废弃不推荐
  • dbType:指定后端连接的数据库类型。比如mysql、mongodb、oracle、spark等。
  • dbDriver:连接后端数据库使用的Driver,目前可选的值有native和JDBC。使用native 的话,因为这个值执行的是二进制的mysql协议,所以可以使用mysql 和maridb。其他类型的数据库则需要使用JDBC驱动来支持。需要将符合JDBC4标准的驱动JAR包放到MYCAT\lib 目录下,并检查驱动JAR包中包括如下目录结构的文件:META-INF\services\java.sql.Driver。在这个文件内写上具体的Driver类名,
  • switchType:-1表示不自动切换,1表示自动切换(默认),2表示基于主从同步的状态决定是否切换,心跳语句为show slave status,3表示基于MySQL galary cluster的切换机制(适合集群),心跳语句为show status like ‘wsrep%’
  • slaveThreshold:Mycat心跳机制通过检测show slave status中的"Seconds_Behind_Master", “Slave_IO_Running”,“Slave_SQL_Running” 三个字段来确定当前主从同步的状态以及Seconds_Behind_Master主从复制时延,当Seconds_Behind_Master>slaveThreshold 时,读写分离筛选器会过滤掉此Slave 机器,防止读到很久之前的旧数据

(6)heartbeat标签
这个标签内指明用于和后端数据库进行心跳检查的语句
(7)writeHost 和readHost标签
用来指定后端数据库的相关配置,writeHost指定写实例、readHost指定读实例。
在一个dataHost内可以定义多个writeHost和readHost。但是如果writeHost指定的后端数据库宕机,那么这个writeHos 绑定的所有readHost都将不可用。这个writeHost宕机系统会自动的检测到,并切换到备用的writeHost上去

  • host:用于标识不同实例,一般writeHost使用M1,readHost用S1
  • url:后端实例连接地址,如果是使用native的dbDriver为address:port 这种形式。用JDBC为jdbc:mysql://localhost:3306/
  • user:后端存储实例连接用户名
  • password:后端存储实例连接密码
  • weight:readhost中作为读节点的权重(1.4以后)
  • usingDecrypt:是否对密码加密默认0,1位开启,同时使用加密程序对密码加密,加密命令为:java -cp Mycat-server-1.4.1-dev.jar io.mycat.util.DecryptUtil 1:host:user:password。jia包在mycat的download下载目录

4.3.2 server.xml

mycat需要的系统配置信息。
(1)user标签

<user name="test">
<property name="password">test</property>
<property name="schemas">TESTDB</property>
<property name="readOnly">true</property>
<property name="benchmark">11111</property>
<privileges check="false">
<schema name="TESTDB" dml="0010" showTables="custome/mysql">
<table name="tbl_user" dml="0110"></table>
<table name="tbl_dynamic" dml="1111"></table>
</schema>
</privileges>
</user>

主要用于定义登录mycat的用户和权限。

  • Benchmark:mycat连接服务降级处理,benchmark基准,当前端的整体connection数达到基准值时, 对来自该账户的请求开始拒绝连接,0 或不设表示不限制

(2)privileges标签
user标签子节点。对用户的schema及下级的table进行精细化的DML权限控制,节点中的check属性是用于标识是否开启DML权限检查,默认false。
(3)system标签

  • charset:字符集设置
  • processors:用于指定系统可用的线程数,默认值为机器CPU核心线程数
  • processorBufferChunk:指定每次分配Socket Direct Buffer 的大小,默认是4096 个字节。这个属性也影响buffer pool的长度
  • processorExecutor:用于指定NIOProcessor上共享的businessExecutor固定线程池大小。mycat在需要处理一些异步逻辑的时候会把任务提交到这个线程池中。新版本中这个连接池的使用频率不是很大了,可以设置一个较小的值
  • sequnceHandlerType:指定使用Mycat全局序列的类型。0 为本地文件方式,1 为数据库方式,2 为时间戳序列方式,3 为分布式ZK ID生成器,4 为zk递增id生成,1.6增加两种ZK的全局ID生成算法
  • idleTimeout:指定连接的空闲超时时间,默认30 分钟
  • bindIp:mycat监听的IP地址,默认值为0.0.0.0
  • serverPort:定义mycat的使用端口,默认值为8066
  • managerPort:定义mycat的管理端口,默认值为9066
  • fakeMySQLVersion:mycat模拟的mysql版本号,默认值为5.6 版本,目前支持设置5.5、,5.6 版本,其他版本可能会有问题
  • useGlobleTableCheck:全局表一致性检测,0为关闭。原理通过在全局表增加_MYCAT_OP_TIME字段来进行一致性检测,类型为bigint,create语句通过mycat执行会自动加上这个字段,其他情况请自己手工添加
  • handleDistributedTransactions:分布式事务开关,0 为不过滤分布式事务,1 为过滤分布式事务,如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但记录分布式事务日志
  • useOffHeapForMerge:1表示使用非堆内存(Direct Memory)处理跨分片结果集的Merge/order by/group by/limit

4.3.3 rule.xml

定义了对表进行拆分所涉及到的规则定义。
(1)tableRule标签

  • name:指定唯一的名字,标识不同的表规则

(2)rule标签
tableRule内子标签,指定对物理表中的哪一列进行拆分和使用的路由算法。

  • columns:指定要拆分的列名字
  • algorithm:使用function标签的name属性。连接表规则和具体路由算法

(3)function标签

  • name:指定算法的名字
  • class:制定路由算法具体的类名
  • property:具体算法需要用到的一些属性

4.4 分片规则

(1)主键分片vs 非主键分片
当没有任何字段可以作为分片字段的时候,主键分片就是唯一选择,其优点是按照主键的查询最快。若有某个合适的业务字段比较合适作为分片字段,则建议采用此业务字段分片,选择分片字段的条件如下:

  • 尽可能的比较均匀分布数据到各个节点上
  • 该业务字段是最频繁的或者最重要的查询条件
  • 尽量规避跨库Join

4.4.1 分片枚举

在配置文件中配置可能的枚举id,自己配置分片,本规则适用于特定的场景,比如按照省份分区,配置如下:

<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>

其中mapFile 标识配置文件名称,type 默认值为0,0 表示Integer,非零表示String,
所有的节点配置都是从0 开始,0代表节点1
defaultNode默认节点,小于0 表示不设置默认节点,大于等于0 表示设置默认节点。枚举分片时,如果碰到不识别的枚举值,就让它路由到默认节点。

10000=0
10010=1
DEFAULT_NODE=1

4.4.2 固定分片hash算法

本条规则类似于十进制的求模运算,区别在于是二进制的操作,取id的二进制低10 位,即id二进制&1111111111。

<function name="func1" class="io.mycat.route.function.PartitionByLong">
<property name="partitionCount">2,1</property>
<property name="partitionLength">256,512</property>
</function>

其中partitionCount分片个数列表,partitionLength分片范围列表,最大支持1024个 分区。count,length 两个数组的长度必须是一致的。
1024 = sum((count[i]*length[i]))。
本例的分区策略:希望将数据水平分成3 份,前两份各占25%,第三份占50%。

4.4.3 范围约定

此分片适用于提前规划好分片字段的某个范围属于哪个分片,
start <= range <= end.
range start-end ,data node index
K=1000,M=10000.

<function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txt</property>
<property name="defaultNode">0</property>
</function>

其中,mapFile 代表配置文件路径,defaultNode超过范围后的默认节点。

0-500M=0
500M-1000M=1
1000M-1500M=2

4.4.4 取模

此规则为对分片字段求摸运算。

<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<property name="count">3</property>
</function>

4.4.5 按日期(天)分片

此规则为按天分片。

<function name="sharding-by-date" class="io.mycat.route.function.PartitionByDate">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2014-01-01</property>
<property name="sEndDate">2014-01-02</property>
<property name="sPartionDay">10</property>
</function>

其中dateFormat为日期格式,sBeginDate是开始日期,sEndDate为结束日期,sPartionDay为分区天数。

4.4.6 取模范围约束

此种规则是取模运算与范围约束的结合。

<function name="sharding-by-pattern" class="io.mycat.route.function.PartitionByPattern">
<property name="patternValue">256</property>
<property name="defaultNode">2</property>
<property name="mapFile">partition-pattern.txt</property>
</function>

其中patternValue 即求模基数,defaoultNode默认节点,mapFile 配置文件路径。

4.4.7 截取数字做hash 求模范围约束

此种规则类似于取模范围约束,支持数据符号字母取模。

<function name="sharding-by-pattern"
class="io.mycat.route.function.PartitionByPrefixPattern">
<property name="patternValue">256</property>
<property name="prefixLength">5</property>
<property name="mapFile">partition-pattern.txt</property>
</function>

其中patternValue即求模基数,prefixLength截取的位数,mapFile 配置文件路径。
这里采取的是将列种获取前prefixLength位列所有ASCII 码的和进行求模。

4.4.8 截取数字hash解析

此规则是截取字符串中的int 数值hash 分片。

<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>

其中partitionLength代表字符串hash求模基数,partitionCount分区数,hashSlice是hash预算位,即根据子字符串中int值hash运算。

4.4.9 一致性hash

一致性hash 预算有效解决了分布式数据的扩容问题。

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

一致性哈希

  • 首先求出服务器(节点)的哈希值,并将其配置到0~2的32次方的圆上。
  • 然后采用同样的方法求出存储数据的键的哈希值,并映射到相同的圆上。
  • 然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上

一致性哈希算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题。
为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。

4.4.10 按单月小时拆分

此规则是单月内按照小时拆分,最小粒度是小时,可以一天最多24个分片,最少1个分片,一个月完后下月从头开始循环。
每个月月尾,需要手工清理数据。

<function name="sharding-by-hour" class="io.mycat.route.function.LatestMonthPartion">
<property name="splitOneDay">24</property>
</function>

其中splitOneDay为一天切分的分片数

4.4.11 范围求模分片

先进行范围分片计算出归属分片组,组内再根据组内分片数量求模。

<function name="rang-mod"
class="io.mycat.route.function.PartitionByRangeMod">
<property name="mapFile">partition-range-mod.txt</property>
<property name="defaultNode">21</property>
</function>

其中mapFile代表配置文件路径,defaultNode默认节点。
以下配置一个范围代表一个分片组,=号后面的数字代表该分片组所拥有的分片的数量。

0-200M=5 //代表有5 个分片节点
200M1-400M=1
400M1-600M=4
600M1-800M=4
800M1-1000M=6

4.4.12 日期范围hash分片

思想与范围求模一致,当由于日期在取模会有数据集中问题,所以改成hash方法。
先根据日期分组,再根据时间hash使得短期内数据分布的更均匀。

<function name="range-date-hash"
class="io.mycat.route.function.PartitionByRangeDateHash">
<property name="sBeginDate">2014-01-01 00:00:00</property>
<property name="sPartionDay">3</property>
<property name="dateFormat">yyyy-MM-dd HH:mm:ss</property>
<property name="groupPartionSize">6</property>
</function>

其中sPartionDay代表多少天分一个分片,groupPartionSize代表分片组的大小,例子中分片组共包含天数为6*3=18天。

4.4.13 自然月分片

按月份列分区,每个自然月一个分片。

<function name="sharding-by-month" class="io.mycat.route.function.PartitionByMonth">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2014-01-01</property>
</function>

其中dateFormat为日期字符串格式,默认为yyyy-MM-dd,sBeginDate为开始日期,sEndDate为结束日期。

4.4.14 自然月分片应用指定

此规则是在运行阶段有应用自主决定路由到那个分片。

<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">8</property>
<property name="defaultPartition">0</property>
</function>

配置说明:
此方法为直接根据字符子串(必须是数字)计算分区号(由应用传递参数,显式指定分区号)。
例如id=05-100000002在此配置中代表根据id中从startIndex=0,开始截取siz=2位数字即05,05就是获取的分区,如果没传默认分配到defaultPartition。

5. mycat架构

在这里插入图片描述
Mycat由几个模块组成:通信协议、路由解析、结果集处理、数据库连接、监控等模块。
(1)通信协议
通信协议模块承担底层的收发数据、线程回调处理工作,主要采用Reactor(默认)、proactor模式来提高效率。协议层采用 MySQL协议。
(2)路由解析
路由解析模块对SQL语句进行语法解析,解析从MySQL协议中解析出来并进入该模块的SQL语句的条件、语句类型、携带的关键字等,对符合要求的SQL语句进行相关优化,最后根据这些路由计算单元进行路由计算。
(3)结果集处理
结果集处理对跨分片的结果进行汇聚、排序、截取等
(4)数据库连接模块
数据库连接模块负责创建、管理、维护后端的连接池。
(5)监控管理
监控管理负责对Mycat中的连接、内存等资源进行监控和管理。
(7)SQL执行模块
SQL执行模块负责从连接池中获取相应的目标连接,对目标连接进行信息同步后,再根据路由解析的结果,把SQL语句分发到相应的节点执行。
主要流程
由通信协议模块的读写事件发起通知。读写事件通知具体的回调代码进行这次读写事件的处理。管理模块的执行流程由定时器事件进行资源检查和资源释放时发起。
客户端发送过来的数据通过协议解析、路由解析等流程进入执行组件。通过执行组件把数据发送到通信协议模块,最终数据被写入目标数据库。
后端数据库返回数据,通过协议解析后发送至回调模块。如果是涉及多节点的数据,则执行流程将会先进入结果集汇聚、排序等模块中,然后将处理后的数据通过通信协议模块返回到客户端。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章