lnmp架构(七)——nginx-sticky-module+tomcat实现负载均衡中的会话保持

一、会话保持

会话保持,有时又可叫做 粘滞会话(Sticky Sessions)。

  • 会话保持是指:在负载均衡器上的一种机制,可以识别客户端与服务器之间交互过程的关连性,在作负载均衡的同时还保证一系列相关连的访问请求都会分配到一台机器上。 通俗讲就是,在一次会话过程中发起的多个请求都会落到同一台机器上。

概念:cookie和session(本篇以cookie为例)

cookie

  • 在网站中,http请求是无状态的。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题,第一次登录后服务器返回一些数据( cookie )给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把.上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。

客户端向服务器发起请求,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。

打个比方,我们去银行办理储蓄业务,第一次给你办了张银行卡,里面存放了身份证、密码、手机等个人信息。当你下次再来这个银行时,银行机器能识别你的卡,从而能够直接办理业务。

  • cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小的数据,由一个名称(Name)、一个值(Value)和其它几个用于控制Cookie有效期、安全性、使用范围的可选属性组成。。

在 Web认证中 ,因为HTTP协议本身的局限,必须采用其他技术将相关认证标记以某种方式持续传送,以免客户从一个页面跳转至另一个页面时重新输入认证信息 [5] 。基于Cookie的认证过程,主要由以下三个阶段组成:

(1)发布Cookie。当用户试图访问某Web站点中需要认证的资源时,Web服务器会检查用户是否提供了认证Cookie,如果没有,则将用户重定向到登录页面。在用户成功登录后,Web服务器会产生认证Cookie,并通过HTTP响应中的Set-Cookie头发送给客户端,用于对用户随后的请求进行检查和验证,接着将用户重定向到初始请求的资源 [5] 。

(2)检索Cookie。在用户随后的访问请求中,客户端浏览器检索Path和Domain等属性与用户请求资源相匹配的Cookie,并将找到的Cookie通过HTTP请求中的Cookie头提交给Web服务器 [5] 。

(3)验证CookieWeb服务器提取客户端浏览器递交的Cookie,验证其中的访问令牌。若合法,则将访问请求的资源发送给客户端浏览器;反之则拒绝用户的访问请求。Cookie 认证技术简化了用户访问 Web 网站资源的过程,即用户只需在初次登录网站时输入身份信息进行认证,随后便可以访问被授权的所有站点资源,不再需要重复手工提交身份信息 [5] 。

session

session和cookie的作用有点类似,都是为了存储用户相关的信息。不同的是,cookie是存储在本地浏览器,而session存储在服务器。存储在服务器的数据会更加的安全,不容易被窃取。但存储在服务器也有一定的弊端,就是会占用服务器的资源,但现在服务器已经发展至今,一些session信息还是绰绰有余的。

使用方法

Session 是 用于保持状态的基于Web服务器的方法。Session允许通过将对象存储在Web服务器的内存中在整个用户会话过程中保持任何对象。

Session通常用于执行以下操作

存储需要在整个用户会话过程中保持其状态的信息,例如登录信息或用户浏览Web应用程序时需要的其它信息。
存储只需要在页面重新加载过程中或按功能分组的一组页之间保持其状态的对象。
Session的作用就是它在Web服务器上保持用户的状态信息供在任何时间从任何设备上的页面进行访问。因为浏览器不需要存储任何这种信息,所以可以使用任何浏览器,即使是像Pad或手机这样的浏览器设备。

cookie和session结合使用

web开发发展至今,cookie和session的使用已经出现了一些非常成熟的方案。在如今的市场或者企业里,一般有两种存储方式:

  • 存储在服务端:通过cookie存储一个session_ id,然后具体的数据则是保存在session中。如果用户已经登录,则服务器会在cookie中保存一个session id,下次再次请求的时候,会把该session_ id携带上来,服务器根据session_ id在session库中获取用户的session数据。就能知道该用户到底是谁,以及之前保存的一些状态信息。这种专业术语叫做server side session。

  • 将session数据加密,然后存储在cookie中。这种专业术语叫做client side session。flask采用的就是这种方式,但是也可以替换成其他形式

1.1 会话(session)与连接(connection)之间的区别

连接: 我们都知道TCP/IP协议中经常提到的:”三次握手,四次挥手“的问题。自然也知道客户端和服务器端是经过三次握手以后,建立了连接(connection)。当它们建立了连接以后,那么客户端就可以向服务端发送多次的请求。如果客户端和服务器端需要断开连接,那么就需要经过四次的挥手过程才能够断开连接。

会话: 如果用户需要登录,那么可以理解为经过三次握手以后,客户端与服务器端建立的就是会话(session)。如果用户不需要登录,那么可以理解为经过三次握手以后,客户端与服务器端建立的就是连接(connection).

1.2 为什么要会话保持?

实际上,会话保持机制负载均衡的基本功能是完全矛盾的。

  • 负载均衡希望将来自客户端的连接、请求均衡的转发至后端的多台服务器,以避免单台服务器负载过高;
  • 会话保持机制却要求将某些请求转发至同一台服务器进行处理。

原始负载均衡的基本原理:

  • **对于同一个连接中的数据包,负载均衡会将其进行NAT转换后,转发至后端固定的服务器进行处理,这是负载均衡最基本、最原始的功能。**负载均衡系统内部会专门有一张表来记录这些连接的状况,包括:[源IP:端口]、[目的IP:端口]、[服务器IP:端口]、空闲超时时间(Idle Timeout)等等。

由于这张表需要消耗系统的内存资源,因此,这张表不可能无限大,所有厂家都会有一定的限制。这张表的大小一般称之为最大并发连接数,也就是系统同时能够容纳的连接数量。考虑到建立连接的客户端或服务器会发生异常状况,导致连接不能被正常终结掉,因此,负载均衡的当前连接状态表项中有一个空闲超时时间的参数。如果在规定的时间内某个连接不再有请求,那么这个连接就会被清除掉,释放系统资源。那么,删除连接以后,客户端的请求将无法继续发往同一个后端的服务器,那么就会导致数据丢失等等。

常见的异常场景包括:

  • 客户端输入了正确的用户名和密码,但却反复跳到登录页面;
  • 客户端放入购物篮的物品丢失;
  • 用户输入了正确的验证码,但是总提示验证码错误

因此,会话保持机制的意义就在于,确保将来自相同客户端的请求,转发至后端相同的服务器进行处理。如果在客户端和服务器之间部署了负载均衡设备,很有可能,这多个连接会被转发至不同的服务器进行处理。如果服务器之间没有会话信息的同步机制,会导致其他服务器无法识别用户身份,造成用户在和应用系统发生交互时出现异常。

1.3 会话保持在Nginx中的实现

1、ip_hash机制

  • ip_hash技术能够将 某个ip 的请求定向到同一台后端web机器中, 这样一来这个ip 下的客户端和某个后端web机器就能建立起稳固的session.
  • ip_hash技术能够让某一客户机在相当长的一段时间内只访问固定的后端的某台真实的web服务器,这样会话就会得以保持,在网站页面进行login的时候就不会在后面的web服务器之间跳来跳去了,也不会出现登录一次的网站又提醒重新登录的情况.

缺陷:

  • nginx不是最前端的服务器:当多个客户是通过 代理或地址转换 的方式来访问服务器时,由于都分配到同一台服务器上,会导致服务器之间的负载严重失衡。例如,使用的是squid反代为最前端.那么nginx取ip时只能得到squid的服务器ip地址,用这个地址来作分流肯定是不对的。
  • nginx的后端还有其它负载均衡:若nginx后端还有其它负载均衡,将请求又通过另外的方式分流了。

2、nginx-sticky-module这个第三方模块

Sticky是基于cookie的一种负载均衡解决方案,通过分发和识别cookie,使来自同一个客户端的请求落在同一台服务器上,换一种说法,服务器给客户端下发一个cookie,具有特定cookie的请求会分配给它的发行者,默认cookie标识名为route 。
工作原理

  1. 客户端首次发起访问请求,nginx接收后,发现请求头没有cookie,则以轮询方式将请求分发给后端服务器。
  2. 后端服务器处理完请求,将响应数据返回给nginx。
  3. 此时nginx生成带route的cookie,返回给客户端。route的值与后端服务器对应,可能是明文,也可能是md5、sha1等Hash值
  4. 客户端接收请求,并保存带route的cookie。
  5. 当客户端下一次发送请求时,会带上route,nginx根据接收到的cookie中的route值,转发给对应的后端服务器。

二、实现会话保持具体过程

在上一篇博客中,我们已经实现了负载均衡,但是遗留问题:新的数据覆盖旧的数据内容,造成数据的丢失,现在我们就来解决它。

这里通过在nginx中加入nginx-sticky-module模块来会话保持,
实验环境

主机(版本:ip) 功用
虚拟机server1(rhel6.5:172.25.2.1) lnmp环境主机+tomcat1服务器
虚拟机server2(rhel6.5:172.25.2.2) tomcat2服务器
真机(rhel7.3:172.25.2.250) 测试机

1、在nginx-1.14中不支持nginx-sticky-module模块,所以使用nginx-1.10版本,重新编译nginx

tar zxf nginx-1.10.1.tar.gz
tar zxf nginx-sticky-module-ng.tar.gz -C /usr/local/

在这里插入图片描述
2、注释掉debug日志,不显示nginx的版本号,把openresty的nginx关掉,否则会占用80端口,导致服务器起不来

/usr/local/openresty/nginx/sbin/nginx -s stop

在这里插入图片描述
3、重新编译,加入sticky模块,然后安装:

./configure  --prefix=/usr/local/lnmp/nginx  \
--with-http_ssl_module  \
--with-http_stub_status_module  \
--with-threads --with-file-aio  \
--user=nginx --group=nginx  \
--add-module=/mnt/nginx-sticky-module-ng

make && make install

在这里插入图片描述
编译完,我们可以查看是否加入了nginx-sticky-module
在这里插入图片描述
安装
在这里插入图片描述
4、编辑nginx配置文件,。

cd /usr/local/lnmp/nginx/conf/
vim nginx.conf

 17 http {
 18     include       mime.types;
 19     default_type  application/octet-stream;
 20         upstream tomcat {
 21                 server 172.25.2.1:8080;		#后端服务器
 22                 server 172.25.2.2:8080;		#后端服务器
 23 }

 47         location / {
 48             root   /usr/local/tomcat/webapps/ROOT;
 49             index  index.html index.htm;
 50         }


 63         location ~ \.jsp$ {
 64             proxy_pass   http://tomcat;
 65         }

nginx -t
nginx -s reload
不用的代码可以注释掉。 没有用ip_hash

在这里插入图片描述
在这里插入图片描述
5、创建软链接,并启动nginx。

[root@server1 nginx-1.10.1]# ln -s /usr/local/lnmp/nginx/sbin/nginx /sbin/
[root@server1 nginx-1.10.1]# nginx
[root@server1 nginx-1.10.1]# netstat -tnlp
nginx -t
nginx -s reload

在这里插入图片描述
6、server1删除原有测试页,再编辑新测试页test.jsp,并发送server2


[root@server1 conf]# cd /usr/local/tomcat/webapps/ROOT/
[root@server1 ROOT]#  rm -fr test.jsp 
[root@server1 ROOT]# vim test.jsp 

<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="java.util.*" %>
<html><head><title>Cluster App Test</title></head>
<body>
Server Info:
<%
out.println(request.getLocalAddr() + " : " + request.getLocalPort()+"<br>");%>
<%
out.println("<br> ID " + session.getId()+"<br>");
String dataName = request.getParameter("dataName");
if (dataName != null && dataName.length() > 0) {
String dataValue = request.getParameter("dataValue");
session.setAttribute(dataName, dataValue);
}
out.print("<b>Session list</b>");
Enumeration e = session.getAttributeNames();
while (e.hasMoreElements()) {
String name = (String)e.nextElement();
String value = session.getAttribute(name).toString();
out.println( name + " = " + value+"<br>");
System.out.println( name + " = " + value);
}
%>
<form action="test.jsp" method="POST">
name:<input type=text size=20 name="dataName">
<br>
key:<input type=text size=20 name="dataValue">
<br>
<input type=submit>
</form>
</body>
</html>
[root@server1 ROOT]# scp test.jsp server2:/usr/local/tomcat/webapps/ROOT/

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在server2上:
在这里插入图片描述
7.在server1和server2上都重启tomcat,并查看端口

  • tomcat的重启只能先关闭先开启
[root@server1 bin]# cd /usr/local/tomcat/bin/
[root@server1 bin]# ./shutdown.sh
[root@server1 bin]#  ./startup.sh 
[root@server1 bin]# netstat -tnlp

在这里插入图片描述
在这里插入图片描述
8、先清除缓存,访问测试页http://172.25.2.1/test.jsp
在这里插入图片描述
在这里插入图片描述

  • 注意:在企业里这两个页面是一样的,用户根本不知道访问的那个服务器,这里只是为了实验效果而区别开来,也可以使用以下代码做的测试页,可以更加明显:这与上一篇负载均衡博客编写的测试页面一样,都是·为了测试效果。

我们添加数据,发现数据不丢失,而且id号不改变,到此我们实现了会话保持。

9、此时,我们关闭tomcat1,再次访问测试页面,却发现server1上面的数据没有同步到server2

[root@server1 bin]# pwd
/usr/local/tomcat/bin
[root@server1 bin]# ./shutdown.sh 

在这里插入图片描述
在这里插入图片描述
我们可以看出,客户会一直访问同一台tomcat服务器,实现了会话保持,即使后台一台tomcat服务器宕机,切换到另外一台tomcat服务器上面依然可以实现会话保持,但是此时在第一个tomcat主机上面的数据丢失。
在下一篇博客中,我们解决此问题。

发布了184 篇原创文章 · 获赞 7 · 访问量 3620

猜你喜欢

转载自blog.csdn.net/weixin_43936969/article/details/104717928