## HTTP
邮件服务器必须得管理会话,因为如果不管理的话,多个人的邮件就混到一起去了。
但是很早之前的Web基本上就是文档的浏览而已,服务器根本不需要记住谁在一段时间里浏览了什么文档。
## Session
后来大家不满足静态的HTML文档了,交互式的Web开始兴起。
此时Web服务器必须管理会话,必须知道哪些人登录了系统,哪些人往自己的购物车里面放了东西。
由于HTTP协议的无状态特性,必须曲线救国
可以给每个人发一个会话标识session id,也就是一个随机字符串,当浏览器发起HTTP请求的时候,会把这个session id一起带过来,就可以区分谁是谁了。
## 沉重的负担
使用session id的坏处在于,服务器需要保存所有人的session id。
这是巨大的开销,严重限制了扩展能力,比如说两个机器组成了集群,一个人通过机器A登录了系统,那么session id会保存在机器A上,但是如果下一次请求发到了机器B怎么办?
于是可以使用session sticky。也就是说这个人的请求一直都只转发到机器A上。
那么机器A如果挂了怎么办?
只要做session 复制了,这样又涉及到session id在两个机器之间搬来搬去
![](http://p8a6vmhkm.bkt.clouddn.com/picgo20180830091805.png?picgo)
后来Memcached将session id放到一个地方,所有机器都来访问这个地方的数据。
但是又增加了单点失败的可能性。
![](http://p8a6vmhkm.bkt.clouddn.com/picgo20180830091939.png?picgo)
如果不存储session id的机器又搞出个集群,感觉对一个小小的session 还杀鸡用牛刀
## 时间换空间
那么Web服务器可以不保存session吗?
但是如果不保存session,如何验证客户端发过来的session id是服务器生成的,而非伪造的呢?
所以关键点在于验证。
比如说一个人登录了系统,就可以给他发一个token,这个token需要包含这个人的user id 。
下次这个人再访问服务器的时候,可以把这个token顺道带过来。
但是依然没有解决易被伪造的问题。
那么就可以对数据做一个签名,比如使用HMAC-SHA256算法,加上一个不公开的密钥,可以对数据做签名。
这个签名与数据放在一起做为token
只要保管好了token,别人就无法伪造。
![](http://p8a6vmhkm.bkt.clouddn.com/picgo20180830092732.png?picgo)
所以服务器不需要保存token,当人们把 token发过来的时候,可以使用SHA256算法+密钥,再对数据重新计算一次,并与token 中的签名做比较。
如果相同,则说明一定登录过了。
![](http://p8a6vmhkm.bkt.clouddn.com/picgo20180830093015.png?picgo)
Token 中的数据是明文保存的,所以不能在其中保存像密码那样的敏感信息
如果token被偷走了,也没有办法,这和一个人的session id被偷走了一样。
总之,服务器是使用CPU计算时间来获取了session 的存储空间。
这样,机器集群可以轻松做水平扩展,用户量增大,直接加机器即可。