nginx负载均衡和配置PHP-FPM
PHP开发基本上都知道两种运⾏环境,分别是LNMP和LAMP。区别主要在N和A上,当然从细节上来区分,两个P也有不⼀样的地⽅。不谈之前的浅淡理解,最近⼀个项⽬上要配合进⾏PHP服务器指向的切换。发现A服务器上安装了apache,B服务器上安装了nginx,每次请求B服务器的nginx,业务逻辑在A上执⾏。
这和我之前所了解到的不太⼀样,⼀般来说apache和php通过mod_php⽅式运⾏,⽽要是⽤到nginx,往往就直接⽤了php-fpm。在⼀番查看后发现,确实基本apache的mod_php进⾏PHP解析,通过访问B返回了正确的脚本执⾏结果,⽽直接访问了A,发现也得到了正确的结果。区别仅在于ip地址和端⼝的差别。
打开nginx的配置⽂件f发现类似如下⼀段信息:
location /papa/ {
proxy_pass 192.168.3.100/;
}
proxy模块相关配置参数很多,proxy_pass简单来说就是做⼀遍HTTP请求转发。暂时不去深究为什么⽤了nginx,⼜⽤了apache。个⼈认为这种⽅式存在不⾜之处,nginx⼀直以来以其静态处理性能强劲闻名(当然现在动态处理能⼒也很强),通过配置location匹配抓取访问URL指定字段,再转发请求到apache服务器。可以看出来动态和静态请求都全部推给了apache,那么nginx仅仅就是做了个转发,HTTP 转发这种事情,总会存在损耗。完全没有利⽤起来nginx强劲的效果,唯⼀的好处可能就是做了负载均衡,⽅便布置集。
第⼀想聊聊,基于压测,要求部署两套PHP的执⾏环境。
location /papa/ {
proxy_pass test_common/;
}
upstream test_common {
server 127.0.0.1;
}
proxy_pass 配置转发请求地址,upstream配置多个server地址,且功能真的强⼤,举⼏个简单的例⼦。
普通轮询模式:按照1:1的⽐例轮询服务器执⾏脚本
upstream test_common {
server 192.168.0.1;
server192.168.0.2;
}
权重轮询模式:按照设置的⽐例轮询服务器执⾏脚本
upstream test_common {
server 192.168.0.1 weight=3;
server192.168.0.2 weight=2;
}
IP分配模式:根据请求的IP分配执⾏服务器,保证相同IP在⼀个服务器上执⾏脚本。
之前在发布到线上的时候,由于部署了两套服务器,导致基于SESSION的部分,出现问题,现在来看,⼀句话就能搞定。
upstream test_common {
ip_hash;
server 192.168.0.1 weight=3;
server192.168.0.2 weight=2;
}
重启nginx,⼀访问报了个400的错误。
改动f配置⽂件,访问出现400异常,那么暂时认定配置⽂件的改动问题,根据页⾯报错信息查错,过程⽐较持久和繁杂,也没有能解决的⽅法。
后来想想,继续是nginx配置后出错了,那就查查nginx的运⾏⽇志吧,进⼊到nginx根⽬录,执⾏tail -f logs/access.log
访问⼀次后,发现新增⼀⾏
实际上这是apache的返回内容,进⾏apache⽇志⽬录,查看⽇志
诶,发现确实有点搞头了,居然是apache报的错,结合之前的资料搜索,有粗略提到头部问题,就决定看看能不能抓到请求的头部信息来试试⽔了。
执⾏命令:tcpdump -i lo port 80 -s 1024 -l –A
Host是upstream定义的虚拟名称,f改回初始配置继续抓包结果为:
同时设置apache⽇志级别为debug后,定位⽇志:
AH02415: [strict] Invalid host name'test_common', problem near: _commo
AH00550: Client sent malformed Host header:test_common
定位到是请求头Host的问题,可以使⽤proxy_set_header来设置Host信息
location /papa/ {
proxy_pass test_common/;
proxy_set_header Host $host;
}
修改如上配置,继续调试,
nginx和apache区别
抓取头部发现变更成了IP地址,同时请求执⾏不再报400错误。
根据结果验证过程,查了下nginx负载均衡相关,发现确实都有设置Host⼀项。
要特别说明的是,线上及以上重现为apache2.4和PHP5.6版本。后续在另外apache2.2和PHP5.3版本上测试时,发现不添加
proxy_set_header Host $host;脚本执⾏成功,Host也确实异常。
apache2.4和apache2.2对HTTP请求Host的检测规则可能不⼀样?
两个版本造成不同结果的原因点,没出来。
第⼆想聊聊nginx和php-fpm之间的配置。
php-fpm安装⽐较⽅便,基于5.3.3以上的版本已经被PHP集成,因此编译的时候加⼊--enable-fpm即可。
单纯的执⾏.php⽂件,配置⾮常⽅便,f注释的内容打开简单修改就能直接⽤。
不过⽇常开发的项⽬都是基于TP框架,当然laravel原理也⼀样。隐藏了⼊⼝⽂件index.php,同时访问
路由通过URL携带进⾏解析后执⾏。
if (!-e $request_filename) {
rewrite  ^/(.*)$  /index.php/$2 last;
}
这个配置主要是为了对访问URL进⾏重写操作,如果不存在此⽂件,在最前端写⼊index.php,这和apache的.htaccess⽂件功能⼀样。last⽹上的说法是重新发起⼀个请求(这⾥存在疑问,重新发起请求是指新的⼀个HTTP请求吗?观察执⾏⽇志并没有两条请求,我个⼈感觉可以理解为,继续匹配后续的location了),相对的break会停⽌对后续location的匹配。
在经过URL重写后,要对php⽂件继续做location的匹配,当到匹配,则发送请求到php-fpm。
观察nginx⽇志,提⽰/index.php/tp/Index/index has been denied。暂不考虑其他的,这个tp和index.php位置就不对,⽽apache重写的rewrite正则相似,但是能正确的写⼊index.php。
新改动如下:
if (!-e $request_filename) {
rewrite  ^/(.*?)/(.*)$  /$1/index.php/$2  last;
}
重新的URL是正确了,因为没法使⽤域名来测试,域名包含了项⽬名,应该不会出现这种情况。
剩下就是对php⽂件location部分改动了,默认是
location ~ \.php$ {
root          html;
fastcgi_pass  127.0.0.1:9000;
fastcgi_index  index.php;
fastcgi_param SCRIPT_FILENAME  /scripts$fastcgi_script_name;
include        fastcgi_params;
}
刚开始想着对正则改改,如:~ \.php(.*)$。毕竟index.php后⾯携带了内容嘛,后来想想有点傻,实际上并不存在类似
tp/index.php/Index/index⽂件。
查配置
location ~ \.php($|/) {
include                fastcgi_params;
fastcgi_pass          127.0.0.1:9000;
fastcgi_index          index.php;
set $path_info "/";
set $real_script_name $fastcgi_script_name;
if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
set $real_script_name $1;
set $path_info $2;
}
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param SCRIPT_FILENAME $document_root$real_script_name;
}
和默认配置区别在于除了转发请求,还设置了脚本⽂件名、PATH_INFO变量(业务执⾏⽂件相关参数)、脚本⽂件绝对路径。这三个变量都能通过SERVER变量打印观察。
总结⼀下,其实对这⼀块的梳理还挺乱的,不过算是了解了下nginx和其与php-fpm之间的配置关系。其本质是⼀个代理服务器,在能够⾼效处理静态资源的同时,作为类似Web请求中转站和php-fpm建⽴联系,以sockt⽅式通信达到运⾏PHP⽂件的⽬的。
另外配置参数挺多,所以还是好好看看官⽅⽂档来做到知根知底吧。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。