2010年10月8日星期五

Django 服务器的一点认识

概念较多,很多地方暂没法求甚解,只能做一些感性的介绍,说的不清楚或有错误的地方大家再讨论。

以下代码可能有省略。

1. HTTP 基本原理

  • 服务器上需要运行 web server 软件(下面以 nginx 为例,常见的还有 apache、lighttpd),nginx 以守护进程模式运行后,默认监听 tcp 的 80 端口,准备响应客户端的请求。
  • 客户端(这里指浏览器)需要访问站点时,浏览器打开本地一个临时端口,主动向服务器上的 80 端口建立 tcp 连接,以和 nginx 进程进行通信。
  • 连接建立后,浏览器发起请求


    GET /index.html HTTP/1.1
    HOST: test.com

  • nginx 响应请求,这里客户端请求的是静态文件,直接返回即可;对于动态内容的请求,见下一小节

HTTP/1.1 200 OK
Content-type: text/html
Date: Mon, 26 Apr 2010 20:23:51 GMT
Server: nginx/0.6.35

1e24
<html>
<head>
<title>首页</title>
<script type="text/javascript" src="http://test.com/jiaoben.js"></script>
</head>
..........................
..........................
</html>
0

Connection closed by foreign host.

此响应包含 http header 和 html文本 两大部分。

  • 浏览器解析响应。对于 html 响应中包含的元素,需要进行新的一次请求,如上例中的 js 文件;若浏览器和服务器软件协商打开 keepalive 模式,则此次新的请求可以在已有的 tcp 连接上进行,否则需要重新三次握手来建立新连接。


2. 动态内容处理

往往我们看到的网页都是用各种语言动态生成的,如 PHP 语言和使用 python 语言的 django 框架。

  • 用户输入 http://www.test.com/ 这样的 url,请求网站的根目录。
  • 对于 php,配置服务器,指定默认的响应文件,如 index.php,并且配置以何种方式处理以 .php 结尾的文件。

    location / {
    index index.php;
    location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000; # 我们以这种方式来处理 php 文件,某程序监听了本机的9000端口。
    }
    }

    location 后面跟的是相对目录,即 url 中 host 后面的目录部分。

  • 对于 django 这种提供较完善解决方案的框架,它靠匹配 url 来进行决策,我们就不指定默认文件了,把所有请求全部交给某程序处理,配置如下。

    location / {
    fastcgi_pass 127.0.0.1:8000;
    }

    我们还可以控制让静态文件直接由 nginx 返回而不让 django 处理。

    location /static/ {
    alias /var/www/djangoproject/static/;
    }

上述配置使用了 fastcgi 的方式,由 web server 将请求转交给监听在 8000 端口的 fastcgi 服务器,fastcgi 服务器处理后返回结果给 web server,再由 web server 返回给浏览器,流程如下图(图片源自《python 核心编程》)。



2.1 CGI & FASTCGI

apache、lighttpd 等 web server 软件都支持传统的 CGI,在简单配置后,将如下脚本(hello.py)放入指定目录。

#!/usr/bin/python
print "Content-type: text/html"
print ""
print ""
print "Hello World"
print ""

然后访问 http://test.com/cgi-path/hello.py 就能看到相应内容了。

其处理的过程大概是这样:对于每一个请求,创建一个新进程,然后初始化并执行上述程序,最后将数据返回给 web server 并释放内存资源。

后来出现的 fastcgi 方式对传统方法进行了改进,首先启动一个或多个 fastcgi 进程(可理解为 fastcgi 服务器/网关),然后对于每一个浏览器请求,web server 去连接已经启动好的 fastcgi 进程并转发请求,待得到结果后关闭此连接。

当然 fastcgi 方式和协议需要服务器软件支持,上述 3 种 web server 软件都支持,有关 fastcgi 好处和性能的讨论这里不再介绍,网上一抓一大把。

2.2 django

对于 django,概念有些拗口,注意区分 fastcgi 方式和协议的区别。

  • WSGI,Web Server Gateway Interface,是 Python 应用程序和 Web 服务器之间的一种接口,以 fastcgi 作为两者通信的底层协议规范

  • django 能以 fastcgi 方式(而不是协议)启动自带的服务器进程,此进程叫做 WSGIServer,该 server 由 python 的 flup 库提供,具体采用什么协议可以在 manage.py runfcgi 的 protocol 参数中指定,注意除了fastcgi 协议(参数中写为 fcgi)还能选择 scgi 等其他协议。

  • 现在我们知道 WSGIServer 就是上面介绍的 fastcgi 服务器/网关,它监听一个 tcp 端口(还能以 unix socket 方式监听,这里不再介绍),也就是前面配置文件中的 8000 端口。

  • 在启动 WSGIServer 的时候需要指定一个 WSGIHandler,这个 Handler 关联了请求(request)和我们写的 django 应用,在每次请求到来时 Handler 会加载应用的 settings、middleware 和 环境变量,然后请求经 url 解析并交给指定 views 处理,最终处理结果返回给 WSGIServer。


一些参考:
  • django/core/servers/fastcgi.py
  • django/core/handlers/wsgi.py
  • http://blogs.sun.com/oswald/entry/good_idea_python_with_fastcgi CGI 和 FASTCGI 的区别
  • http://osdcpapers.cgpublisher.com/product/pub.84/prod.21 WSGI 入门的 PDF
  • http://www.douban.com/note/13508388/ WSGI、flup、fastcgi、web.py的关系