精华 Web开发Session相关
发布于 4 年前 作者 luicfer 6430 次浏览 最后一次编辑是 3 年前 来自 分享

Web 应用由于 http 协议本身是无状态的,当前后有两个请求进来的时候,我们无法知道这两个请求是否属于同一个用户。所以我们需要设置一些用户相关的状态,主流有两种方案。本文主要讲 Session。

  • Cookie
  • Session

Cookie

Cookie保存在客户端的浏览器上,每次请求的时候放在 http 的 header 里面发送给服务器,经由服务器解析得到相关数据。

Cookie 由于保存在用户端,对服务器端的压力较小,但是每次请求带上Cookie的网络IO消耗也存在。有一种 Web 应用的优化方式就是静态资源如图片放在另外一个域名下面,这样在浏览器请求静态资源的时候就省了Cookie的IO消耗哦。当然,如果你是用二级域名放静态资源,Cookie作用域又设置了/,请允许我呵呵你。

Cookie 本身对用户是完全可见的(不讨论加密的情况)。有些时候,你设置一些状态可能不希望用户知道,Cookie 无法满足这一需求。

Session

Session 可以简单的认为是服务器端的 Cookie 。一般在客户端Cookie设置Session的 Id,然后其余数据存储在服务器端,服务器通过每次请求带过来的 Id 来查找对应的数据。Session 存储在服务器端,对服务器端压力要大于 Cookie,但是网络IO消耗比之 Cookie 要小(只有一个Id嘛)。Session 和 Cookie 用哪个,请根据实际情况自行考虑。

存储方式

由于 Session 在服务器端,存储方式要比 Cookie 多样的多,我将其分成了两种类型

  • 本地式
  • 集中式

本地式

本地式常见的存储方式有

  • 文件(这么慢真的好么)
  • 内存

讲讲本地式的优点,简单,开箱即用。

缺点:现在什么都讲究什么大并发啊,高可用巴拉巴拉一大堆。本地存储,我要水平拓展,怎么加机器?我要消除单点故障怎么破?举个简单的例子。Node.js为了利用多核性能可以用cluster启动多个进程。假设启动了2个进程。用户登录操作被分配到进程1,用户刷新下浏览器,这个请求被分配到了进程2,然后用户发现他居然没有登录!!这不是坑爹么。这种情况也适用于多机器的情况。

对于上面讲的情况也有两种方式解决

  1. 粘性Session
  2. SessionS复制

方案1:同一个用户的请求被分配到同一个机器(进程)处理。但是还是有一点小问题,当某一台机器(进程)挂掉,它上面的 Session 也就掉光光了。

方案2:一个机器设置Session后,将Session同步到集群内所有机器(进程)。能解决一台机器挂掉后,所属的 Session 丢失的问题,但是实施起来较为麻烦,以Node.js来举例,要处理进程间通信,和机器间的同步。同时整个集群里面有N个完整的 Session 副本。

集中式

所有 Session 集中存储在另外的 Session 服务器上。也是现在 Node.js 比较主流的做法。较少自己造轮子,多采用成熟的技术和对应的协议来实现。

  • memcached
  • redis
  • mongodb
  • Mysql

优点:比起粘性Session,Web服务器随便挂,挂了再起就是。对比Session复制,实施起来比较容易,同时没有N份副本的消耗。

缺点:集中后虽然Web服务器可以随便挂,但是Session服务器挂了,你就Duang了=。= 简单说一下上面4个常见的挂掉的情况。

  • memcached 挂了就是挂了,重启掉光光,没商量
  • redis 挂了硬盘上还有,重启读进去,还能抢救下
  • Mongodb 挂了是什么,重启还是一条好汉
  • Mysql 同上,我就是效率比上面3个要低点

要提高可用性,请参见各自的集群大法。

结束

好了就到这里。另外由于本人知识有限,难免有错漏,欢迎指正。

15 回复

挺好,redis和mongodb这两个方案的优劣能否介绍下?

这个帖子有干货

通俗易懂 受教了👍

@SoaringTiger 其实对于 Session 我本身倾向使用K/V系统,Session本身就是一个K/V,Cookie带Key 服务端提供 V存储和对应的映射关系。 不需要什么查询条件 > 什么的。以及Session本身是用于保存状态,还有有效期等,数据量不会太大。所以反正我是会选 K/V系统做存储的。 当然,我最爱的还是 Redis,万一重启还可以抢救下嘛。最后说下我个人大致的选择 1.Redis 2. memcached 3. Mongodb 4.Mysql。基本优先选序号小的,除非被逼的实在没法子了。如果被逼的选4.也就是关系型数据库,我会想跳楼的

@SoaringTiger @luicfer,实际上抢救的话要跟 Memcached 比而不是 MongoDB。

做 session 的话还是 Redis 和 memcached 比 MongoDB 这类合适。

不过这两个有一个劣势就是内存大户——就算持久化,所有数据在运行时也还是在内存。

推荐尝试下 Riak,个人推荐而已。

@xadillax 其实说抢救,对比的也是 Memcached 和 Redis。 做session我也基本不会考虑 MongoDB 和 MySQL。 内存大户,其实我觉得还好。 最后,我知道你为什么推荐 Riak,因为某个项目被穷怕了2333

@luicfer 主要是 Riak 结合了内存和持久化,并不是所有数据都在内存,然后又非常符合 KV 场景。

在硬件限制的条件下是一个折中的方案。

看好楼主的文风

cookie session一直很喜欢这种,屌丝的解决方案,成本为0,就是要控制好不要往session里丢太多东西

@DavidCai1993 看好文风,好评

有没有更详细的介绍?

精得这么快?就没深入了解下内存有无泄露的毛病?以及众session中间件的优劣。

@hezedu 其实这个讲的大致的方案,而且和语言之类相关不大。 如果要详细的讲到方案的实施,就想你说的 session 中间件很多, 而且express 和 Koa 中间件还不一样呢。这里面的东西就多了,再说还有其他语言对吧

回到顶部