集群环境下的用户会话方案
集群环境下的用户会话方案
南湖船老大 发表于1年前
集群环境下的用户会话方案
  • 发表于 1年前
  • 阅读 52
  • 收藏 1
  • 点赞 0
  • 评论 0

集群环境下,必然需要考虑用户和会话的问题,如果不加处理的话,由于每一个会话cookies是对应服务器后端的一个session(Java是jsessionid,PHP是PHPSESSID),也就是说session是和具体的服务器绑定的,一旦后端IP轮询切换,会话cookies找不到对应的session,会话也就断了。在这种场景下,就存在5种处理方案。下文主要讨论的是Java和PHP的处理,对于其他语言一样适用。

    1、依然使用集群,但集群的轮训策略使用hash ip,将每一个客户和后端服务器绑定,这样一来,用户的会话始终落在一台固定的服务器上,这也是成本最小的方案。如果是很老的架构的话,这种方案是改造成本最小的。

upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
    server.backend3.example.com;
}

但这样存在一个问题,就是一旦某台服务器挂了,切换到另外一台服务器后,对应的会话也就丢了。还存在一个情况就是如果前端是CDN的话,客户端IP可能变化的频率是很高的,有可能是一个小时或更短就变一次,在校园网这种网络环境下也容易产生这种情况。

2、使用session复制方案。这是早期tomcat采用的方案。

    session复制模式就可以很好的解决failureover的问题,即某一台web服务器挂掉后,用户的请求还会被负载到其他的web服务器上,而且由于session也被复制了,这样对用户而言就像是在同一台机器上操作一样。不好的地方就是session复制需要系统资源和网络的开销,也就是所谓的“网络风暴”,尤其是当web服务器多的时候或session里存储的数据量大的时候,这点将会比较的明显。
  session复制本身的操作还是比较复杂的,但是对于服务器来说,配置也算简单,但性能是个很大的问题。当处于一个大于两台服务器的集群中时,复制就比较吃力了。这种方案现在一般不使用了。

3、Nginx的sticky方案。

    其实sticky方案和方案一类似,但是sticky能做到把会话死死的粘滞在其中一台服务器上,算是方案一的补充,可以避免CDN网络下的客户端IP突变。很明显,方案1和方案3都存在failover的问题。

4、方案4,NoSQL的集中存储方案

    基于Redis等NoSQL的session集中存储。这种是目前最流行的方案,早期的方案是用MySQL来存储。但仍然存在以下问题:

(1)redis有单点,并且redis的引入增加了系统复杂度,要解决这个单点就得使用redis集群方案,比如codis。

(2)用户量大的情况下,用来连接redis的类库可能存在瓶颈,比如有部分用户反应jedis性能不稳定,高并发下容易挂。

但是就配置而言,不论是PHP还是Java都相对很简单,例如对于PHP而言,只需要安装predis扩展,在php.ini里配置下session存储方案即可

vi /etc/php.ini
session.save_handler = redis
session.save_path = "tcp://192.168.1.102:6379?timeout=15"

注意注释掉/etc/php-fpm.d/www.conf里session的配置,以免配置被覆盖而无效。

对于Java而言,只需要引入一个jar包(https://github.com/jcoleman/tomcat-redis-session-manager),配置server.xml即可。

    不过,对于tomcat而言,tomcat在启动时就会创建一个session,当会话越多的时候,session也就越多。而session在tomcat中属于重量级对象。一个没有任何内容的空session就需要消耗1.5K的内存存储空间。当然,使用redis都是默认内存足够大。

5、放弃session,使用纯cookies

    纯cookies,不使用session,天然分布式。存在的问题:

(1)cookies需要加解密,性能消耗要考虑,而且不能存太多东西,如果cookies存放了一些复杂的数据时,序列化本身消耗也不少。

(2)对于浏览器而言,每次请求都会带上cookies,包括JS和CSS等请求,浪费宽带,除非部署了CDN或专用服务器。这时就需要为静态文件配置一个独立的域名了。其实这个问题,前面几个方案同样存在。

  另外也可以转用token与openid等方式验证用户。

    我个人所使用的方案是方案5+方案4的结合,即仅使用cookies来存储会话标记,不使用应用服务器本身自带的session方案,对于会话信息,不使用session存储,而是直接存放到Redis中。本质上就是方案4的基础上,自己实现一套session机制。这种实现要看具体的语言而定。对于PHP而言,这种做法是多此一举。而对于Java而言,由于tomcat的session实现比较重量级,这种做法能提高一些性能。针对这种方案,我实现了一个自定义的session管理器,用来替代tomcat的默认session管理器,达到节省内存,提高性能的目的。地址在此:

https://github.com/iminto/tomcat-no-session

    需要注意的是:对于方案5,存在一个问题就是如果应用需要考虑“禁止同时登录”的时候,用cookies的解决方案就麻烦很多了。

      如果有更好的方案,也希望你能提供给我。

共有 人打赏支持
粉丝 674
博文 12
码字总数 11172
×
南湖船老大
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: