Python Flask Gevent堆栈-简单;“你好,世界”;当进行基准测试时,应用程序显示为低效

Python Flask Gevent堆栈-简单;“你好,世界”;当进行基准测试时,应用程序显示为低效,python,gevent,Python,Gevent,我有以下简单的“Hello World”应用程序: 正如你所看到的,这很简单 问题在于,尽管如此简单,但它非常缓慢/低效,正如以下基准测试(使用Apache基准测试制作)所示: 最终,增加连接和/或并发的数量并不能带来更好的结果,事实上它会变得更糟 我最担心的是,我不能超过每秒700个请求,传输速率也不能超过每秒98千字节 此外,每个请求的个人时间似乎太多 我很好奇Python和Gevent在后台做了什么,或者更好,操作系统在做什么,所以我使用了strace来确定最终的系统端问题,结果如下: %

我有以下简单的“Hello World”应用程序:

正如你所看到的,这很简单

问题在于,尽管如此简单,但它非常缓慢/低效,正如以下基准测试(使用Apache基准测试制作)所示:

最终,增加连接和/或并发的数量并不能带来更好的结果,事实上它会变得更糟

我最担心的是,我不能超过每秒700个请求,传输速率也不能超过每秒98千字节

此外,每个请求的个人时间似乎太多

我很好奇Python和Gevent在后台做了什么,或者更好,操作系统在做什么,所以我使用了strace来确定最终的系统端问题,结果如下:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 56.46    0.000284           0      1386           close
 24.25    0.000122           0      1016           write
 10.74    0.000054           0      1000           send
  4.17    0.000021           0      3652      3271 open
  2.19    0.000011           0       641           read
  2.19    0.000011           0      6006           fcntl64
  0.00    0.000000           0         1           waitpid
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         3           time
  0.00    0.000000           0        12        12 access
  0.00    0.000000           0        32           brk
  0.00    0.000000           0         5         1 ioctl
  0.00    0.000000           0      5006           gettimeofday
  0.00    0.000000           0         4         2 readlink
  0.00    0.000000           0       191           munmap
  0.00    0.000000           0         1         1 statfs
  0.00    0.000000           0         1         1 sigreturn
  0.00    0.000000           0         2           clone
  0.00    0.000000           0         2           uname
  0.00    0.000000           0        21           mprotect
  0.00    0.000000           0        69        65 _llseek
  0.00    0.000000           0        71           rt_sigaction
  0.00    0.000000           0         1           rt_sigprocmask
  0.00    0.000000           0         3           getcwd
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0       243           mmap2
  0.00    0.000000           0      1838       748 stat64
  0.00    0.000000           0        74           lstat64
  0.00    0.000000           0       630           fstat64
  0.00    0.000000           0         1           getuid32
  0.00    0.000000           0         1           getgid32
  0.00    0.000000           0         1           geteuid32
  0.00    0.000000           0         1           getegid32
  0.00    0.000000           0         4           getdents64
  0.00    0.000000           0         3         1 futex
  0.00    0.000000           0         1           set_thread_area
  0.00    0.000000           0         2           epoll_ctl
  0.00    0.000000           0        12         1 epoll_wait
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0        26           clock_gettime
  0.00    0.000000           0         2           openat
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         1           eventfd2
  0.00    0.000000           0         1           epoll_create1
  0.00    0.000000           0         1           pipe2
  0.00    0.000000           0         1           socket
  0.00    0.000000           0         1           bind
  0.00    0.000000           0         1           listen
  0.00    0.000000           0      1000           accept
  0.00    0.000000           0         1           getsockname
  0.00    0.000000           0      2000      1000 recv
  0.00    0.000000           0         1           setsockopt
------ ----------- ----------- --------- --------- ----------------
100.00    0.000503                 24977      5103 total
正如您所看到的,有5103个错误,最严重的错误是打开的系统调用,我怀疑这与找不到文件有关(enoint)。令我惊讶的是,埃波尔看上去不像一个麻烦者,因为我听说了很多关于它的恐怖故事

我想发布完整的strace,详细介绍每一次通话,但它太大了

最后一个音符;我还设置了以下系统参数(这是允许的最大数量),希望它能改变这种情况,但它没有:

echo “32768 61000″ > /proc/sys/net/ipv4/ip_local_port_range
sysctl -w fs.file-max=128000
sysctl -w net.ipv4.tcp_keepalive_time=300
sysctl -w net.core.somaxconn=61000
sysctl -w net.ipv4.tcp_max_syn_backlog=2500
sysctl -w net.core.netdev_max_backlog=2500
ulimit -n 1024
我的问题是,考虑到我正在使用的示例不能改变太多来修复这些问题,我应该在哪里纠正它们

更新 我使用Wheezy.web和Gevent编写了以下“Hello World”脚本,每秒收到约2000个请求:

from gevent import monkey
monkey.patch_all()
from gevent import pywsgi
from wheezy.http import HTTPResponse
from wheezy.http import WSGIApplication
from wheezy.routing import url
from wheezy.web.handlers import BaseHandler
from wheezy.web.middleware import bootstrap_defaults
from wheezy.web.middleware import path_routing_middleware_factory

def helloworld(request):
    response = HTTPResponse()
    response.write('hello world')
    return response


routes = [
    url('hello', helloworld, name='helloworld')
]


options = {}
main = WSGIApplication(
    middleware=[
        bootstrap_defaults(url_mapping=routes),
        path_routing_middleware_factory
    ],
    options=options
)


server = pywsgi.WSGIServer(('127.0.0.1', 5000), main, backlog=128000)
server.serve_forever()
以及基准结果:

ab -k -n 1000 -c 1000 http://127.0.0.1:5000/hello

Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        
Server Hostname:        127.0.0.1
Server Port:            5000

Document Path:          /front
Document Length:        11 bytes

Concurrency Level:      1000
Time taken for tests:   0.484 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Keep-Alive requests:    0
Total transferred:      170000 bytes
HTML transferred:       11000 bytes
Requests per second:    2067.15 [#/sec] (mean)
Time per request:       483.758 [ms] (mean)
Time per request:       0.484 [ms] (mean, across all concurrent requests)
Transfer rate:          343.18 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    8  10.9      0      28
Processing:     2   78  39.7     56     263
Waiting:        2   78  39.7     56     263
Total:         18   86  42.6     66     263

Percentage of the requests served within a certain time (ms)
  50%     66
  66%     83
  75%    129
  80%    131
  90%    152
  95%    160
  98%    178
  99%    182
 100%    263 (longest request)

我觉得Wheezy.web的速度很快,但我还是喜欢使用Flask,因为它更简单,也更省时。

您使用的是什么gevent版本?尝试将软件堆栈简化到最低限度,并尝试他们在github上的示例


您是否将基准测试与非gevent版本进行比较?我经常使用这个库,所以我会进一步研究。

我有最新的版本(1.0.1),我只是在终端上以
python app.py
的形式运行这个代码片段。我尝试了您链接的示例,获得了每秒约1400个请求和每秒约160 Kbytes的传输速率,但一旦我将应用程序定义(从第7行开始)替换为烧瓶路由(与您在我的问题中看到的相同),我就回到了基准中概述的问题。目前看来Flask路由是一个性能瓶颈。不要太担心传输速率。你不会用大量的greenlet或线程返回一个小字符串来命中max。这里有一篇来自2010年benchmarking gevent的文章,在其中,他们展示了它每秒可以达到8000个请求:也许你需要调整你的基准实用程序?他使用autobench,而不是ApacheBench,并提供了所使用的配置。我曾试图重现那个家伙所做的,但结果没有太大的不同。我认为问题在于Flask在后台做了很多route regex和其他东西,这解释了与简单的一条路线“hello world”相比,输出减半的原因。不知道如何修复它,但我听说瓶子修复了它们的路线实现。还有一个Wheezy.web,速度快约3倍,但设置起来要复杂得多。
from gevent import monkey
monkey.patch_all()
from gevent import pywsgi
from wheezy.http import HTTPResponse
from wheezy.http import WSGIApplication
from wheezy.routing import url
from wheezy.web.handlers import BaseHandler
from wheezy.web.middleware import bootstrap_defaults
from wheezy.web.middleware import path_routing_middleware_factory

def helloworld(request):
    response = HTTPResponse()
    response.write('hello world')
    return response


routes = [
    url('hello', helloworld, name='helloworld')
]


options = {}
main = WSGIApplication(
    middleware=[
        bootstrap_defaults(url_mapping=routes),
        path_routing_middleware_factory
    ],
    options=options
)


server = pywsgi.WSGIServer(('127.0.0.1', 5000), main, backlog=128000)
server.serve_forever()
ab -k -n 1000 -c 1000 http://127.0.0.1:5000/hello

Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        
Server Hostname:        127.0.0.1
Server Port:            5000

Document Path:          /front
Document Length:        11 bytes

Concurrency Level:      1000
Time taken for tests:   0.484 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Keep-Alive requests:    0
Total transferred:      170000 bytes
HTML transferred:       11000 bytes
Requests per second:    2067.15 [#/sec] (mean)
Time per request:       483.758 [ms] (mean)
Time per request:       0.484 [ms] (mean, across all concurrent requests)
Transfer rate:          343.18 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    8  10.9      0      28
Processing:     2   78  39.7     56     263
Waiting:        2   78  39.7     56     263
Total:         18   86  42.6     66     263

Percentage of the requests served within a certain time (ms)
  50%     66
  66%     83
  75%    129
  80%    131
  90%    152
  95%    160
  98%    178
  99%    182
 100%    263 (longest request)