第一章 概述
11 数据库切分概述
1-1-1 OLTP和OLAP
联机事务处理(OLTP)也称为面向交易的处理系统,其基本特征是原始数据可以立即传送到计算中心进行处理,并在很短的时间内给出处理结果。
联机分析处理(OLAP)是指通过多维的方式对数据进行分析、查询和报表,可以同数据挖掘工具、统计分析
工具配合使用,增强决策分析功能。
1-1-2 关系型数据库和NoSQL数据库
0 | 关系型数据库 | NoSQL 数据库 |
---|---|---|
特点 | -数据关系模型基于关系模型,结构化存储,完整性约束。-基于二维表及其之间的联系,需要连接、并、交、差、除等数据操作。-采用结构化的查询语言(SQL)做数据读写。-操作需要数据的一致性,需要事务甚至是强一致性。 |
|
优点 |
|
|
缺点 |
|
|
1-1-3 数据切分
数据的切分(Sharding)根据其切分规则的类型,可以分为两种切分模式。一种是按照不同的表(或者
Schema)来切分到不同的数据库(主机)之上,这种切可以称之为数据的垂直(纵向)切分;另外一种则是根据
表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库(主机)上面,这种切分称之为数据的水平(横向)切分。
垂直切分优缺点:
优点 | 缺点 |
---|---|
|
|
水平切分优缺点:
优点 | 缺点 |
---|---|
|
|
共同的缺点:
- 引入分布式事物的问题。
- 跨节点join的问题。
- 跨节点合并排序分页问题。
- 多数据源管理问题。
针对数据源管理,目前有两种思路:
1. 客户端模式,在每个应用程序模块中配置管理自己需要的一个(或者多个)数据源,直接访问各个数据库,在模块内完成数据的整合。
2. 通过中间代理层来统一管理所有的数据源,后端数据库集群对前端应用程序透明。
由于数据切分后数据join的难度,关于数据切分的经验:
- 第一原则:能不切分尽量不要切分
- 第二原则:如果要切分一定要选择合适的切分规则,提前规划好。
- 第三原则:数据切分尽量通过数据冗余或表分组(Table Group)来降低跨库join的可能。
- 第四原则:由于数据库中间件对数据join实现的优劣难以把握,而且实现高性能难度极大,业务读取尽量少使用多表join。
第二章 MyCat简介
2-1 MyCat概述
Mycat 背后是阿里曾经开源的知名产品——Cobar。Cobar 的核心功能和优势是 MySQL 数据库分片。
2-1-1 MyCat原理
Mycat 的原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的 SQL 语句,首先对 SQL 语句做了
一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此 SQL 发往后端的真实数据库,
并将返回的结果做适当的处理,最终再返回给用户。
执行过程:
上述图片里,Orders 表被分为三个分片 datanode(简称 dn),这三个分片是分布在两台 MySQL Server 上
(DataHost),即 datanode=database@datahost 方式,因此你可以用一台到 N 台服务器来分片,分片规则为
(sharding rule)典型的字符串枚举分片规则,一个规则的定义是分片字段(sharding column)+分片函数(rule
function),这里的分片字段为 prov 而分片函数为字符串枚举方式。
当 Mycat 收到一个 SQL 时,会先解析这个 SQL,查找涉及到的表,然后看此表的定义,如果有分片规则,
则获取到 SQL 里分片字段的值,并匹配分片函数,得到该 SQL 对应的分片列表,然后将 SQL 发往这些分片去执
行,最后收集和处理所有分片返回的结果数据,并输出到客户端。以 select * from Orders where prov=?语句为
例,查到 prov=wuhan,按照分片函数,wuhan 返回 dn1,于是 SQL 就发给了 MySQL1,去取 DB1 上的查询
结果,并返回给用户。
如果上述 SQL 改为 select * from Orders where prov in (‘wuhan’,‘beijing’),那么,SQL 就会发给
MySQL1与MySQL2 去执行,然后结果集合并后输出给用户。但通常业务中我们的 SQL 会有Order By 以及Limit 翻页语法,此时就涉及到结果集在 Mycat 端的二次处理,这部分的代码也比较复杂,而最复杂的则属两个表的 Jion 问题,
为此,Mycat 提出了创新性的 ER 分片、全局表、**HBT(Human Brain Tech)人工智能的
Catlet**、以及结合 Storm/Spark 引擎等十八般武艺的解决办法,从而成为目前业界最强大的方案,这就是开源的力量!
2-1-2 应用场景
- 单纯的读写分离,此时配置最为简单,支持读写分离,主从切换
- 分表分库,对于超过1000万的表进行分片,最大支持1000亿的单表分片
- 多租户应用,每个应用一个库,但应用程序
- 报表系统,借助于Mycat的分表能力,处理大规模报表的统计
- 替代Hbase,分析大数据
- 作为海量数据实时查询的一种简单有效方案,比如100亿条频繁查询的记录需要在3秒内查询出来结果,除了基于主键的查询,还可能存在范围查询或其他属性查询
第三章 MyCat中的概念
3-1 数据库中间件
MyCat是一个开源的分布式数据库系统,但是它并没有存储引擎,并不是完全意义的分布式数据库系统,MyCat是数据库中间件,就是介于数据库与应用之间,进行数据处理与交互的中间服务。
如上图所表示,数据被分到多个分片数据库后,应用如果需要读取数据,就要需要处理多个数据源的数据。
如果没有数据库中间件,那么应用将直接面对分片集群,数据源切换、事务处理、数据聚合都需要应用直接处
理,原本该是专注于业务的应用,将会花大量的工作来处理分片后的问题,最重要的是每个应用处理将是完全的
重复造轮子。
所以有了数据库中间件,应用只需要集中与业务处理,大量的通用的数据聚合,事务,数据源切换都由中间件来处理,中间件的性能与处理能力将直接决定应用的读写性能,所以一款好的数据库中间件至关重要。
3-2 逻辑库(schema)
在云计算时代,数据库中间件可以以多租户的形式给一个或多个应用提供服务,每个应用访问的可能是一个
独立或者是共享的物理库,常见的如阿里云数据库服务器 RDS。
3-3 逻辑表(table)
3-3-1 逻辑表
逻辑表,可以是数据切分后,分布在一个或多个分片库中,也可以不做数据切分,不分片,只有一个表构成。
3-3-2 分片表
分片表,是指那些原有的很大数据的表,需要切分到多个数据库的表,这样,每个分片都有一部分数据,所以由分片构成了完整的数据。
例如在mycat配置中的t_node就属于分片表,数据按照规则被分到dn1,dn2两个分片节点(dataNode)上。
<table name="t_node" primaryKey="vid" autoIncrement="true" dataNode="dn1,dn2" rule="rule1" />
3-3-3 非分片表
一个数据库中并不是所有的表都很大,某些表是可以不用进行切分的,非分片是相对分片表来说的,就是那
些不需要进行数据切分的表。
如下配置中t_node,只存在于分片节点(dataNode)dn1上。
<table name="t_node" primaryKey="vid" autoIncrement="true" dataNode="dn1" />
3-3-4 ER表
关系型数据库是基于实体关系模型(Entity-Relationship Model)之上,通过其描述了真实世界中事物与关系,Mycat 中的 ER 表即是来源于此。根据这一思路,提出了基于 E-R 关系的数据分片策略,子表的记录与所关联的父表记录存放在同一个数据分片上,即子表依赖于父表,通过表分组(Table Group)保证数据 Join 不会跨库操作。
3-3-5 全局表
一个真实的业务系统中,往往存在大量的类似字典表的表,这些表基本上很少变动,字典表具有以下几个特
性:
- 变动不频繁
- 数据量总体变化不大
- 数据规模不大,很少有超过数十万条记录。
对于这类的表,在分片的情况下,当业务表因为规模而进行分片以后,业务表与这些附属的字典表之间的关
联,就成了比较棘手的问题,所以 Mycat中通过数据冗余来解决这类表的join,即所有的分片都有一份数据的拷贝,所有将字典表或者符合字典表特性的一些表定义为全局表。
3-4 分片节点(dataNode)
数据切分后,一个大表被分到不同的分片数据库上面,每个表分片所在的数据库就是分片节点(dataNode)。
3-5 节点主机(dataHost)
数据切分后,每个分片节点(dataNode)不一定都会独占一台机器,同一机器上面可以有多个分片数据库,
这样一个或多个分片节点(dataNode)所在的机器就是节点主机(dataHost),为了规避单节点主机并发数限
制,尽量将读写压力高的分片节点(dataNode)均衡的放在不同的节点主机(dataHost)。
3-6 分片规则
前面讲了数据切分,一个大表被分成若干个分片表,就需要一定的规则,这样按照某种业务规则把数据分到
某个分片的规则就是分片规则,数据切分选择合适的分片规则非常重要,将极大的避免后续数据处理的难度。
3-7 全局序列号(sequence)
数据切分后,原有的关系数据库中的主键约束在分布式条件下将无法使用,因此需要引入外部机制保证数据
唯一性标识,这种保证全局性的数据唯一标识的机制就是全局序列号(sequence)。
3-8 多租户
多租户技术或称多重租赁技术,是一种软件架构技术,它是在探讨与实现如何于多用户的环境下共用相同的系统或程序组件,并且仍可确保各用户间数据的隔离性。在云计算时代,多租户技术在共用的数据中心以单一系统架构与服务提供多数客户端相同甚至可定制化的服务,并且仍然可以保障客户的数据隔离。目前各种各样的云计算服务就是这类技术范畴,例如阿里云数据库服务(RDS)、阿里云服务器等等。多租户在数据存储上存在三种主要的方案,分别是:
3-8-1 独立数据库
一个租户一个数据库,这种方案的用户数据隔离级别最高,安全性最好,但成本也高。
优点:
- 为不同的租户提供独立的数据库,有助于简化数据模型的扩展设计,满足不同租户的独特需求;
- 如果出现故障,恢复数据比较简单。
缺点:
- 增大了数据库的安装数量,随之带来维护成本和购置成本的增加。
这种方案与传统的一个客户、一套数据、一套部署类似,差别只在于软件统一部署在运营商那里。如果面对
的是银行、医院等需要非常高数据隔离级别的租户,可以选择这种模式,提高租用的定价。如果定价较低,产品
走低价路线,这种方案一般对运营商来说是无法承受的。
3-8-2 共享数据库,隔离数据架构
多个或所有租户共享 Database,但是每个租户一个 Schema。
优点:
- 为安全性要求较高的租户提供了一定程度的逻辑数据隔离,并不是完全隔离;每个数据库可以支持更多的租
户数量。
缺点:
- 如果出现故障,数据恢复比较困难,因为恢复数据库将牵扯到其他租户的数据;
- 如果需要跨租户统计数据,存在一定困难。
3-8-3 共享数据库,共享数据架构
租户共享同一个 Database、同一个Schema,但在表中通过 TenantID 区分租户的数
据。这是共享程度最高、隔离级别最低的模式。
优点:
- 三种方案比较,第三种方案的维护和购置成本最低,允许每个数据库支持的租户数量最多。
缺点:
- 隔离级别最低,安全性最低,需要在设计开发时加大对安全的开发量;
- 数据备份和恢复最困难,需要逐表逐条备份和还原。
第四章 MyCat安装
4-1 配置文件
conf目录下存放配置文件:
- server.xml是MyCat服务器参数调整和用户授权的配置文件
- schema.xml是逻辑库定义和表以及分片定义的配置文件
- rule.xml是分片规则的配置文件
日志存放在logs/mycat.log中,每天一个文件,日志的配置在conf/log4j.xml中,根据自己的需要,可以调整输出级别为debug,debug级别下,会输出更多的信息,方便排查问题。
4-2 schema.xml
schema标签
schema标签用于定义MyCat实例中的逻辑库,MyCat可以有多个逻辑库,每个逻辑库都有自己的相关配置,可以使用schema标签来划分这些不同的逻辑库。
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100"></schema>
属性值 | 描述 |
---|---|
dataNode | 用于绑定逻辑库到某个具体的database上 |
checkSQLschema | row 2 col 2 |
sqlMaxLimit | 当该值设置为某个数值时。每条执行的 SQL 语句,如果没有加上 limit 语句,MyCat 也会自动的加上所对应的值。需要注意的是,如果运行的 schema 为非拆分库的,那么该属性不会生效。需要手动添加 limit 语句。 |
table标签
<table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" ></table>
属性值 | 描述 |
---|---|
name | 逻辑表的表名 |
dataNode | 节点名称 |
rule | 规则名称 |
ruleRequired | 是否绑定分片规则 |
primaryKey | 该逻辑表对应的真实表的主建 |
type | 逻辑表的类型:全局表:global;普通表 |
autoIncrement | 自动增长主建 |
subTables | |
needAddLimit | 指定表是否需要自动的在每个语句后面加上limit限制 |
childTable | 用于定义E-R分片的子表,通过标签上的属性与父表进行关联 |
dataNode标签
dataNode标签定义了MyCat中的数据节点,即数据分片,一个dataNode标签就是一个独立的数据分片
<dataNode name="dn1" dataHost="lch3307" database="db1" ></dataNode>
dataHost标签
作为 Schema.xml 中最后的一个标签,该标签在 mycat 逻辑库中也是作为最底层的标签存在,直接定义了具体的数据库实例、读写分离配置和心跳语句。
4-3 server.xml
server.xml 几乎保存了所有 mycat 需要的系统配置信息。其在代码内直接的映射类为 SystemConfig 类。
user标签
用于定义登录 mycat 的用户和权限
system标签
这个标签内嵌套的所有 property 标签都与系统配置有关
rule.xml
rule.xml 里面就定义了我们对表进行拆分所涉及到的规则定义。
第五章 MyCat的分片join
第六章 MyCat防火墙配置
白名单和SQL黑名单:
<firewall>
<whitehost>
<host user="mycat" host="127.0.0.1"></host> ip 白名单 用户对应的可以访问的 ip 地址
</whitehost>
<blacklist check="true">
<property name="selelctAllow">false</property> 黑名单允许的 权限 后面为默认
</blacklist>
</firewall>
黑名单拦截明细配置
配置项 | 缺省值 | 描述 |
---|---|---|
selelctAllow | true | 是否允许执行 SELECT 语句 |
selectAllColumnAllow | true | 是否允许执行 SELECT * FROM T 这样的语句。 |
selectIntoAllow | true | SELECT 查询中是否允许 INTO 字句 |
deleteAllow | true | 是否允许执行 DELETE 语句 |
updateAllow | true | 是否允许执行 UPDATE 语句 |
insertAllow | true | 是否允许执行 INSERT 语句 |
replaceAllow | true | 是否允许执行 REPLACE 语句 |
mergeAllow | true | 是否允许执行 MERGE语句,这个只在 Oracle 中有用 |
callAllow | true | 是否允许通过 jdbc 的 call 语法调用存储过程 |
setAllow | true | 是否允许使用 SET 语法 |
truncateAllow | true | truncate 语句是危险,缺省打开,若需要自行关闭 |
createTableAllow | true | 是否允许创建表 |
alterTableAllow | true | 是否允许执行 Alter Table 语句 |
dropTableAllow | true | 是否允许修改表 |
commentAllow | false | 是否允许语句中存在注释,Oracle 的用户不用担心,Wall 能够识别 hints和注释的区别 |
noneBaseStatementAllow | false | 是否允许非以上基本语句的其他语句,缺省关闭,通过这个选项就能够屏蔽 DDL。 |
multiStatementAllow | false | 是否允许一次执行多条语句,缺省关闭 |
useAllow | true | 是否允许执行 mysql 的 use 语句,缺省打开 |
describeAllow | true | 是否允许执行 mysql 的 describe 语句,缺省打开 |
showAllow | true | 是否允许执行 mysql 的 show 语句,缺省打开 |
commitAllow | true | 是否允许执行 commit 操作 |
rollbackAllow | true | 是否允许执行 roll back 操作 |
拦截配置 - 永真条件
配置项 | 缺省值 | 描述 |
---|---|---|
selectWhereAlwayTrueCheck | true | 检查 SELECT 语句的 WHERE 子句是否是一个永真条件 |
selectHavingAlwayTrueCheck | true | 检查 SELECT 语句的 HAVING 子句是否是一个永真条件 |
deleteWhereAlwayTrueCheck | true | 检查 DELETE 语句的 WHERE 子句是否是一个永真条件 |
deleteWhereNoneCheck | false | 检查 DELETE 语句是否无 where 条件,这是有风险的,但不是 SQL 注入类型的风险 |
updateWhereAlayTrueCheck | true | 检查 UPDATE 语句的 WHERE 子句是否是一个永真条件 |
updateWhereNoneCheck | false | 检查 UPDATE 语句是否无 where 条件,这是有风险的,但不是SQL 注入类型的风险 |
conditionAndAlwayTrueAllow | false | 检查查询条件(WHERE/HAVING 子句)中是否包含 AND 永真条件 |
conditionAndAlwayFalseAllow | false | 检查查询条件(WHERE/HAVING 子句)中是否包含 AND 永假条件 |
conditionLikeTrueAllow | true | 检查查询条件(WHERE/HAVING 子句)中是否包含 LIKE 永真条件 |
其他拦截配置
配置项 | 缺省值 | 描述 |
---|---|---|
selectIntoOutfileAllow | false | SELECT … INTO OUTFILE 是否允许,这个是 mysql 注入攻击的常见手段,缺省是禁止的 |
selectUnionCheck | true | 检测 SELECT UNION |
selectMinusCheck | true | 检测 SELECT MINUS |
selectExceptCheck | true | 检测 SELECT EXCEPT |
selectIntersectCheck | true | 检测 SELECT INTERSECT |
mustParameterized | false | 是否必须参数化,如果为 True,则不允许类似 WHERE ID = 1 这种不参数化的 SQL |
strictSyntaxCheck | true | 是否进行严格的语法检测,Druid SQL Parser 在某些场景不能覆盖所有的SQL 语法,出现解析 SQL 出错,可以临时把这个选项设置为 false,同时把 SQL 反馈给 Druid 的开发者。 |
conditionOpXorAllow | false | 查询条件中是否允许有 XOR 条件。XOR 不常用,很难判断永真或者永假,缺省不允许。 |
conditionOpBitwseAllow | true | 查询条件中是否允许有”&”、”~”、” |
conditionDoubleConstAllow | false | 查询条件中是否允许连续两个常量运算表达式 |
minusAllow | true | 是否允许 SELECT * FROM A MINUS SELECT * FROM B 这样的语句 |
intersectAllow | true | 是否允许 SELECT * FROM A INTERSECT SELECT * FROM B 这样的语句 |
constArithmeticAllow | true | 拦截常量运算的条件,比如说 WHERE FID = 3 - 1,其中”3 - 1”是常量运算表达式。 |
limitZeroAllow | false | 是否允许 limit 0 这样的语句 |
禁用对象检测配置
配置项 | 缺省值 | 描述 |
---|---|---|
tableCheck | true | 检测是否使用了禁用的表 |
schemaCheck | true | 检测是否使用了禁用的 Schema |
functionCheck | true | 检测是否使用了禁用的函数 |
objectCheck | true | 检测是否使用了“禁用对对象” |
variantCheck | true | 检测是否使用了“禁用的变量” |
readOnlyTables | 空 | 指定的表只读,不能够在 SELECT INTO、DELETE、UPDATE、INSERT、MERGE 中作为”被修改表”出现 |