假设我们某个业务使用User表,User表有16亿调数据记录,若将对这16亿数据记录进行的增删改查操作都放在一个数据库中,则性能一定不会太好,根据经验,一般数据库如MySQL,单表存储5000万条数据基本上已经到达瓶颈,所以,我们需要对这数据进行分片存储,首先,按照5000万条数据记录一个单位来切分,将这16亿的数据记录切分成32个分片,如下图所示:
假设将这32个切片对于32个表,并把它们放在同一个数据库实例和一个数据库中,那么单个数据库实例的网卡I/O、内存、CPU和磁盘性能都是有限的,随着数据访问频率的增加会导致单个实例和单个库遇到瓶颈,因此我们需要将这32个表散列到多个数据库实例和多个数据库中,这里将16亿的数据记录的User表数据拆分成4个数据库实例,每个实例有两个数据库,每个数据库有4个表(分库分表),如下图所示:
分库分表的架构设计
通过上面两个图片,我们大体了解了分库分表的大概逻辑,简单来说,数据的切分就是通过某种特定的条件,将我们存在同一个数据库中的数据散列存放到多个数据库(主机)中,已达到分散单台设备负载的效果,即为分库分表。
数据的切分根据其切分的规则类型,可以分为如下两种切分模式:
- 垂直(纵向)拆分:把单一的表拆分成多个表,并分散到不同的数据库(主机)上。
- 水平(横向)拆分:根据表中数据的逻辑关系,将同一个表的数据按照某种条件拆分到多太数据库(主机)上。
一、垂直拆分
优点:
- 拆分后业务清晰,拆分规则明确。
- 系统之间进行整合或扩展容易。
- 按照成本、应用的等级、应用的类型将表放到不同的机器上,便于管理。
- 变异实现动静分离、冷热分离的数据库表设计模式。
- 数据维护简单 缺点:
- 部分业务无法关联(join),只能通过代码方式解决,提高系统的复杂度。
- 受每种业务的不同限制,存在单库性能瓶颈,不易于进行数据扩展和提升性能。
- 事务处理复杂
二、水平拆分
与垂直拆分相比,水平拆分不是对表进行分类,而是将其按照某个字段的某种规则分散到多个库中,比如:时间,在每一个表中包含一部分数据,所有的表加起来就是全量的数据,简单来说,我们可以将对数据水平切分理解为按照数据进行切分,就是将表中部分行切分到不同的数据库表中,例如将用户表拆分成User1、User2、User3等,表的结构完全一样,我们通常根据某些特定的规则来划分表,比如根据用户的ID来取模划分。
水平拆分的优点如下:
- 单库单表的数据保持在一定的量级,有助于性能的提升。
- 切分的表结构相同,应用层改造较少,只需要
增加路由规则即可。 - 体改系统的稳定性和负载能力。 水平拆分的缺点如下:
- 切分后,数据的分散的,很难利用数据库的join操作,跨库join性能比较差。
- 拆分规则难以抽象。
- 分片事务的一致性难以解决。
- 数据扩容的难度和维护量极大。
综上所述,垂直拆分和水平筛分的共同点如下:
- 存在分布式事务问题。
- 存在跨节点Join问题。
- 存在跨节点合并排序、分页问题。
- 存在多数据源管理问题。
在了解这两种切分方式的特点后,我们可以根据自己的业务需求来做选择,通常会同时使用这两种方式,垂直拆分更偏向与业务拆分的过程,推荐在设计数据库结构时,就考虑垂直拆分,根据冷热分离、动静分离的原则,有效的提升数据库查询的性能,在技术上我们更关注水平拆分的方案。
水平拆分方式的路由过程和拆分维度
路由过程
我们在设计表的时候需要确定对表按照什么样的规则进行分库分表,例如:当有新用户注册的时候,程序的确定将此用户信息添加到那个表中,同理,用户在登录时我们需要到那个表查找用户的信息,所有这些都需要按照某一个规则进行路由请求,因为请求所需要的数据分布在不用的分片表中。
针对这样的请求,通过分库分表规则查找到对应的表和库的过程叫路由,例如,分库分表规则是user_id%4,当用户新注册一个账号时,假设用户的ID是123,可以得到123%4=3,确定这个用户应该被保存到User3表,当ID为123的用户登录时,我们可以通过123%4=3计算后,确定从User3表查询用户的信息。
拆分维度
第一种:按照哈希拆分
对数据的某个字段求hash,再除以分片总数后取模,取模后相同的数据为一个分片,这样的将数据分成多个分片的方式叫哈希分片。
这种切分方式的好处是数据切分比较均匀,对数据的压力分散的效果比较好,缺点是数据分散后,对于查询需求需要聚合处理。
第二种:按照时间拆分
与哈希分片不同,这种方式是按照时间的范围将数据分布到不同的分片上,例如:一个订单表的数据有近10年的数据,我们可以将交易的订单数据按年或者是月进行切分,或者是按照季度进行切分,有交易的数据多少来决定按照什么样的时间周期对数据进行切分。
在实际的生产实践中,按照哈希切片和按照时间切片都是常用的分库分表方式,并被广泛的使用,我们可以结合自己的业务场景使用这两种切分方式,例如:对交易的订单数据线按照季度进行切分,然后对某一个季度的数据按照主键哈希进行分片。