Python的tornado框架性能研究

Python的tornado框架性能研究

1. Summary

  Tornado框架算是Python Web框架中比较有名的一个。以前一直没空研究,最近因为要做个项目,干脆深入考察一下tornado的性能。

2. 测试环境

2.1 软硬件环境

keyvalue
CPU【腾讯云VPS虚拟机】8 核心 Intel(R) Xeon(R) CPU E5-26xx v3
内存8GB
硬盘100GB
操作系统Ubuntu Server 16.04LTS 64bit
python2.7.12 64bit
tornado4.4.2
pycurl7.43.0
nginx1.10.0
ab【包含在apache2-utils里的一个压测命令】2.3

2.2 关于ab

考虑到我们即将要压测,而现在Linux系统大多都有并发连接数限制,所以我们必须要做下面几件事

  1. 执行以下命令,使得Linux下单进程可以打开的文件句柄数大于1024
    ulimit -u 40960
  2. 编辑/etc/sysctl.conf文件
    设置net.ipv4.tcp_syncookies = 0

2.3 测试代码

# -.- coding:utf-8 -.-
import platform
import tornado.ioloop
import tornado.web
import tornado.gen
import tornado.options
import select
import tornado.httpserver
import tornado.httpclient
import tornado.concurrent

__author__ = 'chenjm'


class BlockHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous  # 重要!这个装饰器使得当前请求变成长连接,直到调用self.finish()为止
    @tornado.gen.coroutine  # 重要! tornado的重要装饰器,使得当前请求可以用yield异步执行IO操作
    def get(self):
        yield tornado.gen.sleep(3)  # 模拟长达3秒的IO操作,但是不阻塞主线程
        self.write("i sleep 3s\n")
        self.finish()  # 结束本次连接


class AsyncBlockHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    @tornado.gen.coroutine
    def get(self, *args, **kwargs):
        http_client = tornado.httpclient.AsyncHTTPClient()  # tornado异步客户端
        http_req = tornado.httpclient.HTTPRequest(
            url='http://127.0.0.1:8000/block',
            method='GET',
            validate_cert=False,
            request_timeout=30)

        response = yield tornado.gen.Task(http_client.fetch, http_req)  # 执行异步HTTP请求

        if response.code == 200:
            self.write(response.body)
        else:
            print "error code = ", response.code
        self.finish()


class TestHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    @tornado.gen.coroutine
    def get(self, *args, **kwargs):
        self.write("Hello Word")
        self.finish()


class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            ('/block', BlockHandler),
            ('/async_block', AsyncBlockHandler),
            ('/test', TestHandler),
        ]
        super(Application, self).__init__(handlers)


if __name__ == "__main__":
    # tornado框架可以解析命令行参数,如果有这一句话,那么就可以传入--port=XX参数来指定socket绑定端口
    tornado.options.define("port", default=8000, help="run on the given port", type=int) 

    # 分析命令行
    tornado.options.parse_command_line()

    # 生成http服务器对象
    http_server = tornado.httpserver.HTTPServer(Application())

    print u"Current System:", platform.system()

    # 可以看看是否启用了epoll(仅对Linux系统有效)
    print "epoll enabled : ", hasattr(select, "epoll")

    # 如果不写这句话,那么tornado会使用默认的异步HTTP客户端,作者测试过,性能比较低。
    # 所以最好按照官方文档给出的做法,使用基于libcurl的客户端框架,但是前提是安装pycurl
    tornado.httpclient.AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient")

    # tornado默认异步客户端最大并发是10,所以要把这个开大点,否则影响并发
    # 注意!如果你启用了上述libcurl客户端,那么这句话一定要写在后面
    tornado.httpclient.AsyncHTTPClient.configure(None, max_clients=20000)

    # 侦听socket端口
    http_server.listen(tornado.options.options.port)

    # 启动事件循环
    tornado.ioloop.IOLoop.current().start()

3. Tornado性能考察

3.1 Hello World!

我们先来测试一下test接口

3.1.1 1000个客户端,总共请求1000次

执行命令:【注意:不带-k参数】

ab -c 1000 -n 1000 "http://127.0.0.1:8000/test"

结果:

Document Path:          /test
Document Length:        10 bytes
Concurrency Level:      1000
Time taken for tests:   0.954 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      205000 bytes
HTML transferred:       10000 bytes
Requests per second:    1048.56 [#/sec] (mean)
Time per request:       953.685 [ms] (mean)
Time per request:       0.954 [ms] (mean, across all concurrent requests)
Transfer rate:          209.92 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    2   4.9      0      15
Processing:     1  110  39.7    105     799
Waiting:        1  110  39.7    105     799
Total:         14  113  39.1    105     799

Percentage of the requests served within a certain time (ms)
  50%    105
  66%    114
  75%    118
  80%    143
  90%    146
  95%    167
  98%    182
  99%    187
 100%    799 (longest request)

我们发现,大部分请求在200ms之内都被处理完毕,tornado应付得轻轻松松

3.1.2 2000个客户端,总共请求2000次

执行命令:

ab -c 2000 -n 2000 "http://127.0.0.1:8000/test"

结果:

Document Path:          /test
Document Length:        10 bytes

Concurrency Level:      2000
Time taken for tests:   1.895 seconds
Complete requests:      2000
Failed requests:        0
Total transferred:      410000 bytes
HTML transferred:       20000 bytes
Requests per second:    1055.60 [#/sec] (mean)
Time per request:       1894.649 [ms] (mean)
Time per request:       0.947 [ms] (mean, across all concurrent requests)
Transfer rate:          211.33 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   76 260.1      0    1001
Processing:     1  164 180.8    105     888
Waiting:        1  164 180.8    105     888
Total:         21  240 429.3    105    1887

Percentage of the requests served within a certain time (ms)
  50%    105
  66%    108
  75%    125
  80%    186
  90%    260
  95%   1814
  98%   1861
  99%   1875
 100%   1887 (longest request)

我们发现90%的请求在260ms之内得到相应,但是“Requests per second”仍然维持在1000次左右,也许这是个瓶颈。

3.1.3 2000个客户端,总共请求20000次(模拟用于通过浏览器访问网站)

执行命令:【注意,这里带-k开关, 因为现在大多数浏览器都是keep_alive访问网站】

ab -c 2000 -n 20000 -k "http://127.0.0.1:8000/test"

结果:

Document Path:          /test
Document Length:        10 bytes

Concurrency Level:      2000
Time taken for tests:   13.474 seconds
Complete requests:      20000
Failed requests:        0
Keep-Alive requests:    20000
Total transferred:      4580000 bytes
HTML transferred:       200000 bytes
Requests per second:    1484.34 [#/sec] (mean)
Time per request:       1347.402 [ms] (mean)
Time per request:       0.674 [ms] (mean, across all concurrent requests)
Transfer rate:          331.95 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0  110 773.9      0    7011
Processing:     1  461 145.0    452     908
Waiting:        1  461 145.0    452     908
Total:         22  572 789.7    464    7919

Percentage of the requests served within a certain time (ms)
  50%    464
  66%    559
  75%    604
  80%    610
  90%    620
  95%    625
  98%   1547
  99%   7286
 100%   7919 (longest request)

我们发现95%的请求在625ms之内得到相应,“Requests per second”维持在1500次左右,此时有很多连接的“Connect”花了很长时间,这说明,Tornado针对“listen+accept”操作的速度趋向于饱和。

3.2 连接保持很长的时间

未完待续。。。
to be continued……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值