django 的并发能力真的是令人担忧,这里就使用 nginx + uwsgi 提供高并发
nginx 的并发能力超高,单台并发能力过万(这个也不是绝对),在纯静态的 web 服务中更是突出其优越的地方,由于其底层使用 epoll 异步IO模型进行处理,使其深受欢迎
做过运维的应该都知道,php 需要使用 nginx + fastcgi 提供高并发,java 需要使用 nginx + tomcat 提供 web 服务
如何再次增加并发量
采用nginx做负载
去掉自增主键
原因很简单,因为自增主键的存在写库存在抢锁, 可以利用全局id生成器提前生成id直接写入数据库
换成异步任务去写库
如果数据只是存在mysql中做备份,建议使用异步的方式写入库,先把数据写到缓存下发给用户,之后在利用后台异步任务一点点的写入,例如聊天系统可以这样干
换成更高效的框架或者语言
可以试试tornado, 如果tornado依然无法满足,可以尝试使用golango,毕竟golang是以高并发著称, 而且是编译语言,而且基于它的web框架也很容易上手,性能很可观,例如Iris
======================================
django
毫无疑问,用原生django的server做处理的表现是最烂的,在10000次请求的情况下brokenpipe的几率极高,只有1400次请求被处理,成功率只有14%,我也懒得继续测下去了。
django + nginx
这次搭上了nginx做反向代理,也使的脆弱的django服务器的情况有所缓解,但成功率仍然不高(10000次请求中有3684个请求被处理)。
uwsgi + nginx
uwsgi是性能极高的一个由C编写的服务器,它使用uwsgi协议,这次让它配合nginx处理django的request,参数为4进程+2线程,性能立即直线上升,处理请求的成功率也基本在90%左右,不过我在测试时遇到了一个坑,就是uwsgi在处理请求的时候发送了队列溢出的问题,因为当前测试设置的并发数为每秒1000次并发,而uwsgi的处理队列容量默认为100,导致处理请求的时间加长,而这个问题则可以通过修改somaxcon的大小解决,总的来说,使用uwsgi+nginx是一个理想的选择。
gunicorn + nginx
gunicorn跟uwsgi类似,也是一个高性能的http服务器,它由ruby的unicorn项目移植,是由python编写的,它的配置简单,而且可以灵活地搭配其他网络库,部署十分方便,在测试数据中可以看到,用这种配置运行django能在短时间内就能处理大量的并发请求,成功率在90%左右。
gunicorn + nginx + gevent
前面说的几种环境,看似不错,但我们需要追求完美!由于gunicorn是同步(sync)单线程模型的,有的时候它不免会发生一些阻塞问题,这时候我们为gunicorn加上-k gevent参数来用gevent做处理接口,这就比较靠谱地处理了阻塞问题,从数据中可以看到,gunicorn + nginx + gevent的模式不仅拥有100%的处理成功率,而且时间也在很短之内完成,是5组测试数据当中的性能最好的。
多套方案来提高 python web 框架的并发处理能力
Python 常见部署方法有 :
- fcgi :用 spawn-fcgi 或者框架自带的工具对各个 project 分别生成监听进程,然后和 http 服务互动
- wsgi :利用 http 服务的 mod_wsgi 模块来跑各个 project(Web 应用程序或框架简单而通用的 Web 服务器 之间的接口)。
- uWSGI 是一款像 php-cgi 一样监听同一端口,进行统一管理和负载平衡的工具,uWSGI,既不用 wsgi 协议也不用 fcgi 协议,而是自创了一个 uwsgi 的协议,据说该协议大约是 fcgi 协议的 10 倍那么快。
其实 WSGI 是分成 server 和 framework (即 application) 两部分 (当然还有 middleware)。
严格说 WSGI 只是一个协议, 规范 server 和 framework 之间连接的接口。
WSGI server 把服务器功能以 WSGI 接口暴露出来。比如 mod_wsgi 是一种 server, 把 apache 的功能以 WSGI 接口的形式提供出来。
- WSGI framework 就是我们经常提到的 Django 这种框架。不过需要注意的是, 很少有单纯的 WSGI framework , 基于 WSGI 的框架往往都自带 WSGI server。比如 Django、CherryPy 都自带 WSGI server 主要是测试用途, 发布时则使用生产环境的 WSGI server。而有些 WSGI 下的框架比如 pylons、bfg 等, 自己不实现 WSGI server。使用 paste 作为 WSGI server。
- Paste 是流行的 WSGI server, 带有很多中间件。还有 flup 也是一个提供中间件的库。
- 搞清除 WSGI server 和 application, 中间件自然就清楚了。除了 session、cache 之类的应用, 前段时间看到一个 bfg 下的中间件专门用于给网站换肤的 (skin) 。中间件可以想到的用法还很多。
- 这里再补充一下, 像 django 这样的框架如何以 fastcgi 的方式跑在 apache 上的。这要用到 flup.fcgi 或者 fastcgi.py (eurasia 中也设计了一个 fastcgi.py 的实现) 这些工具, 它们就是把 fastcgi 协议转换成 WSGI 接口 (把 fastcgi 变成一个 WSGI server) 供框架接入。整个架构是这样的: django -> fcgi2wsgiserver -> mod_fcgi -> apache 。
- 虽然我不是 WSGI 的粉丝, 但是不可否认 WSGI 对 python web 的意义重大。有意自己设计 web 框架, 又不想做 socket 层和 http 报文解析的同学, 可以从 WSGI 开始设计自己的框架。在 python 圈子里有个共识, 自己随手搞个 web 框架跟喝口水一样自然, 非常方便。或许每个 python 玩家都会经历一个倒腾框架的
uWSGI 的主要特点如下:
- 超快的性能。
- 低内存占用(实测为 apache2 的 mod_wsgi 的一半左右)。
- 多app管理。
- 详尽的日志功能(可以用来分析 app 性能和瓶颈)。
- 高度可定制(内存大小限制,服务一定次数后重启等)。
你应该是使用了Django自己的开发服务器跑的例子,在Django关于manage.py的文档中写道:
--nothreading
The development server is multithreaded by default. Use the --nothreading option to disable the use of threading in the development server.
也就是说,默认情况下你使用./manage.py runserver
会开启多个线程对HTTP请求进行伺服,所以第二个请求进来时虽然第一个请求仍在sleep,但已经新开了一个线程进行响应处理,看起来像是“非阻塞”的工作模式,其实质是多线程而非单线程,想禁用这一行为也已经给出了答案,加上--nothreading
参数:./manage.py runserver --nothreading
即可。