Session机制详解以及Session的相关应用

sessionweb开发里一个重要的概念,在大多数web应用里session都是被当作现成的东西,拿来就直接用,可是一些复杂的web应用里能拿来用的session已经知足不了实际的需求,当碰到这样的状况时候咱们须要更加深刻的理解session的机制,本文将梳理下session的相关知识,为设计可替代web容器自带的session机制打个基础。php

1.1 Session的概念

在计算机专业术语里:session是指一个终端用户与交互系统进行通讯的时间间隔,一般指从注册入系统到注销系统之间所通过的时间以及若是须要的话,可能还有必定操做空间。html

具体到web应用里的session,你们都作过web开发,这里我就先不提出websession的定义,先和大伙讲下和session相关的技术背景。html5

早期的web应用或者说早期的网站都是一种处理静态资源的网站,功能主要是查看文档,看看图片,而如今的web应用和早期的差异已经很大,互联网的网站更准确的定义应该是互联网软件即网站就是软件,网站所表明的软件和早期软件的定义是不同的,早期的软件都是在单机环境下运行,而互联网的普及让软件和网络技术融合在一块儿,这就要求网站所表明的软件应该要有一个对事务处理的记忆功能事务处理的记忆功能就是咱们常说的要有状态。而实现Web应用技术的核心HTTP协议是一个无状态的协议,HTTP这种设计也许是历史遗留问题,也许无状态的HTTP 最简单也是最有效的通信方式,可是当网站成为软件后,状态的保持就是一个很重要的功能。java

所以在Web应用开发里就出现了保持HTTP连接状态的技术:一个是cookie技术,另外一种是session技术。nginx

Cookie技术是客户端的解决方案(固然随着html5的出现,比cookie更为强劲和安全的技术出现了,可是鉴于html5的普及度不够,就不作本文讨论的内容了),Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,而后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。让咱们说得更具体一些:当用户使用浏览器访问一个支持Cookie的网站的时候,用户会提供包括用户名在内的我的信息而且提交至服务器;接着,服务器在向客户端回传相应的超文本的同时也会发回这些我的信息,固然这些信息并非存放在HTTP响应体(Response Body)中的,而是存放于HTTP响应头(Response Header);当客户端浏览器接收到来自服务器的响应以后,浏览器会将这些信息存放在一个统一的位置,对于Windows操做系统而言,咱们能够从: [系统盘]:\Documents and Settings\[用户名]\Cookies目录中找到存储的Cookie;自此,客户端再向服务器发送请求的时候,都会把相应的Cookie再次发回至服务器。而此次,Cookie信息则存放在HTTP请求头(Request Header)了。有了Cookie这样的技术实现,服务器在接收到来自客户端浏览器的请求以后,就可以经过分析存放于请求头的Cookie获得客户端特有的信息,从而动态生成与该客户端相对应的内容。一般,咱们能够从不少网站的登陆界面中看到“请记住我”这样的选项,若是你勾选了它以后再登陆,那么在下一次访问该网站的时候就不须要进行重复而繁琐的登陆动做了,而这个功能就是经过Cookie实现的。程序员

Session技术则是服务端的解决方案,它是经过服务器来保持状态的。因为Session这个词汇包含的语义不少,所以须要在这里明确一下Session的含义。首先,咱们一般都会把Session翻译成会话,所以咱们能够把客户端浏览器与服务器之间一系列交互的动做称为一个Session。从这个语义出发,咱们会提到Session持续的时间,会提到在Session过程当中进行了什么操做等等;其次,Session指的是服务器端为客户端所开辟的存储空间,在其中保存的信息就是用于保持状态。从这个语义出发,咱们则会提到往Session中存放什么内容,如何根据键值从 Session中获取匹配的内容等。要使用Session,第一步固然是建立Session了。那么Session在什么时候建立呢?固然仍是在服务器端程序运行的过程当中建立的,不一样语言实现的应用程序有不一样建立Session的方法,而在Java中是经过调用HttpServletRequestgetSession方法(使用true做为参数)建立的。在建立了Session的同时,服务器会为该Session生成惟一的Session id,而这个Session id在随后的请求中会被用来从新得到已经建立的Session;在Session被建立以后,就能够调用Session相关的方法往Session中增长内容了,而这些内容只会保存在服务器中,发到客户端的只有Session id;当客户端再次发送请求的时候,会将这个Session id带上,服务器接受到请求以后就会依据Session id找到相应的Session,从而再次使用之。正式这样一个过程,用户的状态也就得以保持了。web

由此咱们能够得出,Session是解决HTTP协议无状态问题的服务端解决方案,它能让客户端和服务器端的一系列交互动做变成一个完整的事务能使网站变成一个真正意义上的软件。redis

1.2 CookieSession的关系

cookiesession的方案虽然分别属于客户端和服务端,可是服务端的session的实现对客户端的cookie有依赖关系的,上面我讲到服务端执行session机制时候会生成sessionid值,这个id值会发送给客户端,客户端每次请求都会把这个id值放到http请求的头部发送给服务端,而这个id值在客户端会保存下来,保存的容器就是cookie,所以当咱们彻底禁掉浏览器的cookie的时候,服务端的session也会不能正常使用(注意:有些资料说ASP解决这个问题,当浏览器的cookie被禁掉,服务端的session任然能够正常使用,ASP我没试验过,可是对于网络上不少用phpjsp编写的网站,我发现禁掉cookie,网站的session都没法正常的访问)数据库

1.3 Session实现的原理

JavaWeb容器都实现了session机制,实现的逻辑思想都是一致的,可是具体方案可能会存在必定差别,这里我以tomcat容器为例,探讨下session实现的机制。apache

下图是tomcat源码里session实现:

实现包的路径是:org.apache.catalina.sessionTomcat对外提供session调用的接口不在这个实现包里,对外接口是在包javax.servlet.http下的HttpSession,而实现包里的StandardSessionTomcat提供的标准实现,固然对外Tomcat不但愿用户直接操做StandardSession,而是提供了一个StandardSessionFacade类,Tomcat容器里具体操做session的组件是servletservlet操做session是经过StandardSessionFacade进行的,这样就能够防止程序员直接操做StandardSession所带来的安全问题。(StandardSessionFacade使用了设计模式里的Façade(外观)模式,外观模式能让不一样逻辑层的组件进行解耦

实现类里有Manager的类是用来管理session的工具类,它负责建立和销毁session对象,其中ManagerBase是全部session管理工具类的基类,它是一个抽象类,全部具体实现session管理功能的类都要继承这个类,该类有一个受保护的方法,该方法就是建立sessionId值的方法(Tomcatsessionid值生成的机制是一个随机数加时间加上JVMid值,JVMid值会根据服务器的硬件信息计算得来,所以不一样JVMid值都是惟一的),StandardManager类是Tomcat容器里默认的session管理实现类,它会将session的信息存储到Web容器所在服务器的内存里。PersistentManagerBase也是继承ManagerBase类,它是全部持久化存储session信息的基类,PersistentManager继承了PersistentManagerBase,可是这个类只是多了一个静态变量和一个getName方法,目前看来意义不大,对于持久化存储sessiontomcat还提供了StoreBase的抽象类,它是全部持久化存储session的基类,另外Tomcat还给出了文件存储FileStore和数据存储JDBCStore两个实现。

1.4 在实际运用中Session所带来的问题

由上面所描述的session实现机制,咱们会发现,为了弥补http协议的无状态的特色,服务端会占用必定的内存和cpu用来存储和处理session计算的开销,这也就是tomcat这个的web容器的并发链接那么低(tomcat官方文档里默认的链接数是200)缘由之一。所以不少java语言编写的网站,在生产环境里web容器以前会加一个静态资源服务器,例如:apache服务器或nginx服务器,静态资源服务器没有解决http无状态问题的功能,所以部署静态资源的服务器也就不会让出内存或cpu计算资源专门去处理像session这样的功能,这些内存和cpu资源能够更有效的处理每一个http请求,所以静态资源服务器的并发链接数更高,因此咱们可让那些没有状态保持要求的请求直接在静态服务器里处理,而要进行状态保持的请求则在java的web容器里进行处理,这样能更好的提高网站的效率。

当下的互联网网站为了提升网站安全性和并发量,服务端的部署的服务器的数量每每是大于或等于两台,多台服务器对外提供的服务是等价的,可是不一样的服务器上面确定会有不一样的web容器,由上面的讲述咱们知道session的实现机制都是web容器里内部机制,这就致使一个web容器里所生成的sessionid值是不一样的,所以当一个请求到了A服务器,浏览器获得响应后,客户端存下的是A服务器上所生成的sessionid,当在另外一个请求分发到了B服务器,B服务器上的web容器是不能识别这个sessionid值,更不会有这个sessionID所对应记录下来的信息,这个时候就须要两个不一样web容器之间进行session的同步。Tomcat容器有一个官方的解决方案就是使用apache+tomcat+mod_jk方案,当一个web容器里session的信息发生变化后,该web容器会向另外一个web容器进行广播,另外一个web收到广播后将session信息同步到本身的容器里,这个过程是十分消耗系统资源,当访问量增长会严重影响到网站的效率和稳定性。

我如今所作的网站里有一个解决方案,当用户请求网站的时候会先将请求发送给硬件的负载均衡设备,该设备能够截获客户端发送过来的sessionid值,而后咱们根据这个id值找到产生这个session的服务器,将请求直接发送给这台服务器。这种解决方案看起来解决了session共享问题,其实结果是将集群系统最终变回了单点系统,若是处理请求的web容器挂掉了,那么用户的相关会话操做也就废掉了。此外,这种作法也干扰了负载均衡服务器的负载均衡的计算,让请求的分发并非公平的。

通常大型互联公司的网站都是有一个个独立的频道所组成的,例如咱们经常使用的百度,会有百度搜索,百度音乐,百度百科等等,我相信他们不会把这些不一样频道都给一个开发团队完成,应该每一个频道都是一个独立开发团队,由于每一个频道的应用的都是独立的web应用,那么就存在一个跨站点的session同步的问题,跨站点的登陆可使用单点登陆的(SSO)的解决方案,可是无论什么解决方案,跨站点的session共享任然是逃避不了的问题。

1.5 解决Session相关问题的技术方案

由上所述,session一共有两个问题须要解决:

1) session的存储应该独立于web容器,也要独立于部署web容器的服务器;

2) 如何进行高效的session同步。

在讲到解决这些问题以前,咱们首先要考虑下session如何存储才是高效,是存在内存、文件仍是数据库了?文件和数据库的存储方式都是将session的数据固化到硬盘上,操做硬盘的方式就是IOIO操做的效率是远远低于操做内存的数据,所以文件和数据库存储方式是不可取的,因此将session数据存储到内存是最佳的选择。所以最好的解决方案就是使用分布式缓存技术,例如:memcachedredis,将session信息的存储独立出来也是解决session同步问题的方法。

Tomcatsession同步也有使用memcache的解决方案,你们能够参加下面的文章:

http://blog.sina.com.cn/s/blog_5376c71901017bqx.html

可是该方案只是解决了同步问题,session机制任然和Web容器紧耦合,咱们须要一个高效、可扩展的解决方案,那么咱们就应该不是简单的把session独立出来存储而是设计一个彻底独立的session机制,它既能给每一个web应用提供session的功能又能够实现session同步,下面是一篇用zookeeper实现的分布式session方案:

http://www.open-open.com/lib/view/open1378556537303.html

好了写完了,今天只是简单剖析下session机制,之后有机会我拿出一套最好的独立session设计机制方案来的。

相关文章
相关标签/搜索