Gunicorn 一次不响应超过 6 个请求

Mau*_*cio 2 python concurrency gunicorn kubernetes

给你一些背景:

我有两个运行同一个应用程序的服务器环境。第一个,我打算放弃,是一个有很多限制的标准 Google App Engine 环境。第二个是使用 Gunicorn 运行我的 Python 应用程序的 Google Kubernetes 集群。

并发

在第一台服务器上,我可以向应用程序发送多个请求,它会同时响应多个请求。我在两种环境中对应用程序运行两批同时请求。在 Google App Engine 中,第一批和第二批同时响应,第一批不会阻止第二批。

在 Kubernetes 中,服务器只同时响应 6 个,第一个批次阻止第二个。我读过一些关于如何使用 gevent 或多线程实现 Gunicorn 并发的文章,他们都说我需要 CPU 内核,但问题是无论我投入多少 CPU,限制仍然存在。我已经尝试了从 1VCPU 到 8VCPU 的 Google 节点,它没有太大变化。

你们能给我任何关于我可能遗漏的想法吗?也许谷歌集群节点限制?

Kubernetes 响应瀑布

如您所见,第二批仅在第一批开始完成后才开始响应。

在此处输入图片说明

App Engine 响应瀑布

在此处输入图片说明

小智 5

您所描述的内容似乎表明您运行 Gunicorn 服务器并使用同步工作程序类为 I/O 绑定应用程序提供服务。你能分享你的 Gunicorn 配置吗?

Google 的平台是否可能具有某种自动缩放功能(我对他们的服务不太熟悉),而您的 Kubernetes 配置却没有触发该功能?

一般来说,增加单个实例的核心数量只会在您还增加为处理传入请求而产生的工作线程数量时有所帮助。请参阅Gunicorn 的设计文档,其中特别强调了 worker 类型部分(以及为什么syncworker 不是 I/O 绑定应用程序的最佳选择)——这是一本很好的读物,并提供了关于这个问题的更详细的解释。

只是为了好玩,这里有一个小练习来比较这两种方法:

import time

def app(env, start_response):
    time.sleep(1) # takes 1 second to process the request
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return [b'Hello World']
Run Code Online (Sandbox Code Playgroud)

使用 4 个同步工作者运行 Gunicorn: gunicorn --bind '127.0.0.1:9001' --workers 4 --worker-class sync --chdir app app:app

我们同时触发8个请求: ab -n 8 -c 8 "http://localhost:9001/"

This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient).....done


Server Software:        gunicorn/19.8.1
Server Hostname:        localhost
Server Port:            9001

Document Path:          /
Document Length:        11 bytes

Concurrency Level:      8
Time taken for tests:   2.007 seconds
Complete requests:      8
Failed requests:        0
Total transferred:      1096 bytes
HTML transferred:       88 bytes
Requests per second:    3.99 [#/sec] (mean)
Time per request:       2006.938 [ms] (mean)
Time per request:       250.867 [ms] (mean, across all concurrent requests)
Transfer rate:          0.53 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.2      1       1
Processing:  1003 1504 535.7   2005    2005
Waiting:     1002 1504 535.8   2005    2005
Total:       1003 1505 535.8   2006    2006

Percentage of the requests served within a certain time (ms)
  50%   2006
  66%   2006
  75%   2006
  80%   2006
  90%   2006
  95%   2006
  98%   2006
  99%   2006
 100%   2006 (longest request)
Run Code Online (Sandbox Code Playgroud)

大约 2 秒完成测试。这就是您在测试中得到的行为 - 前 4 个请求让您的工作人员忙碌,第二批排队直到第一批被处理。


相同的测试,但让我们告诉 Gunicorn 使用异步工作者: unicorn --bind '127.0.0.1:9001' --workers 4 --worker-class gevent --chdir app app:app

与上面相同的测试: ab -n 8 -c 8 "http://localhost:9001/"

This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient).....done


Server Software:        gunicorn/19.8.1
Server Hostname:        localhost
Server Port:            9001

Document Path:          /
Document Length:        11 bytes

Concurrency Level:      8
Time taken for tests:   1.005 seconds
Complete requests:      8
Failed requests:        0
Total transferred:      1096 bytes
HTML transferred:       88 bytes
Requests per second:    7.96 [#/sec] (mean)
Time per request:       1005.463 [ms] (mean)
Time per request:       125.683 [ms] (mean, across all concurrent requests)
Transfer rate:          1.06 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.4      1       2
Processing:  1002 1003   0.6   1003    1004
Waiting:     1001 1003   0.9   1003    1004
Total:       1002 1004   0.9   1004    1005

Percentage of the requests served within a certain time (ms)
  50%   1004
  66%   1005
  75%   1005
  80%   1005
  90%   1005
  95%   1005
  98%   1005
  99%   1005
 100%   1005 (longest request)
Run Code Online (Sandbox Code Playgroud)

我们实际上在这里将应用程序的吞吐量翻了一番——回复所有请求只需要大约 1 秒。

为了理解发生了什么,Gevent 有一个关于其架构的很棒的教程这篇文章有一个关于协程的更深入的解释。


如果对您的问题的实际原因有一定的了解,我提前道歉(我确实相信您的初始评论中缺少一些额外的信息,以便任何人都能得到确凿的答案)。如果不是对你,我希望这对其他人有帮助。:)

还要注意,我已经把事情简化了很多(我的例子是一个简单的概念证明),调整 HTTP 服务器配置主要是一种反复试验 - 这完全取决于应用程序的工作负载类型和它的硬件坐在。