引言:原文链接http://www.mamicode.com/info-detail-1734969.html
任何一个七层的http负载均衡器,都应该具备一个功能:会话保持。会话保持是保证客户端对动态应用程序正确请求的基本要求。
还是那个被举烂了却最有说服力的例子:客户端A向服务端B请求将C商品加入它的账户购物车,加入成功后,服务端B会在某个缓存区域中记录下客户端A和它的商品C,这个缓存的内容就是session上下文环境。而识别客户端的方式一般是设置session ID(如PHPSESSID、JSESSIONID),并将其作为cookie的内容交给客户端。客户端A再次请求的时候(比如将购物车中的商品下订单)只要携带这个cookie,服务端B就可以从中获取到session ID并找到属于客户端A的缓存内容(商品C),也就可以继续执行下订单部分的代码。
假如这时使用负载均衡软件对客户端的请求进行负载,就必须要保证能将客户端A的请求再次引导到服务端B,而不能引导到服务端X、服务端Y,因为X、Y上并没有缓存和客户端A对应的session内容,也就无法为客户端A下订单。
因此,反向代理软件必须具备将客户端和服务端"绑定"的功能,也就是所谓的提供会话保持,让客户端A后续的请求一定转发到服务端B上。
这里讨论的对象是http的动态应用请求,它要求会话保持。更通用地,只要负载均衡软件负载的不是"无状态"的协议或服务,就应该提供会话保持能力,除非它是四层负载软件。
haproxy提供了3种实现会话保持的方式:
- (1).源地址hash;
- (2).设置cookie;
- (3).会话粘性表stick-table;
一、源地址hash(用户IP识别)
haroxy 将用户IP经过hash计算后 指定到固定的真实服务器上(类似于nginx 的IP hash 指令)。
缺陷——当后端一台服务器挂了以后会造成部分session丢失。
#配置指令:
backend SOURCE_srv
mode http
balance source
server app-node1 10.31.1.179:80 check port 80 inter 3000 rise 3 fall 3
server app-node2 10.31.1.191:80 check port 80 inter 3000 rise 3 fall 3
server app-node3 10.31.0.35:80 check port 80 inter 3000 rise 3 fall 3
二、cookie 识别
haproxy 将WEB服务端返回给客户端的cookie中插入haproxy中特定的字符串(或添加前缀)在后端的服务器COOKIE ID。
backend COOKIE_srv
mode http
cookie SERVERID insert indirectnocache
server app-node1 10.31.1.179:80 check port 80 cookie a inter 3000 rise 3 fall 3
server app-node2 10.31.1.191:80 check port 80 cookie b inter 3000 rise 3 fall 3
server app-node3 10.31.0.35:80 check port 80 cookie c inter 3000 rise 3 fall 3
cookie参数说明:
cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
1)[ rewrite | insert | prefix ] /*三者互斥,只能选一*/
rewrite //表示cookie由服务器生成并且haproxy会在其值中注入该服务器的标识符;此关键字不能在HTTP隧道模式下工作。
insert //表示如果客户端没有cookie信息且有权限访问服务器时,持久性cookie必须通过haproxy穿插在服务器的响应报文中。当服务器收到相同名称的cookie并且没有“preserve(保存)”选项时,将会移除之前已存的cookie信息。因此,insert可视作"rewrite"的升级版。cookie信息仅仅作为会话cookie且不会存到客户端的磁盘上。默认除非加了“indirect(间接)”选项,否则服务器端会看到客户端端发送的cookie信息。由于缓存的影响,最好加上“nocache”或“postonly”选项。
prefix //表示不依赖专用的cookie做持久性,而是依赖现成的。用在某些特殊的场景,如客户端不支持一个以上的cookie和应用程序需求它。每当服务器建立一个名为<name>的cookie时,它将以服务器的标识符和分隔符为前缀。来自于客户端的请求报文中的前缀将会被删除以便服务器端能识别出它所发出的cookie,由于请求和响应报文都被修改过,所以此模式不能工作在隧道模式中。且不能和“indirect”共用,否则服务器端更新的cookie将不会被发到客户端.
2)[ indirect ] //指定此选项时,将不会向客户端发送服务器已经处理过请求的且可用的cookie信息。如果服务器设置这样一个cookie本身,它将被删除,除非“保存”选项也设置。在“插入”模式下,将从发送给服务器的请求中删除cookie,使持久机制从应用程序的角度完全透明。
3)[ nocache ] //当客户端和haproxy间存在缓存时,使用此选项和insert搭配最好,以便确保如果一个cookie需要被插入时,可被缓存的响应会被标记成不可缓存。这很重要,举个例子:如果所有的持久cookie被添加到一个可缓存的主页上,之后所有的客户将从外部高速缓存读取页面并将共享相同的持久性cookie,会造成服务器阻塞。
在LB1上配置好HAProxy后,LB1将接受用户的所有请求。如果一个用户请求不包含任何cookie,那这个请求将被HAProxy转发到一台可用的WEB服务器。可能是webA,webB,webC或webD。然后HAProxy将把处理这个请求的WEB服务器的cookie值插入到请求响应中。如SERVERID=A。当这个客户端再次访问并在HTTP请求头中带有SERVERID=A,HAProxy将会把它的请求直接转发给webA处理。在请求到达webA之前,cookie将被移除,webA将不会看到这个cookie。如果webA不可用,对应的请求将被转发到其他可用的WEB服务器,相应的cookie值也将被重新设置。
三、基于session
haproxy 将后端服务器产生的session和后端服务器标识存在haproxy中的一张表里。客户端请求时先查询这张表。
配置参数:appsession JSESSIONID len 64 timeout 5h request-learn
backend APPSESSION_srv
mode http
appsession JSESSIONID len 64 timeout 5h request-learn
server REALsrv_70 184.82.239.70:80 cookie 11 check inter 1500 rise 3 fall 3 weight 1
server REALsrv_120 220.162.237.120:80 cookie 12 check inter 1500 rise 3 fall 3 weight 1
注意使用事项;
(1).如果客户端使用HTTP1.1(keep-alive),只有第一个响应才会被插入cookie,并且HAProxy只会分析每个session的第一个请求。在使用cookie的插入模式下,可能不会造成什么问题,因为HAProxy会立即在第一个响应中插入cookie,同一个session中的所有请求将被转发到同一台服务器上。但是,到达服务器端的请求中的cookie不会被删除,所以这要求后端服务器对来历不明的cookie不作敏感处理。如果不想引起其他的问题,可以使用以下参数关掉keep-alive
option httpclose
(2).由于一些原因,一些客户端不能识别多个cookie,并且后端应用已经设置了cookie,如果HAProxy再对响应插入cookie后,这些客户端可能不能识别cookie。这种情况下,可以使用cookie的prefix模式。
(3).LB1成为整个架构中的瓶颈,如果LB1不可用,那么客户端的所有请求都得不到响应。可以使用Keepalived配置HAProxy解决LB1单点故障的问题。
(4).在以上配置中后端服务器是看不到客户端的真实IP地址的。可以使用 forwardfor 参数,它能够在客户端的请求头中增加 X-Forwarded-For 字段。同时需要配置使用 httpclose 参数,确保每个请求都被重写,而不只是第一个请求被重写。
option httpclose
option forwardfor
后端WEB服务器上的Nginx的日志格式需要增加$http_x_forwarded_for 变量;
log_format main ‘$remote_addr - $remote_user [$time_local] "$request" ‘
‘$status $body_bytes_sent "$http_referer" ‘
‘"$http_user_agent" "$http_x_forwarded_for"‘;
(5).在有些情况下,一些用户会将他们的浏览器的cookie功能关闭。这时候可能没法访问WEB服务器的内容。这种情况下,可以使用HAProxy的 source 负载均衡算法替代 roundroubin算法。source 算法可以确保来自同一个IP的所有请求都到达同一台WEB服务器,但是前提是,可用的服务器的数量保持不变。
(6).不要在一个小型网络和代理服务器后面使用source 算法,因为请求分发会不太公平,但是在大型内部网络或互联网上使用source算法,转发效率很好。对于那些具有动态IP地址的客户端,只要它们能够接收cookie,那么请求转发就不会受到影响,因为HAProxy对cookie的处理具有较高优先级。
本文非原创,转载请注明原文链接!