Pulpcode

捕获,搅碎,拼接,吞咽

0%

为python web项目找一个服务器

当你用python写了一个web应用,你就不得不将其布置到一个web的服务器上,这篇博客将列举下可以使用的web服务器有哪些。

在这之前先简单的介绍一下其它知识。

wsgi

WSGI 的官方定义是,the Python Web Server Gateway Interface

Gateway是一个网关。网关的作用就是在协议之间进行转换。
那么wsgi用来做什么之间的转换呢?它实际上定义一种协议,使得实现wsgi的web框架(app)和实现wsgi的web服务器可以进行“插拔”。
这就是为什么我之前的flask项目可以直接部署到tornado上去运行。所以说以下介绍的web服务器,之所以可以部署python的web项目,是因为它们都实现了wsgi。顺便说一句,wsgi这个思想,应该是从java的servlet中借鉴过来的。

轻量级

轻量级就是个很扯淡的东西,所谓轻量级就是什么都没有。大多数python web框架都说自己轻量级,那只不过是因为自己几乎没什么功能罢了。所以开发起来基本就是造轮子。

tornado

第一个列举tornado是因为,这是我使用的最多也最熟练的web服务器了。这个服务器被很多脑残pythoner炒的热火,还说这个能处理高并发,实际上其本身并没有传说的那么邪乎,而且很多人也是没看懂文档就瞎用。我以后可能会专门写一篇博客讲讲tornado的相关故事,这里主要就讲讲它的异步非阻塞了。

首先你要明白tornado其实是由两部分构成的,web框架的部分其实类似于web.py,而web服务器是在内部使用了epoll,轮询io复用,非阻塞IO。而到底是使用多线程还是使用io复用,一直是一个长久争议的话题。目前我的理解是,多线程适合做“重业务”的需求,也就是说对于一个请求而言,业务处理是重要的过程,比如说提交一个表单,逻辑处理,入库,返回之类。而轮询io复用,适合于处理“轻业务”的需求,类似于web在线聊天,处理大量请求转发。同时向数以万计的用户推送消息服务。我觉得它们的业务都是很轻的。甚至可以说是短连接适合开线程,长连接适合用非阻塞io,我之所以这样说因为我觉得,短连接需要cpu,而长连接更需要io。当然这是我目前的看法,以后可能还会有更深的理解。

总之用tornado你要考虑一点的是,如果你的处理逻辑中途阻塞了,那么你的整个服务器都堵塞了,这样你的服务器是无法处理其它请求的。而多线程是不用考虑此问题的,因为每来一个请求会开一个线程,而你的epoll,从头到尾就只有一个线程,它要拿出准备好的io,还要处理逻辑,这也就是为什么适合做一个类似“反向代理”的服务,因为它有一个异步客户端,用来将http请求,也扔到这个ioloop里。

所以如果是一个轻业务的web服务,tornado还是很适合的。

uwsgi

uwsgi其实是业界普遍用的做法了,flask和django一般都会部署在uwsgi,前面可能还会部署一个nginx,用来做负载均衡和提供静态文件访问。

uwsgi处理请求的做法就是,来一个请求打开一个进程。很多人认为开销大,但其实uwsgi开进程的开销并不大,而且一般每个进程里也只开一个线程,因为python的线程确实不好使。像我之前说的,开进程让你把心思放在业务处理上,而不是想,“这里会不会阻塞服务器”。

我之前开发的项目,就是使用flask进行开发的,最后就是使用uwsgi进行部署的。flask算是我除了tornado之后,最熟悉的python web框架了,我觉得业务系统用flask是一个很好的选择,功能基本齐全,还有些方便的第三方插件,项目做大了也还算能hold住,django本身又太重,换个orm都费劲。所以我的基本搭配就是nginx+uwsgi+flask+sqlalchemy+mysql

apache

python的服务是可以部署到apache服务器上的,后期直接开发django和tornado的同学可能认识不到这一点。因为他们可能不知道在早期做web开发的前辈们在用的一种叫cgi的技术。

有了cgi,才算是从静态web进化到动态web页面。你写好的cgi程序,其实就是用来给apache来使用CGI协议来解释python文件。

每当客户请求CGI的时候,WEB服务器就请求操作系统生成一个新的CGI解释器进程(如php-cgi.exe),CGI 的一个进程则处理完一个请求后退出,下一个请求来时再创建新进程。

而django本身内部其实也是在玩cgi。所以也会把django部署到apache上,这其实是mod_python,是apache的内置模块。
不过现在好像很少看见有人这么玩了。

nginx

之前提到cgi每次请求来了都要去fork,非常的花时间。而FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,只要激活后,不会每次都要花费时间去fork一次。

很常见的做法就是将fastcgi部署到nginx上。不过还要有flup模块来配合,我实际并没有操作过,不好评价。

其它

这里不是说其它的部署方式,实际上,目前而言,我所使用或知道的部署方式就只有这些了。在这里我还想讨论一下之前和同事讨论的一个问题。

之前说到tornado,我跟他们说过,tornado是单线程的,业务复杂搞不好就堵了,尽量用flask+uwsgi,但是他们给我的解决方案,居然是同时部署多台就可以了,然后用nginx挡在前面。首先不得不说uwsgi,才是服务器本身处理一个请求的解决方案,而部署多台,已经到运维级别的解决方案了,部署多态本身是用来防止有服务中途挂掉,或者通过负载均衡来保证更高的处理量,但是我们谈论的其实并不是运维级的部署方案。

以上就是可供选择的python web服务器,像其它类似什么CherryPy,或者是bottle自带的服务器之类的就不多说了,没意义。