多个数据库调用与对Web API的网络调用真的很重要吗?


16

在我的一位雇主中,我们开发了REST(但也适用于SOAP)API。客户端即应用程序UI,将通过Web(在典型的生产部署中为LAN)对API进行调用。API将调用数据库。

在我们的讨论中反复出现的一个主题是性能:团队中的某些人认为,由于性能,您不应从单个API调用中进行多个数据库调用(通常是读取)。您应该对其进行优化,以便每个API调用仅(完全)一个数据库调用。

但这真的很重要吗?考虑到UI必须对API进行网络调用;相当大(毫秒级)。数据库经过优化,可以将内容保存在内存中并非常非常快地执行读取操作(例如,SQL Server可以将所有内容加载并保存在RAM中,如果可以的话,将消耗几乎所有的可用RAM)。

TLDR:当我们已经通过LAN进行网络调用时,担心多个数据库调用真的很重要吗?如果是这样,为什么?

明确地说,我说的是数量级-我知道这取决于具体情况(机器硬件,API和DB的选择等)。如果我有一个调用需要O(毫秒),那么是否会针对DB进行优化呼叫数量少一个数量级,实际上重要吗?还是这个问题比这还重要?

编辑:对于后代,我认为宣称在这种情况下我们需要通过组合数据库调用来提高性能是非常荒谬的,尤其是缺乏概要分析时。但是,是否执行此操作不是我的决定;我想知道认为这是优化Web API调用的正确方法的基本原理。


API层和数据库之间是否没有其他网络调用?
签署

4
您的计时测试显示了什么?
Dan Pichelman 2014年

@Sign API与数据库之间没有网络调用。据我所知,它们被保证在同一台机器上。
ashes999 2014年

@DanPichelman这也是我要问的。似乎没有人愿意参加并计时。我们只是得到了“通过将所有数据库调用组合到一个调用中来固定X的性能”的要求。
ashes999

Answers:


25

但这真的很重要吗?考虑到UI必须对API进行网络调用;相当大(毫秒级)。数据库经过优化,可以将内容保存在内存中并非常非常快地执行读取操作(例如,SQL Server可以将所有内容加载并保存在RAM中,如果可以的话,将消耗几乎所有的可用RAM)。

逻辑

从理论上讲,您是正确的。但是,此原理存在一些缺陷:

  1. 根据您所说的,尚不清楚您是否实际测试/配置了您的应用程序。换句话说,您实际上是否知道从应用程序到API的网络传输是最慢的组件?因为这很直观,所以很容易假设是这样。但是,在讨论性能时,您永远不要假设。在我的雇主中,我是绩效负责人。当我第一次加入时,人们一直基于对瓶颈的直觉来谈论CDN,复制等。事实证明,我们最大的性能问题是数据库查询性能不佳。

  2. 您说的是,由于数据库擅长检索数据,因此该数据库必须以最佳性能运行,并且已得到最佳利用,因此无法采取任何措施来对其进行改进。换句话说,数据库被设计为快速的,所以我永远不必担心它。另一个危险的思路。这就像说汽车要快速行驶,所以我不需要换油。

  3. 这种思维方式一次假设一个过程,或者换句话说,没有并发性。它假定一个请求不能影响另一个请求的性能。资源是共享的,例如磁盘I / O,网络带宽,连接池,内存,CPU周期等。因此,减少一个数据库调用对共享资源的使用可以防止它导致其他请求变慢。当我第一次加入现任雇主时,管理层认为调整3秒的数据库查询是浪费时间。3秒这么少,为什么要浪费时间呢?使用CDN或压缩或其他方式,我们会更好吗?但是,如果我可以让3秒的查询在1秒内​​运行,例如通过添加一个索引,即减少了2/3的阻塞,减少了2/3的线程占用时间,更重要的是,从磁盘读取的数据更少,

理论

有一个普遍的观念,即软件性能仅仅与速度有关。

从纯粹的速度角度来看,您是对的。系统仅与其最慢的组件一样快。如果您分析了代码并发现Internet是最慢的组件,则其他所有内容显然都不是最慢的部分。

但是,鉴于以上所述,我希望您能看到资源争用,缺少索引,编写不良的代码等如何在性能上产生令人惊讶的差异。

假设

最后一件事。您提到,与从应用程序到API的网络调用相比,数据库调用应该便宜。但是您还提到了该应用程序和API服务器在同一LAN中。因此,它们两者都不能与网络通话媲美吗?换句话说,当它们具有相同的可用带宽时,为什么要假设API传输比数据库传输慢几个数量级?当然,协议和数据结构是不同的,但我对此表示怀疑,因为它们的数量级不同。

哪里有墨鱼

整个问题是关于“多个”与“单个”数据库调用的。但目前尚不清楚有多少个倍数。基于上述,基于一般经验,我建议根据需要进行尽可能少的数据库调用。但这只是一个经验法则。

原因如下:

  1. 数据库非常擅长读取数据。它们是存储引擎。但是,您的业务逻辑存在于您的应用程序中。如果您制定了一个规则,即每个API调用仅导致一个数据库调用,那么您的业务逻辑可能会最终出现在数据库中。也许没关系。许多系统都这样做。但是有些没有。关于灵活性。
  2. 有时要实现良好的解耦,您希望将2个数据库调用分开。例如,也许每个HTTP请求都通过通用安全过滤器进行路由,该过滤器从DB验证用户是否具有正确的访问权限。如果是这样,请继续对该URL执行适当的功能。该功能可以与数据库交互。
  3. 循环调用数据库。这就是为什么我问有多少个倍数。在上面的示例中,您将有2个数据库调用。2很好。3可能很好。N不好。如果您在循环中调用数据库,则现在已使性能线性化,这意味着循环输入中的时间越长,花费的时间就越长。因此明确地说,API网络时间是最慢的,完全可以忽略异常,例如由于尚未发现的循环(调用数据库10,000次)而花费很长时间的流量占了您的流量的1%。
  4. 有时,您的应用程序在某些方面比较擅长,例如一些复杂的计算。您可能需要从数据库中读取一些数据,进行一些计算,然后根据结果将参数传递给第二个数据库调用(也许要写入一些结果)。如果仅出于一次调用数据库的目的而将它们组合为一个调用(如存储过程),则您将自己强制用于应用程序服务器可能更擅长的数据库。
  5. 负载平衡:您有1个数据库(大概)和多个负载平衡的应用程序服务器。因此,应用程序执行的工作越多,数据库工作越少,扩展就越容易,因为添加应用程序服务器通常比设置数据库复制更容易。根据前面的要点,运行SQL查询,然后在应用程序中进行所有计算(分布在多个服务器上),然后在完成后写入结果,可能是有意义的。这样可以提供更好的吞吐量(即使总交易时间相同)。

TL; DR

TLDR:当我们已经通过LAN进行网络调用时,担心多个数据库调用真的很重要吗?如果是这样,为什么?

是的,但仅在一定程度上。在实际可行的情况下,应尽量减少数据库调用的次数,但不要为了合并它们而将彼此无关的调用合并。另外,请避免不惜一切代价循环调用数据库。


3

听起来您的团队在没有理由之前就在进行优化。您是否测量了执行这些请求的时间?很有可能迫使这种范例为最终用户带来更差的性能,因为与Web服务器的往返行程将比从Web服务器到数据库的连接时间具有更高的延迟。最重要的是,大多数Web浏览器将仅对单个Web服务器建立2个并发连接,因此对于复杂的页面,您可能会遇到瓶颈。

无论哪种方式,都应该在没有数据备份的情况下做出优化决策。测量它并找出最适合您的应用程序。


1
这是对我们不良的性能实践的很好评价,但没有回答我有关已经有网络调用时是否需要担心数据库调用的问题。
ashes999

1
通常,我发现进行多个数据库调用不是问题。这主要是由于连接池以及数据库服务器和Web服务器之间的等待时间短。在某种程度上,进行大量不同的数据库调用会对性能产生负面影响,但是我对您而言并没有一个硬性数字。这完全取决于环境和应用程序。只有测量才能为您找到答案。
brianfeucht 2014年

它不(必须)依赖于细节,因为我在说数量级。
ashes999 2014年

粗略的猜测(您需要测量):从Web服务器连接到DB的平均时间:2毫秒从客户端连接到Web服务器的平均时间:20毫秒因此,假设我随机选择的这些数字是正确的,则可以做10次数据库调用所需的时间来进行一次Web服务调用。假设数据库查询花费相同的时间。这些数字非常依赖于环境。如果进行Web服务调用的客户端是本地客户端,则可能会将其下降几个数量级。
brianfeucht 2014年

2

我们不能告诉你。

我们不是您的查询。我们不知道他们需要多长时间才能完成。我们不知道对您的API服务器的每个请求涉及多少开销。我们不知道您的客户在地理位置上有多分散。等等。

如果这是一种需要优化的方案,并且您可以决定是将呼叫拆分还是合并在一起,则需要两种方式对其进行基准测试:确定要优化的内容(UI延迟,服务器CPU负载,竞争,等),然后选择一种可以更好地实现您的优化目标的选择。


除此之外,我可以相对确定地添加的唯一件事是:

在单个请求中,您应该执行生成响应所需的所有查询。

换句话说,如果直到执行完所有N个查询才能生成响应,将它们分开通常是没有意义的。如果您可以在每次查询后生成有意义的结果(无论是中间结果还是完整结果),请开始进行基准测试。


1

两个想法:

首先,对于使用API​​的消费者,他要进行一次调用以完成一项任务。服务器收到呼叫以填充请求之后发生的事情应该不会那么刻板。如果来自消费者的一个呼叫需要10个子工作项来将数据收集在一起并返回,则应该可以接受。

第二:您是否看到有关流程的实际数据库性能问题?我的经验表明,与简单地对数据进行三到四个调用相比,经常尝试将数据库请求的所有方面放入单个调用中会导致调用效率降低。现代数据库在缓存和执行计划方面非常有效。通常,当您尝试执行过多操作时,您会看到带有游标的过程(由于数据是逐行而不是按组操作,因此对性能非常不利),并且代码生成的计划效率要比中断时低只需几个简单的步骤即可完成通话。

出于简单的代码组织,我同意每个API调用都应该调用一个存储过程(或db函数),该存储过程又负责填充请求。该过程可能不止一个步骤。


我同意您对绩效的评估,似乎没有人在做。没有证据表明这会更快,但是它一直在增长。当我们进行一些调用(例如1000 DB)时,性能就成为一个问题SELECT
ashes999 2014年

@ ashes999虽然您可以更快地查看数据库调用的数量,但更可能在索引策略等中找到,而不是调用的数量。正如每个人都指出的那样,请查看性能数据。
理查德

理查德,我同意,实际上我知道这一点。我的问题是为什么当涉及网络调用时,为什么人们会不断提出“多个数据库调用很慢”的观点。我真的不知道它有多重要。
ashes999 2014年

@ ashes999对不起,也许您应该进一步了解网络通话,因为这似乎很明显,我认为您的问题还有更多。我觉得我们在您的问题中遗漏了一些东西。您将始终遭受一些网络延迟,并且每次调用可能会使每次调用的确增加“ x”倍(简单来说)。表面上的语句为真,多次网络调用将比对数据库的一次网络调用慢。这就是为什么我建议一次调用存储过程,然后可以对数据库进行多次调用而无需多网络调用。
理查德

1

如果数据库与REST服务位于不同的服务器上,则每个数据库调用都会导致网络往返,这可能会严重影响性能:

我曾经观察到一个Web服务调用可以转换为大约500个数据库查询-当Web服务和数据库都位于同一台计算机上时,这几乎不是问题,但是当它们位于不同的计算机上时,响应时间为6-7秒机器。

显然,到数据库的500次往返是非常极端的。我不确定您的性能要求是什么,但是根据经验法则,我想说的是,如果每个REST调用的数据库查询数不超过10个,则不会对性能造成重大影响。


1

我们有几个非常有趣的应用程序。每个数据库都有一个数据库调用。单。小。事情。一次又一次地提供参考数据是系统工作量的主要部分。即使没有实际的磁盘IO,所有有关工作线程的调度,获取和释放锁,计划缓存检查等的总和也会加在一起。争用较高,因为事务必须在多个数据库调用之间保持锁,因此吞吐量比可能低得多。因此,这些团队正在考虑必须购买新的,非常昂贵的数据库服务器。

因此,尽管系统当前配置中的大部分经过时间都是通过REST API调用获得的,但忽略数据库级别的性能仍在存储着将来的问题。


0

提出的优化路径仅仅是看待事物的错误方式。

API调用应该是原子的。换句话说,我应该能够进行1个Web API调用来执行所需的操作。无论是获取数据,更新记录还是其他。进行此操作绝不应超过1次呼叫。并且,应该像瘟疫一样避免在多个呼叫之间利用交易。

有时,一个动作相当复杂。例如,获取从多个来源合并的数据:同样,这应该是单个调用。整个事情要么成功,要么整个失败。

现在,说一个API调用只能执行一个数据库查询就太麻烦了。正如您所指出的,就整个时间而言,通过网络编组呼叫的开销通常要贵几个数量级。

我可以从某种程度上理解他们的说法,即单个查询的运行速度比几个查询快。但这会给人留下错误的印象,因为它忽略了数据库和网络的总负载。只有通过概要分析将数据从数据库中拉出的各种方式,您才能弄清楚问题出在哪里。我确信每个人都有一个故事,其中一个特定查询的执行频率比预期的要高100倍,这会杀死系统,直到建立了适当的索引为止。

最终,您将无法通过说服他们说服他们。为这两种方法都建立一个测试用例,并对它们进行概要分析。注意获取所需数据的总时间,生成的网络流量,数据库调用的数量和时间等。采取整体方法-意味着您要研究整个系统-最终应有很多吃乌鸦的数据或向他们展示黄金路的数据。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.