分布式系统下的session怎样存储

x33g5p2x  于2022-02-11 转载在 其他  
字(5.6k)|赞(0)|评价(0)|浏览(615)

📒博客首页:崇尚学技术的科班人
🍣今天给大家带来的文章是《分布式系统下的session怎样存储》🍣
🍣希望各位小伙伴们能够耐心的读完这篇文章🍣
🙏博主也在学习阶段,如若发现问题,请告知,非常感谢🙏
💗同时也非常感谢各位小伙伴们的支持💗

1、什么是分布式系统?

(1)、定义

这里我引用名人Leslie Lamport一句话

  • 旨在支持应用程序和服务的开发,可以利用物理架构由 多个自治的处理元素不共享主内存,但 通过网络发送消息合作

(2)、三个特点和三个概念

三个特点

  1. 多节点
  2. 消息通信
  3. 不共享内存

三个概念

  1. 分布式系统:假如微信订单系统上的多台服务器上,有的服务器上部署的是卖家端,而有的服务器上部署的是买家端,那么这样的集群就是分布式系统。
  2. 集群:假如一个项目中的系统上的多台服务器上,所有服务器上部署的都是相同的内容,那么这样的多台服务器所形成的就是集群。
  3. 分布式计算:就是我们把一个任务进行拆分成多个小任务,然后将多个小任务的结果结合在一起形成总的任务的结果,这样的过程就是分布式计算。

(3)、分布式和集群的区别和联系

  1. 分布式系统可以包含集群。比如说,我们的一个分布式项目,它上面的部署了很多的功能模块节点,它的每一个功能模块节点上可以部署了很多的集群。所以分布式系统中可以包含集群。
  2. 但是一个集群不一定是一个分布式系统。例如,我们一个All In One的项目,它上面部署了很多的集群节点,但是它就不是分布式系统。

2、广义的session

  1. 在我们的一个项目的用户的登录和登出模块,用户登录就是验证身份和存储信息用户登出就是将浏览状态失效
  2. http协议是无状态的,对于同一次http请求是没有上下文关系的。
  • 面临的问题:用户状态怎样存储?
    通过session(会话控制)来存储用户信息和用户浏览状态。

2.1、实现方式一:sessionId

  • 当浏览器发起请求的时候,服务器会创建一个JSESSIONIDkeyvalue。服务器通过setCookieJSESSIONID设置在http请求头上,客户端会将该信息存储在客户端内部,然后每一次请求都会带上该信息。

2.2、实现方式二:token

  • 如果是token方式的话,我们需要手动的在http请求头上或者url上设置token字段,请求发送到服务器的时候,服务器回去出token字段的相关值进行验证。如果要求十分严格的话,token会结合签名一起使用。

3、分布式系统下的session

1. 非分布式系统下的架构情况

2. 分布式系统下的架构情况

  • **水平扩展:**该扩展方法就是将一个服务器进行克隆的多部署几台服务器,每一台服务器上的部署的内容都是相同的。
  • **垂直扩展:**垂直扩展就是将一个服务项目进行拆分成多个模块然后部署在多个tomcat服务器上,这样多个服务器上的部署内容是不相同的。
  • **逃不开的问题:**那就是session该如何进行存储?

**解决该问题的最好的方法:**就是利用redis做缓存,然后多台tomcatredis进行查询,进而获得对应用户的信息,进而进行后续操作。这样就能很好的解决分布式系统下的session问题。

4、解决办法

  • ReidsConstant
  1. /**
  2. * redis常量
  3. * @author :小肖
  4. * @date :Created in 2022/2/7 21:41
  5. */
  6. public interface RedisConstant {
  7. String TOKEN_PREFIX = "token_%s";
  8. Integer EXPIRE = 7200; // 设置过期时间,单位是s
  9. }
  • CookieConstant
  1. /**
  2. * @author :小肖
  3. * @date :Created in 2022/2/7 21:55
  4. */
  5. public interface CookieConstant {
  6. String TOKEN = "token";
  7. Integer expire = 7200; // 单位是秒
  8. }
  • CookieUtil
  1. import javax.servlet.http.Cookie;
  2. import javax.servlet.http.HttpServletRequest;
  3. import javax.servlet.http.HttpServletResponse;
  4. import java.util.HashMap;
  5. import java.util.Map;
  6. /**
  7. * @author :小肖
  8. * @date :Created in 2022/2/7 21:47
  9. */
  10. public class CookieUtil {
  11. public static void set(HttpServletResponse response,
  12. String name,
  13. String value,
  14. int maxAge){
  15. Cookie cookie = new Cookie(name,value);
  16. cookie.setPath("/");
  17. cookie.setMaxAge(maxAge);
  18. response.addCookie(cookie);
  19. }
  20. public static Cookie get(HttpServletRequest request,
  21. String name){
  22. Map<String, Cookie> cookieMap = getCookieMap(request);
  23. if(cookieMap.containsKey(name)){
  24. return cookieMap.get(name);
  25. }else{
  26. return null;
  27. }
  28. }
  29. private static Map<String,Cookie> getCookieMap(HttpServletRequest request){
  30. Map<String,Cookie> map = new HashMap<>();
  31. Cookie[] cookies = request.getCookies();
  32. if(cookies != null){
  33. for(Cookie cookie : cookies){
  34. map.put(cookie.getName(),cookie);
  35. }
  36. }
  37. return map;
  38. }
  39. }
  • ProjectUrl
  1. import lombok.Data;
  2. import org.springframework.boot.context.properties.ConfigurationProperties;
  3. import org.springframework.stereotype.Component;
  4. /**
  5. * @author :小肖
  6. * @date :Created in 2022/2/7 15:19
  7. */
  8. @ConfigurationProperties("projectUrl")
  9. @Data
  10. @Component
  11. public class ProjectUrl {
  12. /**
  13. * 微信公众平台授权url
  14. */
  15. public String wechatMpAuthorize;
  16. /**
  17. * 微信开放平台授权url
  18. */
  19. public String wechatOpenAuthorize;
  20. /**
  21. * 项目地址
  22. */
  23. public String sell;
  24. }
  • SellerUserController
  1. import com.xiao.bean.SellerInfo;
  2. import com.xiao.config.ProjectUrl;
  3. import com.xiao.constant.CookieConstant;
  4. import com.xiao.constant.RedisConstant;
  5. import com.xiao.enums.ResultEnum;
  6. import com.xiao.service.SellerService;
  7. import com.xiao.utils.CookieUtil;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.data.redis.core.StringRedisTemplate;
  10. import org.springframework.stereotype.Controller;
  11. import org.springframework.web.bind.annotation.GetMapping;
  12. import org.springframework.web.bind.annotation.RequestMapping;
  13. import org.springframework.web.bind.annotation.RequestParam;
  14. import org.springframework.web.servlet.ModelAndView;
  15. import javax.servlet.http.Cookie;
  16. import javax.servlet.http.HttpServletRequest;
  17. import javax.servlet.http.HttpServletResponse;
  18. import java.util.Map;
  19. import java.util.UUID;
  20. import java.util.concurrent.TimeUnit;
  21. /**
  22. * 卖家用户信息
  23. * @author :小肖
  24. * @date :Created in 2022/2/7 21:26
  25. */
  26. @Controller
  27. @RequestMapping("/seller")
  28. public class SellerUserController {
  29. @Autowired
  30. private SellerService sellerService;
  31. @Autowired
  32. private StringRedisTemplate redisTemplate;
  33. @Autowired
  34. private ProjectUrl projectUrl;
  35. /**
  36. * 该url可以和微信登录的扫码登录进行配置,可以作为returnUrl进行配置
  37. * 登录
  38. * @param openid
  39. * @param response
  40. * @param map
  41. * @return
  42. */
  43. @GetMapping("/login")
  44. public ModelAndView login(@RequestParam("openid") String openid,
  45. HttpServletResponse response,
  46. Map<String, Object> map) {
  47. // 1. 查询数据库匹对信息
  48. SellerInfo sellerInfo = sellerService.findSellerInfoByOpenid(openid);
  49. if(sellerInfo == null){
  50. map.put("msg", ResultEnum.LOGIN_FAIL.getMessage());
  51. map.put("url","/sell/seller/order/list");
  52. return new ModelAndView("common/error", map);
  53. }
  54. // 2. 向redis 中设置token
  55. String token = UUID.randomUUID().toString();
  56. Integer expire = RedisConstant.EXPIRE;
  57. redisTemplate.opsForValue().set(String.format(RedisConstant.TOKEN_PREFIX,token),openid,expire, TimeUnit.SECONDS);
  58. // 3. 添加cookie
  59. CookieUtil.set(response, CookieConstant.TOKEN,token,expire);
  60. return new ModelAndView("redirect:" + projectUrl.getSell() + "/sell/seller/order/list");
  61. }
  62. /**
  63. * 登出
  64. * @param request
  65. * @param response
  66. * @param map
  67. * @return
  68. */
  69. @GetMapping("/logout")
  70. public ModelAndView logout(HttpServletRequest request,
  71. HttpServletResponse response,
  72. Map<String, Object> map) {
  73. Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN);
  74. if(cookie != null){
  75. // 1. 清除redis
  76. redisTemplate.opsForValue().getOperations().delete(String.format(RedisConstant.TOKEN_PREFIX,cookie.getValue()));
  77. // 2. 清除cookie
  78. CookieUtil.set(response,CookieConstant.TOKEN,null,0);
  79. }
  80. map.put("msg",ResultEnum.LOGOUT_SUCCESS.getMessage());
  81. map.put("url","/sell/seller/order/list");
  82. return new ModelAndView("common/success",map);
  83. }
  84. }
  • 其上实现的逻辑就是我们将用户的相关信息设置进redis缓存中,并设置相关的过期时间,如果用户登出的时候我们就将其在redis缓存中删除。

相关文章