分布式Session

背景:对于秒杀服务,实际的应用可能部署在不止一个服务器上,而是分布式的多台服务器,这时候要是用户登录是在第一个服务器,但是操作的时候第二个请求在第二个服务器,就会丢失用户的Session信息,最少你的重新登录。

一。分布式Session的几种实现方式

1.基于数据库的Session共享

2.基于NFS共享文件系统
3.基于memcached 的session,如何保证 memcached 本身的高可用性?
4. 基于resin/tomcat web容器本身的session复制机制
5. 基于TT/Redis 或 jbosscache 进行 session 共享。

6. 基于cookie 进行session共享

链接:

转载自:http://blog.csdn.net/u014352080/article/details/51764311       分布式Session的几种实现方式

本文的方式:利用一台缓存服务器集中管理session。

缓存集中式管理

       简介:将Session存入分布式缓存集群中的某台机器上,当用户访问不同节点时先从缓存中拿Session信息

       使用场景:集群中机器数多、网络环境复杂

       优点:可靠性好

       缺点:实现复杂、稳定性依赖于缓存的稳定性、Session信息放入缓存时要有合理的策略写入

相对还有其他几种: 各有优缺点

Session Replication 方式管理 (即session复制)

        简介:将一台机器上的Session数据广播复制到集群中其余机器上

        使用场景:机器较少,网络流量较小

        优点:实现简单、配置较少、当网络中有机器Down掉时不影响用户访问

        缺点:广播式复制到其余机器有一定廷时,带来一定网络开销

Session Sticky 方式管理

        简介:即粘性Session、当用户访问集群中某台机器后,强制指定后续所有请求均落到此机器上

       使用场景:机器数适中、对稳定性要求不是非常苛刻

       优点:实现简单、配置方便、没有额外网络开销

        缺点:网络中有机器Down掉时、用户Session会丢失、容易造成单点故障


一、Session Replication 方式管理 (即session复制)

        简介:将一台机器上的Session数据广播复制到集群中其余机器上

        使用场景:机器较少,网络流量较小

        优点:实现简单、配置较少、当网络中有机器Down掉时不影响用户访问

        缺点:广播式复制到其余机器有一定廷时,带来一定网络开销


二、Session Sticky 方式管理

        简介:即粘性Session、当用户访问集群中某台机器后,强制指定后续所有请求均落到此机器上

       使用场景:机器数适中、对稳定性要求不是非常苛刻

       优点:实现简单、配置方便、没有额外网络开销

        缺点:网络中有机器Down掉时、用户Session会丢失、容易造成单点故障


本文实现:


    /*到达这里说明登陆成功
    * 需要保存 相关 session信息写入 cookie 用于登陆*/
    /*封装一个addCookie 方法 方便 重用*/
    String token = UUIDUtill.uuid();
    addCookie(miaoshaUser,token,response);//登陆成功 写入token ,同时写入 缓存和 cookie 之中
    return true;

}

本项目的做法:

在登录完成的最后一步,需要带着Session信息。 1.利用uuid生成秘钥(sessionId) 2.将user信息,对象。同时写入cookie cookie作为response返回给客户端, 另外 将sessionId +前缀 一起作为Key,存入Redis 缓存中。当访问其他页面的时候,就可以从cookie中获取 token,再访问redis 拿到用户信息来判断登录情况了。

后续这个还有可以优化----解析参数,在获取token后在WebConfig中直接加入这个session的方法来拿到user


    private void addCookie(MiaoshaUser miaoshaUser,String token,HttpServletResponse response){
//        String token = UUIDUtill.uuid();  当我们延长有效期的时候 没有必要每次都生成新的token 直接延用 老的就可以了

        /*将用户sessionId和用户信息 以键值形式 保存到 redis */
        redisService.set(MiaoshaUserKey.token,token,miaoshaUser);
        /*cookie 键值对都是 String类型*/
        Cookie cookie = new Cookie(COOKIE_TOKEN_NAME,token);
        /*设置cookie的过期时间*/
        cookie.setMaxAge(MiaoshaUserKey.token.expireSeconds());
        /*cookie 保存路径*/
        cookie.setPath("/");
        /*需要一个 response 对象 将cookie 返回给 客户端*/
        response.addCookie(cookie);
    }
}
 

Session 有效期处理,将cookie的有效期,设置在缓存的有效期。

2个关键的地方:1.再次访问,延长session有效期,即我们取到user对象之后,先不返回,再利用token 添加到缓存中,就可以实现每次访问页面都会延长时间。

public MiaoshaUser getByToken(HttpServletResponse response,String token) {
    if (StringUtils.isEmpty(token)){
        return null;
    }
    /*根据token 和前缀  去redis 中取出 对应的 用户信息值*/
    MiaoshaUser user =  redisService.get(MiaoshaUserKey.token,token,MiaoshaUser.class);
    /*延长有效期*/
    if (user!=null){
        addCookie(user,token,response);
    }
    return user;
}


优化:

 虽然已经实现分布式session,但是每次都要访问页面都要通过cookie中拿到token,然后token 再去redis中取出user信息,来判断登录情况。很麻烦。

我们知道SpringMVC中的controller 方法中可以有很多参数,有些参数不需要传值,就可以直接获取(解析到),这里就会用到addArguementResolver() 和 HandlerMethodArguementResolver类。

HandlerMethodArgumentResolver

/* 通过 重写 springmvc 配置 方法 达到 无需传递参数的效果 自动获取 user session */
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter{
    @Autowired
    private  UserArguementResolver userArguementResolver;

    @Autowired
    AccessInterceptor accessInterceptor;
    /*解析参数*/
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(userArguementResolver);

    }
/*要将 MiaoshaUser 类 参数对象 注册 进来*/
@Service
public class UserArguementResolver implements HandlerMethodArgumentResolver {

    @Autowired
    private MiaoshaUserService miaoshaUserService;
    /* 判断是否是MiaoshaUser  */
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        Class<?> clazz = methodParameter.getParameterType();/*获取参数类型*/
        return clazz == MiaoshaUser.class; /* 若是 MiaoshaUser 类 才进行下一步*/
    }
    /*具体操作  获取到user 对象的参数 值 */
    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
                                  NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        return UserContext.getUser();

一、Session Replication 方式管理 (即session复制)

        简介:将一台机器上的Session数据广播复制到集群中其余机器上

        使用场景:机器较少,网络流量较小

        优点:实现简单、配置较少、当网络中有机器Down掉时不影响用户访问

        缺点:广播式复制到其余机器有一定廷时,带来一定网络开销


二、Session Sticky 方式管理

        简介:即粘性Session、当用户访问集群中某台机器后,强制指定后续所有请求均落到此机器上

       使用场景:机器数适中、对稳定性要求不是非常苛刻

       优点:实现简单、配置方便、没有额外网络开销

        缺点:网络中有机器Down掉时、用户Session会丢失、容易造成单点故障

做法:重写上述2个方法:

就是遍历Controller 参数列表,如果有User这个参数,就解析他,然后根据request cookie 拿到我们cookie 在从cookie

取缓存,并赋值给这个参数。

        /*第一步 : 取出request ,response */
        HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
        HttpServletResponse response = nativeWebRequest.getNativeResponse(HttpServletResponse.class);
        /*第二步 : 取出token */
        String paramToken = request.getParameter(MiaoshaUserService.COOKIE_TOKEN_NAME);
        String cookieToken = getCookieValue(request,MiaoshaUserService.COOKIE_TOKEN_NAME);

        if (StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken))
        {/*如果 cookie 中都没有值 返回 null 此时返回的 值 是给 MiaoshaUser 对象的 就是解析的参数值*/
            return null;
        }
        /*有限从paramToken 中取出 cookie值 若没有从 cookieToken 中取*/
        String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken;
        return miaoshaUserService.getByToken(response,token);/*拿到 user 对象*/
//    }
//
    private String getCookieValue(HttpServletRequest request, String cookieTokenName) {
        /*在 请求中 遍历所有的cookie 从中取到 我们需要的那一个cookie 就可以的*/
        Cookie[] cookies =  request.getCookies();
        /*请求中没有cookies 的时候返回null ?? 没有cookie ? 没有登录吗?*/
        if (cookies == null || cookies.length ==0)
        {
            return null;
        }
        for (Cookie cookie: cookies) {
            if (cookie.getName().equals(cookieTokenName))
                return cookie.getValue();
        }
        return null;
    }

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值