浅析微服务架构中的会话管理
什么是会话?
会话,简单点来理解就是客户端和服务端进行交互的过程,比如你在浏览器打开了一个www.baidu.com 的页面,那就说明你当前的浏览器和百度服务器建立了一个会话。
我们都知道 HTTP 是一种无状态的协议,无状态就是说在我们退出当前会话之后,再次建立连接的时候;服务端不会认识我们,也不知道我们曾经和它建立过连接,进行过什么样的数据交互。
这乍一听似乎也没有什么特别的影响,但是试想一下,假设目前你刚登录了百度网盘的账号,一个不小心点了页面刷新,这时候你再去访百度网盘的时候,又需要重新登录,这是不是很麻烦??
如果真的是这样的话,那我们用户的体验感是非常的不好的!
不过我们也知道事实上并不是这样,当我们二次访问百度网盘的时候并不需要重新登录。
慢着,慢着,这是为什么呢?刚不是说着 HTTP 是无状态的吗,怎么现在看来服务端还是认出我们来了??
其实HTTP还是无状态的,不过是现在都会引用一些会话技术,通过一些手段去记录状态罢了。
管理会话的技术
到会话管理技术,就不得不提提我们的 cookies 和 session 了。
引发需要重新登录的问题,最主要的就是因为服务端无法辨别用户对应的是谁;哪怕服务端是有该用户的数据的,但是因为服务端并没有认出它来,所以不会让该用户对应的数据返回,必须让其重新登录。
客户端:我想去你那
服务端:???,你是谁啊,我们认识?(无状态)
客户端:我是你的老朋友啊(再次登录)
服务端:哦豁,原来是你小子啊,过来吧
Cookie 的工作原理
- 浏览器第一次发送请求到服务端
- 服务器端创建Cookie,该Cookie中包含用户的信息,然后将该Cookie发送到浏览器端
- 浏览器端再次访问服务器端时会携带服务器端创建的Cookie
- 服务器端通过Cookie中携带的数据区分不同的用户
这样有了 cookie ,服务端就可以区别出每一个用户了,如果是已经登录过了的,都会携带 cookie 的,则无须重新登录。
如果想更深入地了解cookie 的话,可以阅读以下文章:
好好了解一下Cookie(强烈推荐)_基础知识 (jb51.net)
cookie是什么?有什么用?cookie详解,一篇文章彻底搞懂cookie
session 的工作原理
- 浏览器端第一次发送请求到服务器端,服务器端创建一个Session,同时会创建一个特殊的Cookie(name为JSESSIONID的固定值,value为session对象的ID),然后将该Cookie发送至浏览器端
- 浏览器端发送第N(N>1)次请求到服务器端,浏览器端访问服务器端时就会携带该name为JSESSIONID的Cookie对象
- 服务器端根据name为JSESSIONID的Cookie的value(sessionId),去查询Session对象,从而区分不同用户。 如果找不到对应的 session 对象,则需要回到第一步。
可以深入了解: Session详解,学习 Session对象一篇文章就够了
cookie 和 session 的区别
- cookie数据存放在客户的浏览器上,session数据放在服务器上
- 因为 cookie 是存储在客户端本地的,所以存在一定的安全隐患,容易发生 “cookie 欺骗”的现象。
- 因为 session 是保存在服务器上的,当访问增多,不仅占空间,而且还会占用服务器的性能;如果要考虑这些方面的话,那么用 cookie 会相对合适一些。
- cookie 所能存储的信息大小较 session 的小,cookie 一般不超过 4k
cookie 和 session 的生命周期:
cookie 有两种:一、没有设置过期时间(存在内存),则在浏览器关闭时失效;二、设置了过期时间(存在磁盘),则到期失效。
session 一般是 30 min 后失效。
在我们平时的编程中可能会碰到这样的问题:打开浏览器测试后一段时间不去理会它,再次刷新时发现 session 失效了。
之前有很多小伙伴都有疑惑,是不是在关闭浏览器之后,session 就失效了呢?
是不是在关闭浏览器之后,session 就失效了呢?
其实事实并不是如此,按常理来说,session是存储在服务端的,所以关闭浏览器对它是否失效是没有影响的 。
tomcat 的默认的 session 存储时间为30分钟,从第一次请求创建 session 开始计时,超时后不论浏览器是否关闭,session 都会失效。
session 是服务器对象,每个 session 都由唯一的 sessionid 标识。sessionid 存储于内存中Cookie,关闭浏览器时 sessionid 可能会随内存中 Cookie 消失,而session 不会随之消失。不过再次打开浏览器发送请求时,服务端已经无法找到原有的 session了;也就是说session 是存在的 (session 超时后会被清除) ,但是没能根据 id 找到了。
浏览器禁用cookie了,怎么办?
- 重写 URL ,在 URL 后面以参数的形式带上 sessionid
同源 vs 跨域
同源策略是浏览器的一个重要的安全策略,它用于限制一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互。
简单点来说就是:.com下的js脚本采用ajax读取b.com里面的文件数据是会报错的。
那什么叫同源呢?
如果两个 URL 的协议、端口 (en-US)(如果有指定的话)和主机都相同的话,则这两个 URL 是同源的
下表给出了与 URL http://store.company.com/dir/page.html 的源进行对比的示例:
| URL | 结果 | 原因 |
|---|---|---|
http://store.company.com/dir2/other.html | 同源 | 只有路径不同 |
http://store.company.com/dir/inner/another.html | 同源 | 只有路径不同 |
https://store.company.com/secure.html | 失败 | 协议不同 |
http://store.company.com:81/dir/etc.html | 失败 | 端口不同(http:// 默认端口是 80) |
http://news.company.com/dir/other.html | 失败 | 主机不同 |
那什么是跨域呢?
可以简单点理解为:不同源访问即跨域
跨域里面有涉及到资源共享等知识,有兴趣的小伙伴可以参考:跨源资源共享(CORS) - HTTP | MDN (mozilla.org)
分布式中的场景
刚刚我们讨论的cookie 、session都是默认在单体架构上讨论的,可是现在技术更新飞快,动不动就分布式。。。
所以如果是在分布式架构中,还是会有新问题的。
可以看到在上图中,用户只在订单服务A中生成了session,而订单服务B中没有,这导致他下一次请求被路由到订单服务B的时候需要重新登录。
这是不符合预期的,因为在用户的角度看来,他只知道他刚在订单服务登录了,你现在又要他登录(订单服务的个数对用户透明)。
为解决此问题可以有两种解决方案:
- 服务间同步session
- 共享session
服务间同步session
但是这种方法对占用一定的服务器性能!
共享session
参考文献: