使用 Nginx + Apache + PHP 均衡负载环境
网站随着改版,用户的活跃度,以及搜索引擎的优化都带来了流量激增。
原本单台服务器平均 CPU 6~10 增高到 30~40 晚上高峰期明显感到点击的反应的延迟。
是需要用到集群的时候了。
在脑中设计该集群的思路, 使用 Nginx 用于流量分发以及静态文件处理,多Apache 负责处理PHP程序。
这是一种很简单的均衡负载方式,在Nginx中配置好 upteam,Localhost 与APP0 服务器的文件同步采用NFS,再公用一个单独的Mysql_server主机。
脑子中的这个设计蓝图,一下子就能配置出来。但我所要分享的,是一些细微但作用确相当重要的技巧。
首先说一下文件同步,NFS。
程序根目录下有个 attachments 目录,用于写入存放上传的附件,除此之外为了优化反应速度以及减少传输量,我把除此以外根目录下的所有程序文件都复制到 APP0 的本地硬盘上。
好了,一开始就是这么一架构,开始试验。
发生的第一个问题是当论坛站长(管理员) 登陆后台的时候, 由于均衡负载在不停的 2 个 apache 上跳,所以导致输入密码之后怎样都进不了后台。(后台的 cookies 在一关闭浏览器之后就会自动清除)
怎么办? 你可以使用另一个二级域名域名,指到同一个目录,但不绑到 Nginx 的 upteam,proxy 的时候直接写的是 但一台主机apache 的地址. 例如:proxy_pass http://127.0.0.1:8080;
但还有一个方法是我现在所用的,直接把后台的php程序过滤出来,绑定在localhost 的Apache上,不参与均衡负载。
location ~ admincp.php$ {
proxy_pass http://127.0.0.1:8080;
include proxy.conf;
}
把以上这配置加插在Nginx php的过滤语法之上, 其实原理跟过滤PHP是一样的。
凡是 admincp.php 的文件,都proxy 送至 http://127.0.0.1:8080
下边这段是 Nginx 用于过滤处理 php 的语法。
location ~ \.php$ {
proxy_pass http://server_gznow;
include proxy.conf;
}
这么一来,Nginx 负责出来所有除 php 以外的请求,而php 就交由后方 apache 处理。并配置了 upteam 均衡负载,因此会分配到各个apache 处理达到流量分摊。而 admincp.php 在Nginx 过滤所有php进行均衡负载之前已绑定在单一个apache 上,就是说该程序并没设置到均衡复制,所以刚才无法登陆后台的问题解决。
好了,这么做下一个继续测试,上传文件,出问题了。
上传文件为了标明版权或者防盗链,可以在后台中设置为图片打上水印。
在均衡负载的情况下,使用批量上传功能upload的图片会发生一部分有水印,一部分没有的情况。这就肯定跟配置了均衡负载的原因有关。
水印功能需要用到 GD 的JPEG函数,经检测,2台用于均衡负载的服务器 GD支持 JPEG 的环境是没问题的。不使用均衡负载的情况下所有图片都能打上水印,这是为什么呢? 这跟批量上传构造有关。也不大好说明,但通过以下方法能解决。
从web日志观察所得,用户发帖,会用到 post.php 这个程序文件,而上传,即会用到 misc.php
于是我们就跟之前解决后台登陆的方法一样,先把 misc.php 绑定在localhost上,经测试。不成功,图片上传依旧一部分图片没有水印。看来 misc.php 只负责上传,而打水印的函数应用恐怕就是 post.php 负责的。
所以我就干脆把 misc.php 跟 post.php 都绑定在单独的一台 localhost 上。
这么有个好处,更加省了 APP0 NFS 同步的流量。原来上传图片,用户都需要兜圈 Nginx --> APP0 --> NFS --> local --> Nginx
现在直接就能 Nginx <--> local
坏处就是,post.php 跟 misc.php 都不能参与均衡复制了,如果用户发帖上传得厉害,这就要以后再想别的办法了....
但就又悟出了一个道理,如果日后Mysql 撑不住了,想进行读写分离的时候!可以用同样的方法。
例子:先把Mysql 配置为主从复制
把帖子浏览或板块浏览的程序 viewthread.php forumdisplay.php 等紧紧读数据的程序 绑在 APP0 ,然后 conf.inc.php 配置文件中 mysql 的地址指定为mysql 从服务器的地址。
因为帖子浏览紧紧需要在 mysql 进行读的操作,而写的操作,例如 post.php 以及一些版主管理的页面都帮到 localhost 然后在conf.inc.php 配置中配置 mysql 主 的服务器地址。这么读写就能分开了!
然后还有一个问题,是后台设置后,Discuz 是有缓存的,往往需要更新缓冲设置才能在前台中显示出来。
但由于设置的admincp.php被绑在单独一台服务器上,所以就算更新缓存,也只更新了一台服务器的缓存。
你可以有2个方法。
1,修改 Nginx 的配置把 admincp.php 指向到另外一台服务器,更新完之后再换回来。
2,用 Rsync ! 配置好同步的参数,写成 shell 程序,一执行即刻往主机上同步,这样就什么 cache 也跟主机上一样了。