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,然后用户发现他居然没有登录!!这不是坑爹么。这种情况也适用于多机器的情况。
对于上面讲的情况也有两种方式解决
- 粘性Session
- 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个要低点
要提高可用性,请参见各自的集群大法。
结束
好了就到这里。另外由于本人知识有限,难免有错漏,欢迎指正。
@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