实现lighttpd-1.5+mod_proxy_core+多 Fastcgi backends 解析PHP负载平衡

实现lighttpd-1.5+mod_proxy_core+多 Fastcgi backends 解析PHP负载平衡

2007年3月13日改

在lighttpd.conf 中加入server.network-backend = "linux-aio-sendfile"

欢迎转载哦,记得保留

作者为wigeboy
邮箱wigeboy<at>gmail.com
CU首发

标题起的比较诡异,呵呵.这里最主要的想法是多个backends对PHP进行解析,达到负载平衡.

在lighttpd 1.5 已经和之前的版本有了很多新的元素同时也和之前的版本配置上略有不同,下面谈谈我个人的记录笔记.
我们先使用一个新的元素linux-aio-sendfile.和之前有什么不同,我们转一下lighhtpd BLOG上面的数据

大家可以去http://blog.lighttpd.net/articles/2006/11/12/lighty-1-5-0-and-linux-aio查看详细数据.

QUOTE:

Using Async IO allows lighttpd it overlap file-operations. We send a IO-request for the file and get notified when it is ready. Instead of waiting for the file (as in the normal sendfile()) and blocking the server, we can handle other requests instead.
On the other side we give the kernel to reorder the file-requests as it wants to.
Taking this two improments we can increase the throughput by 80%.
On the other side we don’t spend any time in wait in lighty itself. 64 kernel threads are handling the read()-calls for us in the background which increases the idle-time from 12% to 40%, a improvement of 230% .

1.下载编译
lighttpd-1.5

先确保有装 libaio

[Copy to clipboard] [ - ]
CODE:
wget http://www.lighttpd.net/download/lighttpd-1.5.0-r1477.tar.gz

tar -zxvf lighttpd-1.5.0-r1477.tar.gz

cd lighttpd-1.5.0

./configure --prefix=/usr/local/lighttpd --with-linux-aio

没有出错的话就

[Copy to clipboard] [ - ]
CODE:
make

make install

LightHttpd 会出现在 /usr/local/lighttpd

为lighttpd 建立 用户

[Copy to clipboard] [ - ]
CODE:
groupadd lighttpd
useradd -g lighttpd -s /sbin/nologin -d /dev/null lighttpd

mkdir /usr/local/lighttpd/conf
mkdir /usr/local/lighttpd/log

mv ./doc/lighttpd.conf /usr/local/lighttpd/conf/

chown -R lighttpd:lighttpd /usr/local/lighttpd

2.下载编译PHP
使用--enable-fastcgi 来编译 这里不多说了.

记得在php.ini 中把,同时奉上防呆有情提醒,把前面的注释去掉

[Copy to clipboard] [ - ]
CODE:
cgi.fix_pathinfo = 0  改为 cgi.fix_pathinfo = 1

3.启动Fastcgi backends

在doc目录内寻找spawn-php.sh

[Copy to clipboard] [ - ]
CODE:
vi spawn-php.sh



QUOTE:

#!/bin/bash
## ABSOLUTE path to the spawn-fcgi binary
SPAWNFCGI="/usr/local/lighttpd/bin/spawn-fcgi"              #<===修改这个,找到你的lighttpd相应目录中的spawn-fcgi
## ABSOLUTE path to the PHP binary
FCGIPROGRAM="/usr/php/bin/php"                                #<===修改为你的PHP路径,注意并非目录
## TCP port to which to bind on localhost
FCGIPORT="1026"                                                       #<===端口,一会多backends需要修改
## number of PHP children to spawn
PHP_FCGI_CHILDREN=10
## maximum number of requests a single PHP process can serve before it is restarted
PHP_FCGI_MAX_REQUESTS=1000
## IP addresses from which PHP should access server connections
FCGI_WEB_SERVER_ADDRS="127.0.0.1"                          #<===如果前台httpd非本机,请填写前台服务器相应IP
# allowed environment variables, separated by spaces
ALLOWED_ENV="ORACLE_HOME PATH USER"
## if this script is run as root, switch to the following user
USERID=lighttpd                                                            #<===运行用户
GROUPID=lighttpd

################## no config below this line
if test x$PHP_FCGI_CHILDREN = x; then
  PHP_FCGI_CHILDREN=5
fi
export PHP_FCGI_MAX_REQUESTS
export FCGI_WEB_SERVER_ADDRS
ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_MAX_REQUESTS FCGI_WEB_SERVER_ADDRS"
if test x$UID = x0; then
  EX="$SPAWNFCGI -p $FCGIPORT -f $FCGIPROGRAM -u $USERID -g $GROUPID -C $PHP_FCGI_CHILDREN"
else
  EX="$SPAWNFCGI -p $FCGIPORT -f $FCGIPROGRAM -C $PHP_FCGI_CHILDREN"
fi
# copy the allowed environment variables
E=
for i in $ALLOWED_ENV; do
  E="$E $i=${!i}"
done
  
# clean the environment and set up a new one
env - $E $EX

如果想多个backends 那么只需要copy 多几个 spawn-php.sh 为 spawn-php.1sh   等等再修改上面的端口为 1027,1028.

假设我需要在本机运行3个backends 分别对应 spawn-php.sh 1026 | spawn-php1.sh 1027 |spawn-php2.sh 1028

[Copy to clipboard] [ - ]
CODE:

./spawn-php.sh
./spawn-php1.sh
./spawn-php2.sh

好了,可以在top 命令下看见PHP的进程了.


4.OK,下面配置lighhtpd

[Copy to clipboard] [ - ]
CODE:
vi /usr/local/lighttpd/conf/lighttpd.conf



QUOTE:

#lighttpd configuration file
# use it as a base for lighttpd 1.0.0 and above
#
# $Id: lighttpd.conf,v 1.7 2004/11/03 22:26:05 weigon Exp $
############ Options you really have to take care of ####################
## modules to load
# at least mod_access and mod_accesslog should be loaded
# all other module should only be loaded if really neccesary
# - saves some time
# - saves memory
server.modules              = (
                               "mod_rewrite",
                               "mod_redirect",
#                               "mod_alias",
                                "mod_access",
#                               "mod_cml",
#                               "mod_trigger_b4_dl",
#                               "mod_auth",
#                               "mod_status",
#                               "mod_setenv",
                               "mod_proxy_core",                                                   #<===将几个需要用到的mod前的#去掉
                              "mod_proxy_backend_http",
                               "mod_proxy_backend_fastcgi",
#                               "mod_proxy_backend_scgi",
#                               "mod_simple_vhost",
#                               "mod_evhost",
#                               "mod_userdir",
#                               "mod_cgi",
#                               "mod_compress",
#                               "mod_ssi",
#                               "mod_usertrack",
#                               "mod_expire",
#                               "mod_secdownload",
#                               "mod_rrdtool",
                                "mod_accesslog" )
## a static document-root, for virtual-hosting take look at the
## server.virtual-* options
server.document-root        = "/var/www/bbs/"                         #<===WEB目录
## where to send error-messages to
server.errorlog             = "/usr/local/lighttpd//log/lighttpd.error.log"                #<===错误日志
# files to check for if .../ is requested
index-file.names            = ( "index.php", "index.html",
                                "index.htm", "default.htm","index.php" )                          #<===首页
## set the event-handler (read the performance section in the manual)
# server.event-handler = "freebsd-kqueue" # needed on OS X

# mimetype mapping
mimetype.assign             = (
  ".pdf"          =>      "application/pdf",
  ".sig"          =>      "application/pgp-signature",
  ".spl"          =>      "application/futuresplash",
  ".class"        =>      "application/octet-stream",
  ".ps"           =>      "application/postscript",
  ".torrent"      =>      "application/x-bittorrent",
  ".dvi"          =>      "application/x-dvi",
  ".gz"           =>      "application/x-gzip",
  ".pac"          =>      "application/x-ns-proxy-autoconfig",
  ".swf"          =>      "application/x-shockwave-flash",
  ".tar.gz"       =>      "application/x-tgz",
  ".tgz"          =>      "application/x-tgz",
  ".tar"          =>      "application/x-tar",
  ".zip"          =>      "application/zip",
  ".mp3"          =>      "audio/mpeg",
  ".m3u"          =>      "audio/x-mpegurl",
  ".wma"          =>      "audio/x-ms-wma",
  ".wax"          =>      "audio/x-ms-wax",
  ".ogg"          =>      "application/ogg",
  ".wav"          =>      "audio/x-wav",
  ".gif"          =>      "image/gif",
  ".jpg"          =>      "image/jpeg",
  ".jpeg"         =>      "image/jpeg",
  ".png"          =>      "image/png",
  ".xbm"          =>      "image/x-xbitmap",
  ".xpm"          =>      "image/x-xpixmap",
  ".xwd"          =>      "image/x-xwindowdump",
  ".css"          =>      "text/css",
  ".html"         =>      "text/html",
  ".htm"          =>      "text/html",
  ".js"           =>      "text/javascript",
  ".asc"          =>      "text/plain",
  ".c"            =>      "text/plain",
  ".cpp"          =>      "text/plain",
  ".log"          =>      "text/plain",
  ".conf"         =>      "text/plain",
  ".text"         =>      "text/plain",
  ".txt"          =>      "text/plain",
  ".dtd"          =>      "text/xml",
  ".xml"          =>      "text/xml",
  ".mpeg"         =>      "video/mpeg",
  ".mpg"          =>      "video/mpeg",
  ".mov"          =>      "video/quicktime",
  ".qt"           =>      "video/quicktime",
  ".avi"          =>      "video/x-msvideo",
  ".asf"          =>      "video/x-ms-asf",
  ".asx"          =>      "video/x-ms-asf",
  ".wmv"          =>      "video/x-ms-wmv",
  ".bz2"          =>      "application/x-bzip",
  ".tbz"          =>      "application/x-bzip-compressed-tar",
  ".tar.bz2"      =>      "application/x-bzip-compressed-tar"
)
# Use the "Content-Type" extended attribute to obtain mime type if possible
#mimetype.use-xattr        = "enable"

## send a different Server: header
## be nice and keep it at lighttpd
# server.tag                 = "lighttpd"
#### accesslog module
accesslog.filename          = "/usr/local/lighttpd/log/access.log"                  #<===日志
## deny access the file-extensions
#
# ~    is for backupfiles from vi, emacs, joe, ...
# .inc is often used for code includes which should in general not be part
#      of the document-root
url.access-deny             = ( "~", ".inc" )
$HTTP["url"] =~ "\.pdf$" {
  server.range-requests = "disable"
}
##
# which extensions should not be handle via static-file transfer
#
# .php, .pl, .fcgi are most often handled by mod_fastcgi or mod_cgi
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
######### Options that are good to be but not neccesary to be changed #######
## bind to port (default: 80)
#server.port                = 81
## bind to localhost (default: all interfaces)
#server.bind                = "grisu.home.kneschke.de"
## error-handler for status 404
#server.error-handler-404   = "/error-handler.html"
#server.error-handler-404   = "/error-handler.php"
## to help the rc.scripts
server.pid-file            = "/var/run/lighttpd.pid"                      #<===pid

###### virtual hosts
##
##  If you want name-based virtual hosting add the next three settings and load
##  mod_simple_vhost
##
## document-root =
##   virtual-server-root + virtual-server-default-host + virtual-server-docroot
## or
##   virtual-server-root + http-host + virtual-server-docroot
##
#simple-vhost.server-root   = "/home/weigon/wwwroot/servers/"
#simple-vhost.default-host  = "grisu.home.kneschke.de"
#simple-vhost.document-root = "/pages/"

##
## Format: <errorfile-prefix><status-code>.html
## -> ..../status-404.html for 'File not found'
#server.errorfile-prefix    = "/home/weigon/projects/lighttpd/doc/status-"
## virtual directory listings
#dir-listing.activate       = "enable"
## enable debugging
#debug.log-request-header     = "enable"
#debug.log-response-header    = "enable"
#debug.log-request-handling   = "enable"
#debug.log-file-not-found     = "enable"
#debug.log-condition-handling = "enable"
### only root can use these options
#
# chroot() to directory (default: no chroot() )
#server.chroot              = "/"
## change uid to <uid> (default: don't care)
server.username            = "lighttpd"                                      #<===运行用户
## change uid to <uid> (default: don't care)
server.groupname           = "lighttpd"                                     #<===运行组
#### compress module
#compress.cache-dir         = "/tmp/lighttpd/cache/compress/"
#compress.filetype          = ("text/plain", "text/html")
#### proxy module
## read proxy.txt for more info
#$HTTP["url"] =~ "\.php$" {
# proxy-core.balancer = "round-robin"
# proxy-core.allow-x-sendfile = "enable"
# proxy-core.protocol = "http"
# proxy-core.backends = ( "192.168.0.101:80" )
# proxy-core.max-pool-size = 16
#}

#### fastcgi module
## read fastcgi.txt for more info
## for PHP don't forget to set cgi.fix_pathinfo = 1 in the php.ini
$HTTP["url"] =~ "\.php$" {                                                                     #<===关键,将#去掉.
proxy-core.balancer = "round-robin"
proxy-core.allow-x-sendfile = "enable"                                                        #<===新的元素.
proxy-core.check-local = "enable"                                                              #<===先检查是否有文件,再发送请求给后台.
proxy-core.protocol = "fastcgi"
proxy-core.backends = ( "127.0.0.1:1026","127.0.0.1:1027","127.0.0.1:1028" )                      #<===对应之前的设的backends
proxy-core.max-pool-size = 16                                                                   #<===别弄大了,死的很惨的><.
}

#### CGI module
#cgi.assign                 = ( ".pl"  => "/usr/bin/perl",
#                               ".cgi" => "/usr/bin/perl" )
#
#### SSL engine
#ssl.engine                 = "enable"
#ssl.pemfile                = "server.pem"
#### status module
#status.status-url          = "/server-status"
#status.config-url          = "/server-config"
#### auth module
## read authentication.txt for more info
#auth.backend               = "plain"
#auth.backend.plain.userfile = "lighttpd.user"
#auth.backend.plain.groupfile = "lighttpd.group"
#auth.backend.ldap.hostname = "localhost"
#auth.backend.ldap.base-dn  = "dc=my-domain,dc=com"
#auth.backend.ldap.filter   = "(uid=$)"
#auth.require               = ( "/server-status" =>
#                               (
#                                 "method"  => "digest",
#                                 "realm"   => "download archiv",
#                                 "require" => "user=jan"
#                               ),
#                               "/server-config" =>
#                               (
#                                 "method"  => "digest",
#                                 "realm"   => "download archiv",
#                                 "require" => "valid-user"
#                               )
#                             )
#### url handling modules (rewrite, redirect, access)
#url.rewrite                = ( "^/$"             => "/server-status" )
#url.redirect               = ( "^/wishlist/(.+)" => "http://www.123.org/$1" )
#### both rewrite/redirect support back reference to regex conditional using %n
#$HTTP["host"] =~ "^www\.(.*)" {
#  url.redirect            = ( "^/(.*)" => "http://%1/$1" )
#}
#
# define a pattern for the host url finding
# %% => % sign
# %0 => domain name + tld
# %1 => tld
# %2 => domain name without tld
# %3 => subdomain 1 name
# %4 => subdomain 2 name
#
#evhost.path-pattern        = "/home/storage/dev/www/%3/htdocs/"
#### expire module
#expire.url                 = ( "/buggy/" => "access 2 hours", "/asdhas/" => "access plus 1 seconds 2 minutes")
#### ssi
#ssi.extension              = ( ".shtml" )
#### rrdtool
#rrdtool.binary             = "/usr/bin/rrdtool"
#rrdtool.db-name            = "/var/www/lighttpd.rrd"
#### setenv
#setenv.add-request-header  = ( "TRAV_ENV" => "mysql://user@host/db" )
#setenv.add-response-header = ( "X-Secret-Message" => "42" )
## for mod_trigger_b4_dl
# trigger-before-download.gdbm-filename = "/home/weigon/testbase/trigger.db"
# trigger-before-download.memcache-hosts = ( "127.0.0.1:11211" )
# trigger-before-download.trigger-url = "^/trigger/"
# trigger-before-download.download-url = "^/download/"
# trigger-before-download.deny-url = "http://127.0.0.1/index.html"
# trigger-before-download.trigger-timeout = 10
## for mod_cml
## don't forget to add index.cml to server.indexfiles
# cml.extension               = ".cml"
# cml.memcache-hosts          = ( "127.0.0.1:11211" )
#### variable usage:
## variable name without "." is auto prefixed by "var." and becomes "var.bar"
#bar = 1
#var.mystring = "foo"
## integer add
#bar += 1
## string concat, with integer cast as string, result: "www.foo1.com"
#server.name = "www." + mystring + var.bar + ".com"
## array merge
#index-file.names = (foo + ".php") + index-file.names
#index-file.names += (foo + ".php")
#### include
#include /etc/lighttpd/lighttpd-inc.conf
## same as above if you run: "lighttpd -f /etc/lighttpd/lighttpd.conf"
#include "lighttpd-inc.conf"
#### include_shell
#include_shell "echo var.a=1"
## the above is same as:
#var.a=1

好了,我们现在运行lighttpd吧

[Copy to clipboard] [ - ]
CODE:
/usr/local/lighttpd/sbin/lighttpd -f /usr/local/lighttpd/conf/lighttpd.conf

关闭就用

[Copy to clipboard] [ - ]
CODE:
ps -A

查PID, 对应的kill掉


当然对应的proxy-core.balancer = "round-robin" 这个负载平衡还有其他几种不同的.不过数RR这个最简单.第一个给A1 第二个给A2,第三个给A3,第四个又给回A1.

这里只罗列单服务器的多个backends,多服务器只需要修改相应的IP即可.



欢迎给小弟的email 来信探讨 wigeboy<at>gmail.com,或QQ 558857

thanks
有個問題
记得在php.ini 中把cgi.fix_pathinfo = 0  改为 cgi.fix_pathinfo = 1
但是在php.ini裡面.cgi.fix_pathinfo這段是被註解起來的.也就是沒有發生作用.那改不改有差別嗎?還是要把前面";"給去掉?


PS:實際投入運作之後發現.lighttpd會自動退出.也許還是還有bug.也許是上述說明只是安裝成功.但還要加上微調參數才能穩定吧?希望樓主繼續測試.謝謝

另外再問一個問題.如果使用三個backends.端口分別使用的是1206,1027,1028.那防火牆這3個port要打開嗎?
顶楼主,不过lighttpd有其优点但至少在今日其稳定性,安全性,维护成本和apache这名将还有差距,如果比较商业化的运用,大多数人都还是会选apache的吧,如果有多服务器的话合理配置优化好SQUID+apache架构,足够WEB应用了,有更大负载可以使用LVS对缓存服务器等进行集群式管理.LVS站点:   http://zh.linuxvirtualserver.org/
请问lighttpd支持c语言程序的fastcgi吗?


QUOTE:
原帖由 j9595 于 2007-2-23 23:25 发表
有個問題
记得在php.ini 中把cgi.fix_pathinfo = 0  改为 cgi.fix_pathinfo = 1
但是在php.ini裡面.cgi.fix_pathinfo這段是被註解起來的.也就是沒有發生作用.那改不改有差別嗎?還是要把前面";"給去掉 ...

当然需要去掉注解拉


QUOTE:
原帖由 j9595 于 2007-2-25 02:08 发表
另外再問一個問題.如果使用三個backends.端口分別使用的是1206,1027,1028.那防火牆這3個port要打開嗎?

这个也是必须的,特别是在有多台server的情况下


QUOTE:
原帖由 dream8888 于 2007-3-3 21:11 发表
顶楼主,不过lighttpd有其优点但至少在今日其稳定性,安全性,维护成本和apache这名将还有差距,如果比较商业化的运用,大多数人都还是会选apache的吧,如果有多服务器的话合理配置优化好SQUID+apache架构,足够WEB应用了 ...

如果这样的话,http://www.youtube.com/ 不就完蛋了嘛?特别是在小RAM的server中 lighty非常适合,具体情况具体分析,不要说的那么绝对。



QUOTE:
原帖由 dream8888 于 2007-3-3 21:11 发表
顶楼主,不过lighttpd有其优点但至少在今日其稳定性,安全性,维护成本和apache这名将还有差距,如果比较商业化的运用,大多数人都还是会选apache的吧,如果有多服务器的话合理配置优化好SQUID+apache架构,足够WEB应用了 ...

你是沒用過吧?不要老說apache.換個腦袋嘗試看看再說.apache誰沒用過阿.當然是覺得有缺點才嘗試其他的阿.話不要說得太早