如何衡量数据库性能

238 阅读10分钟

如何衡量数据库性能

Krzysztof Ksiazek 【hudson译】

2021年6月2日

图片

在运行生产环境时,您可能想知道数据库的性能如何?它是否提供了适当的性能水平?我们如何衡量它?数据库性能是一个非常广泛的话题,但我们想深入探讨一下,并讨论一下在谈论数据库性能时应该关注什么。

如何定义性能?

我们必须问自己的第一个问题是:我们衡量 数据库性能 的单位是什么? 这本身不是一个容易回答的问题。

每秒查询数(QPS)

显而易见的选择是使用每秒查询数或QPS。数据库在给定的时间段内可以执行多少个查询?问题是一个查询与另一个查询不同。我们可以有INSERTs、UPDATEs和SELECTs。我们可以有使用索引甚至主键访问数据的简单查询,也可以有连接多个表的复杂查询。我们可以比较单个查询或特定的、精确控制的查询组合的性能,但仅此而已。

在现实世界中,工作负载会波动,很难判断应该使用什么作为一组查询来比较不同配置版本之间的性能。在给定的时间内,您可能会提出一个查询组合,但如果您想在几个月后重复基准测试,则很可能会面临不同的查询组合,这使得很难比较随时间推移的性能。

每秒事务数(TPS)

这是另一个选项–在给定的时间段内我们可以执行多少事务?这种方法与使用QPS有很多相同的问题。事务中涉及的查询将随着时间的推移而变化,将引入新的事务类型。计算每秒事务数可能在给定的时刻有效,但随着时间的推移很难比较结果。

延迟(P99)

让我们试着从另一个角度来探讨这个话题。当我们谈论性能时,什么是最重要的?它是我们每秒可以执行的事务或查询数吗?如果您必须等待两倍的时间才能完成给定的查询,您可以将QPS提高30%吗?你可能会问这怎么可能?事实上,这很简单。您必须记住,在大多数情况下,在大多数数据库中,一个查询只能使用一个CPU核心。是的,在某些情况下,查询可以并行处理,但让我们继续处理大部分工作负载。因此,CPU核心等于一个查询。这意味着,如果您运行的查询数量与CPU内核数量一样多,那么您运行查询的速度将是最快的。这样我们可以最小化查询执行时间。另一方面,我们可以尝试最大化总吞吐量。可以想象,执行查询的过程不是最佳的,它没有充分利用CPU。如果我们开始对查询进行排队,并让CPU调度程序处理多个进程或线程,我们可以同时处理更多查询。由于这一点,我们可以显著提高吞吐量(以每秒查询数计算),但我们增加了查询的执行时间——现在每个线程都可以与其他线程共享CPU。因此,查询运行速度较慢,但我们仍然可以同时运行更多的查询。

延迟也应该是可预测的——用户希望查询运行得快一些,但如果查询运行得稍微慢一些,如果这样可以提高查询执行时间的稳定性,那么他们可能没问题。这是因为如果有一件事用户不喜欢的话,那就是速度慢的应用程序会间歇性变慢,而且没有什么好的理由。吞吐量的增加通常意味着延迟也会增加,但最重要的是,它可能变得更加不稳定。

如您所见,这给我们的性能讨论增加了更多的复杂性。显然,用户希望他们的应用程序能够快速运行并具有响应能力(因此,我们希望延迟较低)。另一方面,如果我们有许多用户,我们也希望能够同时运行许多查询(因此,吞吐量应该很高)。

如何提高数据库性能?

我们已经讨论了如何衡量性能,它有两个主要方面:延迟和吞吐量。要回答的另一个重要问题是如何提高数据库性能?一般来说,我们讨论的是几个选项。

硬件改进

显然,性能与可用资源有关。如果我们改进数据库运行的硬件,将影响数据库的性能 显然,性能与可用资源有关。如果我们改进数据库运行的硬件,将影响数据库的性能。具体的改进是什么,这取决于所做的更改和我们正在查看的工作负载类型。简而言之,工作负载主要有两种类型。

CPU绑定的工作负载

CPU绑定的工作负载是指性能受CPU资源限制的情况。我们在这里讨论的是活动数据集适合内存且磁盘活动最少的情况。它可能是由大量快速查询(例如索引查找)或少量长查询(涉及JOIN或排序和分组的繁重分析查询)引起的。在这种情况下,通过添加更多的内核或将CPU替换为更新的模型来提高CPU性能,从而提高每个内核的性能,可以提高数据库的整体性能。

I/O绑定工作负载

I/O绑定的工作负载是指I/O子系统上有大量负载的情况,通常是磁盘。这可能是由不同的情况引起的,但最常见的是这两种情况。首先,您的工作量很大,需要在数据库中插入或修改大量数据。因此,保存这些修改所需的写入量堆积起来,磁盘驱动器成为瓶颈。第二种最常见的情况是活动数据集不适合内存。活动数据集是应用程序经常访问的数据库中存储的数据的一部分。请记住,您可以拥有比可用内存大得多的数据集,但只要数据保存在磁盘上,就没有问题。当数据库必须不断地交换内存中的数据以满足应用程序的需要时,就会出现问题。在这种情况下,我们观察到对磁盘的读取增加。

正如您所料,这两种类型的问题应该在硬件级别上得到不同的解决。对于CPU绑定的流量,我们应该考虑通过提供更多的CPU内核或提高每个内核的性能来提高服务器的计算能力,这是典型的情况,尽管当您将CPU更改为较新的型号时,增加的幅度很小。如果我们谈论的是I/O绑定工作负载,我们可能有两种改进方法。显然,首先是提高磁盘子系统的性能。向RAID中添加更多驱动器,使用更高性能的RAID级别(RAID 10而不是RAID 5或6),交换磁盘驱动器以提高性能。或者,如果遇到大量读取的问题,可以尝试增加可用内存:更多内存将允许数据库在内存中缓存来自活动数据集的更多数据,从而减少从磁盘读取非缓存数据的需要。

配置调整

数据库有自己的配置,用户可以在其中调整一些设置以提高数据库的性能。有些设置可能更适合CPU绑定的工作负载,有些则更适合I/O绑定的工作负荷。您可能听说过自动配置调优脚本或DBA秘籍深藏StackOverflow或Quora中。事实上,除非数据库完全未配置,否则调整配置不大可能带来巨大的性能提升。是的,当然,你可以稍微提高你的表现,但仅此而已。不要指望能够将数据库速度提高十倍。

###查询优化

能将性能提高十倍的是查询调优。以更高效的形式重写查询,添加缺少的索引。在这里,你可以看到不同 监控工具 的巨大好处,就像那些在网络上共享的漂亮屏幕截图一样, 您可以看到CPU利用率从90%以上降至10%以下。如果查询不必要地访问甚至数千行,而使用适当的索引,它只能访问一行,那么是的,这会大大加快速度。详细描述查询调优过程超出了本文的范围,但要点是您应该收集与查询相关的指标——它们的执行时间、查询经历的等待时间、从数据库读取的行数、发送到应用程序的行数。

数据越多越好,具体可以收集什么取决于数据库类型,但大多数数据存储都提供了一些与其查询相关的性能数据。如果您可以使用工具来帮助您处理这些原始数据,无论是内置软件还是外部软件,那就更好了。它应该可以帮助您更好地理解数据库中发生的事情、它的执行方式以及有问题的查询是什么。

然后,作为下一步,您可能希望尝试了解有问题的查询的行为。通常你有 然后,作为下一步,您可能希望尝试了解有问题的查询的行为。通常,您可以访问某种查询执行计划——数据库优化器认为最佳的执行过程的详细概述。同样,不同数据库之间的细节有所不同,但我们在这里讨论的是如何访问给定的数据,使用哪种方法,是否涉及任何索引,如果是,涉及哪些索引?如果我们讨论的是关系数据库,您可能会看到JOIN中表的顺序是什么,以及使用的JOIN方法是什么。这将有助于您确定执行计划是否确实是最佳的,或者可能缺少一些潜在的改进。

一旦找出缺陷是什么,您可以尝试通过改进索引甚至将查询重写为更优化的形式来修复它。请记住,即使您使用的是无法修改的外部应用程序,在某些情况下,也有一些方法可以即时重写查询。通常发生在负载平衡器级别。

衡量性能

完成调优后,您可以稍等片刻,看看该查询的最重要指标是如何变化的。查询访问的行是否更少?它使用索引更好吗?它执行得更快吗?这几乎就是衡量数据库性能的过程。您应该跟踪所有查询类型的延迟p99。您应该跟踪所有查询类型的其他性能指标。

您应该尝试优化查询,然后通过持续不断度量采集,您应该能够知道最重要的度量是如何变化的。延迟是否已减少?现在稳定了吗?给定的查询类型在磁盘上存储了多少数据?同样的过程也适用于硬件更改或配置调整。如果您能够及时绘制p99延迟,您可以清楚地看到您所做的更改是否影响了性能,以及以何种方式影响了性能?是好是坏?因此,秘密酱汁非常简单——在数据库工作时始终收集性能指标。当您决定进行更改时,您将清楚地看到所引入更改的结果。

正如您所看到的,数据库性能是一个巨大的主题,我们希望您会发现这篇博客文章很有帮助。如果你想分享你的一些想法,请在下面的评论中自由发表。