标记CPU使用率:同步与异步HTTP客户端

时间:2019-02-27 02:22:26

标签: http asynchronous benchmarking cpu-usage synchronous

我一直在系统上执行一些基准测试,而我一直在仔细观察的一件事是程序的行为,该行为随时间执行许多HTTP调用。更具体地说,我拥有的是一个微服务,该微服务可应要求提供同步HTTP调用。我决定通过向系统中注入一些负载来对此进行压力测试,从而依次触发微服务以执行一个又一个的同步HTTP调用。 (每次调用大约需要1秒才能返回响应,即阻塞1秒)。

事实证明,CPU使用率由程序的这一部分支配。在其他部分随时间占用5-10%的CPU使用率的情况下,该部分随时间占用高达50%的常量,这是一个巨大的差异,并且存在明显的瓶颈。

我的问题是,如果我使用异步HTTP客户端重新运行此测试,我是否可以看到HTTP调用会消耗如此大量的CPU?由于HTTP调用仍然需要1s来返回响应,因此它是否会给CPU带来高负载以进行轮询以检查是否已返回响应?还是因为一个线程可以处理更多工作,它会要求CPU减少更多负载?随着时间的推移,CPU使用率会是什么样?

2 个答案:

答案 0 :(得分:1)

在第一部分中您已经提到

我决定通过向系统中注入一些负载来进行压力测试 进而触发微服务执行一次同步 HTTP通话。 (每次通话大约需要1秒才能返回一个 响应,即被阻止1秒钟)。

然后,“随着时间的流逝,这部分占据的常数高达50%”。

重复的HTTP调用占用更多的CPU时间和线程创建时间

进程背后的CPU使用率

导致这种CPU使用率升高的原因不是轮询,而是上下文切换线程创建。

当应用程序运行重复的HTTP调用时,它会在Network Diver中创建多个线程。每个线程在完成之前持续 1秒

Histogram: Process launch dominates over thread launch over context switching etc

每个线程启动和上下文切换都获得CPU时间,并且当您连续进行操作时,就像运行无限循环while(true) 但是如果它是像无穷循环这样的完全顺序任务,它将占用一个CPU内核。

异步任务使并行内核更忙

那发生了什么?

从脚本创建线程不是顺序任务。它是平行的。

因为您的脚本按顺序在循环中执行此操作:

while(true){
    create_http_request();
}

假设此函数调用导致创建线程的系统调用:

function create_network_socket(){
    @syscall.createThread();
}

,假设您的脚本create_http_request()大约需要1个我们才能将异步调用转换为系统调用。

因此它可以在1秒内迭代大约一百万次(关闭线程)。

但是在每次调用中,脚本都会为作业调用操作系统syscall(创建线程)。

假设需要5个时间。

所以这将是一秒钟内发生的事情:

  • 脚本中的顺序任务以1个CPU内核运行。

  • 它要求操作系统提供一百万个工作,这需要4,000,000 us CPU时间才能完成。

  • 并且它需要5个额外的CPU内核才能异步执行作业。

它具有6个满载内核。

逆关系瓶颈

HTTP请求脚本和系统调用之间的异步使得可以进行并行作业。这就是导致CPU使用率达到50%的原因。

运行刺激任务的瓶颈是依次调用HTTP请求。

因此,获取速度越快,它每秒执行的HTTP请求就越多,因此其他部分(操作系统)要完成这项工作就消耗更多的CPU。

因此,似乎存在逆关系瓶颈。

Http异步请求

数据流中发生了什么

当脚本请求HTTP调用时,发生的事情可以看作是从脚本到目标并返回的数据流。我将通过一些稍后讨论的简单步骤来说明它:

script function call
--> framework/lib function call
    --> interpreter/module call
        --> OS socket lib call
            --> OS system call
                --> driver call
                    --> hardware invocation (NIC)
                        --> physical media buffering and signalling 

在此流程中,您可以考虑一些节点和一些链接。

根据技术,每个链接可以是半双工或全双工。每个节点都可以使用稍后介绍的不同技术来实现。

但是在我们的冯·诺依曼(Von Neumann)架构的低层以及运行具有跳转功能的顺序机器代码的CPU中会发生什么?

这些代码将陆续运行,并且可以从数据更改中得到通知的唯一方法是2:

  • 他们检查位置:轮询您所提及的
  • 其他信号中断,并通知他们。 (需要额外的信号链接)

当上述节点之一(脚本,驱动程序,任何函数调用)需要使用数据且数据尚未准备就绪时,它应等待数据可用后,才通过轮询或中断通知该数据。

但是当数据还没有准备好时,它可以以两种不同的方式表现:

  • 阻止:同步。线程等待数据,然后将CPU传递给OS进行另一个进程。
  • 非阻塞:异步。线程等待数据。但是另一个线程开始执行不需要此数据的另一部分。

在每个节点中同步和异步

该流链中的每个节点都有自己的机制来与链中的其他节点链接。每个节点都可以与其他节点进行(同步或异步)操作,并且每个链接都可以得到响应(通过 polling interruption)。

例如:

即使您向服务器运行同步HTTP请求,您的驱动程序也不会阻止其他作业。

在某些链接中,它可能是中断,例如NIC可以通过以太网从两条RX线接收信号,或者可以像线程一样轮询IPC管道。

结论

如果您异步调用HTTP请求,则数据流链中的其他节点的行为将与以前相同(其中大多数是异步的)(取决于程序/技术)。

链接保持不变。

唯一的区别是基准脚本。

如果脚本中还有其他Foo个作业,则可以执行以下操作:

  • 阻止:HTTP响应后
  • 非阻塞:在HTTP请求调用之后

是否有其他工作都没关系。

长跑

因为基准测试是循环1秒的无状态作业,所以1秒后,在请求或响应后执行 Foo Job 没什么区别。

答案 1 :(得分:0)

异步调用可以将工作委派给OS,当然,联网就是其中一种情况。 This link from microsoft.com is about .net yet is valid for any async capable framework/language

尽管工作是在某种情况下执行的(也就是说,OS确实必须将数据传递给设备驱动程序并响应中断),但是没有专用于等待请求中的数据返回的线程。这样一来,系统就可以处理大量工作,而不必等待一些I / O调用完成。

假设您的微服务在这样的语言/框架上运行,那么肯定会获得异步调用的好处,因为不会浪费花费大部分时间空闲的线程,但是这仍然会在内存和cpu上造成代价。

尽管您仍然可以看到大量的CPU消耗。

一次一次http调用不会给cpu带来太大压力,因此对您系统的多个请求必须触发并行的http请求序列才能占用cpu。如果不考虑方程式的代码效率,而该代码中没有解析/详细说明,则实际上是在消耗CPU的网络数据处理。

减轻网络cpu压力的一种方法是启用tcp-offloading和其他可用的“分流”(如果支持)到网络接口。

tcp offloading wikipedia

TCP卸载引擎(TOE)是网络接口卡(NIC)中使用的一项技术,用于将整个TCP / IP堆栈的处理卸载到网络控制器。它主要用于高速网络接口,例如千兆以太网和10千兆以太网,这些网络接口的处理开销变得很大。

尽管我不会马上就认为CPU使用率是50%是明显的瓶颈,但这意味着CPU使用率越来越高,您必须进行测试和测量