17.proxy优化模块与Nginx负载均衡后端状态
算法名称 | 简称 | 概述 |
---|---|---|
轮询(默认) | round-robin(RR) | 按照时间顺序逐一分配到后端不同的服务器 |
weight | weight-round-robin(WRR) | 加权轮询,weight值越大,分配到的访问几率越高 |
ip_hash | ip_hash | 每个请求按访问IP的hash结果分配,这样来自同一IP的固定访问一个后端服务 |
url_hash | url_hash | 按照访问URL的hash结果来分配请求,是每个URL定向到同一个后端服务器 |
least_conn | least_conn | 最少链接数,那个机器链接数少就分发 |
proxy优化模块
[ ~]# vim /etc/nginx/proxy_params proxy_set_header Host $http_host; # 请求头带上的域名 proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 客户端真实IP # nginx代理与后端服务器连 proxy_connect_timeout 30; # nginx代理等待后端服务器的响应时间 proxy_send_timeout 60; # 后端服务器数据回传给nginx代理超时时间 proxy_read_timeout 60; ## 优化缓冲区 proxy_buffering on; proxy_buffer_size 32k; proxy_buffers 4 128k; # 解决负载均衡常见典型故障 proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
轮询
upstream zh_lb { server 10.0.0.7; # 依次分配请求 server 10.0.0.8; } server { listen 80; server_name zh.com; location / { proxy_pass http://zh_lb; include proxy_params; # 包含的优化 } }
加权轮询
upstream zh_lb { server 10.0.0.7 weight=6; # 按照6:1来分配请求 server 10.0.0.8 weight=1; } server { listen 80; server_name zh.com; location / { proxy_pass http://zh_lb; include proxy_params; }
ip_hash
具体配置不能和weight一起使用。
# 如果客户端都走相同代理, 会导致某一台服务器连接过多 upstream zh_lb { ip_hash; server 10.0.0.7; # 固定访问服务器 server 10.0.0.8; } server { listen 80; server_name zh.com; location / { proxy_pass http://zh_lb; include proxy_params; } }
url_hash 具体配置
# 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,要配合缓存命中来使用。同一个 资源多次请求,可能会到达不同的服务器上,导致不必要的多次下载,缓存命中率不高,以及一些资源时间的 浪费。而使用url_hash,可以使得同一个url(也就是同一个资源请求)会到达同一台服务器,一旦缓存住 了资源,再此收到请求,就可以从缓存中读取。 upstream load_pass { hash $request_uri;#实现每个url定向到同一个后端服务器 server 10.0.0.7:80; server 10.0.0.8:80; server 10.0.0.9:80; }
least_conn 最少链接数
# 把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相 同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就 可以达到更好的负载均衡效果。 upstream load_pass { least_conn; server 10.0.0.7:80; server 10.0.0.8:80; server 10.0.0.9:80; }
面试问题
面试官:请问贵公司会话保持(session共享)是怎么做的?
我们从开发层面上实现
记录用户的登录状态,将登录状态保存到我们的redis服务器中(更倾向),nfs共享存储,MySQL数据库我们从运维层面上实现
因为开发没有写会话保持的功能,所以我们只能在nginx中使用upstream模块的ip_hash调度算法,但是
这个算法,可能会负载不均衡,有弊端...什么是session?
什么是cookie?
1.cookie是客户端浏览网站的的时候,把客户端信息以某种形式记录在浏览器上。
2.session是客户端浏览服务端的时候,服务端把客户端信息以某种形式记录在服务器上,这种记录就是Session,用来保护cookie
Nginx负载均衡后端状态
状态 | 概述 |
---|---|
down | 当前的server暂时不参与负载均衡(和注释一样) |
backup | 预留的备份服务器(当所有机器挂了的时候就会使用) |
max_fails | 允许请求失败的次数 |
fail_timeout | 经过max_fails失败后, 服务暂停时间 |
max_conns | 限制最大的接收连接数 |
环境准备
角色 | 服务器web |
---|---|
down | web01 |
backup | web02 |
max_fails,fail_timeout,max_conns | web03 |
负载均衡 | lb01 |
web01 down了
[ ~]# vim /etc/nginx/conf.d/wp_lb.conf upstream backend { server 10.0.0.7 down; server 10.0.0.8; server 10.0.0.9; } server { listen 80; server_name www.wp.com; location / { proxy_pass http://backend; include proxy_params; } } [ ~]# nginx -s reload
web02 做backup
[ ~]# vim /etc/nginx/conf.d/wp_lb.conf upstream backend { server 10.0.0.7 down; server 10.0.0.8 backup; server 10.0.0.9; } server { listen 80; server_name www.wp.com; location / { proxy_pass http://backend; include proxy_params; } } [ ~]# nginx -s reload
web03,请求失败后暂停时间max_fails,fail_timeout
# 允许请求失败的次数,经过max_fails次失败后, 服务暂停时间fail_timeout。 # 需要配合proxy_next_upstream error timeout http_500 http_502 http_503 http_504 http_404 http_403; [ ~]# vim /etc/nginx/conf.d/wp_lb.conf upstream backend { server 10.0.0.7 down; server 10.0.0.8 backup; server 10.0.0.9 max_fails=1 fail_timeout=5s; } server { listen 80; server_name www.wp.com; location / { proxy_pass http://backend; include proxy_params; proxy_next_upstream error timeout http_500 http_502 http_503 http_504 http_404 http_403; } } [ ~]# nginx -s reload
max_conns,接收连接数
upstream backend { server 10.0.0.7; server 10.0.0.8; # 限制最大的接收连接数 server 10.0.0.9 max_conns=1; } ...
Nginx负载均衡会话保持
在使用负载均衡的时候会遇到会话保持的问题,可通过如下方式进行解决。
1.使用nginx的ip_hash
,根据客户端的IP,将请求分配到对应的IP上
2.基于服务端的session
会话共享(NFS,MySQL,memcache,redis,file)
在解决负载均衡绘画问题,我们需要了解session
和cookie
的区别。
浏览器端存的是cookie
每次浏览器发请求到服务端时,报文头是会自动添加cookie
信息的。
服务端会查询用户的cookie
作为key去存储里找对应的value(session)
同一域名下的网站的cookie
都是一样的,所以无论几台服务器,无论请求分配到哪一台服务器上同一用户的cookie
是不变的。也就是说cookie
对应的session
也是唯一的。所以,这里只要保证多台业务服务器访问同一个共享存储服务器(NFS,MySQL,memcache,redis,file)就行了。
1.编辑配置文件
[ ~]# vim /etc/nginx/conf.d/myadmin.conf server { listen 80; server_name admin.com; root /code/phpMyAdmin-4.9.0.1-all-languages; index index.php index.html; access_log /var/log/nginx/admin_access.log main; location ~\.php$ { root /code/phpMyAdmin-4.9.0.1-all-languages; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } [ ~]# nginx -s reload
2.上传安装phpmyadmin(web02也装)
# 1.创建配置文件 [ ~]# mkdir /code # 2.上传解压安装 [ ~]# cd /code [ /code]# rz [ /code]# unzip phpMyAdmin-4.9.0.1-all-languages_(1).zip # 3.放到站点目录下 [ ~]# mv phpMyAdmin-4.9.0.1-all-languages /code/ # 4.授权站点目录 [ ~]# chown -R www.www /code/ # 5.修改代码 [ ~]# cd /code/phpMyAdmin-4.9.0.1-all-languages/ [ /code/phpMyAdmin-4.9.0.1-all-languages]# cp config.sample.inc.php config.inc.php [ /code/phpMyAdmin-4.9.0.1-all-languages]# vim config.inc.php ... /* Server parameters */ # 修改数据库ip $cfg[‘Servers‘][$i][‘host‘] = ‘172.16.1.51‘; ... # 6.配置授权 [ ~]# chown -R www.www /var/lib/php/
3.打开浏览器
admin.com
1.填写昨天用数据库创建的登入账号和密码
2.执行后打开页面
4.将web01上配置好的phpmyadmin以及nginx的配置文件推送到web02主机上
[ ~]# scp -rp /code/phpMyAdmin-4.9.0.1-all-languages 172.16.1.8:/code/ [ ~]# scp /etc/nginx/conf.d/myadmin.conf 172.16.1.8:/etc/nginx/conf.d/
5.授权
[ ~]# chown www.www -R /code/ [ ~]# chown -R www.www /var/lib/php/
6.接入负载均衡
[ conf.d]# vim proxy_php.com.conf upstream shuju { server 10.0.0.7; server 10.0.0.8; server 10.0.0.9; } server { listen 80; server_name admin.com; location / { proxy_pass http://shuju; include proxy_params; } } # 检查语法 [ conf.d]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful # 重新加载 [ conf.d]# systemctl restart nginx
使用负载均衡的轮询功能之后,会发现,如果将session保存在本地文件的话,永远都登录不上去,下面使用redis解决会话登入问题
7.使用redis解决会话登录问题
在数据库的主机上安装redis
# 1.安装redis [ ~]# yum install redis -y # 2.配置redis监听在172.16.1.0网段上 # 修改redis的配置文件 [ ~]# sed -i ‘/^bind/c bind 127.0.0.1 172.16.1.51‘ /etc/redis.conf # 3.启动redis [ ~]# systemctl start redis [ ~]# systemctl enable redis # 4.php配置session连接redis # 4.1修改/etc/php.ini文件 [ ~]# vim /etc/php.ini ... session.save_handler = redis ... session.save_path = "tcp://172.16.1.51:6379" ;session.save_path = "tcp://172.16.1.51:6379?auth=123" #如果redis存在密码,则使用该方式 ... session.auto_start = 1 ... #5.注释php-fpm.d/www.conf里面的两条内容,否则session内容会一直写入/var/lib/php/session目录中 ... ;php_value[session.save_handler] = files ;php_value[session.save_path] = /var/lib/php/session # 6.重启php-fpm [ ~]# systemctl restart php-fpm # 7.将web01上配置好的文件推送到web02 [ ~]# scp /etc/php.ini :/etc/php.ini [ ~]# scp /etc/php-fpm.d/www.conf :/etc/php-fpm.d/ # 8.上web02上重启php-fpm [ code]# systemctl restart php-fpm # 9. redis查看数据 [ redis]# redis-cli 127.0.0.1:6379> keys * 1) "PHPREDIS_SESSION:3c17869121aa396a4c5f47708ec53d0b" 2) "PHPREDIS_SESSION:69835e2371529a213edd566a5f065f9f"
看图