数据库性能优化之高并发架构设计 学习笔记

224 阅读6分钟

前言

对于数据库性能的优化,除了合理使用索引等SQL执行计划细节上的优化之外,在高并发场景,我们还需要在架构层面进行优化,提高数据库的读写性能。

例如,有个项目需求,为了达成下面的接口性能目标,我们应该如何进行数据库架构的优化?

  • 读接口高峰 10w QPS(Queries Per Second)
  • 写接口高峰 10w TPS(Transactions per Second)

读性能优化

在实际的业务实践过程中,我们通常会采用为服务增添更多机器资源的方式,来应对高 QPS 的业务诉求。

而针对数据库层面,为了使其同样能够通过增加机器达成高 QPS 读操作的要求,在业界广泛应用着一种名为读写分离的数据库集群架构方案。 image.png 在读写分离这种架构模式里,数据库被划分为主库与从库两个部分。其中,主库承担着所有数据写入的任务,而从库则主要负责处理数据的读操作

那么,我们可以通过扩充从库,来增加数据库集群可承载的读 QPS 上限。比如,我们现在压测出来单库读 QPS 上限是 1w QPS,那么我们就可以通过增加 10 个从库,来达到整体读 10w QPS 的性能目标。

值得注意的是,在读写分离架构中,写入主库的数据会通过特定的数据同步机制(例如binlog)及时地传输并更新至从库之中,从而确保整个数据库系统的数据一致性,为高 QPS读操作提供坚实稳定的架构支撑。

因此,增加从库实现数据库集群整体可承载读 QPS 上限提升的同时,主从同步这一过程会额外占用主库的硬件资源。针对主库的写操作,在数据写入 binlog 日志后,主库会启用一个特定线程,将 binlog 日志同步传输至从库。如此一来,主从同步操作便会消耗主库的 CPU 、网卡带宽等硬件资源,并且从库数量越多,主库所需消耗的硬件资源也就越多。由于单台主库设备的硬件资源规格是存在上限的,这就意味着从库数量无法无限制地扩充image.png 为了实现整体性能目标,在从库数量受限的情况下,我们务必确保单库的读 QPS 上限不至于过低。而影响单库读 QPS 上限的一个重要因素,就是表里数据的行数。单表数据行数过多,会使查询变慢(慢SQL问题),在影响数据库可承载 QPS 的同时,还可能导致单个请求的延时达不到业务诉求。

怎么避免单表数据行数过多?很显然,应该分表!

分表策略

分表实际上分为两个维度:垂直拆分和水平拆分

垂直拆分一般是为了解决单表字段过多,尤其还是很多占用空间大的字段类型时,一次select查询一行记录的整体I/O耗时会上升,有的时候即使命中了索引,也会出现慢查询。因此一般在业务上,我们会采用拆分表结构的思路,将业务信息表拆分为主表和扩展表。只有当需要所有信息的查询时,再进行一些联表查询。

而针对单表数据行数过多,主要是探讨水平分表这个角度

在实践中,我们能够借助压测的手段来确定单表可存储数据量的上限,与此同时,还要依据对业务数据量的预估,来推断单表可能会存储的最大数据量规模,以此作为判断单表行数是否超出合理范围的重要依据。

另外,网上常有种说法,MySQL 表行数超过 2000w 左右,一般会被认为是大表,需要做拆分。具体这个数值如何计算出来的,可以参考这篇文章

当单表数据量过大,导致查询性能变差时,我们可以将这个大的数据表,按照一定的规则拆分成多个较小的数据表,从而提升表数据查询的性能。

关于分表规则,业界也有几种常见的参考方案:

  1. 范围路由:是指针对整型、时间戳等数据类型,按照其数值范围进行拆分,使处于不同范围的数据分别存储到不同的子表之中。例如,利用雪花算法生成业务主键ID,作为sharing key,然后按年,按季度,按月,按周拆分表。
  2. hash路由:通过计算某个特定列的 hash 值,然后依据该 hash 值将数据路由分配至不同的子表当中。
  3. 配置路由:通过相关配置,使得数据依据某个列的值来完成路由操作。例如,对于一张专门用于存储用户位置信息的单表,我们可以在远程配置文件里设定城市路由规则,这样一来,不同城市的用户数据便会被分别存储到不同的子表之中。再进行读写操作时,通过一层proxy或DAL,按城市配置路由到不同的分表上。此外,为了充分利用表资源,避免数据量分布不均的状况,我们还可以对一些数据量少的城市合并到一张表里,根据不同城市的具体情况进行针对性配置。

写性能优化:分库

与优化读性能的思路相似,针对高 TPS 写操作而言,很容易想到的策略便是增添机器资源。为了确保数据库在面临高 TPS 写需求时,同样能够通过增加机器的方式达到目标,在业界存在一种名为分库的数据库集群架构方案。

所谓分库的方案,是指在单库写操作的 TPS 处于较高水平时,我们能够对数据库进行拆分,构建出多个主库,通过把写操作合理地分配到多个主数据库,数据库集群便能够并行处理数量更多的写请求,从而有效提升整个数据库集群整体的写 TPS 上限。 image.png 和分表方案一样,在分库规则方面,较为常用的方案同样是:范围路由、hash 路由以及配置路由这三种类型

小结

高并发场景下的数据库架构设计分为几个方向:

  1. 读写分离架构:当我们数据库读 QPS 过高时,可以通过读写分离架构,增加从库来提升数据库集群的读 QPS。
  2. 分表架构:当我们单表数据行数太多,导致读性能下降时,可以用分表架构,将一张表拆成多张小表,从而提升读性能。
  3. 分库架构:当我们数据库写入 TPS 过高时,可以用分库架构,通过增加多个主库,分散单库的写压力,从而提升数据库整体的写 TPS 上限。

参考

《go服务开发高手课》