数据库优化之垂直拆分和水平拆分

491 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情

概述

随着系统的稳定运行,数据量越来越大,随着数据量的增加,系统性能经历了优化数据库索引、加入缓存、读写分离,现在系统的数据处理是增删改都走主库,查询走缓存或者从库,大大提升了系统对数据的读写能力。随着访问量的继续增加,读的能力可以通过增加从数据库进行扩展,但是没办法提升主库的写数据能力了。

image.png

垂直分库

分析一下目前数据库的现状,商品模块、订单模块、用户模块的数据数据都存储在一个数据库实例中,使用同一个服务器资源,同时对服务造成很大的压力。对数据库按模块进行垂直拆分,不同的模块分别使用独立的数据库。

image.png

原来很多模块共用一个数据库资源,经过垂直分库后,商品模块、订单模块和用户模块等使用了单独自己的数据库资源,各个模块项目资源的竞争就不存在了。

  • 垂直分库的好处

经过对数据库按模块垂直分库后,减轻了数据库的压力;每个数据库分摊了数据,提高了查询的效率;对每个数据库的访问相应的CPU、内存、网络压力变小了;业务更加清晰,各个业务模块在编码和资源上进行了解耦;系统变得易扩展了。

  • 垂直拆分的不足

垂直分库后增加了系统的复杂性;多个数据库数据表关联查询变得复杂;从单库的事务变成了多了数据源的事务控制;垂直拆分未解决单表数据量很大的情况。

水平拆分

垂直分库未解决单表数据量很大的问题。下面以用户查询订单信息跟踪订单进度的场景进行说明。

履约系统是指订单和仓储(骑手)系统之间的支撑系统。用户跟踪订单信息的请求为什么需要进行水平拆分呢?当用户请求履约系统跟踪订单进度的时候,履约系统会调用订单系统,通过RPC请求调用,比如用duboo进行服务间的通信,设置服务间的访问超时时间为1s,因为订单数据量特别大,订单模块查询订单基本信息耗时400ms,查询订单明细信息耗时500ms,这样订单系统查询订单耗时就快1s了,服务间通信需要建立网络连接,网络传输上也需要耗费时间,这样履约系统与订单系统的交互很容易超时。

如果将履约系统与订单系统之间的访问超时调大一些,比如设置超时时间为5s,这样用户体验会很差,还有就是如果一旦设置超时时间为5s,履约系统的线程池很容易被打满,线程池打满后就会导致服务资源迅速被耗尽,最终履约系统的服务会崩掉,导致系统不可用。

所以如果系统出现性能问题,增加服务间的调用超时时间是存在很大风险的,是一个治标不治本的方式,最终还是要进行系统优化,必须解决服务的耗时问题。

image-20220804163145060.png

那么如何解决单表数据量过大的问题呢?常用手段可以进行水平拆分。

  • 水平拆表

拆分的表都有相同的表结构,只是每个表中存储部分数据。

image-20220804165002221.png

  • 水平拆库

水平拆表后,拆分的表依然分布在同一个数据库中,竞争同一个服务资源。可以进一步对数据库进行拆分。

image-20220804165529121.png

分库分表

如果拆分的数据库中的表数据量也很大的时候就会又回到单库单表大数据量的情况,这个时候可以再进行分表。就形成了分库分表。

image-20220804171044214.png

  • 水平拆分的不足

水平拆分的过程比较复杂;事务处理也变得了复杂(可以自己代理数据源实现分布式事务、也可以通过MQ进行处理);多库多表联查难度增加;水平拆分之后单表的数据会分散到不同的数据源中,造成了多数据源管理的问题。

总结

水平分库分表后解决了单表大数据量访问造成的系统性能问题,但是同时也带来了系统的复杂性问题。

  • 路由策略如何设计
  • 全局ID如何保证
  • 历史数据如何迁移
  • 系统流量如何切换
  • 多数据源如何管理

后期将针对这一些列问题分析和落地相应的解决方案。