分布式 Session 原理,最简单而高效的实现方式

Posted sp42a

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式 Session 原理,最简单而高效的实现方式相关的知识,希望对你有一定的参考价值。

问题1,你要理解 JSESSIONID 与 cookie 是什么关系,session 与 cookie 到底有什么关系。

简单来说,当第一次 request serve r时,server 产生 JSESSIONID 对应的值1,通过 http header set-cookie,传递给 browser,browser 检测到 http response header 里带 set-cookie,那么 browser 就会 create 一个 cookie,key=JSESSIONID,value=值1,而后的每次请求,browser 都会把 cookie 里的键值对,放到 http request header 里,传递给 server。

当在 server 端调用 http.getSession() 方法时,server 会先从 http request header 里解析出来 JSESSIONID 的值,再从一个 Map 容器里去找有没有 value,如果没有,就会产生一个 HttpSessioon 对象,放到这个 Map 容器里,同时设置一个最大生存时间。HttpSession 你也可以把它想象成是一个 Map,可以 getAttribute(),可以 setAttribute()。

cookie 和 session 就这么简单。好,现在我们说说分布式 Session 如何实现。

最前端的负载均衡器,如 nginx,会把 request 原封不动的平均分配到集群中的一台机器,所谓原封不动,就是指的 request header 里的内容不变。我们先来看看 tomcat 是怎么处理单机的 session 的。




问题2,具体实现分布式 Session

好,看明白了吧,其实要实现分布式 Session,只要得到 JSESSIONID 的值就可以了,剩下的操作无非就是根据 key 去 redis 或 memcache 中存取值,并缓存到本机内存中。

String requestedSessionId = req.getRequestedSessionId();//这就代表某一位用户了,至于有没有登录,那就看 Session 属性里是否有登录后的信息即可。

//TODO, DSession dSession= DistributeSessionManager.getDistributeSession(requestedSessionId);

//TODO, DSession 是一个接口,至少要提供以下相类似的方法

问题3,在集群中的某一台机器上,如何高效的判断Session过期

tomcat 源码是得到一个 sessionList,然后遍历,这种做法是相当低效的,源码分析请参考 http://www.tuicool.com/articles/6fMZvq

有个叫 Timing Wheel(时间轮) 的东西,这个东西很棒,可以高效的管理超大量的定时任务,也是能想到的最高效最好的设计方案,而且 Timing Wheel 的 java 实现也简单。

问题4,分布式session,如何处理 logout

loginIn 还好说,直接根据 sessionid 从 cache 中拿数据即可。但是怎么处理 logout 呢,logout 时,要清理 local cache 中与 session 相关的信息。由于 logout 对实时性要求几乎没有,晚个几少钟几十秒钟都无所谓的,所以可以利用消息中间件来处理,比如 ActiveMQ 等。

问题5,最好的分布式 session 处理方法是什么

最好的处理方法就是让前端的 LoadBalance,根据 sessionId,把请求进行 hash 或一致性 hash,让用户固定到集群中的某台机器上,这样做最大的好处是,可以充分利用内存,相当于单机处理逻辑了。所以呢,分布式 Session 处理方案就被简化了太多太多了,与单机处理逻辑没有任何差别。

我在分布式 session 上的一些实践

https://blog.csdn.net/u012422829/article/details/72957189

系统拓扑

  • 1台 Redis 服务器,用来存储 session。
  • 2台 Tomcat 服务器,访问 Redis 进行 session存储。
  • 1台 Nginx 服务器,作为反向代理以及负载均衡器,把请求转发到 Tomcat 服务器上
  • 用户直接访问 Nginx 服务器

Nginx 作为反向代理

由于 Nginx 的多进程模式以及事件驱动, 它作为一个 web 服务器的性能是相当好的。 至于怎么用它来做反向代理,只需要很简单的配置 nginx.conf 文件的以下部分并且重启 Nginx 即可:

upstream web_app
    server      ip1:port;
    server      ip2:port;


server 
    listen       80;
    server_name  localhost;

 
    location / 
        proxy_pass      http://web_app;
        proxy_set_header        X-Real-IP       $remote_addr;
    

这里的 ip1, ip2 以及 port 就是你的两台 tomcat 的地址。

使用 Redis 存储 Session

Tomcat 默认会把 session 存储在内存中,一方面限制了最大 session 数量,另一方面又阻碍了做分布式拓展。 一个解决方案就是用 Redis 或者别的数据库来持久化 session。在 SpringMVC 中的实现就很简单了,只要在 spring 配置文件中配置以下的 bean 即可:

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxTotal" value="$redis.maxTotal"/>
    <property name="maxIdle" value="$redis.maxIdle"/>
    <property name="maxWaitMillis" value="$redis.maxWaitMillis"/>
    <property name="testOnBorrow" value="$redis.testOnBorrow"/>
</bean>
 
<bean id="jedisConnectionFactory"
      class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="hostName" value="$redis.host"/>
    <property name="port" value="$redis.port"/>
    <property name="timeout" value="$redis.timeout"/>
    <property name="poolConfig" ref="jedisPoolConfig"/>
</bean>
 
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory"/>
</bean>

    <bean id="redisHttpSessionConfiguration"
          class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        <property name="maxInactiveIntervalInSeconds" value="1800"/>
    </bean>

这个配置是什么意思呢?

首先前3个 bean 配置了对 redis 的连接和访问,我们可以在代码中直接用 redisTemplate 去操作 Redis。最后一个 bean 的作用是配置 web 容器(在这里是 tomcat)对 Session 的管理方法。

至于 Tomcat 是如何管理 Session 的,可以参考这篇文章: http://www.cnblogs.com/interdrp/p/4935614.html

以上是关于分布式 Session 原理,最简单而高效的实现方式的主要内容,如果未能解决你的问题,请参考以下文章

详解Dubbo的原理以及详细原理配置

如何使用Spring Session实现分布式Session管理

Redis实战和核心原理详解使用Spring Session和Redis解决分布式Session跨域共享问题

详解集群内Session高可用的实现原理

dubbo实现原理

Dubbo的原理以及详细原理配置