什么是Session/Cookie
用户使用网站的服务,基本上需要浏览器与Web服务器的多次交互。HTTP协议本身是无状态的,当用户的第一次访问请求结束后,后端服务器就无法知道下一次来访问的还是不是上次访问的用户。我们需要基于HTTP协议支持会话状态的机制,这样的机制可以使Web服务器从多次单独的HTTP请求中知道哪些请求是来自哪个会话的。
Session与Cookie的作用都是为了保持访问用户与后端服务器的交互状态。
理解Cookie
Cookie的作用通俗的说就是当一个用户通过HTTP协议访问一个服务器的时候,这个服务器会将一些Key/Value键值对返回给客户端浏览器,并给这些数据加上一些限制条件,在条件符合时这个用户下次访问这个服务器的时候,数据又被完整地带回给服务器。
理解Session
Cookie可以让服务端程序跟踪每个客户端的访问,但是每次客户端的访问都必须传回这些Cookie,如果Cookie很多,这无形地增加了客户端与服务端的数据传输量,而Session的出现正是为了解决这个问题。
同一个客户端每次和服务端交互时,不需要每次都传回所有的Cookie值,而是只要传回一个会话标识(SessionId),这个ID是客户端第一次访问服务器的时候生成的,而且每个客户端是唯一的。这样每个客户端就有一个唯一的ID,客户端只要传回这个ID就行了,这个ID通常是NAME为JSESIONID的一个Cookie。在Web服务器上,各个会话独立存储保存不同会话的信息。如果遇到禁用Cookie的情况,一般的做法就是把这个会话标识放到URL的参数中。
总结
Cookie和Session都是为了保持用户访问的连续状态,之所以要保持这种状态,一方面是为了方便业务实现,另一方面就是简化服务端程序设计,提高访问性能。但也带来了一些问题,如安全问题、集群环境下Session同步问题等
集群遇到的问题
当我们的应用服务器变为多台的时候就会遇到Session共享的问题。当我们第一次访问网站的时候,负载均衡将本地的请求分配到Web服务器1,那么Session创建在Web服务器1,第二次访问的时候如果我们不做处理就不能保证还是会落到Web服务器1了。
解决集群Session共享问题
1. Session Sticky
让负载均衡器能够根据每次的请求的会话标识来进行请求的转发,这样就能保证每次都能落到同一台服务器上面,这种方式称为Session Sticky方式。如下图:
存在问题:
1. 如果这一台Web服务器宕机或者重启了,服务器上的会话数据会丢失,用户需要重新登陆等。
2. 会话标识是应用层的信息,那么负载均衡器要将同一个会话的请求都保存到同一个Web服务器上的话,就需要进行应用层的解析,这个开销比第四层交换(LVS负载均衡器属于第四层)要大。
3. 负载均衡器变为一个有状态的节点,要将会话保存到具体的Web服务器的映射。和无状态的节点相比,内存消耗会更大,容灾方面会更麻烦。
打个比方,比如Web服务器是饭店,会话数据是碗筷。要保证每次吃饭都用自己的碗筷的话,我就把餐具存在某一家饭店,并且每次都去这家店吃饭。
2. Session Replication
还是以吃饭的例子,如果我们在每个饭店都存放一套自己的碗筷,就可以自己的选择去哪家吃饭了。这就是Session Replication。如下图:
此方案不用再要求负载均衡器保证同一个会话的多次请求必须到同一个Web服务器上了。我们在Web服务器之间增加了会话数据的同步,通过同步就保证了不同Web服务器之间Session数据的一致。一般应用容器都支持Session Replication方式,与Session Sticky方案相比,Session Replication方式对负载均衡器没有那么多的要求。
存在问题:
1. 同步Session数据造成了网络带宽的开销。只要Session数据有变化,就需要将数据同步到所有其他机器上,机器越多,同步带来的网络带宽开销就越大。
2. 每台Web服务器都要保存所有Session数据,如果整个集群的Session数据很多(很多人同时访问网站)的话,每台机器用于保存Session数据的内容占用会很严重。
这个方案是靠应用容器来完成Session的复制从而解决Session的问题的,应用本身并不关心这个事情。
这个方案不适合集群机器数多的场景。如果只有几台机器,用这个方案是可以的。