12.17 Nginx负载均衡
要理解负载均衡,必须先搞清楚正向代理和反向代理
1、正向代理
正向代理类似一个跳板机,代理访问外部资源,正向代理 是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。
正向代理的用途:
(1)访问原来无法访问的资源,如google
(2) 可以做缓存,加速访问资源
(3)对客户端访问授权,上网进行认证
(4)代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息
2、反向代理
客户端是无感知代理的存在的,反向代理对外都是透明的,访问者者并不知道自己访问的是一个代理。因为客户端不需要任何配置就可以访问。
反向代理(Reverse Proxy)实际运行方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
反向代理的作用:
(1)保证内网的安全,可以使用反向代理提供WAF功能,阻止web×××
大型网站,通常将反向代理作为公网访问地址,Web服务器是内网。
(2)负载均衡,通过反向代理服务器来优化网站的负载
3、nginx的负载均衡
nginx是通过反向代理实现网站的负载均衡。代理一台机器为代理,多台机器,就叫负载均衡
Nginx负载均衡算法
(1)、轮询(默认)
每个请求按时间顺序逐一分配到不同的后端服务,如果后端某台服务器死机,自动剔除故障系统,使用户访问不受影响。
(2)、weight(轮询权值)
weight的值越大分配到的访问概率越高,主要用于后端每台服务器性能不均衡的情况下。或者仅仅为在主从的情况下设置不同的权值,达到合理有效的地利用主机资源。
(3)、ip_hash
每个请求按访问IP的哈希结果分配,使来自同一个IP的访客固定访问一台后端服务器,并且可以有效解决动态网页存在的session共享问题。
(4)、fair 第三方
比 weight、ip_hash更加智能的负载均衡算法,fair算法可以根据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间 来分配请求,响应时间短的优先分配。Nginx本身不支持fair,如果需要这种调度算法,则必须安装upstream_fair模块。
(5)、url_hash 第三方
按访问的URL的哈希结果来分配请求,使每个URL定向到一台后端服务器,可以进一步提高后端缓存服务器的效率。Nginx本身不支持url_hash,如果需要这种调度算法,则必须安装Nginx的hash软件包。
4、配置nginx负载均衡
通过dig可以查看到域名的解析IP地址,如果没有这个命令可以安装包
yum -y install bind-utils
我们用dig解析www.qq.com得到两个IP,用来做实验
[root@lnmp-server ~]# dig www.qq.com
; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> www.qq.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12037
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.qq.com. IN A
;; ANSWER SECTION:
www.qq.com. 95 IN A 59.37.96.63
www.qq.com. 95 IN A 58.60.9.21
上面得到有两个IP 59.37.96.63和58.60.9.21,用来模拟nginx负载均衡的后端机器 先新建一个虚拟主机配置文件
[root@lnmp-server ~]# vi /usr/local/nginx/conf/vhost/ld.conf #写入以下内容
upstream qq
{
ip_hash;
server 58.60.9.21:80;
server 59.37.96.63:80;
}
server
{
listen 80;
server_name www.qq.com;
location /
{
proxy_pass http://qq;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
说明:
upstream qq : upstream是一个模块,qq是模块名,这个名字可以自定义,在代理的时候需要用到 ip_hash: nginx负载均衡算法之一,保持同一用户始终在同一台服务器上,可以解决会话共享问题 server 两台机器:后端服务器,这里用dig解析出来的两台来模拟 listen 80; #定义监听端口 server_name www.qq.com; #定义域名 proxy_pass http://qq; ##upstream定义的名称,这个名称代表着upstream里定义的ip
编辑完之后保存退出,先不要重新加载配置文件,先测试一下用本机ip去访问www.qq.com这个域名看看结果会是什么:
[root@lnmp-server vhost]# curl -x127.0.0.1:80 www.qq.com
This is default server aaa
因为还没加载配置,所以www.qq.com解析到默认虚拟主机去了 检测配置是否有错并重载配置
[root@lnmp-server ~]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@lnmp-server ~]# /usr/local/nginx/sbin/nginx -s reload
再用curl测试www.qq.com的结果
[root@lnmp-server ~]# curl -x127.0.0.1:80 www.qq.com
出现了qq网站的源代码,说明配置成功
关于Nginx负载均衡方面要注意一点:
Nginx不支持直接代理https,只能代理http,也就是说443端口不支持只支持80端口。如果非要代理https,只能是用户访问Nginx代理服务器时使用https,然后Nginx去访问后端的web服务器时使用http,属于折中的一种方式,依然不能直接代理。
12.18 ssl原理
https就是使用ssl加密的http,是一种加密的超文本传输协议。如果http不加密的话,被人抓包或监听了数据包,就能很轻易地看到数据包里面的数据内容,那样的话你的信息就泄露了。
如果使用的是https协议,那么你的数据包就会被加密,即便被人抓包了,也没有那么轻易破解加密算法,因为数据包只能使用服务器上的私钥解密,而服务器根本不会在任何情况下发送私钥,想要不通过私钥来直接破解数据包几乎是不可能的。
12.19 生成ssl密钥对
理解了ssl原理后,现在我们可以在虚拟机上去生成ssl密钥对,也就是自己制作证书。我们需要使用一个工具来生成密钥对,把密钥对放在nginx的conf目录下
[root@lnmp-server ~]# cd /usr/local/nginx/conf/
生成ssl密钥对需要使用到的工具是openssl,如果你虚拟机没有此命令,需要自己安装,安装命令:
yum -y install openssl
生成私钥
[root@lnmp-server conf]# openssl genrsa -des3 -out tmp.key 2048
Generating RSA private key, 2048 bit long modulus
........................................................................................................................................................+++
.....................+++
e is 65537 (0x10001)
Enter pass phrase for tmp.key:
Verifying - Enter pass phrase for tmp.key:
命令说明:生成rsa格式的私钥,名字为tmp.key 长度2048,生成的时候要求给tmp.key设置密码 转换key,取消密码 由于生成私钥时设置了密码,这样每次访问https的网页时都需要输入密码,过于麻烦,因此可以通过转换key的方式将密码取消
[root@lnmp-server conf]# openssl rsa -in tmp.key -out luo.key
Enter pass phrase for tmp.key:
writing RSA key
说明:把之前生成的需要密码的tmp.key转换成无需密码的luo.key,这里要求输入之前给tmp.key设置的密码 此时存在两个key,tmp.key和luo.key,二者的内容完全相同,只是前者带有密码,后者没有密码,因此可将前者删除
[root@lnmp-server conf]# rm -f tmp.key
生成证书请求文件 用转换的私钥luo.key生成证书请求文件luo.csr
[root@lnmp-server conf]# openssl req -new -key luo.key -out luo.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
说明 :这里会要求你输入一些信息,因为做实验默认直接回车,如果是购买的正式证书要认真填写,后期可能会用到 生成公钥文件 用生成的证书请求文件luo.csr和私钥文件luo.key一起生成公钥文件luo.crt
[root@lnmp-server conf]# openssl x509 -req -days 365 -in luo.csr -signkey luo.key -out luo.crt
Signature ok
subject=/C=XX/L=Default City/O=Default Company Ltd
Getting Private key
生成完成后conf目录有三个文件
[root@lnmp-server conf]# ll luo*
-rw-r--r-- 1 root root 1103 7月 10 14:20 luo.crt
-rw-r--r-- 1 root root 952 7月 10 14:15 luo.csr
-rw-r--r-- 1 root root 1679 7月 10 14:11 luo.key
证书请求文件luo.csr,私钥文件luo.key,公钥文件luo.crt,至此,生成ssl密钥对完成
12.20 Nginx配置ssl
生成完ssl密钥对之后,需要在虚拟主机配置文件中配置ssl,这里新建个ssl.conf配置文件
[root@lnmp-server conf]# vi /usr/local/nginx/conf/vhost/ssl.conf #加入以下内容
server
{
listen 443 ssl;
server_name luo.com;
index index.html index.php;
root /data/wwwroot/luo.com;
ssl on;
ssl_certificate luolinux.crt;
ssl_certificate_key luo.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
}
解析说明:
server
{
listen 443 ssl; #ssl监听端口,格式不能写错
server_name luo.com; #网站域名
index index.html index.php; #支持的默认索引页
root /data/wwwroot/luo.com; #网站根目录
ssl on; #开启ssl
ssl_certificate luolinux.crt; #前面生成的公钥文件
ssl_certificate_key luo.key; #前面生成的私钥文件
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #支持的协议
}
检测配置是否有错
[root@lnmp-server conf]# /usr/local/nginx/sbin/nginx -t
nginx: [emerg] unknown directive "ssl" in /usr/local/nginx/conf/vhost/lemssl.conf:7
nginx: configuration file /usr/local/nginx/conf/nginx.conf test failed
在检测时出现了报错,原因是编译Nginx时没有添加ssl模块,因此需要重新编译Nginx,加上--with-http_ssl_modul,所以说源码包不要删除,后期增加一些配置的时候会用到:
cd /usr/local/src/nginx-1.12.1
./configure --prefix=/usr/local/nginx --with-http_ssl_module
make && make install
这里省略重新编译过程 重新检测配置文件看到已经可以识别ssl了,重新加载配置
[root@lnmp-server conf]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx//conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx//conf/nginx.conf test is successful
[root@lnmp-server conf]# /usr/local/nginx/sbin/nginx -s reload
检测端口是否有443
[root@lnmp-server conf]# netstat -lnp |grep nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 5661/nginx: master
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 5661/nginx: master
用https进行访问测试 用curl测试不直观,这里我们用windows机器绑定hosts进行测试,先编辑一下hosts文件,文件路径为: C:\Windows\System32\drivers\etc/hosts,在后面写入:
192.168.66.132 luo.com
在网站根目录下新建个index.html测试文件
[root@lnmp-server conf]# cat /data/wwwroot/luo.com/index.html
This is ssl test.
用浏览器进行https访问
会提示一些不安全信息,这是因为浏览器不信任这个证书,点开高级-继续前往
可以看到,已经能正常https访问了,想要没有这些警告的话,可以自己去买正规受信任的证书。我们可以访问https://www.12306.cn看看,相信这个网站大家都不陌生,访问它的https也是会有警告:
这不是因为政府没钱买证书,而是不相信那些外部购买的证书,所以使用自己内部颁发的证书。
因此可以知道,显示这个警告的原因仅仅是因为浏览器没有认可这个证书,并非是真的不安全
12.21 php-fpm的pool
pool是PHP-fpm的资源池,如果多个站点共用一个pool,则可能造成资源池中的资源耗尽,最终访问网站时出现502。 为了解决上述问题,我们可以配置多个pool,不同的站点使用不同的pool,保证充足的资源 编辑php-fpm配置文件,增加一个新的pool
vim /usr/local/php-fpm/etc/php-fpm.conf
[luo.com] //修改pool的名称
listen = /tmp/luo.sock //修改sock文件名称
listen.mode = 666
user = php-fpm
group = php-fpm
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
rlimit_files = 1024
//其余选项按需更改
检测文件&&重启
/usr/local/php-fpm/sbin/php-fpm -t
/etc/init.d/php-fpm reload
查看系统进程
php-fpm 5707 0.0 0.4 227488 4772 ? S 11:30 0:00 php-fpm: pool www
php-fpm 5708 0.0 0.4 227488 4772 ? S 11:30 0:00 php-fpm: pool www
php-fpm 5709 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool www
php-fpm 5710 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool www
php-fpm 5711 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool www
php-fpm 5712 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool www
php-fpm 5713 0.0 0.4 227488 4772 ? S 11:30 0:00 php-fpm: pool luo.com
php-fpm 5714 0.0 0.4 227488 4772 ? S 11:30 0:00 php-fpm: pool luo.com
php-fpm 5715 0.0 0.4 227488 4772 ? S 11:30 0:00 php-fpm: pool luo.com
php-fpm 5716 0.0 0.4 227488 4772 ? S 11:30 0:00 php-fpm: pool luo.com
php-fpm 5717 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool luo.com
php-fpm 5718 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool luo.com
php-fpm 5719 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool luo.com
发现新的pool已经添加成功 将站点添加至新的pool中
server
{
listen 80 default_server;
server_name lem.com;
index index.html index.htm index.php;
root /data/wwwroot/luo.com;
location ~ \.php$
{
include fastcgi_params;
fastcgi_pass unix:/tmp/luo.sock; //要使站点使用某个pool,需要修改这里,sock文件与pool中保持一致
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data/wwwroot/luo.com$fastcgi_script_name; //对应站点的文件名
}
}
通过过include语法创建多个pool(类似于Nginx的vhost) 我们可以在php-fpm.conf配置中直接定义多个pool,也可以把多个pool拆分成不同的文件,编辑php-fpm配置文件,在[global]部分增加include = etc/php-fpm.d/*.conf这一行
[global]
pid = /usr/local/php-fpm/var/run/php-fpm.pid
error_log = /usr/local/php-fpm/var/log/php-fpm.log
include = etc/php-fpm.d/*.conf
创建并进入include所对应的目录
mkdir /usr/local/php-fpm/etc/php-fpm.d/
cd /usr/local/php-fpm/etc/php-fpm.d/
创建各个pool的.conf文件
[root@lnmp-server conf]# vim /usr/local/php-fpm/etc/php-fpm.d/luo.com.conf #写入下面的内容
[luo.com]
listen = /tmp/test.sock
;listen = 127.0.0.1:9000
listen.mode = 666
user = php-fpm
group = php-fpm
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
rlimit_files = 1024
[root@lnmp-server conf]# vim /usr/local/php-fpm/etc/php-fpm.d/www.conf #写入下面的内容
[www]
listen = /tmp/php-fcgi.sock
listen.mode = 666
user = php-fpm
group = php-fpm
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
rlimit_files = 1024
可以看到两个pool的sock文件是不一样,不同的站点想使用不同的pool,只要修改对应的sock文件即可,定义完成后主配置文件php-fpm.conf定义的pool可以删除歌者注释掉 检测并重载配置使其生效
/usr/local/php-fpm/sbin/php-fpm -t
/etc/init.d/php-fpm reload
12.22 php-fpm慢执行日志
通过慢执行日志,我们可以查看哪些PHP脚本执行的速度慢,非常实用,我们可以在站点使用的pool池中定义慢执行日志 编辑pool的www.conf文件
vim /usr/local/php-fpm/etc/php-fpm.d/www.conf #在最后面增加下面两行
request_slowlog_timeout = 2 //请求执行时间超出2秒钟的日志
slowlog = /usr/local/php-fpm/var/log/www-slow.log //定义慢执行日志的位置
定义完后检测并重载配置使其生效
/usr/local/php-fpm/sbin/php-fpm -t
/etc/init.d/php-fpm reload
在pool对应的站点中编写PHP测试脚本,故意使其执行慢
vim /data/wwwroot/test.com/sleep.php
<?php echo
"test slow log";
sleep(2);
echo "done";
?>
效果测试
[root@lnmp-server conf]# curl -x127.0.0.1:80 test.com/sleep.php
test slow logdone[root@lnmp-server conf]# cat /usr/local/php-fpm/var/log/www-slow.log
[10-Jul-2018 15:25:39] [pool www] pid 1107
script_filename = /data/wwwroot/test.com/sleep.php //执行时间超过设置时间(2秒)的“慢脚本”的名称
[0x00007f0f364cb280] sleep() /data/wwwroot/test.com/sleep.php:3 //该脚本具体哪一行执行的慢
正常PHP脚本的执行时间在1~2秒之间,因此设置超过两秒的脚本记录慢执行日志即可
12.23 open_basedir
open_basedir 的作用是限制php在指定的目录里活动。
在php.ini中修改会针对所有站点生效,具有一定局限性,因此可在不同的pool中进行配置,类似于在Apache中的虚拟主机配置文件中进行配置。 配置open_basedir
vim /usr/local/php-fpm/etc/php-fpm.d/www.conf//在最后面加入下面一行
php_admin_value[open_basedir]=/data/wwwroot/test.com:/tmp/ #不同的站点定义不同的网站根目录和活动目录
可以故意改错open_basedir的路径,并打开错误日志,查看效果 修改php.ini配置文件
vim /usr/local/php-fpm/etc/php.ini
关闭浏览器报错显示 在生产环境中,直接将网站服务器报错信息显示在服务器上是不安全的,往往是将错误日志记录在指定的日志文件中。在php.ini搜索关键字“display_errors"将其修改成Off
; Production Value: Off
; http://php.net/display-errors
display_errors = Off
打开错误日志(在php.ini搜索关键字“log_errors"将其修改成On)
; Production Value: On
; http://php.net/log-errors
log_errors = On
定义错误日志存放的路径(搜索关键字log_errors,并在下面定义一行)
;error_log = php_errors.log
; Log errors to syslog (Event Log on Windows).
;error_log = syslog
error_log =/usr/local/php-fpm/var/log/php_errors.log
定义日志级别(搜索关键字error_reporting)
; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
; Development Value: E_ALL
; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT
; http://php.net/error-reporting
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
创建错误日志对应路径文件,并赋予777权限
[root@lnmp-server conf]# touch /usr/local/php-fpm/var/log/php_errors.log
[root@lnmp-server conf]# chmod 777 /usr/local/php-fpm/var/log/php_errors.log
配置完后检测并重载
[root@lnmp-server conf]# /usr/local/php-fpm/sbin/php-fpm -t
[10-Jul-2018 15:47:15] NOTICE: configuration file /usr/local/php-fpm/etc/php-fpm.conf test is successful
[root@lnmp-server conf]# /etc/init.d/php-fpm reload
Reload service php-fpm done
12.24 php-fpm进程管理
pm = dynamic //表示进程以动态的形式启动,动态就是一开始为一个数值,根据需求再自动生成,服务器比较闲的时候还会去销毁,销毁到一定程度还有自动生成;根据下面的设置去进行设定“start_servers ”、“min_spare_servers ”、“max_spare_servers ”、“max_requests ”
pm 也可以设置成是 static ,也就是静态,一旦选择这个设置,下面的pm的各种设置只会有一个max_children生效