session原理及实现共享

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的文件里面,每次读取都要反序列化程序可以理解的数据,写的时候又需要序列化为持久的数据格式。

较好理解的描述:
session被用于表示一个持续的连接状态,在网站访问中一般指代客户端浏览器的进程从开启到结束的过程。session其实就是网站分析的访问(visits)度量,表示一个访问的过程。
session的常见实现形式是会话cookie(session cookie),即未设置过期时间的cookie,这个cookie的默认生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。实现机制是当用户发起一个请求的时候,服务器会检查该请求中是否包含sessionid,如果未包含,则系统会创造一个名为JSESSIONID的输出 cookie返回给浏览器(只放入内存,并不存在硬盘中),并将其以HashTable的形式写到服务器的内存里面;当已经包含sessionid是,服务端会检查找到与该session相匹配的信息,如果存在则直接使用该sessionid,若不存在则重新生成新的 session。这里需要注意的是session始终是有服务端创建的,并非浏览器自己生成的。 但是浏览器的cookie被禁止后session就需要用get方法的URL重写的机制或使用POST方法提交隐藏表单的形式来实现。
  
二、如何实现session的共享?


首先我们应该明白,为什么要实现共享,如果你的网站是存放在一个机器上,那么是不存在这个问题的,因为会话数据就在这台机器,但是如果你使用了负载均衡把请求分发到不同的机器呢?这个时候会话id在客户端是没有问题的,但是如果用户的两次请求到了两台不同的机器,而它的session数据可能存在其中一台机器,这个时候就会出现取不到session数据的情况,于是session的共享就成了一个问题。

1.各种web框架早已考虑到这个问题,比如asp.net,是支持通过配置文件修改session的存储介质为sql server的,所有机器的会话数据都从同一个数据库读,就不会存在不一致的问题;

2.以cookie加密的方式保存在客户端.优点是减轻服务器端的压力,缺点是受到cookie的大小限制,可能占用一定带宽,因为每次请求会在头部附带一定大小的cookie信息,另外这种方式在用户禁止使用cookie的情况下无效.

3.服务器间同步。定时同步各个服务器的session信息,此方法可能有一定延时,用户体验也不是很好。

4.php支持把会话数据存储到某台memcache服务器,你也可以手工把session文件存放的目录改为nfs网络文件系统,从而实现文件的跨机器共享。

还有一个简单的办法可以用于会话信息不会频繁变更的情况,在机器a设置用户会话的时候,把会话数据post到机器b的一个cgi,机器b的cgi把会话数据存下来,这样机器a和b都会有同一份session数据的拷贝。

》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》

 

伴随网站业务规模和访问量的逐步发展,原本由单台服务器、单个域名的迷你网站架构已经无法满足发展需要。

此时我们可能会购买更多服务器,并且启用多个二级子域名以频道化的方式,根据业务功能将网站分布部署在独立的服务器上;或通过负载均衡技术(如:DNS轮询、Radware、F5、LVS等)让多个频道共享一组服务器。

OK,头脑中我们已经构思了这样的解决方案,不过进入深入开发后新的技术问题又随之而来:

我们把网站程序分布部署到多台服务器上,而且独立为几个二级域名,由于Session受实现原理的局限(PHP中Session默认以文件的形式保存在本地服务器的硬盘),使得我们的网站用户不得不经常在几个频道间来回输入用户名、密码登入,导致用户体验大打折扣;另外,原本程序可以直接从用户Session变量中读取的资料(如:昵称、积分、登入时间等),因为无法跨服务器同步更新Session 变量,迫使开发人员必须实时读写数据库,从而增加了数据库的负担。

于是,解决网站跨服务器之间的Session共享方案需求变得迫切起来,最终催生了多种解决方案,下面列举4种较为可行的方案进行对比探讨:

1. 基于NFS的Session共享

NFS是Net FileSystem的简称,最早由Sun公司为解决Unix网络主机间的目录共享而研发。

这个方案实现最为简单,无需做过多的二次开发,仅需将共享目录服务器mount到各频道服务器的本地session目录即可,缺点是NFS依托于复杂的安全机制和文件系统,因此并发效率不高,尤其对于session这类高并发读写的小文件,会由于共享目录服务器的io-wait过高,最终拖累前端WEB应用程序的执行效率。

2. 基于数据库的Session共享

首选当然是大名鼎鼎的MySQL数据库,并且建议使用内存表Heap,提高session操作的读写效率。这个方案的实用性比较强,相信大家普遍在使用,它的缺点在于session的并发读写能力取决于Mysql数据库的性能,同时需要自己实现session淘汰逻辑,以便定时从数据表中更新、删除 session记录,当并发过高时容易出现表锁,虽然我们可以选择行级锁的表引擎,但不得不否认使用数据库存储Session还是有些杀鸡用牛刀的架势。

3. 基于Cookie的Session共享

这个方案我们可能比较陌生,但它在大型网站中还是比较普遍被使用。原理是将全站用户的Session信息加密、序列化后以Cookie的方式,统一种植在根域名下(如:.host.com),利用浏览器访问该根域名下的所有二级域名站点时,会传递与之域名对应的所有Cookie内容的特性,从而实现用户的Cookie化Session 在多服务间的共享访问。

这个方案的优点无需额外的服务器资源;缺点是由于受http协议头信心长度的限制,仅能够存储小部分的用户信息,同时Cookie化的 Session内容需要进行安全加解密(如:采用DES、RSA等进行明文加解密;再由MD5、SHA-1等算法进行防伪认证),另外它也会占用一定的带宽资源,因为浏览器会在请求当前域名下任何资源时将本地Cookie附加在http头中传递到服务器。

4. 基于Memcache的Session共享

Memcache由于是一款基于Libevent多路异步I/O技术的内存共享系统,简单的Key + Value数据存储模式使得代码逻辑小巧高效,因此在并发处理能力上占据了绝对优势,目前本人所经历的项目达到2000/秒 平均查询,并且服务器CPU消耗依然不到10%。

另外值得一提的是Memcache的内存hash表所特有的Expires数据过期淘汰机制,正好和Session的过期机制不谋而合,降低了过期Session数据删除的代码复杂度,对比“基于数据库的存储方案”,仅这块逻辑就给数据表产生巨大的查询压力。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/112991.html原文链接:https://javaforall.net

(0)
上一篇 2021年10月26日 下午4:00
下一篇 2021年10月26日 下午5:00


相关推荐

  • 跟我一起写 Makefile(二)

    跟我一起写 Makefile(二)三、make是如何工作的在默认的方式下,也就是我们只输入make命令。那么,   1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件。   2、如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“edit”这个文件,并把这个文件作为最终的目标文件。   3、如果edit文件不存在,或是edit所依赖的后面的.o文件的文

    2022年5月4日
    42
  • OJ错误提示类型

    OJ错误提示类型答案正确(Acepted,AC)  恭喜你!所提交的代码通过了数据!这个评测结果应该是大家最喜欢见到的,也非常好理解。如果是单点测试,那么没通过一组数据,就会返回一个Accepted;如果是多点测试,那么只有当通过了所有数据时,才会返回Accepted。编译错误(CompileError,CE)  很显然,如果代码没有办法通过编译,那么就会返回CompileError。这是要…

    2022年6月24日
    24
  • Linux——iscsiadm基本用法

    Linux——iscsiadm基本用法1 存储介质 1 磁盘阵列 磁盘阵列是一种采用 RAID 技术 冗余技术和在线维护技术制造的一种高性能 高可用的磁盘存储设备 2 IP SAN 存储 SAN StorageAreaN 存储区域网络 是计算机信息处理技术中的一种架构 它将服务器和远程的计算机存储设备 如磁盘阵列 磁带库 连接起来 使得这些存储设备看起来就像是本地一样 SAN 就理解成存储虚拟化 而 IP SAN 就是采

    2026年3月17日
    1
  • java中jersey什么意思_java jersey介绍

    java中jersey什么意思_java jersey介绍简介Jersey是JAX-RS(JSR311)开源参考实现用于构建RESTfulWebservice,它包含三个部分:核心服务器(CoreServer):通过提供JSR311中标准化的注释和API标准化,可以用直观的方式开发RESTfulWeb服务。核心客户端(CoreClient):Jersey客户端API能够帮助开发者与RESTful服务轻松通信;集成(Integration):J…

    2022年7月12日
    47
  • js 数组插入删除[通俗易懂]

    js 数组插入删除[通俗易懂]常用的方法是遍历数组,然后使用splice()删除这里我们使用es6中findIndex()查找,然后删除functiondeleteFromArray(arr,compare){constindex=arr.findIndex(compare)if(index>-1){arr.splice(index,1)}}插入数据functioninsertArray(arr,val,compare,maxLen){//返回位置consti

    2022年9月30日
    4
  • Scene Graph(视觉关系场景图检测)

    Scene Graph(视觉关系场景图检测)SceneGraphNe SceneGraphPa 开山经典之作 motif 指场景图中重复出现的子结构 引入 relationprio 主语和宾语确定 relation 很容易确定 并且类似的 motif 会大量出现 后 直接通过统计的方法 不需要图片信息就能得到较高的准确率 文中的方法先将图片做 proposal

    2026年3月19日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号