深入原理64式:14 数据库分库分表基础

数据切分根据其切分类型,可以分为两种方式:垂直(纵向)切分和水平(横向)切分

1 垂直切分
垂直切分常见有垂直分库和垂直分表两种。
1.1 垂直分库
垂直分库就是根据业务耦合性,将关联度低的不同表存储在不同的数据库。做法与大系统拆分为多个小系统类似,按业务分类进行独立划分。与"微服务治理"的做法相似,每个微服务使用单独的一个数据库。

        Application
客户        存款        贷款        支付
cluster    cluster    cluster    cluster

1.2 垂直分表
思想: 基于数据库中的列进行,某个表字段较多,可以新建一张扩展表,将不经常用的字段或较长的字段拆分到扩展表中。避免跨页问题。
原因: mysql通过数据页存储,一条记录占用空间过大会导致跨页。
原理:
假设有一张表包含如下字段:
c1    c2    c3    c4
拆分为
c1    c3    c4

c1    c2

优点:
解决业务系统层面的耦合,与微服务理念相似,对不同业务数据分级管理,
高并发下可以一定成都提升IO瓶颈。

缺点:
部分表无法join,只能通过接口聚合;分布式事务处理复杂。

2 水平切分
2.1 水平切分基础
种类:
库内分表和分库分表。
将同一个表按不同条件分散到多个数据库或多个表中,每个表中只包含一部分数据,
减少单表的数量。

原理:
        Application
客户        存款        贷款        支付
Cluster    Cluster    Cluster    Cluster

客户DB 1
T_Customer
T_Address
......

客户DB 2
T_Customer
T_Address
......

客户DB 3
T_Customer
T_Address
......

该方法是按照表内某个字段的某种规则来将数据分散存储于不同的数据库(或不同的表),
也就是按照数据行来切分数据。

库内分表:
只解决了单一表数据量过大问题,没有将表分布到不同机器的库上,帮助不是很大。
最好通过分库分表来解决。

水平切分:
优点: 不存在单库数据量过大瓶颈,应用端改造较小
缺点: 跨分片的事务一致性难以保证,跨库的join关联查询性能较差。

2.2 分片规则:
1) 根据数值范围
按照时间区间或ID区间区分。
优点: 单表大小可控,连续分片可块度定位分片进行快速查询。
缺点: 热点数据成为性能瓶颈
结构:
        sharding key
[0, 1000]    [1001, 2000]    [2001, 3000]    ... [m, n]


2) 根据数值取模
采用hash取模mod的切分方式。
例如根据用户id字段切分到4个库中,余数为0的放到第一个库,余数为1的放到第二个库,。。。
优点:
数据分片比较均匀
缺点:
集群扩容,需要迁移旧的数据(使用一致性哈希能较好解决)
跨分片查询问题。查询条件不带id字段,将无法定位数据库,需要同时向所有数据库查询。

3 分库分表的问题
3.1 事务一致性问题
1) 分布式事务
当更新内容同时分布式在不同库中,带来跨库事务问题。

解决方法:
可使用XA协议和两阶段提交处理。
待补充。

3.2 跨节点关联查询join问题
切分后,数据可能分布在不同节点,尽量避免join查询。

解决方法:
全局表: 数据字典表在每个数据库中都报错一份
字段冗余: 定单表保存userId时,将userName也冗余保存一份。只适合依赖字段较少的情况。
数据组装: 分两次查询,第一次查询的结果集找到关联数据id,然后根据id发起第二次请求得到关联数据,
将获得的数据进行字段拼接。
ER分片: 

3.3 跨节点分页、排序问题
分页:需要按照指定字段进行排序。排序: 需要先在不同分片节点中将数据进行排序返回,
然后将不同分片返回的结果集进行汇总和再次排序。

3.4 全局主键避重问题
之前的主键值自增长策率无用。
常用主键生成策略:
1) uuid
32个16进制数字 8-4-4-4-12共36个字符。

2) 结合数据库维护主键id表
建立sequence表,设置stub字段为唯一索引,

3) 分布式自增ID算法
生成64位的Long型数字:
第一位未使用
接下来41位时毫秒级时间
5位datacenterId, 5位workerId。最多支持1024个节点
最后12位时毫秒内的计数。
一般用这个。

4 一个例子
4.1 用户中心业务
User(uid, login_name, passwd, sex, age, nickname)

uid为用户ID,  主键
login_name, passwd, sex, age, nickname,  用户属性

4.2 水平切分方法
上文描述的切分方法有"根据数值范围"和"根据数值取模"。
"根据数值范围":以主键uid为划分依据,按uid的范围将数据水平切分到多个数据库上。例如:user-db1存储uid范围为0~1000w的数据,user-db2存储uid范围为1000w~2000wuid数据。
"根据数值取模":也是以主键uid为划分依据,按uid取模的值将数据水平切分到多个数据库上。例如:user-db1存储uid取模得1的数据,user-db2存储uid取模得0的uid数据。
优点是:数据量和请求量分布均均匀
不足是:扩容麻烦,当容量不够时,新增加db,需要rehash。需要考虑对数据进行平滑的迁移。

4.3非uid查询方法
而按非uid的查询,例如login_name,就不知道具体该访问哪个库了
1) 建立非uid属性到uid的映射关系
login_name不能直接定位到数据库,可以建立login_name→uid的映射关系,用索引表或缓存来存储。当访问login_name时,先通过映射表查询出login_name对应的uid,再通过uid定位到具体的库。

2) 基因法
分库基因:假如通过uid分库,分为8个库,采用uid%8的方式进行路由,此时是由uid的最后3bit来决定这行User数据具体落到哪个库上,那么这3bit可以看为分库基因。

5 分库分表中间件
Cobar,Vitess等

6 总结
6.1) 垂直分库
垂直分库将关联度低的不同表存储在不同的数据库。
原理:
        Application
客户        存款        贷款        支付
cluster    cluster    cluster    cluster

6.2)垂直分表
垂直分表基于数据库中的列进行,某个表字段较多,可以新建一张扩展表,将不经常用的字段或较长的字段拆分到扩展表中。避免跨页问题。
原理:
假设有一张表包含如下字段:
c1    c2    c3    c4
拆分为
c1    c3    c4

c1    c2
缺点:
部分表无法join,只能通过接口聚合;分布式事务处理复杂。

6.3) 库内分表
将同一个表按不同条件分散到多个数据库或多个表中,每个表中只包含一部分数据,
减少单表的数量。

原理:
        Application
客户        存款        贷款        支付
Cluster    Cluster    Cluster    Cluster

客户DB 1
T_Customer
T_Address
......

客户DB 2
T_Customer
T_Address
......

客户DB 3
T_Customer
T_Address

分片规则:
跟据数值范围
按照时间区间或ID区间区分。
优点: 单表大小可控,连续分片可块度定位分片进行快速查询。
缺点: 热点数据成为性能瓶颈

根据数值取模
采用hash取模mod的切分方式。
优点:
数据分片比较均匀
缺点:
集群扩容,需要迁移旧的数据(使用一致性哈希能较好解决)
跨分片查询问题。

6.4) 分库分表的问题
事务一致性问题
当更新内容同时分布式在不同库中,带来跨库事务问题。
可使用XA协议和两阶段提交处理。

跨节点关联查询join问题
解决方法:
数据组装: 分两次查询,第一次查询的结果集找到关联数据id,然后根据id发起第二次请求得到关联数据,
将获得的数据进行字段拼接。

全局主键避重问题
分布式自增ID算法
生成64位的Long型数字:
第一位未使用
接下来41位时毫秒级时间
5位datacenterId, 5位workerId。最多支持1024个节点
最后12位时毫秒内的计数。
一般用这个。

6.5)
业务垂直切分,对某些字段垂直拆分(将某些频繁访问的字段拆分出去),
水平切分来确保每个库只有一部分数据。

参考:
https://www.cnblogs.com/butterfly100/p/9034281.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值