谈天说地

说说lighttpd的fastcgi

本原创文章属于《Linux大棚》博客,博客地址为http://roclinux.cn。文章作者为roc。

===

【简介】

lighttpd提供了一种外部程序调用的接口,即FastCGI接口。这是一种独立于平台和服务器的接口,它介于Web应用程序和Web服务器之间。关于FastCGI接口的具体内容可以在其官网上找到。

Fastcgi logo
FastCGI logo

这就意味着能够在Apache服务器上运行的FastCGI程序,也一定可以无缝的在lighttpd上使用。

【FastCGI广告时间】

1 就像CGI一样,FastCGI也是独立于编程语言的。

2 就像CGI一样,FastCGI程序运行在完全独立于核心Web Server之外的进程中,和API方式相比,提供了很大的安全性。(API会将程序代码与核心Web Server挂接在一起,这就意味着基于问题API的应用程序可能会使整个Web Server或另一个应用程序崩溃;一个恶意API还可以从核心Web Server或另一个应用程序中盗取安全密钥)

3 虽然FastCGI不能一夜之间复制CGI的所有功能,但是FastCGI一直宣扬开放,这也使得我们拥有很多免费的FastCGI应用程序库(C/C++、Java、Perl、TCL)和免费的Server模块(Apache、ISS、Lighttpd)。

4 就像CGI一样,FastCGI并不依附于任何Web Server的内部架构,因此即使Server的技术实现变动,FastCGI仍然非常稳定;而API设计是反映Web Server内部架构的,因此,一旦架构改变,API要随之变动。

5 FastCGI程序可以运行在任何机器上,完全可以和Web Server不在一台机器上。这种分布式计算的思想可以确保可扩展性、提高系统可用性和安全性。

6 CGI程序主要是对HTTP请求做计算处理,而FastCGI却还可以做得更多,例如模块化认证、授权检查、数据类型转换等等。在未来,FastCGI还会有能力扮演更多角色。

7 FastCGI移除了CGI程序的许多弊端。例如,针对每一个新请求,WebServer都必须重启CGI程序来处理新请求,这导致WebServer的性能会大受影响。而FastCGI通过保持进程处理运行状态并持续处理请求的方式解决了该问题,这就将进程创建和销毁的时间节省了出来。

8 CGI程序需要通过管道(pipe)方式与Web Server通信,而FastCGI则是通过Unix-Domain-Sockets或TCP/IP方式来实现与Web Server的通信。这确保了FastCGI可以运行在Web Server之外的服务器上。FastCGI提供了FastCGI负载均衡器,它可以有效控制多个独立的FastCGI Server的负载,这种方式比load-balancer+apache+mod_php方式能够承担更多的流量。

【fastcgi模块】

若要lighttpd支持fastcgi,则需要配置如下内容:

在fastcgi.conf中配置

server.modules += ( "mod_fastcgi" )

在module.conf中配置

include "conf.d/fastcgi.conf"

【fastcgi配置选项】

lighttpd通过fastcgi模块的方式实现了对fastcgi的支持,并且在配置文件中提供了三个相关的选项:

1 fastcgi.debug

可以设置一个从0到65535的值,用于设定FastCGI模块的调试等级。当前仅有0和1可用。1表示开启调试(会输出调试信息),0表示禁用。例如:

fastcgi.debug = 1

2 fastcgi.map-extentsions

同一个fastcgi server能够映射多个扩展名,如.php3和.php4都对应.php。例如:

fastcgi.map-extensions = ( ".php3" => ".php" )

or for multiple

fastcgi.map-extensions = ( ".php3" => ".php", ".php4" => ".php" )

3 fastcgi.server

这个配置是告诉Web Server将FastCGI请求发送到哪里,其中每一个文件扩展名可以处理一个类型的请求。负载均衡器可以实现对同一扩展名的多个对象的负载均衡。

fastcgi.server的结构语法如下:

( <extension> =>
  ( [ <name> => ]
    ( # Be careful: lighty does *not* warn you if it doesn't know a specified option here (make sure you have no typos)
      "host" => <string> ,
      "port" => <integer> ,
      "socket" => <string>,                 # either socket or host+port
      "bin-path" => <string>,               # optional
      "bin-environment" => <array>,         # optional
      "bin-copy-environment" => <array>,    # optional
      "mode" => <string>,                   # optional
      "docroot" => <string> ,               # optional if "mode" is not "authorizer"
      "check-local" => <string>,            # optional
      "max-procs" => <integer>,             # optional - when omitted, default is 4
      "broken-scriptfilename" => <boolean>, # optional
      "kill-signal" => <integer>,           # optional, default is SIGTERM(15) (v1.4.14+)
    ),
    ( "host" => ...
    )
  )
)

其中:

  • <extentsion>:文件名后缀或以”/”开头的前缀(也可为文件名)
  • <name>:这是一个可选项,表示handler的名称,在mod_status中用于统计功能,可以清晰的分辨出是哪一个handler处理了<extension>。
  • host:FastCGI进程监听的IP地址。此处不支持hostname形式。
  • port:FastCGI进程所监听的TCP端口号
  • bin-path:本地FastCGI二进制程序的路径,当本地没有FastCGI正在运行时,会启动这个FastCGI程序。
  • socket:unix-domain-socket所在路径。
  • mode:可以选择FastCGI协议的模式,默认是“responder”,还可以选择authorizer。
  • docroot:这是一个可选项,对于responder模式来讲,表示远程主机docroot;对于authorizer模式来说,它表示MANDATORY,并且指向授权请求的docroot。
  • check_local:这是一个可选项,默认是enable。如果是enable,那么server会首先在本地(server.document-root)目录中检查被请求的文件是否存在,如果不存在,则给用户返回404(Not Found),而不会把这个请求传递给FastCGI。如果是disable,那么server不会检查本地文件,而是直接将请求转发给FastCGI。(disable的话,server从某种意义上说就变为了一个转发器)
  • broken-scriptfilename:以类似PHP抽取PATH_INFO的方式,抽取URL中的SCRIPT_FILENAME。

如果bin-path被设置了,那么:

  • max-procs:设置多少个FastCGI进程被启动
  • bin-environment:在FastCGI进程启动时设置一个环境变量
  • bin-copy-environment:清除环境,并拷贝指定的变量到全新的环境中。
  • kill-signal:默认的话,在停止FastCGI进程时,lighttpd会发送SIGTERM(-15)信号给子进程。此处可以设置发送的信号。

【举例】

多个文件扩展名对应一台主机:

fastcgi.server = (
  ".php" =>
  (( "host" => "127.0.0.1",
     "port" => 1026,
      "bin-path" => "/usr/local/bin/php"
  )),
  ".php4" =>
  (( "host" => "127.0.0.1",
     "port" => 1026
  ))
)

使用前缀来对应主机:

fastcgi.server = (
  "/remote_scripts/" =>
  (( "host" => "192.168.0.3",
     "port" => 9000,
     "check-local" => "disable",
     "docroot" => "/" # remote server may use
                      # it's own docroot
  ))
)

如果有一个请求“http://my.example.org/remote_scripts/test.cgi”,那么server会将其转发给192.168.0.3的9000端口,并且SCRIPT_NAME会被赋值为“/remote_scripts/test.cgi”。如果所设置的handler的末尾不是“/”,那么会被认为是一个文件。

【负载均衡】

FastCGI模块提供了一种在多台FastCGI服务器间负载均衡的方法。

例如:

fastcgi.server = ( ".php" =>
  (
    ( "host" => "10.0.0.2",
      "port" => 1030
    ),
    ( "host" => "10.0.0.3",
      "port" => 1030 )
    )
  )

为了更好的理解负载均衡实现的原理,建议你置fastcgi.debug为1。即使对于本机的多个FastCGI,你也会获得如下输出:

  proc: 127.0.0.1 1031  1 1 1 31454
  proc: 127.0.0.1 1028  1 1 1 31442
  proc: 127.0.0.1 1030  1 1 1 31449
  proc: 127.0.0.1 1029  1 1 2 31447
  proc: 127.0.0.1 1026  1 1 2 31438
  got proc: 34 31454
  release proc: 40 31438
  proc: 127.0.0.1 1026  1 1 1 31438
  proc: 127.0.0.1 1028  1 1 1 31442
  proc: 127.0.0.1 1030  1 1 1 31449
  proc: 127.0.0.1 1031  1 1 2 31454
  proc: 127.0.0.1 1029  1 1 2 31447

上述信息显示出了IP地址,端口号、当前链接数(也就是负载)(倒数第二列)、进程ID(倒数第一列)等等。整个输出信息总是以负载域来从小到大排序的。

【FastCGI和PHP】

在你编译PHP时,需要去除类似“–with-apxs/–with-apxs2”等选项,而要加入如下选项:

  $ ./configure \
    --enable-fastcgi \
    --enable-force-cgi-redirect \
    ...

这样,PHP才会支持CGI方式。在安装结束后,可以这样检查:

  $ php -v
  PHP 4.3.3RC2-dev (cgi-fcgi) (built: Oct 19 2003 23:19:17)

其中最重要的部分是(cgi-fcgi)

在lighttpd中配置fastcgi.server时,可以有多种选择:

最简方法:

  fastcgi.server = ( ".php" =>
    (( "socket" => "/tmp/php-fastcgi.socket",
        "bin-path" => "/usr/local/bin/php"
    ))
  )

中等方法(可以通过两个环境变量来控制workder的数量,以及一个workder可以承受的请求数目):

fastcgi.server = ( ".php" =>
  (( "socket" => "/tmp/php-fastcgi.socket",
     "bin-path" => "/usr/local/bin/php",
     "bin-environment" => (
       "PHP_FCGI_CHILDREN" => "16",
       "PHP_FCGI_MAX_REQUESTS" => "10000"
     )
  ))
)

安全方法(可以在环境变量方面加强安全性):

fastcgi.server = ( ".php" =>
   (( "socket" => "/tmp/php-fastcgi.socket",
      "bin-path" => "/usr/local/bin/php",
      "bin-environment" => (
         "PHP_FCGI_CHILDREN" => "16",
         "PHP_FCGI_MAX_REQUESTS" => "10000" ),
      "bin-copy-environment" => (
     "PATH", "SHELL", "USER" )
   ))
 )

如果你希望在PHP编程中使用到PATH_INFO和PHP_SELF两个全局变量,那么你需要做两件事,

第一,在php.ini中设置:

cgi.fix_pathinfo = 1

第二,在fasctcgi.server中添加设置broken-scriptfilename:

fastcgi.server = ( ".php" =>
  (( "socket" => "/tmp/php-fastcgi.socket",
      "bin-path" => "/usr/local/bin/php",
      "bin-environment" => (
        "PHP_FCGI_CHILDREN" => "16",
        "PHP_FCGI_MAX_REQUESTS" => "10000"
      ),
      "bin-copy-environment" => ( "PATH", "SHELL", "USER" ),
      "broken-scriptfilename" => "enable"
  ))
)

【python FastCGI和flup】

配置如下:

fastcgi.server = (
    ".py" =>
    (
        "python-fcgi" =>
        (
         "socket" => socket_dir + "fastcgi.python.socket",
         "bin-path" => "test.py",
         "check-local" => "disable",
         "max-procs" => 1,
        )
    ))

而test.py内容如下:

#!/usr/bin/python2.5
def myapp(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return ['Hello World!\n']

if __name__ == '__main__':
    from flup.server.fcgi import WSGIServer
    WSGIServer(myapp).run()

[参考文献]

http://redmine.lighttpd.net/projects/1/wiki/Docs:ModFastCGI

http://www.fastcgi.com

谢谢!

roc

发表您的评论

请您放心,您的信息会被严格保密。必填项已标识 *