2.2.4.2 解决应用服务器变为集群后的Session问题

先来看一下什么是Session。

用户使用网站的服务,基本上需要浏览器与Web 服务器的多次交互。HTTP 协议本身是无状态的,需要基于HTTP 协议支持会话状态(Session State)的机制。而这样的机制应该可以使Web 服务器从多次单独的HTTP 请求中看到“会话”,也就是知道哪些请求是来自哪个会话的。具体实现方式为:在会话开始时,分配一个唯一的会话标识(SessionId),通过Cookie 把这个标识告诉浏览器,以后每次请求的时候,浏览器都会带上这个会话标识来告诉Web 服务器请求是属于哪个会话的。在Web 服务器上,各个会话有独立的存储,保存不同会话的信息。如果遇到禁用Cookie 的情况,一般的做法就是把这个会话标识放到URL 的参数中。我们可以通过图2-8 来看一下上述过程。

当我们的应用服务器从一台变到两台后,如同图2-7 中的结构,我们就会遇到Session的问题了。具体是指什么问题呢?

我们来看图2-9,当一个带有会话标识的HTTP 请求到了Web 服务器后,需要在HTTP请求的处理过程中找到对应的会话数据(Session)。而问题就在于,会话数据是需要保存在单机上的。

在图2-9 所示的网站中,如果我第一次访问网站时请求落到了左边的服务器,那么我的Session 就创建在左边的服务器上了,如果我们不做处理,就不能保证接下来的请求每次都落在同一边的服务器上了,这就是Session 问题。

我们看看这个问题的几种解决方案。

1.Session Sticky

在单机的情况下,会话保存在单机上,请求也都是由这个机器处理,所以不会有问题。Web 服务器变成多台以后,如果保证同一个会话的请求都在同一个Web 服务器上处理,那么对这个会话的个体来说,与之前单机的情况是一样的。

如果要做到这样,就需要负载均衡器能够根据每次请求的会话标识来进行请求转发,如图2-10 所示,称为Session Sticky 方式。

这个方案本身非常简单,对于Web 服务器来说,该方案和单机的情况是一样的,只是我们在负载均衡器上做了“手脚”。这个方案可以让同样Session 的请求每次都发送到同一个服务器端处理,非常利于针对Session 进行服务器端本地的缓存。不过也带来了如下几个问题:

如果有一台Web 服务器宕机或者重启,那么这台机器上的会话数据会丢失。如如果会话中有登录状态数据,那么用户就要重新登录了。

会话标识是应用层的信息,那么负载均衡器要将同一个会话的请求都保存到同一个Web服务器上的话,就需要进行应用层(第7 层)的解析,这个开销比第4 层的交换要大。负载均衡器变为了一个有状态的节点,要将会话保存到具体Web 服务器的映射。和无状态的节点相比,内存消耗会更大,容灾方面会更麻烦。

这种方式我们称为Session Sticky。打个比方来说,如果说Web 服务器是我们每次吃饭的饭店,会话数据就是我们吃饭用的碗筷。要保证每次吃饭都用自己的碗筷的话,我就把餐具存在某一家,并且每次都去这家店吃,是个不错的主意。

2.Session Replication

如果我们继续以去饭店吃饭类比,那么除了前面的方式之外,如果我在每个店里都存放一套自己的餐具,不就可以更加自由地选择饭店了吗?Session Replication 就是这样的一种方式,这一点从字面上也很容易看出来。

先看一下图2-11,如下。

可以看到,在Session Replication 方式中,不再要求负载均衡器来保证同一个会话的多次请求必须到同一个Web 服务器上了。而我们的Web 服务器之间则增加了会话数据的同步。通过同步就保证了不同Web 服务器之间的Session 数据的一致。就如同每家饭店都有我的碗筷,我就能随便选择去哪家吃饭了。

一般的应用容器都支持(包括了商业的和开源的)Session Replication 方式,与Session Sticky 方案相比,Session Replication 方式对负载均衡器没有那么多的要求。不过这个方案本身也有问题,而且在一些场景下,问题非常严重。我们来看一下这些问题。

同步Session 数据造成了网络带宽的开销。只要Session 数据有变化,就需要将数据同步到所有其他机器上,机器数越多,同步带来的网络带宽开销就越大。

每台Web 服务器都要保存所有的Session 数据,如果整个集群的Session 数很多(很多人在同时访问网站)的话,每台机器用于保存Session 数据的内容占用会很严重。这就是Session Replication 方案。这个方案是靠应用容器来完成Session 的复制从而使得应用解决Session 问题的,应用本身并不用关心这个事情。不过,这个方案不适合集群机器数多的场景。如果只有几台机器,用这个方案是可以的。

3.Session 数据集中存储

同样是希望同一个会话的请求可以发到不同的Web 服务器上,刚才的Session Replication是一种方案,还有另一种方案就是把Session 数据集中存储起来,然后不同Web 服务器从同样的地方来获取Session。大概的结构如图2-12 所示。

可以看到,与Session Replication 方案一样的部分是,会话请求经过负载均衡器后,不会被固定在同样的Web 服务器上。不同的地方是,Web 服务器之间没有了Session 数据复制,并且Session 数据也不是保存在本机了,而是放在了另一个集中存储的地方。这样,不论是哪台Web 服务器,也不论修改的是哪个Session 数据,最终的修改都发生在这个集中存储的地方,而Web 服务器使用Session 数据时,也是从这个集中存储Session 数据的地方来读取。这样的方式保证了不同Web 服务器上读到的Session 数据都是一样的。而存储Session 数据的具体方式,可以使用数据库,也可以使用其他分布式存储系统。这个方案解决了SessionReplication 方案中内存的问题,而对于网络带宽,这个方案也比Session Replication 要好。该方案存在的问题是什么呢?

读写Session 数据引入了网络操作,这相对于本机的数据读取来说,问题就在于存在时延和不稳定性,不过我们的通信基本都是发生在内网,问题不大。

如果集中存储Session 的机器或者集群有问题,就会影响我们的应用。

相对于Session Replication,当Web 服务器数量比较大、Session 数比较多的时候,这个集中存储方案的优势是非常明显的。

4.Cookie Based

Cookie Based 方案是要介绍的最后一个解决Session 问题的方案。这个方案对于同一个会话的不同请求也是不限制具体处理机器的。和Session Replication 以及Session 数据集中管理的方案不同,这个方案是通过Cookie 来传递Session 数据的。还是先看看下面的图2-13吧。

从图2-13 可以看到,我们的Session 数据放在Cookie 中,然后在Web 服务器上从Cookie中生成对应的Session 数据。这就好比我每次都把自己的碗筷带在身上,这样我去哪家饭店吃饭就可以随意选择了。相对于前面的集中存储,这个方案不会依赖外部的一个存储系统,也就不存在从外部系统获取、写入Session 数据的网络时延、不稳定性了。不过,这个方案依然存在不足:

Cookie 长度的限制。我们知道Cookie 是有长度限制的,而这也会限制Session 数据的长度。

安全性。Session 数据本来都是服务端数据,而这个方案是让这些服务端数据到了外部网络及客户端,因此存在安全性上的问题。我们可以对写入Cookie 的Session 数据做加密,不过对于安全来说,物理上不能接触才是安全的。

带宽消耗。这里指的不是内部Web 服务器之间的带宽消耗,而是我们数据中心的整体外部带宽的消耗。

性能影响。每次HTTP 请求和响应都带有Session 数据,对Web 服务器来说,在同样的处理情况下,响应的结果输出越少,支持的并发请求就会越多。

参考:《大型网站系统与Java中间件实践》

http://www.cnblogs.com/zhangkai2237/archive/2012/03/22/2410890.html

http://book.51cto.com/art/201405/439557.htm

http://blog.csdn.net/it_superman/article/details/7866746

解决应用服务器变为集群后的Session问题的更多相关文章

  1. 负载均衡集群中的session解决方案【转】

    通常面临的问题 从用户端来解释,就是当一个用户第一次访问被负载均衡代理到后端服务器A并登录后,服务器A上保留了用户的登录信息:当用户再次发送请求时, 根据负载均衡策略可能被代理到后端不同的服务器,例如 ...

  2. Nginx+PHP负载均衡集群环境中Session共享方案 - 运维笔记

    在网站使用nginx+php做负载均衡情况下,同一个IP访问同一个页面会被分配到不同的服务器上,如果session不同步的话,就会出现很多问题,比如说最常见的登录状态. 下面罗列几种nginx负载均衡 ...

  3. CAS Client集群环境的Session问题及解决方案

    [原创申明:文章为原创,欢迎非盈利性转载,但转载必须注明来源] 之前写过一篇文章,介绍单点登录的基本原理.这篇文章重点介绍开源单点登录系统CAS的登录和注销的实现方法.并结合实际工作中碰到的问题,探讨 ...

  4. nginx负载均衡集群中的session共享说明

    在网站使用nginx+php做负载均衡情况下,同一个IP访问同一个页面会被分配到不同的服务器上,如果session不同步的话,就会出现很多问题,比如说最常见的登录状态. 下面罗列几种nginx负载均衡 ...

  5. Apache + Tomcat + mod_jk实现集群服务及session共享

    实现效果:用apache 分发请求到tomcat中的对应的项目 原理:

  6. apache tomcat搭建负载均衡(实现集群中的session同步)

    原理:tomcat 做个WEB服务器有它的局限性,处理能力低,效率低.承受并发小(1000左右).但目前有不少网站或者页面是JSP的.并采用了tomcat做为WEB,因此只能在此基础上调优. 目前采取 ...

  7. CAS Client集群环境的Session问题及解决方案介绍,下篇介绍作者本人项目中的解决方案代码

    CAS Client集群环境的Session问题及解决方案  程序猿讲故事  2016-05-20  原文 [原创申明:文章为原创,欢迎非盈利性转载,但转载必须注明来源] 之前写过一篇文章,介绍单点登 ...

  8. 【nginx+tomcat集群】Nginx1.12.2+Tomcat7集群+负载均衡+Session共享

    今天想着将项目优化一下,就想的实现集群分布,在本机测试:利用nginx+tomcat实现 通过上一篇博客(http://www.cnblogs.com/qlqwjy/p/8535235.html),N ...

  9. Nginx+tomcat集群中,session的共享

    nginx,tomcat集群后多个session分配到同一个应用 单节点低负荷的情况下,我们通常把一个WEB应用打成WAR包放WEB应用服务器,如TOMCAT下运行就行了(如图1).但随着用户量的增加 ...

随机推荐

  1. Ajax之基础

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/liu_yujie2011com/article/details/29812777         几 ...

  2. rqnoj86 智捅马蜂窝

    题目描述 背景 为了统计小球的方案数,平平已经累坏了.于是,他摘掉了他那800度的眼镜,躺在树下休息. 后来,平平发现树上有一个特别不一样的水果,又累又饿的平平打算去把它摘下来. 题目描述 现在,将大 ...

  3. 开发ArcEngine时的一个提示,无效位图,无法在类“***”中找到资源“***.bmp”

    解决办法:文件属性-生成操作 修改为 :嵌入式资源.

  4. 对The Curse of Dimensionality(维度灾难)的理解

    一个特性:低维(特征少)转向高维的过程中,样本会变的稀疏(可以有两种理解方式:1.样本数目不变,样本彼此之间距离增大.2.样本密度不变,所需的样本数目指数倍增长). 高维度带来的影响: 1.变得可分. ...

  5. 重磅课程|《CNCF x Alibaba 云原生技术公开课》正式开讲!

    ​ 到底什么是“云原生”?云原生与 CNCF.Kubernetes 是什么关系?作为云计算时代的开发者和从业者,我们该如何在“云原生”的技术浪潮中站稳脚跟,将云原生落地.实现个人的自我升级呢? 201 ...

  6. dataframe添加元素指定为列表,不同for循环命名空间下的变量重复问题

    split=pd.DataFrame({'data':[0],'len':0,'count':0},index=[0])for i_t in range(over_128.shape[0]): ct= ...

  7. 前端基础☞CSS

    css的四种引入方式 1.行内式 行内式是在标记的style属性中设定CSS样式.这种方式没有体现出CSS的优势,不推荐使用. <p style="background-color: ...

  8. python if 选择结构

  9. 从零学React Native之06flexbox布局

    前面我们接触了好多React Native代码, 并没有介绍RN中的组件具体是如何布局的,这一篇文章,重点介绍下flexbox布局. 什么是flexbox布局 React中引入了flexbox概念,f ...

  10. 《C语言深度解剖》学习笔记之关键字

    第一章 关键字 C语言共有32个关键字. 关键字   auto 声明自动变量 int 声明整型变量 long 声明长整型变量 char 声明字符型变量 float 声明浮点型变量 short 声明短整 ...