Day59-Nginx反向代理与负载均衡算法精讲及会话保持精讲
- 7.nginx负载均衡调度算法
- 7.1 什么是nginx负载均衡调度算法
- 7.2 nginx负载均衡调度算法有哪些。
- 8.负载均衡后端的会话保持
- 8.1 nginx负载均衡会话(session)保持
- 8.2 负载均衡集群会话保持
- 8.3 实践共享会话保持
7.nginx负载均衡调度算法
7.1 什么是nginx负载均衡调度算法
集群节点有多个,怎么分发请求到不同的节点。
7.2 nginx负载均衡调度算法有哪些。
调度算法一般分为两类:
第一类为静态调度算法,
即负载均衡器根据自身设定的规则进行分配,不需要考虑后端节点服务器情况,
例如:rr、wrr、ip_hash都属于静态调度算法。
第二类为动态调度算法,
即负载均衡器会根据后端节点的当前状态来决定是否分发请求,
例如:连接数少的优先获得请求,响应时间短的优先获得请求。
例如:least_conn、fair等都属于动态调度算法。
3个静态调度算法:
rr:轮询调度,根据请求,均匀分配给资源池各个应用节点
作用:平均分配每个请求到不同节点,特点用于配置相同的服务器。
wrr:加权轮询,根据节点的权重比来调度
作用:解决对配置不同的服务器可以获得不同的调度比例。
ip_hash:根据hash算法计算出最合适的一台A节点处理请求,后续该IP再次请求,还是对应的A节点处理。
hash(客户端IP)/3=0,1,2 当客户端IP不变的时候,请求都会被调度到同一个节点。
实践:当增加节点后,哪怕是down的设置,都会改变请求的服务器。
作用:解决集群的会话保持的问题。
弊端:会导致后端某一个应用节点压力过大,而其他节点没有流量。
问题:调度到的节点故障怎么办?
切换其他可用的节点,故障节点恢复了,则继续调度到该节点。
完美解决方案:
既想使用轮询负载算法,又想解决会话保持的问题,
又不想某个单个节点压力过大,其他空闲:
采用redis缓存,存储所有节点服务器产生的session会话信息。
默认:
[root@web01 conf.d]# ls /var/lib/php/session/
sess_67d11aac46ad07cdd20faf23f2f6ed16
url_hash:和ip_hash类似,这里是根据访问URL的hash结果来分配请求的,让每个URL定向到同一个后端服务器,后端服务器为缓存服务器时效果显著。
Nginx本身不支持url_hash,这种调度算法必须安装Nginx的hash模块软件包。
hash(客户端URL)/3=0,1,2 当客户端URL不变的时候,请求都会被调度到同一个节点。
作用:主要用于缓存服务集群
问题:节点宕机或增加节点,容易出现缓存数据大面积动荡。一致性hash算法。
upstream oldboy_lb {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}
consistent_hash
一致性HASH算法:一般用于代理后端业务为缓存服务(squid,memcached)的场景,通过将用户请求的URI或者指定字符串进行计算,然后调度到后端的服务器上,此后任何用户查找同一个URI或者指定字符串都会被调度到这一台服务器上,
因此后端的每个节点缓存的内容都是不同的,一致性HASH算法可以解决后端某个或几个节点宕机后,
缓存的数据动荡的最小
具体算法,将每个server虚拟成n个节点,均匀分布到hash环上,每次请求,根据配置的参数计算出一个hash值,在hash环
上查找离这个hash最近的虚拟节点,对应的server作为该次请求的后端机器。
该模块可以根据配置参数采取不同的方式将请求均匀映射到后端机器,比如:
consistent_hash $remote_addr: # 可以根据客户端ip映射
consistent_hash $request_uri: # 根据客户端请求的uri映射
consistent_hash $args: # 根据客户端携带的参数进行映射
虽然Nginx本身不支持一致性HASH算法,但Nginx的分支tengine支持。详细可见
链接: http://tengine.taobao.org/document_cn/http_upstream_consistent_hash_cn.html
http {
upstream test {
consistent_hash $request_uri;
server 127.0.0.1:9001 id=1001 weight=3;
server 127.0.0.1:9002 id=1002 weight=10;
server 127.0.0.1:9003 id=1003 weight=20;
}
}
3.consistent hashing算法的原理
Consistent hashing是一种hash算法,简单的说,在移除或添加一个cache节点时,能够尽可能小的改变已存在的key的映射关系,尽可能的满足单调性的要求。
单调性:
为什么要讲?
least_conn(动态调度算法)
least_conn算法会根据后端节点的连接数来决定分配情况,哪个机器连接数少就分发。
除了上面介绍的这些算法外,还有一些第三方的调度算法,例如:url_hash、一致性
fair(动态调度算法)
此算法会根据后端节点服务器的响应时间来分配请求,响应时间短的优先分配。这是更加智能的调度算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身是不支持fair调度算法的,如果需要使用这种调度算法,必须下载Nginx的相关模块
8.负载均衡后端的会话保持
8.1 nginx负载均衡会话(session)保持
会话技术
1)什么是会话?
Http协议是无状态的协议,在网络传输中的每次连接断开后,需要重新再去连接,因此服务器端是无法判断此次连接的客户端是谁。如果每次数据传输都需要进行连接和断开,那造成的开销是很巨大的。并且网站有会员和非会员区别,同时,有浏览网站和登录账户购物等需求,因此就需要一种方法区别不同访问的用户是谁,于是会话就应运而生。会话实现有cookie和session。
2)什么是cookie?
为了解决网络访问的用户是谁的问题,因此cookie应运而生,当用户登陆成功后,服务器会在返回响应数据的同时也携带着cookie信息给到客户端浏览器,之后客户端每次发起请求只要携带着这个cookie信息,服务端就会验证这个cookie信息,进而判断用户是谁,用户则会处于登录的状态,无需再登录,同时也改善了网络传输效率。
但是由于cookie是保存在客户端浏览器的数据,因此也很容易被获取,存在安全方面隐患。
3)什么是session?
session本质是通过以cookie的方式向客户端发送随机字符串,每次客户端发起请求时只要携带
该随机字符串便可被服务端获取进而验证用户登录的身份。session的实现依赖于cookie。
session信息是保存在服务端的数据。
用户请求整个session过程的基本原理。
- 用户发出登录请求。
- 服务端判断用户账户密码是否正确
- 如正确,则返回数据并在cookie中写随机字符串(session ID),并且在服务端以{随机字符串:{‘k’:‘v’}}的形式存储用户相关数据。
- 客户端接收服务端在cookie中写随机字符串(session ID),并且保留在浏览器本地。
- 下次同一个客户发送请求,携带cookie(包含session ID)信息在请求报文里。
- 服务端会判断客户端提交的cookie信息是否包含session ID,如有再去服务器中查询该session ID 是否有对应的session数据,如果有则说明是登录过的用户,返回请求的数据。
4)cookie和session区别?
会话 | cookie | session |
---|---|---|
存放位置 | 客户端浏览器里 | 服务器端(文件、数据库、Redis) |
作用 | 可存放服务器端下发的信息,用户、密码、session id信息等 | 存放用户登录信息,用户、密码、session id、购物车信息等 |
安全性 | 不安全,容易被伪造,出现过很多安全的问题 | 安全,不容易被伪造 |
生产应用 | 其他信息可以放在cookie中 | 登录信息等重要信息存放为session |
客户端解决会话保持问题 | 服务端解决会话保持问题 |
8.2 负载均衡集群会话保持
1)什么是会话保持
会话保持是运行负载均衡集群时需要的一种机制,在负载均衡的同时还保证一系列相关连的访问请求都会分配到同一台机器上。一句话说明就是在一次会话过程中发起的多个请求都会落到同一台机器上。
2)为什么需要会话保持
负载均衡集群后面有多个节点,如果一个用户的多次请求被分配到多个不同节点,就会导致用户登录了网站后(假如分配到A节点),然后在点击进入其它页面后,就会出现未登录状态的问题,这显然是不行的。
3)会话保持的实现方法
1.基于原地址实现:
即使用nginx ip_hash的调度算法,将同一用户的请求始终分配至同一服务器上。
优点:实现简单。缺点:导致负载失衡(特别是NAT上网的情况下)。
2.基于连接超时实现:
负载均衡器会为每一个处于保持状态中的会话设定一个时间值。若一个会话从上一次完成到下次再来之间的间隔时间小于超时值时,负载均衡器将会将新的连接进行会话保持;但如果这个间隔大于该超时值,负载均衡器会将新来的连接认为是新的会话然后进行负载平衡。lvs -p功能。
优点:实现简单。缺点:也会导致负载有一定的失衡,仅LVS等少数软件支持。
3.利用session复制:
即采用复制的方法,当产生session时,同步复制到所有集群节点,tomcat集群功能。
4.把session共享(重要普遍):
即采用将session集中存储到某一固定地点:
a.文件中存放(PHP服务默认)。b.数据库中存放即采用将session存储至MySQL数据库中(例如:discuz论坛)c.内存数据库(memcache,redis)中存放(推荐)
即采用统一的内存数据库存储方式,将session存储到redis,memcached中。中小企业推荐使用内存数据库实现。
优点:速度快。缺点:需要配置内存数据库,并且要配置动态服务配置文件。
链接: https://blog.51cto.com/oldboy/1331316
5.cookie插入方式实现
在基于cookie模式下负载均衡器负责插入cookie,后端服务器无需作出任何修改。当客户端进行第一次请求时,客户端的HTTP request(不带cookie)进入负载均衡器, CLB根据负载平衡算法策略选择后端一台服务器,并将请求发送至该服务器;后端服务器的HTTP response(不带cookie)被发回给负载均衡器。接下来负载均衡器将向该后端服务器插入cookie并将HTTP response返回到客户端。
当客户请求再次发生时,客户HTTP request(带有上次负载均衡器插入的cookie)进入CLB,然后CLB读出cookie里的会话保持数值,将HTTP request(带有与上面同样的cookie)发到指定的服务器,然后后端服务器进行请求回复;由于服务器并不写入cookie,HTTP response将不带cookie,该HTTP response再次经过进入CLB时,CLB将写入更新后的会话保持cookie。腾讯云CLB的7层会话保持能力,就是基于这样的cookie插入的方式实现的。Haproxy也支持cookie插入的方式,但是Nginx默认不支持此种方式。
优点:不需要后端服务和程序支持,只在负载均衡器配置即可(需要负载均衡器支持)。缺点:消耗负载均衡资源
8.3 实践共享会话保持
1)环境准备:
负载均衡: 10.0.0.5
web集群: 10.0.0.7/10.0.0.8
Redis: 10.0.0.51
项目: phpmyadmin
部署顺序:
1. 部署多个节点
2. 接入负载均衡
2)搭建环境(Nginx+php):
3)运行phpmyadmin项目作为测试环境(MySQL数据库的web管理界面,通过web页面的方式管理数据库):
1)部署web01及安装phpmyadmin
笔记已发
[root@web01 ~]# cat /etc/nginx/conf.d/phpmyadmin.etiantian.org.conf
server {
listen 80;
server_name phpmyadmin.etiantian.org;
root /data/phpmyadmin;
index index.php index.html;
location ~ \.php$ {
root /data/phpmyadmin;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
#用户名密码验证
#auth_basic "oldboyedu Auth access";
#auth_basic_user_file /etc/nginx/auth_pass;
#来源IP限制
#allow 172.16.1.0/24; #允许指定的地址或地址段
#deny all; #拒绝所有的地址
}
2)部署web02:
web01:
scp phpmyadmin.etiantian.org.conf 172.16.1.8:/etc/nginx/conf.d
scp -r /data/phpmyadmin 172.16.1.8:/data
web02:
chown -R www.www /data/phpmyadmin/
chown -R www.www /var/opt/remi/php74/lib/php/session #浏览器打开phpmyadmin前可能没有
#htpasswd -cb /etc/nginx/auth_pass oldboy 123456
windows配置host解析
10.0.0.8 phpmyadmin.etiantian.org
浏览器浏览phpmyadmin.etiantian.org
3)部署lb01
phpmyadmin.etiantian.org虚拟主机反向代理lb01配置
[root@lb01 conf.d]# cat /etc/nginx/conf.d/01_test.etiantian.org.conf
upstream backend {
#server backend1.example.com weight=5;
#server backend2.example.com:8080;
#server unix:/tmp/backend3;
server 172.16.1.7 weight=1 ; #默认80端口
server 172.16.1.8 weight=1; #默认80端口
#server 8080.etiantian.org:8080 down;
#server 8080.etiantian.org:8080 backup; #热备
#server backup2.example.com:8080 backup; #热备
}
server {
listen 80;
server_name test.etiantian.org;
location / {
proxy_pass http://backend;
#proxy_pass http://a.etiantian.org:80;
proxy_set_header Host $http_host;
}
}
server {
listen 80;
server_name phpmyadmin.etiantian.org;
location / {
proxy_pass http://backend;
proxy_set_header Host $http_host;
}
}
4)测试浏览器打开phpmyadmin.etiantian.org
登录到数据库,然后刷新感受请求到不同节点后,出现未登录状态。
可以通过谷歌f12查看请求报文和响应报文。
5)登录172.16.1.51部署redis缓存
采用Redis共享方式来实现会话保持:
0.查看php redis访问支持
[root@web01 ~]# rpm -qa|grep redis
php71w-pecl-redis-3.1.6-1.w7.x86_64
1.安装配置redis 10.0.0.51
[root@db01 ~]# yum install redis -y
[root@db01 ~]# sed -i '/^bind/c bind 127.0.0.1 172.16.1.51' /etc/redis.conf
[root@db01 ~]# grep "^bind" /etc/redis.conf
bind 127.0.0.1 172.16.1.51
[root@db01 ~]# systemctl start redis
[root@db01 ~]# systemctl enable redis
[root@db01 ~]# netstat -lntup|grep redis
tcp 0 0 172.16.1.51:6379 0.0.0.0:* LISTEN 2055/redis-server 1
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 2055/redis-server 1
#查看redis中的数据:
[root@db01 ~]# redis-cli
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379>
2.分别将web01,web02的php应用服务器的session信息、修改存储至Redis中(/etc/php.ini)
[root@web01 ~]# vim /etc/php.ini
session.save_handler = redis
session.save_path = "tcp://172.16.1.51:6379?weight=1&timeout=2.5"
#Redis有密码的配置方法
session.save_path = "tcp://172.16.1.51:6379?auth=oldboy123"
#使用;注释如下两行,
[root@web01 ~]# vim /etc/php-fpm.d/www.conf
;php_value[session.save_handler] = files
;php_value[session.save_path] = /var/lib/php/session
重启php-fpm
[root@web01 ~]# systemctl restart php-fpm
注意;web02的特殊,大家可以自己跟web01一样配置
老师的web02安装的是php74,注意路径:
采用方法2:子配置的方法
[root@web02 ~]# cat /etc/opt/remi/php74/php.d/50-redis.ini
session.save_handler = redis
session.save_path = "tcp://db01.etiantian.org:6379?weight=1"
#使用;注释如下两行,
vim /etc/opt/remi/php74/php.ini
session.save_handler = file
session.save_path = "/tmp"
#使用;注释如下两行,
[root@web01 ~]# vim /etc/opt/remi/php74/php-fpm.d/www.conf
;php_value[session.save_handler] = files
;php_value[session.save_path] = /var/lib/php/session
systemctl restart php74-php-fpm.service
3.测试访问
将lb01负载均衡调度修改为默认轮询的方式测试。
检查是不是登录后依然是登录状态。
采用谷歌f12查看本地cookie,同时查看请求报文和响应报文,
看和讲解的session工作原理流程是否一致。
同时,查看redis中是否有session数据。
127.0.0.1:6379> keys *
1) "PHPREDIS_SESSION:5908fd411a39c1149a9db18332830cee"
2) "PHPREDIS_SESSION:be6bb9c370f83cdd5f7c41ac11b96404"
3) "PHPREDIS_SESSION:77bfa030697cc2660fb9000f3553ee85"
127.0.0.1:6379> keys *
1) "PHPREDIS_SESSION:5908fd411a39c1149a9db18332830cee"
2) "PHPREDIS_SESSION:be6bb9c370f83cdd5f7c41ac11b96404"
3) "PHPREDIS_SESSION:77bfa030697cc2660fb9000f3553ee85"
127.0.0.1:6379> keys *
1) "PHPREDIS_SESSION:fa5a092ae9b53f071c5942e18f81d83a"
2) "PHPREDIS_SESSION:be6bb9c370f83cdd5f7c41ac11b96404"
3) "PHPREDIS_SESSION:77bfa030697cc2660fb9000f3553ee85"
127.0.0.1:6379> keys *
1) "PHPREDIS_SESSION:7eff395a4c057891e3bbb03d5ca1ffc9"
2) "PHPREDIS_SESSION:be6bb9c370f83cdd5f7c41ac11b96404"
3) "PHPREDIS_SESSION:77bfa030697cc2660fb9000f3553ee85"
127.0.0.1:6379>