关于数据库分库分表理论基础

数据库 投稿 63600 0 评论

关于数据库分库分表理论基础

分库分表

背景描述

  • 用户请求量大

单台服务器TPS、内存、IO都是有上限的,我们需要将请求分散到多个服务器去

  • 单库数据量太大

  • 单表数据量太大

单表数据量很大了之后,查询、插入、更新操作都会变慢,加字段、索引都会产生高负载。

解决方案:

    垂直拆分

    按照业务切割,如将电商的数据库分为:用户库、商品库、订单库

    将一个表进行切分,如将商品表分为:商品名称表、商品属性表

  1. 2.1 水平分库

    2.2 水平分表

分片规则

  • Range

    • 时间:按照年、月、日去切分

    • 地域:按照省或者市划分

    • 大小:如从0到一千万的数据,每100万放一个表,0-100万、100-200万等。

  • Hash

    • 用户ID取模

  • 一致性Hash

实例:

  1. 用户表

但是这样的话如果是用户需要通过手机号登录,就要查询多个库。

  1. 订单表

划分方法1:按照用户id为分片键。这样每个用户的订单都在一个库。

划分方法2:我们可以采用空间换时间,将订单再按照商家ID进行分片,再存一份数据。

ShardingSphere

  • Sharding JDBC:被定位为轻量级Java框架,在Java的JDBC层提供额外服务,以jar包形式使用

  • Sharding Proxy:被定位为数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。

  • Sharding Sidecar:被定位为Kubernates或Mesos的云原生数据库代理,以DaemonSet的形式代理所有对数据库的访问。

Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar三者区别如下:

Sharding-JDBC

  • 适用于任何基于Java的ORM框架,如:JPA、Hibernate、Mybatis、Spring JDBC Template等

  • 适用于基于任何第三方的数据库连接池,如:DBCP、C3P0、BoneCP、Druid、HikariCP等

  • 支持任意的实现JDBC规范的数据库,目前支持:MySQL、Oracle、SQLServer和PostgreSQL

Sharding-JDBC主要功能:

    • 分库分表

    • 读写分离

    • 分片策略

    • 分布式主键

  • 分布式事务

    • 标准的事务接口

  • XA强一致性事务

  • 柔性事务

    • 配置动态化

  • 编排和治理

  • 数据脱敏

  • 可视化链路追踪

核心概念

  1. 表概念

  • 真实表

  • 逻辑表

数据分片后,同一类表结构的名称。例如b_order

  • 数据节点

  • 绑定表

指的是分片规则一致的关系表(主表、子表),例如订单表和订单明细表,均按照order_id进行分片,则此两个表可以设置为绑定表关系,绑定表之间的连接查询不会出现笛卡尔积关联,提升查询效率。

没配置绑定表的话,关联查询时需要4个sql

select * from order1 left join order_detail1 on ....
select * from order1 left join order_detail2 on ....
select * from order2 left join order_detail1 on ....
select * from order2 left join order_detail2 on ....

配置了绑定表后:

select * from order1 left join order_detail1 on ....
select * from order2 left join order_detail2 on ....
  • 广播表

在使用中,有些表没必要做分片,例如字典表、省份信息等,因为他们数据量不大,而且这种表可能需要跟一些大表关联查询。广播表会在不同的数据节点上进行存储,存储的表结构和数据完全相同。
2. 分片算法

  • 精确分片算法PreciseShardingAlgorithm

用于处理使用单一键作为分片键的=与in进行分片的场景

  • 范围分片算法RangeShardingAlgorithm

  • 复合分片算法ComplexKeysSharingAlgorithm

用于处理使用多键作为分片键进行分片的场景

  • Hint分片算法HintShardingAlgorithm

  1. 分片策略

分片策略包含分片键和分片算法。目前提供5种分片策略:

  • 标准分片策略StandardShardingStrategy

PreciseShardingAlgorithm是必选的,RangeShardingAlgorithm是可选的。但是SQL中使用了范围操作,如果不配置RangeShardingAlgorithm会采用全库路由扫描,效率低。

  • 复合分片策略ComplexShardingStrategy

  • 行表达式分片策略InlineShardingStrategy

只支持单分片键。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发。如: t_user_$->{u_id % 8}表示t_user表根据u_id模8,而分成8张表,表名称为t_user_0到t_user_7。

  • Hint分片策略HintShardingStrategy

  • 不分片策略NoneShardingStrategy

不分片的策略。

SQL使用规范

  • 路由至单数据节点时,目前MySQL数据库100%全兼容,其他数据库完善中

  • 路由至多数据节点时,全面支持DQL、DML、DDL、DCL、TCL。支持分页、去重、排序、分组、聚合、关联查询。不支持CASE WHEN、HAVING、UNION。支持的最复杂的查询示例:

SELECT select_expr [, select_expr ...]
FROM table_reference [, table_reference ...]
 [WHERE predicates]
[GROUP BY {col_name | position} [ASC | DESC], ...]
 [ORDER BY {col_name | position} [ASC | DESC], ...]
 [LIMIT {[offset,] row_count | row_count OFFSET offset}]
  • 支持分页子查询,但是只支持嵌套一层的子查询。

  • 当分片键处于运算表达式或函数中的SQL时,将采用全路由的形式获取结果。

不支持项:

INSERT INTO tbl_name (col1, col2, …) VALUES(1+2, ?, …) //VALUES语句不支持运算表达式

INSERT INTO tbl_name (col1, col2, …) SELECT col1, col2, … FROM tbl_name
WHERE col3 = ? //INSERT .. SELECT

SELECT COUNT(col1) as count_alias FROM tbl_name GROUP BY col1 HAVING
count_alias > ? //HAVING

SELECT * FROM tbl_name1 UNION SELECT * FROM tbl_name2 //UNION

SELECT * FROM tbl_name1 UNION ALL SELECT * FROM tbl_name2 //UNION ALL

SELECT * FROM ds.tbl_name1 //包含schema

SELECT SUM(DISTINCT col1), SUM(col1) FROM tbl_name //同时使用普通聚合函数和DISTINCT

SELECT * FROM tbl_name WHERE to_date(create_time, ‘yyyy-mm-dd’) = ? //会导致全路由

分页查询:

SELECT * FROM b_order ORDER BY id LIMIT 1000000, 10

如果是分为2个库的情况,为了保证数据正确性,SQL会被改写为:

 SELECT * FROM b_order ORDER BY id LIMIT 0, 1000010

并且两个库都会执行这条SQL,然后取10条数据出来。

  • 流式处理+归并排序的方式避免内存的过量占用。

由于SQL改写不可避免的占用了额外的带宽,但并不会导致内存暴涨。与直觉不同,大多数人认为ShardingSphere会将1,000,010*2记录全部加载至内存,进而占用大量内存而导致内存溢出。

  • 对落至单节点的查询进行进一步的优化

落至单分片查询的请求并不需要改写SQL也可以保证记录的正确性,因此在此种情况下,ShardingSphere并未进行SQL改写,从而达到节省带宽的目的。

其他功能

  • Inline行表达式

语法格式:
行表达式的使用非常直观,只需要在配置中使用${expression }或$->{ expression }标识行表达式即可。例如:

${begin..end}  # ..表示范围区间
${[unit1, unit2, unit_x]} # [,,]表示枚举值

行表达式中如果出现多个${}或$->{}表达式,整个表达式结果会将每个子表达式结果进行笛卡尔(积)组合。例如,以下行表达式:

${['online', 'offline']}_table${1..3}
$->{['online', 'offline']}_table$->{1..3}

最终会解析成:

online_table1, online_table2, online_table3,
offline_table1, offline_table2, offline_table3

对于均匀分布的分片还是好写,那么不均匀的呢?

db0
 ├── b_order0
 └── b_order1
db1
 ├── b_order2
 ├── b_order3
 └── b_order4

可以写成这样:

db0.b_order${0..1},db1.b_order${2..4}

编程笔记 » 关于数据库分库分表理论基础

赞同 (65) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽