javaWEB之session

一、Session简介

1.1 Session是什么

Session在网络应用中被称为“会话控制”。

Session存储在服务器端。

用户A访问网站B,A登录网站后,服务器会创建一个Session来保存用户状态和相关信息。每个Session对应一个标识符SessionID来标识用户身份。SessionID一般是由服务器以加密的方式写到cookie中的,这样用户A登录后,访问网站B中不同的网页时请求中会带上SessionID来标识他的身份,以此实现一次登录,访问全网站。(现在大多数站点采用基于cookie的session管理方式:用户登陆成功后,设置一个唯一的cookie标识本次会话,基于这个标识进行用户授权。只要请求中带有这个标识,都认为是登录态。)

1.2 session为什么存在

首先大家知道,http协议是无状态的,即你连续访问某个网页100次和访问1次对服务器来说是没有区别对待的,因为它记不住你。   那么,在一些场合,确实需要服务器记住当前用户怎么办?比如用户登录邮箱后,接下来要收邮件、写邮件,总不能每次操作都让用户输入用户名和密码吧,为了解决这个问题,session的方案就被提了出来,事实上它并不是什么新技术,而且也不能脱离http协议以及任何现有的web技术。   原理很简单,假设你访问网页时就像逛澡堂,第一次进去你是没有钥匙的,这个时候你交了钱服务台就分配一把钥匙给你,你走到哪里都要带上,因为这是你身份的唯一标识,接下来你用这把钥匙可以去打开一个专有的储物柜存储你的衣物,游完泳,你再用钥匙去打开柜子拿出衣物,最后离开游泳池时,把钥匙归还,你的这次游泳的过程就是一次session,或者叫做会话,在这个例子中,钥匙就是session的key,而储物柜可以理解为存储用户会话信息的介质。   那么在web server中如何实现session呢?想必看了上面的例子你会很容易理解,主要是解决两个问题,一个是钥匙的问题,一个是存储用户信息的问题。对于第一个问题,即什么东西可以让你每次请求都会自动带到服务器呢?如果你比较了解http协议,那么答案一目了然,就是cookie,如果你想为用户建立一次会话,可以在用户授权成功时给他一个cookie,叫做会话id,它当然是唯一的,比如PHP就会为建立会话的用户默认set一个名为phpsessid,值看起来为一个随机字符串的cookie,如果下次发现用户带了这个cookie,服务器就知道,哎呀,刚刚这位顾客来了。   剩下的是解决第二个问题,即如何存储用户的信息,服务器知道会话id为abc的用户来了,那abc想存储自己的私人信息,比如购物车信息,如何处理?这个时候可以用内存、也可以用文件,也可以用数据库了,但有个要求是,数据需要用用户的会话id即可取到,比如php就默认会把会话id为abc的用户会话数据存储到/tmp/phpsess_abc【1】的文件里面,每次读取都要反序列化程序可以理解的数据,写的时候又需要序列化为持久的数据格式。

1.3 session一致性问题

只要用户不重启浏览器,每次http短连接请求,理论上服务端都能定位到session,保持会话。

1.4 session共享的实现

  首先我们应该明白,为什么要实现共享,如果你的网站是存放在一个机器上,那么是不存在这个问题的,因为会话数据就在这台机器,但是如果你使用了负载均衡把请求分发到不同的机器呢?这个时候会话id在客户端是没有问题的,但是如果用户的两次请求到了两台不同的机器,而它的session数据可能存在其中一台机器,这个时候就会出现取不到session数据的情况,于是session的共享就成了一个问题。   事实上,各种web框架早已考虑到这个问题,比如asp.NET,是支持通过配置文件修改session的存储介质为sql server的,所有机器的会话数据都从同一个数据库读,就不会存在不一致的问题;php支持把会话数据存储到某台memcache服务器,你也可以手工把session文件存放的目录改为nfs网络文件系统,从而实现文件的跨机器共享。   还有一个简单的办法可以用于会话信息不会频繁变更的情况,在机器a设置用户会话的时候,把会话数据post到机器b的一个cgi,机器b的cgi把会话数据存下来,这样机器a和b都会有同一份session数据的拷贝。

1.5 session的数据保存在哪里呢?

Java中的session存储

  sessionid是一个会话的key,浏览器第一次访问服务器会在服务器端生成一个session,有一个sessionid和它对应。tomcat生成的sessionid叫做jsessionid。   session在访问tomcat服务器HttpServletRequest的getSession(true)的时候创建,tomcat的ManagerBase类提供创建sessionid的方法:随机数+时间+jvmid。   存储在服务器的内存中,tomcat的StandardManager类将session存储在内存中,也可以持久化到file,数据库,memcache,redis等。客户端只保存sessionid到cookie中,而不会保存session,session销毁只能通过invalidate或超时,关掉浏览器并不会关闭session。

那么Session在何时创建呢?当然还是在服务器端程序运行的过程中创建的,不同语言实现的应用程序有不同创建Session的方法,而在Java中是通过调用HttpServletRequest的getSession方法(使用true作为参数)创建的。 在创建了Session的同时,服务器会为该Session生成唯一的Session id,而这个Session id在随后的请求中会被用来重新获得已经创建的Session;在Session被创建之后,就可以调用Session相关的方法往Session中增加内容了,而这些内容只会保存在服务器中,发到客户端的只有Session id;当客户端再次发送请求的时候,会将这个Session id带上,服务器接受到请求之后就会依据Session id找到相应的Session,从而再次使用之。

1.6 session的生命周期

 Session存储在服务器端,一般为了防止在服务器的内存中(为了高速存取),Sessinon在用户访问第一次访问服务器时创建,需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session,可调用request.getSession(true)强制生成Session。

1.7 Session什么时候失效?


(1)服务器会把长时间没有活动的Session从服务器内存中清除,此时Session便失效。Tomcat中Session的默认失效时间为20分钟。

(2)调用Session的invalidate方法。


二、Session一致性解决方案

2.1 session复制(同步)

思路:多个web-server之间相互同步session,这样每个web-server之间都包含全部的session

优点:web-server支持的功能,应用程序不需要修改代码

不足:

(1)session的同步需要数据传输,占内网带宽,有时延

(2)所有web-server都包含所有session数据,数据量受内存限制,无法水平扩展

(3)有更多web-server时要歇菜

2.2 客户端存储法

思路:服务端存储所有用户的session,内存占用较大,可以将session存储到浏览器cookie中,每个端只要存储一个用户的数据了

优点:服务端不需要存储

缺点:

(1)每次http请求都携带session,占外网带宽

(2)数据存储在端上,并在网络传输,存在泄漏、篡改、窃取等安全隐患

(3)session存储的数据大小受cookie限制

2.3 反向代理hash一致性

思路:web-server为了保证高可用,有多台冗余,反向代理层能不能做一些事情,让同一个用户的请求保证落在一台web-server上呢?


方案一:四层代理hash

反向代理层使用用户ip来做hash,以保证同一个ip的请求落在同一个web-server上


方案二:七层代理hash

反向代理使用http协议中的某些业务属性来做hash,例如sid,city_id,user_id等,能够更加灵活的实施hash策略,以保证同一个浏览器用户的请求落在同一个web-server上

优点:

(1)只需要改nginx配置,不需要修改应用代码

(2)负载均衡,只要hash属性是均匀的,多台web-server的负载是均衡的

(3)可以支持web-server水平扩展(session同步法是不行的,受内存限制)

不足:

(1)如果web-server重启,一部分session会丢失,产生业务影响,例如部分用户重新登录

(2)如果web-server水平扩展,rehash后session重新分布,也会有一部分用户路由不到正确的session

总结:

session一般是有有效期的,所有不足中的两点,可以认为等同于部分session失效,一般问题不大。

对于四层hash还是七层hash,个人推荐前者:让专业的软件做专业的事情,反向代理就负责转发,尽量不要引入应用层业务属性,除非不得不这么做(例如,有时候多机房多活需要按照业务属性路由到不同机房web-server

2.4 后端统一集中存储

思路:将session存储在web-server后端的存储层,数据库或者缓存

优点:

(1)没有安全隐患

(2)可以水平扩展,数据库/缓存水平切分即可

(3)web-server重启或者扩容都不会有session丢失

不足:增加了一次网络调用,并且需要修改应用代码

总结:

对于db存储还是cache,个人推荐后者:session读取的频率会很高,数据库压力会比较大。如果有session高可用需求,cache可以做高可用,但大部分情况下session可以丢失,一般也不需要考虑高可用

2.5 总结

保证session一致性的架构设计常见方法:

(1)session同步法:多台web-server相互同步数据

(2)客户端存储法:一个用户只存储自己的数据

(3)反向代理hash一致性:四层hash和七层hash都可以做,保证一个用户的请求落在一台web-server上

(4)后端统一存储:web-server重启和扩容,session也不会丢失


对于方案3和方案4,个人建议推荐后者:

(1)web层、service层无状态是大规模分布式系统设计原则之一,session属于状态,不宜放在web层

(2)让专业的软件做专业的事情,web-server存session?还是让cache去做这样的事情


三、Session管理

3.1 Cookie管理 Session

3.2 Session管理及 Cookie 状态管理

步骤1:客户端把用户 ID 和密码等登录信息放入报文的实体部分,通常是以 POST 方法把请求发送给服务器。

步骤2:服务器会发放用以识别用户的 Session ID。通过验证从客户端发送过来的登录信息进行身份验证,然后把用户的认证状态与 Session ID 绑定后记录在服务器端。向客户端返回响应时,会在首部字段 Set-Cookie 内写入 Session ID。

步骤3:客户端接收到从服务器端发来的 Session ID 后,会将其作为 Cookie 保存在本地。下次向服务器发送请求时,浏览器会自动发送 Cookie,所以 Session ID 也随之发送到服务器。服务器端可通过验证接收到的 Session ID 识别用户和其认证状态。

3.3 Cookie服务的 HTTP 首部字段

Set-Cookie

Cookie

(1)Set-Cookie

服务器管理状态使用到的字段,用于响应首部

一则响应首部的Set-Cookie字段:


(2)Set-Cookie 字段的属性:


(3)Cookie

首部字段Cookie会告知服务器,当客户端想获得 HTTP 状态管理支持时,就会在请求中包含从服务器接收到的 Cookie。接收到多个 Cookie 时,同样可以以多个 Cookie 形式发送

你可能感兴趣的:(javaWEB之session)