如果在数据库中表的数量达到了一定的量级, 则需要进行分表, 分解单表的大数据量对索引査询带来的压力,方便对索引和表结构的变更 。
如果数据库的吞吐量达到了瓶颈,就需要增加数据库实例,利用多个数据库实例来分解大量的数据库请求带来的系统压力。
分库分表就是将一个表分为多个表, 这些表可以放在同一个库里, 也可以放到不同的库里, 甚至可以放在不同的数据库实例上。
(1)单实例单库
单库单表是最常见的数据库设计,目前大部分的系统都是单库单表。
(2)多实例单库
多实例单库常用于读写分离和主备。多个实例之间启用了复制功能。
(3)多库(单实例/多实例)
这里的多库是将原来单库的部分表放在一个数据库,另外一部分放在另外一个数据库。这些数据库可以在一个实例,也可以在多个实例上。
(4)多库多表
多库多表就是在将不同数据表分部在不同的数据库基础上,对同一个表的数据也会拆分放在不同的数据库。
客户端分片有三种:应用层直接实现、定制JDBC协议实现、定制ORM框架实现。
(1)应用层直接实现
应用层直接决定每次操作应该使用哪个数据库实例、数据库及哪个数据库的表等。这种实现方式会让数据库保持的连接比较多。
(2)定制JDBC协议
通过定制JDBC协议来实现,也就是对业务层提供统一的JDBC接口,JDBC内部实现分库分表。这种需要开发人员理解JDBC协议,Sharding JDBC便采用了这种方案。
(3)定制ORM框架
把分片规则实现放到ORM框架中。
代理分片就是在应用层和数据库层之间增加一个代理层。代理层对外提供与JDBC兼容的接口,实现JDBC协议的解析,并通过分片的路由规则来路由请求。不过增加了代理层增加了一层网络传输,对性能是有影响的。
代理分片实现的主要框架有Cobar、Mycat、ShardingSphere等。
直切分是将单一库中的表按业务拆分到多个库或者多个表,甚至分散到不同的实例上。垂直切分除了可以分解单库单表的压力, 也可以实现冷热分离, 因为对拥有不同活跃度的数据的处理方式不同。对于冷数据査询较多, 更新较少,这种可以用MyISAM引擎。对于冷数据可以构建多个从库分解查询压力。而热数据更新比较频繁,适合使用InnoDB存储引擎。对于热数据使用分库分表分解压力。
优点:
拆分后业务清晰,拆分规则明确。系统之间进行整合或扩展很容易。便于实现动静分离、冷热分离的数据库表的设计模式。数据维护简单。
缺点:
无法关联查询,只能程序自行解决,提高了系统的复杂度,事务处理复杂。
根据表中数据逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库。每个表中包含一部分数据, 所有表加起来就是全量的数据。
优点:
单库单表的数据保持在一定的量级,有助于性能的提高。
切分的表的结构相同,应用层改造较少,只需要增加路由规则即可。
提高了系统的稳定性和负载能力 。
缺点:
无法关联查询。事务处理复杂,数据扩容的难度和维护量极大。
通常两种切分方式会同时使用, 垂直切分更偏向于业务拆分, 在技术上我们更关注水平切分的方案。
(1)扩容
在分库分表后, 如果需要对集群进行扩容,这时候 扩容是很麻烦的,因为路由规则可能发生变化,原有数据需要按照新规则迁移。
(2)查询间题
分库分表后,查询的条件不是分库分片的键值,这时候需要全库扫描。
(3)跨库事务
同时更新多个数据库数据的事务
Mycat是一个开源的分布式数据库系统,实现了MySQL协议,也就是前面说的代理分片,其后端可以用MySQL原生协议或者JDBC和多个MySQL服务器通信,其核心功能是分表分库下如何和数据库通信。Mycat目前可以支持MySQL、SQLServer、Oracle、DB2、PostgreSQL、MongoDB等数据库。
Mycat通过拦截用户发的SQL语句,对SQL语句进行分析,如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。
(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)
(1)bin目录
存放了启动脚本,mycat支持命令{console|start|stop|restart|status|dump}。
mycat可通过9066端口进行连接管理。登陆命令:mysql -h主机 -u用户名 -p密码 -P9066 [-d逻辑库]。
管理命令:
(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中。
Schema.xml管理着MyCat的逻辑库、表、分片规则、DataNode 以及DataSource。schema 标签用于定义MyCat 实例中的逻辑库,MyCat 可以有多个逻辑库,每个逻辑库都有自己的相关配置。
(1)schema标签
schema标签来划分不同的逻辑库。如果不配置schema标签,所有的表属于同一个默认的逻辑库。在查询不同的逻辑库中表的时候需要切换到该逻辑库下才可以查询到所需要的表。
schema标签属性:
(2)table标签
Table标签定义了逻辑表,所有需要拆分的表都需要在这个标签中定义。同个schema标签中定义的名称必须唯一。
table标签的相关属性:
(3)childTable标签
用于定义E-R 分片的子表。通过标签上的属性与父表进行关联。配在table标签里。
(4)dataNode标签
定义了MyCat的数据节点,也就是数据分片。一个dataNode标签就是一个独立的数据分片。
dataNode标签属性:
(5)dataHost标签
定义了具体的数据库实例、读写分离配置和心跳语句。
(6)heartbeat标签
这个标签内指明用于和后端数据库进行心跳检查的语句
(7)writeHost 和readHost标签
用来指定后端数据库的相关配置,writeHost指定写实例、readHost指定读实例。
在一个dataHost内可以定义多个writeHost和readHost。但是如果writeHost指定的后端数据库宕机,那么这个writeHos 绑定的所有readHost都将不可用。这个writeHost宕机系统会自动的检测到,并切换到备用的writeHost上去
mycat需要的系统配置信息。
(1)user标签
test
TESTDB
true
11111
主要用于定义登录mycat的用户和权限。
(2)privileges标签
user标签子节点。对用户的schema及下级的table进行精细化的DML权限控制,节点中的check属性是用于标识是否开启DML权限检查,默认false。
(3)system标签
定义了对表进行拆分所涉及到的规则定义。
(1)tableRule标签
(2)rule标签
tableRule内子标签,指定对物理表中的哪一列进行拆分和使用的路由算法。
(3)function标签
(1)主键分片vs 非主键分片
当没有任何字段可以作为分片字段的时候,主键分片就是唯一选择,其优点是按照主键的查询最快。若有某个合适的业务字段比较合适作为分片字段,则建议采用此业务字段分片,选择分片字段的条件如下:
在配置文件中配置可能的枚举id,自己配置分片,本规则适用于特定的场景,比如按照省份分区,配置如下:
partition-hash-int.txt
0
0
其中mapFile 标识配置文件名称,type 默认值为0,0 表示Integer,非零表示String,
所有的节点配置都是从0 开始,0代表节点1
defaultNode默认节点,小于0 表示不设置默认节点,大于等于0 表示设置默认节点。枚举分片时,如果碰到不识别的枚举值,就让它路由到默认节点。
10000=0
10010=1
DEFAULT_NODE=1
本条规则类似于十进制的求模运算,区别在于是二进制的操作,取id的二进制低10 位,即id二进制&1111111111。
2,1
256,512
其中partitionCount分片个数列表,partitionLength分片范围列表,最大支持1024个 分区。count,length 两个数组的长度必须是一致的。
1024 = sum((count[i]*length[i]))。
本例的分区策略:希望将数据水平分成3 份,前两份各占25%,第三份占50%。
此分片适用于提前规划好分片字段的某个范围属于哪个分片,
start <= range <= end.
range start-end ,data node index
K=1000,M=10000.
autopartition-long.txt
0
其中,mapFile 代表配置文件路径,defaultNode超过范围后的默认节点。
0-500M=0
500M-1000M=1
1000M-1500M=2
此规则为对分片字段求摸运算。
3
此规则为按天分片。
yyyy-MM-dd
2014-01-01
2014-01-02
10
其中dateFormat为日期格式,sBeginDate是开始日期,sEndDate为结束日期,sPartionDay为分区天数。
此种规则是取模运算与范围约束的结合。
256
2
partition-pattern.txt
其中patternValue 即求模基数,defaoultNode默认节点,mapFile 配置文件路径。
此种规则类似于取模范围约束,支持数据符号字母取模。
256
5
partition-pattern.txt
其中patternValue即求模基数,prefixLength截取的位数,mapFile 配置文件路径。
这里采取的是将列种获取前prefixLength位列所有ASCII 码的和进行求模。
此规则是截取字符串中的int 数值hash 分片。
512
2
0:2
其中partitionLength代表字符串hash求模基数,partitionCount分区数,hashSlice是hash预算位,即根据子字符串中int值hash运算。
一致性hash 预算有效解决了分布式数据的扩容问题。
0
2
160
一致性哈希:
一致性哈希算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题。
为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。
此规则是单月内按照小时拆分,最小粒度是小时,可以一天最多24个分片,最少1个分片,一个月完后下月从头开始循环。
每个月月尾,需要手工清理数据。
24
其中splitOneDay为一天切分的分片数
先进行范围分片计算出归属分片组,组内再根据组内分片数量求模。
partition-range-mod.txt
21
其中mapFile代表配置文件路径,defaultNode默认节点。
以下配置一个范围代表一个分片组,=号后面的数字代表该分片组所拥有的分片的数量。
0-200M=5 //代表有5 个分片节点
200M1-400M=1
400M1-600M=4
600M1-800M=4
800M1-1000M=6
思想与范围求模一致,当由于日期在取模会有数据集中问题,所以改成hash方法。
先根据日期分组,再根据时间hash使得短期内数据分布的更均匀。
2014-01-01 00:00:00
3
yyyy-MM-dd HH:mm:ss
6
其中sPartionDay代表多少天分一个分片,groupPartionSize代表分片组的大小,例子中分片组共包含天数为6*3=18天。
按月份列分区,每个自然月一个分片。
yyyy-MM-dd
2014-01-01
其中dateFormat为日期字符串格式,默认为yyyy-MM-dd,sBeginDate为开始日期,sEndDate为结束日期。
此规则是在运行阶段有应用自主决定路由到那个分片。
0
2
8
0
配置说明:
此方法为直接根据字符子串(必须是数字)计算分区号(由应用传递参数,显式指定分区号)。
例如id=05-100000002在此配置中代表根据id中从startIndex=0,开始截取siz=2位数字即05,05就是获取的分区,如果没传默认分配到defaultPartition。
Mycat由几个模块组成:通信协议、路由解析、结果集处理、数据库连接、监控等模块。
(1)通信协议
通信协议模块承担底层的收发数据、线程回调处理工作,主要采用Reactor(默认)、proactor模式来提高效率。协议层采用 MySQL协议。
(2)路由解析
路由解析模块对SQL语句进行语法解析,解析从MySQL协议中解析出来并进入该模块的SQL语句的条件、语句类型、携带的关键字等,对符合要求的SQL语句进行相关优化,最后根据这些路由计算单元进行路由计算。
(3)结果集处理
结果集处理对跨分片的结果进行汇聚、排序、截取等
(4)数据库连接模块
数据库连接模块负责创建、管理、维护后端的连接池。
(5)监控管理
监控管理负责对Mycat中的连接、内存等资源进行监控和管理。
(7)SQL执行模块
SQL执行模块负责从连接池中获取相应的目标连接,对目标连接进行信息同步后,再根据路由解析的结果,把SQL语句分发到相应的节点执行。
主要流程:
由通信协议模块的读写事件发起通知。读写事件通知具体的回调代码进行这次读写事件的处理。管理模块的执行流程由定时器事件进行资源检查和资源释放时发起。
客户端发送过来的数据通过协议解析、路由解析等流程进入执行组件。通过执行组件把数据发送到通信协议模块,最终数据被写入目标数据库。
后端数据库返回数据,通过协议解析后发送至回调模块。如果是涉及多节点的数据,则执行流程将会先进入结果集汇聚、排序等模块中,然后将处理后的数据通过通信协议模块返回到客户端。