一般来说,apache的proxy有几个用途:
负载均衡:一台server撑不住,通过proxy把业务处理分流到其他server,让网站更强壮;
安全:前台用porxy或者squide挡一下,受到攻击或者黑客的时候让前端的proxy当靶子;
应用整合:让某些目录proxy到其他webserver的其他端口,不同的server整合到同一个域名下。
在最近的一个项目中,同一个网站应用要推送到不同的前端ip和域名上,而且将会分布在几十台物理服务器上,但流量并不高。惯性思维想到的方案是——发布,再发布,不管数据库还是代码,有更新就从新发布到各个服务器上。虽说我们做了很多自动化的脚本,但是这种方式还是会出现一些问题:
繁琐:每次更新完了beta还需要一个冗长的脚本执行过程,而且为了稳妥更新后的效果还需要去每个server上去人工查看;
数据库无法统一,一些应用不好实现:为了让服务更快,不得不在每台server都放上数据库,但是这样,一来,因为mysql遇到直接dump导入就不能用mysql的主从方式,推送大各个server同步时间较长,不稳定;二来,一些用户信息不方便在各个server之间做同步。
配置一台新的服务器需要时间。
在反复的纠结和测试之后,我采用apache的proxy实现了多前端单一后端的架构:
有应用A,B,C
有服务器:
P ->192.168.1.100
Q->192.168.1.101
R->192.168.1.102
S->192.168.1.103
T->192.168.1.104
给应用A分配的域名:
www.a1.com ->192.168.1.101 (Q)
www.a2.com ->192.168.1.101 (Q)
www.a3.com ->192.168.1.102 (R)
www.a4.com ->192.168.1.102 (R)
……
给应用B分配的域名:
www.b1.com ->192.168.1.101 (Q)
www.b2.com ->192.168.1.101 (Q)
www.b3.com ->192.168.1.102 (R)
www.b4.com ->192.168.1.102 (R)
……
以server P(192.168.1.100)为后端:
把A的后端放在P的81端口
把B的后端放在P的82端口
把C的后端放在P的83端口。
给Q,R,S,T的80配置好proxy和rewrite(具体的配置这里不复述,请百度上自己google一下)。
那么针对Q的80端口对应的目录下的.htaccess做如下配置:
RewriteEngine on
# A ——————–
# server Q (2 sites)
RewriteCond %{HTTP_HOST} ^www.a1.com* [OR]
RewriteCond %{HTTP_HOST} ^www.a2.com*
RewriteRule ^(.*)$ http://192.168.1.100:81/$1 [P,L]
# END A ——————–
# B ——————–
# server Q (2 sites)
RewriteCond %{HTTP_HOST} ^www.b1.com* [OR]
RewriteCond %{HTTP_HOST} ^www.b2.com*
RewriteRule ^(.*)$ http://192.168.1.100:82/$1 [P,L]
# END A ——————–
这样一来指向到serverQ的:
域名 www.a1.com [...]
用来做gzip压缩的deflate模块:
DeflateCompressionLevel 压缩等级,取值范围1–9,越高cpu的load越重。
大致的配置(得先SetOutputFilter再AddOutputFilter):
<IfModule mod_deflate.c>
DeflateCompressionLevel 3
SetOutputFilter DEFLATE
#AddOutputFilterByType DEFLATE php
AddOutputFilter DEFLATE php html htm js css xml
</IfModule>
在apache安装的时候,可以选择–enable-so这一项,那么就可以通过apxs这个文件来扩展更多的apache 模块了。
不懂安装的请看我的“apache在linux上的编译安装”一文。
查看当前的apache是否支持so:
#/path/to/apache/bin/apachectl -l |grep mod_so
如果列表中有mod_so.c这一项,说明你目前的apache是支持,另外,你的/path/to/apache/bin/下面有没有apxs这个文件。
apxs的部分参数说明:
http://www.linux.gov.cn/netweb/mat/ApacheMenu_zh_CN/dso.html
-n modname
它明确设置了-i(install)和-g (template generation)选项的模块名称。 对-g选项,它是必须的; 对-i选项,apxs工具会按文件名判断至少是推测出这个模块名称。
-q
查询某种apxs设置的信息。 query参数可以是下列一个或多个字串:CC, CFLAGS, CFLAGS_SHLIB, INCLUDEDIR, LD_SHLIB, LDFLAGS_SHLIB, LIBEXECDIR, LIBS_SHLIB, SBINDIR, SYSCONFDIR, TARGET.这个参数用于手动查询某些设置。比如,要手动处理Apache的C头文件,可以在Makefile中使用
-g
此选项生成一个名为name的子目录(见选项-n)和其中的两个文件: 一个是名为mod_name.c的样板模块源程序, 可以用作建立你自己的模块的模板,或是学习使用apxs机制的良好开端; 另一个则是对应的Makefile,用于编译和安装此模块。
-c
此选项表示需要执行编译操作。 它首先会编译C源程序(.c)files为对应的目标代码文件(.o), 然后,连接这些目标代码和files中其余的目标代码文件(.o and .a), 以生成动态共享对象dsofile。如果没有指定-o选项, 则此输出文件名由files中的第一个文件名推测得到, 所以,缺省时,它一般会是mod_name.so
-i
此选项表示需要执行安装操作, 以安装一个或多个动态共享对象到服务器的modules目录中。
-a
此选项自动在httpd.conf文件中增加一个LoadModule行,以激活此模块,或者,如果此行已经存在,则启用之。
-A
与-a选项类似,但是它增加的LoadModule指令由一个井号前缀(#), 即,此模块已经准备就绪,但尚处于禁用状态。
-e
此选项表示需要执行编辑操作,它可以与-a和-A选项配合使用, 与-i操作类似,修改Apache的httpd.conf配置文件,但是并不安装此模块。
apxs的运作原理
一般来说,每个module都对应一个.c文件,放在你apache的源文件目录里面,让apache的这个apxs程序去编译对应的module.c的源文件,会在apache安装目录的modules/文件夹中生成对应的.so文件,再在httpd.conf里面添加LoadModule 指令,那么,每次启动apache 就会把对应的这个module载进来。
这写module的源文件有些有相互依存关系,安装的时候需要注意一下顺序和前后摆放。
通过apxs采用DSO方式安装mod_headers和mod_deflate两个模块:
# cd /path/to/apache/bin/
# ./apxs -i -a -c /path/to/source/modules/filters/mod_deflate.c
# ./apxs –i –a –c /path/to/source/modules/filters/mod_headers.c
去httpd.conf里面看看,两个LoadModule 都放在那里了。
http://www.linux.gov.cn/netweb/mat/ApacheMenu_zh_CN/programs/configure.html
apache拥有4层结构,从核心到外层的module。而外层的module可以用通过静态和动态两种方式与apache共同工作。这也就引入下文的“动态”和“静态”两种编译安装方式:
静态编译:
编译的时候,所有的模块自己编译进httpd 这个文件中 ,启动apache的时候这些模块就已经加载进来了,可以直接来使用,而不用再httpd.conf中在LoadModule来加载,只要在 <ifmodule></ifmodule> 中来配置就可以了。
动态编译:
编译的时候,使用enable-module=shared 或者enable-modules-shared=module来动态编译。 动态显然就不编译到httpd里面去了,启动的时候根本不会加载这个模块, 而是给你一个module.so 文件。你想用,就在httpd.conf中使用 loadmodule 这个语法来加载,这个模块才有效。
区别是:
静态的模块通常在http.conf中用<ifmodule></ifmodule> 来配置,动态的要先loadmoule来加载,然后再<ifmodule></ifmodule>配置。
官方说静态的比动态的在性能方面多5%左右。
相对来说,静态的效率高些,而动态方式配置方面灵活。想想如果编译进去的C这个module你想升级或者去掉,静态方式的就只能重新编译apache了。
下面这句在apache源文件夹下运行,可以查看默认情况下apache都给你装了那些module进去:
./configure –help | grep disable
让apache日后可以动态编译和加载模块:
如果想让apache日后可以支持动态编译(DSO)更多的module,需要在初次安装时把so这个模编译到核心。
如果编译中包含任何DSO模块,则mod_so会被自动包含进核心。如果希望核心能够装载DSO,但不实际编译任何DSO模块,则需明确指定:
针对apache1.x: –enable-module=so
针对apache2.x: –enable-so=static
apache模块的类型:
基本(B)模块默认包含,必须明确禁用;
扩展(E)/实验(X)模块默认不包含,必须明确启用。
那么,针对以上这些类型的模块,有以下几种操作方式:
–disable-MODULE
禁用MODULE模块(仅用于基本模块)
–enable-MODULE=shared
将MODULE编译为DSO(可用于所有模块)
–enable-MODULE=static
将MODULE静态连接进核心(仅用于扩展和实验模块)
–enable-mods-shared=MODULE-LIST
将MODULE-LIST中的所有模块都编译成DSO(可用于所有模块)
–enable-modules=MODULE-LIST
将MODULE-LIST静态连接进核心(可用于所有模块)
针对–enable-modules和–enable-module-shared有两个懒办法就是 most参数和all参数,分别表示“很多的”和“所有”。
例如:
mod_alias是个基本模块,不想安装的话就: –disable-alias
mod_rewrite是个扩展模块,想动态加载它:–enable-rewrite=shared,想静态加载就是:–enable-rewrite=static
想静态编译mod_alias和mod_rewrite:–enable-modules=’alias rewrite’
想动态编译mod_alias和mod_rewrite:–enable-modules-shared=’alias rewrite’
针对apache2.2.x的一些例子:
最大化静态安装apache:
./configure –prefix=/path/to/local –enable-modules=all
最大化动态安装apache:
./configure –prefix=/path/to/local –enable-mod-shared=all
静态安装rewrite、动态安装deflate以及headers
./configure –prefix=/path/to/local –enable-rewrite=static –enable-deflate=shared –enable-headers=shared
不安装基本的alais,保留以后的扩展DSO能力:
./configure –prefix=/path/to/local –enable-so=static –disable-alias
在Linux系统下,需要给已经运行的Apache增加mod_proxy模块,编译的时候应该这样:
apxs -c -i mod_proxy.c proxy_util.c
否则你可能会收到这样的错误信息
[root@server1 proxy]# /apache/httpd/bin/apachectl configtest
httpd: Syntax error on line 58 of /apache/httpd-2.2.3/conf/httpd.conf: Cannot load /apache/httpd-2.2.3/modules/mod_proxy.so into server: /apache/httpd-2.2.3/modules/mod_proxy.so: undefined symbol: proxy_lb_workers
如果你还加载了mod_proxy_ajp.so那应该
apxs -c -i mod_proxy_ajp.c ajp*.c
[root@server1 proxy]# /apache/httpd/bin/apachectl configtest
httpd: Syntax error on line 58 of /apache/httpd-2.2.3/conf/httpd.conf: Cannot load /apache/httpd-2.2.3/modules/mod_proxy_ajp.so into server: /apache/httpd-2.2.3/modules/mod_proxy_ajp.so: undefined symbol: ajp_msg_reset
# 基于 NCSA 服务的配置文件。
#
#这是Apache服务器主要配置文件。
#它包含服务器的影响服务器运行的配置指令。
#参见<URL:http://httpd.ache.org/doc-2.0/>以取得关于这些指令的详细信息
#
#不要只是简单的阅读这些指令信息而不去理解它。
#这里只是做了简单的说明,如果你没有参考在线文件,你就会被警告。
#
#这些配置指令被分为下面三个部分:
#1. 控制整个Apache服务器行为的部分(即全局环境变量)
#2. 定义主要或者默认服务参数的指令,也为所有虚拟主机提供默认的设置参数
#3. 虚拟主机的设置参数
#
#配置和日志文件名:如果你指定的文件名以“/”开始(win32下以“dirver:/”),
#服务器将使用绝对路径,如果文件名不是以“/”开始的,那么它将把ServerRoot
#的值附加在文件名的前面,例如,对“logs/foo.log”,如果ServerRoot的值
#为“/usr/local/apache2”,则该文件应为“/usr/local/apache2/logs/foo.log”
#
##第一区:全局环境参数
#
#这里设置的参数将影响整个Apache服务器的行为;
#例如Apache能够处理的并发请求的数量等。
#
#ServerRoot:指出服务器保存其配置、出错和日志文件等的根目录。
#
#注意!如果你想要将它指定为NFS或其它网络上的位置,
#请一定要去阅读与LockFile有关的文档(可能在
#<URL:http://httpd.apache.org/docs-2.0/mod/mpm_common.html#lockfile>)。
#这将会使你自己也能解决很多问题。
#
#路径的结尾不要添加斜线。
#
ServerRoot “/usr/loacl/apache2″
#
#串行访问的锁文件必须保存在本地磁盘上
#
<IfModule !mpm_winnt.c>
<IfModule !mpm_neware.c>
#LockFile logs/accept.lock
</IfModule>
</IfModule>
#ScoreBoardFile:用来保存内部服务进程信息的文件。
#如果未指明(默认),记分板(scoreboard)将被保存在一个匿名的共享内存段中,
#并且它不能被第三方软件所使用。
#如果指定了,要确保不能使用两个Apache使用同一个记分板文件,
#这个记分板文件必须保存在本地磁盘上。
#
<IfModule !mpm_netware.c>
<IfModule !perchild.c>
#ScoreBoardFile logs/apache_runtime_status
<IfModule>
<IfModule>
#
#PidFile:记录服务器启动进程号的文件。
#
<IfModule !mpm_neware.c>
PidFile logs/httpd.pid
</IfModule>
#
#Timeout:接收和发送前超时秒数
#
Timeout 300
#
#KeepAlive:是否允许稳固的连接(每个连接有多个请求),
#设为”Off”则停用。
#
KeepAlive On
#
#MaxKeepAliveRequests:在稳固连接期间允许的最大请求数,
#设为0表示无限制接入。
#我们推荐你将其设为一个较大的值,以便提高性能
MaxKeepAliveRequests 100
#
#KeepAliveTimeout:在同一个连接上从同一台客户上接收请求的秒数
#
KeepAliveTimeout 15
##
##Server-Pool大小设定(针对MPM的)
##
# prefork MPM
# StartServers:启动时服务器启动的进程数
# MinSpareServers:保有的备用进程的最小数目
# MaxSpareServers:保有的备用进程的最大数目
# MaxClients:服务器允许启动的最大进程数
# MaxRequestsPerChild:一个服务进程允许的最大请求数
<IfModule prefork.c>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150
MaxRequestPerChild 0
</IfModule>
# worker MPM
# StartServers:服务器启动时的服务进程数目
# MaxClients:允许同时连接的最大用户数目
# MinSpareThreads:保有的最小工作线程数目
# MaxSpareThreads:允许保有的最大工作线程数目
# ThreadsPerChild:每个服务进程中的工作线程常数
# MaxRequestsPerChild:服务进程中允许的最大请求数目
<IfModule worker.c>
StartServers 2
MaxClients 150
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestsPerChild 0
</IfModule>
# perchild MPM
# NumServers:服务进程数量
# StartThreads:每个服务进程中的起始线程数量
# MinSpareThreads:保有的最小线程数量
# MaxSpareThreads:保有的最大线程数量
# MaxThreadsPerChild:每个服务进程允许的最大线程数
# [...]