写在前面

最近在读一本来自淘宝技术团队大牛的书,名字叫《大型网站系统与Java中间件实践》。开篇的章节详细地介绍了一个网站架构由小变大不断演进的过程,其中从单机架构升级到集群架构的过程中着重介绍了关于session同步问题, 这也是很多人在聊到分布式时绕不过去的话题。下面就整理下书中的内容,也算是做个读书笔记,方便以后参考。

问题从哪来

做web开发的同学应该对session再熟悉不过,它是服务器分配给客户端的会话标识,浏览器每次请求会带上这个标识来告诉服务器我是谁,服务器会在内存中存储这些不同的会话信息,由此来分辨请求来自哪个会话。在单机部署的环境总,因为web服务器和session都是在同一台机器上,所以必然能找到对应的会话数据。但如果有2台web服务器(A和B)提供服务,假如第一次请求落到A上并创建了session,那么如何保证下次落到B的请求能读到session数据?

解决方案

有以下4中常见的解决方案。

1、Session Sticky

这是最简单粗暴的 方法,核心思路就是让同一会话的请求都落地到同一台服务器上,这样处理起来就和单机一样了,我们可以在负载均衡上做一些身份识别并控制转发来达到这个目的。这样做的优势是能像单机一样简化对session处理,也方便做本地缓存,但缺点也是很明显的:

  • 如果这台服务器宕机或重启了,那么所以的会话数据都会丢失,失去了分布式集群带来的高可用特性。

  • 增加了负载均衡器的负担,使它变得有状态了,而且资源消耗会更大,容易成为性能瓶颈。

2、Session Replication

顾名思义,这是一种session复制的方案,核心思路就是通过在服务器之间增加session同步机制来保证数据一致。

看起来比第一种简单了很多,也没有第一种带来的缺陷,但在某些应用场景下还是会有比较严重的问题:

  • 服务器之间的数据同步带来了额外的网络消耗,随着机器数量和数据量的上升,网络带宽将会有很大的压力,也必然会带来延时问题。

  • 每台服务器上都要存储所有的会话数据,如果会话数量很大会占用服务器大部分内存空间。

目前很多应用容器都支持这种同步方式,所以在集群规模和数据量比较小的时候还是一种很好的解决方案。

3、Session集中存储

这种方式的思路就是把所有的会话数据统一存储和管理,所有应用服务器需要对session进行读写都要通过session服务器来操作:

这种方案的好处是独立了session的管理,职责单一化,session服务器采用什么方式存储(内存、数据库、文档、NoSql等等),什么方式对外提供服务都是透明的。不会给应用系统和负载均衡带来额外的开销,不需要进行数据同步就能保证一致性,看起来应该是非常完美了,不过也有自己的一些小缺陷:

  • 对session读写需要网络操作,相比较session直接存储在web服务器的时候增加了时延和不稳定性,好在session服务器和web服务器一般是部署在局域网中,可以最大化减少这个问题。

  • session服务器出现问题将影响所有web服务,如果采用多机部署同时也会带来数据一致性问题。

每种方案带有它独特的优势,同时也会带来相应的新问题,正所谓没有十全十美,只有适合才是最好的。总体来说,这种方案在应用服务器和会话数据量都很大的时候还是非常有优势的。

4、Cookie Base

这种方案是基于cookie的传输来实现的,核心思想很简单,就是把完整的会话数据经过处理后写入到客户端cookie,以后客户端每次请求都带上这个cookie,然后服务端通过解析cookie数据来获取会话信息,如下图所示:

这种方案简单明了,也没有前面几种方案带来的问题,但劣势也非常明显:

  • 首先通过cookie来传递关键数据肯定是不安全的,即便是采用了特殊的加密手段。

  • 如果客户端禁用了cookie,将直接导致服务不可用。

  • cookie的数据是有大小限制的,如果传递的数据超出限制大小,将会导致数据异常。

  • 在http请求中携带大量的数据进行传输会增加网络负担,同样,服务端响应大量数据会导致请求变慢,并发量大的时候会非常可怕。

总结

以上4种方案都是可行的方案,正如前面所说,每种方案各有优劣,不会十全十美,实际应用中要根据需求做权衡和取舍。这些都是属于比较通用的方案,我相信在真正的实践和落地过程中还会有其他问题出现,有经验的过来人或许会有一些另辟蹊径的“套路”,欢迎讨论交流。

最新文章

  1. 巧用transform实现HTML5 video标签视频比例拉伸
  2. Rstudio使用记录
  3. IMoniker接口的成员
  4. java并发库 Lock 公平锁和非公平锁
  5. java 多线程8(守护线程)
  6. DevExpress之lookupedit
  7. Unity GUI 用C#和Javascript写法的区别
  8. BotVS开发基础—2.5 状态信息显示表格
  9. Mysql官方文档翻译系列14.18--MySql备份与恢复
  10. 论文笔记(2):A fast learning algorithm for deep belief nets.
  11. Number and String in JS
  12. 安装Anaconda 之后使用ubuntu自带python
  13. 选择J2EE的SSH框架的理由
  14. c++中的const和volatile知识自我总结
  15. JS 对应CSS 样式
  16. 为什么运行PHP就会出现404错误?
  17. MyEclipse如何安装egi插件及如何将github项目引入MyEclipse中
  18. linux常用命令:scp 命令
  19. 【MVC】View的使用
  20. Hadoop学习之路(七)Hadoop集群shell常用命令

热门文章

  1. Nginx下支持ThinkPHP的Pathinfo和URl Rewrite模式
  2. MFC简单绘制安卓机器人
  3. python list有关remove的问题
  4. php倒计时防刷新
  5. Spring Boot开启https
  6. 增广拉格朗日乘子法(Augmented Lagrange Method)
  7. Linux文件属性上
  8. Failed to sync Gradle project 'XX'错误解决
  9. accp8.0转换教材第11章JAjax加护扩展理解与练习
  10. Mybatis(七) mybatis的逆向工程的配置详解