1.垂直拆分
1.1垂直分库
垂直拆分就是要把表按功能模块划分到不同数据库中,如果你的系统是分布式微服务的架构,那就更好理解了,一般一个微服务对应这一个或多个数据库。比如电商系统一般都会有用户中心、订单、商品等等。用户中心数据库存的都是用户信息相关的,商品数据库存的都是商品相关的数据,订单数据库则是存的订单相关的。
1.2垂直分表
垂直分表是将一张数据表的字段,拆成两张或两张以上的数据进行存放。这样做的目的一个是避免一张表存的字段太多,单条数据的数据量大,不仅会占用更多的物理内容,还会降低查询的性能。而且有些字段查询的不是很频繁,有些字段查询的很频繁,那我们就可以将这查询频繁和查询不频繁的字段分开存放。这样就可以避免磁盘进行不必要的IO,提高系统的性能。我们一般都是把查询频繁的字段放到主表中,查询不频繁且不是很重要的字段放到扩展表中。主表和扩展表是1对1的关系,之间用主键进行关联。
1.3垂直拆分优缺点
优点:
- 解决业务系统层面的耦合,业务清晰。
- 与微服务的治理类似,也能对不同业务的数据进行分级管理、维护、监控、扩展等。
- 并发场景下,垂直切分一定程度的提升IO、数据库连接数、单机硬件资源的瓶颈。
缺点: - 部分表无法join,只能通过接口聚合方式解决,提升了开发的复杂度。
- 分布式事务处理复杂。
- 依然存在单表数据量过大的问题(需要水平切分)。
2.水平拆分
当一个应用已经按照垂直拆分,将数据库或数据表拆的粒度达到了最小,但是单表的数据行数巨大,在进行数据库读写的时候,存储性能还是会很差,这个时候就需要进行水平拆分了。水平拆分又分为库内分表和分库分表,在进行水平分表的时候,需要根据表中存储的数据之间存在的逻辑关系进行拆分。可以根据表中的某个字段取分,比如说用户id。也可以根据时间去分,比如一个月分一次表。这些分表策略最终目的都是为了让单表的数据变小,从而减轻数据表读写的IO压力。
2.1 库内分表
库内分表是在一个数据库中的某张表,数据行数达到了数据库读写性能的瓶颈的时候,将数据平摊到数据表结构一样的数据表中,已达到减少单张表数据,提升数据表读写性能的目的。
2.2 分库分表
库内分表只解决了一个库内单张表的压力,但是如果查询的比较频繁的话,库内分表的那个数据库的整体性能还是很容易达到瓶颈。因为一个物理机的CPU、内容、网络IO都是有限的,所以就需要多个库去分担单库的IO压力。
分库分表就是将原先单库分好的数据表,平摊到各个数据库中,目的就是为了减轻单库的IO性能压力,正所谓人多力量大嘛。
3. 分表策略
3.1 按范围拆分
按照ID区间来切分。例如:将userId为1~9999分到第一个库,10000~19999的分到第二个库,以此类推。某种意义上,某些系统中使用的"冷热数据分离",将一些使用较少的历史数据迁移到其他库中,业务功能上只提供热点数据的查询,也是类似的实践。
优点:
- 单表大小可控。
- 天然便于水平扩展,后期如果想对整个分片集群扩容时,只需要添加节点即可,无需对其他分片的数据进行迁移。
- 使用分片字段进行范围查找时,连续分片可快速定位分片进行快速查询,有效避免跨分片查询的问题。
缺点:
- 热点数据成为性能瓶颈。连续分片可能存在数据热点,例如按时间字段分片,有些分片存储最近时间段内的数据,可能会被频繁的读写,而有些分片存储的历史数据,则很少被查询。
3.2 取模分表
这种分表策略是项目中用的比较多的,字段值取模分表的算法就是用某个字段的值进行取模,即key%n,如果算数据落到哪个库中,则n是数据库的总数。如果算数据落到哪个表中,则n是数据表的总数。Key就是你需要用来取模字段的值,这个可以一般都是根据你项目的业务去定义的,比如:key是userId,那这个人的数据必然会落入到同一个库中。需要注意的是这个key一定要保证是全局唯一id。
优点:
- 数据分片相对比较均匀,不容易出现热点和并发访问的瓶颈。
缺点: - 后期分片集群扩容时,需要迁移旧的数据(使用一致性hash算法能较好的避免这个问题)容易面临跨分片查询的复杂问题。
3.3 时间分表
按照时间进行分表,这个表的拆分周期将会作为表的后缀名,比如按月分表,则表名一般都会跟着这个表是几年几月的。一般都会根据数据量大小决定时间拆分的粒度,数据量有小到大对应的拆分的粒度则是时、日、月、年进行拆分。一般按照时间来进行切分的数据,一般都是日志类的数据。这种数据一般都是查询一些创建时间比较近的数据,历史数据不会轻易查询。
优点:
- 单表大小可控
- 天然便于水平扩展,后期如果想对整个分片集群扩容时,只需要添加节点即可,无需对其他分片的数据进行迁移。
- 使用分片字段进行范围查找时,连续分片可快速定位分片进行快速查询,有效避免跨分片查询的问题。
缺点: - 热点数据成为性能瓶颈。连续分片可能存在数据热点,例如按时间字段分片,有些分片存储最近时间段内的数据,可能会被频繁的读写,而有些分片存储的历史数据,则很少被查询,联表查询困难。
以上总结的是几种比较常用的分库分表策略,还有其它的分库分表策略感兴趣的可以自行去了解。分库分表策略没有哪个是最好的,都是要根据自己的业务场景去选择使用哪种分库分表策略
现在比较流行的几种分库分表中间件有:shardingJDBC,mycat等。掌握一种就可以了,底层的原理都是一样的,概括起来的话就是拦截sql语句,然后根据你配置的分库分表策略去改写sql,路由到对应的数据库中。
4. 主从复制
以mysql为例,在进行master数据库数据的修改数据操作,数据库执行之后,都会将执行日志记录到本地,以二进制文件保存,也就是我们所说的bin-log。
假设master和slave数据配置好了主从关系,实时的对master的数据进行修改,master数据库会通过3306端口,通过网络将bin-log同步给slave数据库。slave执行的并不是二进制日志,由于它是从master的二进制日志复制过来的,并不是自己的数据库变化产生的,有点接力的感觉,称为中继日志,即relay log。这就是所谓的mysql的复制,即MYSQL replication。
可以发现,通过上面的机制,可以保证master和slave的数据库数据一致,但是时间上肯定有延迟,即MYSQL-B的数据是滞后的。即便不考虑什么网络的因素,master的数据库操作是可以并发的执行的,但是slave只能从relay log中读一条,执行下。因此master的写操作很频繁,slave很可能跟不上。
主从复制这块只需要知道它的原理就行,因为配置主从复制有点偏运维,有专门的运维会去做这件事,开发不需要关心。
5. 读写分离
在数据库集群架构中,让主库负责处理事务性查询,而从库只负责处理select查询,让两者分工明确达到提高数据库整体读写性能。当然,主数据库另外一个功能就是负责将事务性查询导致的数据变更同步到从库中,也就是写操作。这就是数据库的读写分离。
优点:
- 分摊服务器压力,提高机器的系统处理效率
- 增加冗余,提高服务可用性,当一台数据库服务器宕机后可以调整另外一台从库以最快速度恢复服务
**觉得写的不错的,可以一键三连哦。想了解更多,或想要直接获取我的后续内容。
Gong#Zhong#Hao:java干货仓库,发送【亿级系统设计】。**