【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【19】认证服务03—分布式下Session共享问题


持续学习&持续更新中…

守破离


【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【19】分布式下Session共享问题

  • session原理
  • 分布式下session共享问题
  • Session共享问题解决—session复制
  • Session共享问题解决—客户端存储
  • Session共享问题解决—hash一致性
  • Session共享问题解决—统一存储
  • Session共享问题解决—不同服务,子域session共享
  • 手动设置Cookie,手动拿取Cookie
  • 整合SpringSession
  • SpringSession核心原理
  • 参考

session原理

在这里插入图片描述

问题:不能跨不同域名共享

在这里插入图片描述

分布式下session共享问题

在这里插入图片描述

在这里插入图片描述

Session共享问题解决—session复制

在这里插入图片描述

优点 :web-server(Tomcat)原生支持,只需要修改配置 文件

缺点 :

  • session同步需要数据传输,占用大量网络带宽,降低了服务器群的业务处理能力
  • 任意一台web-server保存的数据都是所有web- server的session总和,受到内存限制无法水平扩展更多的web-server
  • 大型分布式集群情况下,由于所有web-server都全量保存数据,所以此方案不可取。

Session共享问题解决—客户端存储

在这里插入图片描述

优点

  • 服务器不需存储session,用户保存自己的 session 信息到 cookie 中。节省服务端资源

缺点

  • 都是缺点,这只是一种思路。
  • 具体如下:
  • 每次http请求,携带用户在cookie中的完整信息, 浪费网络带宽
  • session数据放在cookie中,cookie有长度限制 4 K,不能保存大量信息
  • session数据放在cookie中,存在泄漏、篡改、 窃取等安全隐患
  • 这种方式不会使用。

Session共享问题解决—hash一致性

在这里插入图片描述

优点:

  • 只需要改nginx配置,不需要修改应用代码
  • 负载均衡,只要hash属性的值分布是均匀的,多台 web-server的负载是均衡的
  • 可以支持web-server水平扩展(session同步法是不行的,受内存限制)

缺点:

  • session还是存在web-server中的,所以web-server重启可能导致部分session丢失,影响业务,如部分用户需要重新登录
  • 如果web-server水平扩展,rehash 后session 重新分布, 也会有一部分用户路由不到正确的session
  • 但是以上缺点问题也不是很大,因为session本来都是有有效期的。所以这两种反向代理的方式可以使用

Session共享问题解决—统一存储

在这里插入图片描述

优点:

  • 没有安全隐患
  • 可以水平扩展,数据库/缓存水平切分即可
  • web-server重启或者扩容都不会有 session 丢失

不足:

  • 增加了一次网络调用,并且需要修改应用代码;如将所有的getSession方法替换为从Redis查数据的方式。
  • redis获取数据比内存慢很多
  • 上面缺点可以用SpringSession完美解决

Session共享问题解决—不同服务,子域session共享

jsessionid这个cookie默认是当前系统域名的。当我们分拆服务,不同域名部署的时候,我们可以使用如下解决方案;

放大Cookie作用域

在这里插入图片描述

手动设置Cookie,手动拿取Cookie

gulimall-auth:OAuth2Controller

    @GetMapping("/oauth2.0/weibo/success")
    public String weibo(@RequestParam("code") String code, HttpSession session,
                        HttpServletResponse httpServletResponse) throws Exception {
        Map<String, String> headers = new HashMap<>();
        Map<String, String> bodys = new HashMap<>();
        bodys.put("client_id", "3276999101");
        bodys.put("client_secret", "452bbefff4680ac8554b97799a8c12cb");
        bodys.put("grant_type", "authorization_code");
        bodys.put("redirect_uri", "http://auth.gulimall.com/oauth2.0/weibo/success");
        bodys.put("code", code);
        //1、根据code换取accessToken;
        HttpResponse response = HttpUtils.doPost("https://api.weibo.com", "/oauth2/access_token", headers, null, bodys);
        if (response.getStatusLine().getStatusCode() == 200) {
            //2、获取到了 socialUserAccessToken 进行处理
            String json = EntityUtils.toString(response.getEntity());
            SocialUserAccessToken socialUserAccessToken = JSON.parseObject(json, SocialUserAccessToken.class);
//            String uid = socialUserAccessToken.getUid();
            // 通过uid就知道当前是哪个社交用户
            //1)、当前用户如果是第一次进网站,进行自动注册(为当前社交用户生成一个会员信息账号,以后这个社交账号就对应指定的会员账号)
            R r = memberFeignService.socialLogin(socialUserAccessToken);
            if (r.getCode() == BizCodeEnume.SUCCESS.getCode()) {
                //登录或者注册这个社交用户
                //2)、登录成功就跳回首页

                /**
                 * 手动设置Cookie
                 */
                MemberRespVo loginUser = r.getData(new TypeReference<MemberRespVo>() {
                });
                stringRedisTemplate.opsForValue().set("loginUser", JSON.toJSONString(loginUser));
                Cookie cookie = new Cookie("GULIMALL", "loginUser");
                cookie.setDomain("gulimall.com");
                cookie.setMaxAge(24 * 60 * 60);
                cookie.setPath("/");
                httpServletResponse.addCookie(cookie);
                session.setAttribute("loginUser", loginUser);

                return "redirect:http://gulimall.com";
            }
        }
        return "redirect:http://auth.gulimall.com/login.html";
    }

gulimall-product:IndexController

    @GetMapping({"/", "/index.html"})
    public String indexPage(Model model, HttpServletRequest httpServletRequest, HttpSession session) {

        /**
         * 手动获取Cookie
         */
        Cookie[] cookies = httpServletRequest.getCookies();
        if (null != cookies && cookies.length > 0) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equalsIgnoreCase("GULIMALL")) {
                    String loginUserKey = cookie.getValue();
                    String json = stringRedisTemplate.opsForValue().get(loginUserKey);
                    MemberRespVo loginUser = JSON.parseObject(json, new TypeReference<MemberRespVo>(){});
                    session.setAttribute("loginUser", loginUser);
                }
            }
        }

        List<CategoryEntity> categorys = categoryService.listLevel1Categorys();
        model.addAttribute("categorys", categorys);
        return "index";
    }

@Controller
public class LoginController {
    @GetMapping("/login.html")
    public String loginPage() {
        if(stringRedisTemplate.opsForValue().get("loginUser") != null) return "redirect:http://gulimall.com";
        return "login";
    }
}

整合SpringSession

<!-- 1 整合SpringSession完成session共享问题 -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
# 2 整合SpringSession
spring.session.store-type=redis
#server.servlet.session.timeout=60m
# 3 配置Redis的连接信息(之前配过)
#spring.redis.host=xxx
#spring.redis.port=xxx
#spring.redis.password=xxx
@EnableRedisHttpSession // 4 整合Redis作为session存储
// 5 使用SpringSession【跟以前使用session的写法一样】
//第一次使用session;命令浏览器保存卡号。JSESSIONID这个cookie;
//以后浏览器访问哪个网站就会带上这个网站的cookie;
//子域之间; gulimall.com  auth.gulimall.com  order.gulimall.com
//应该做到:发卡的时候(指定域名为父域名),那么,即使是子域系统发的卡,也能让父域直接使用。
// 1、默认发的令牌。session=xxxxxxx。作用域:当前域;(SpringSession默认没有解决子域session共享问题)
// 2、使用JSON的序列化方式来序列化对象数据到redis中
	R r = memberFeignService.socialLogin(socialUserAccessToken);
	if (r.getCode() == BizCodeEnume.SUCCESS.getCode()) {
	    //登录或者注册这个社交用户
	    //2)、登录成功就跳回首页
	
	MemberRespVo loginUser = r.getData(new TypeReference<MemberRespVo>() {
	});
	session.setAttribute("loginUser", loginUser);

//6 配置序列化 + Cookie domain
// 解决子域session共享问题
@Configuration
public class GulimallSessionConfig {

    @Bean
    public CookieSerializer cookieSerializer(){
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();

        cookieSerializer.setDomainName("gulimall.com");
        cookieSerializer.setCookieName("GULISESSION");
//        cookieSerializer.setCookieMaxAge(); // 默认是浏览器的session级别,关闭浏览器就失效

        return cookieSerializer;
    }

    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }
    
}
<!-- 7 给其他服务也整合好SpringSession后,直接取session中的数据即可  -->
 <a  th:if="${session.loginUser!=null}">欢迎:[[${session.loginUser==null?'':session.loginUser.nickname}]]</a>
                    
//    登录页面
    @GetMapping("/login.html")
    public String loginPage(HttpSession session) {
//        if(stringRedisTemplate.opsForValue().get("loginUser") != null) return "redirect:http://gulimall.com";
        Object attribute = session.getAttribute(AuthServerConstant.LOGIN_USER);
        if(attribute != null) return "redirect:http://gulimall.com";
        return "login";
    }

SpringSession核心原理

/**
 * SpringSession 核心原理 装饰者模式;
 * @EnableRedisHttpSession导入RedisHttpSessionConfiguration配置
 *      1、给容器中添加了一个组件
 *          SessionRepository = 》》》【RedisOperationsSessionRepository】==》redis操作session。session的增删改查封装类
 *      2、SessionRepositoryFilter == 》Filter: session'存储过滤器;每个请求过来都必须经过filter
 *          1、创建的时候,就自动从容器中获取到了SessionRepository;
 *          2、原始的request,response都被包装。SessionRepositoryRequestWrapper,SessionRepositoryResponseWrapper
 *          3、以后获取session。SessionRepositoryRequestWrapper.getSession();
 *          4、wrappedRequest.getSession();===> SessionRepository 中获取到的。
 *
 自动延期;用户只要没有关闭浏览器,SpringSession会自动续期,当然,用户关闭了浏览器,redis中的数据也是有过期时间的。
 */

在这里插入图片描述

参考

雷丰阳: Java项目《谷粒商城》Java架构师 | 微服务 | 大型电商项目.


本文完,感谢您的关注支持!


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/776472.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式linux面试1

1. linux 1.1. Window系统和Linux系统的区别 linux区分大小写windows在dos&#xff08;磁盘操作系统&#xff09;界面命令下不区分大小写&#xff1b; 1.2. 文件格式区分 windows用扩展名区分文件&#xff1b;如.exe代表执行文件&#xff0c;.txt代表文本文件&#xff0c;.…

Seatunnel本地模式快速测验

前言 SeaTunnel&#xff08;先前称为WaterDrop&#xff09;是一个分布式、高性能、易于扩展的数据集成平台&#xff0c;旨在实现海量数据的同步和转换。它支持多种数据处理引擎&#xff0c;包括Apache Spark和Apache Flink&#xff0c;并在某个版本中引入了自主研发的Zeta引擎…

【c++】通过写一个C++函数来模拟跨境洗钱和系统警告

效果图&#xff1a; 源码&#xff1a; #include <iostream> #include <cstdlib> #include <ctime> #include <iomanip> #include <chrono> #include <thread> // 引入线程头文件#ifdef _WIN32 // 确保只在Windows上包含Windows.h #inclu…

zigbee笔记:六、看门狗定时器(Watch Dog)

一、看门狗基础 1、看门狗功能&#xff1a; 由于单片机的工作常常会受到来自外界电磁场的干扰&#xff0c;造成各种寄存器和内存的数据混乱&#xff0c;会导致程序指针错误等&#xff0c;程序运行可能会陷入死循环。程序的正常运行被打断&#xff0c;由单片机控制的系统无法继…

芯片的PPA-笔记

写在前面&#xff1a;这个仅记录自己对芯片PPA的一些思考&#xff0c;不一定正确&#xff0c;还请各位网友思辨的看待&#xff0c;欢迎大家谈谈自己的想法。 1 此次笔记的起因 记录的原因&#xff1a;自己在整理这段时间的功耗总结&#xff0c;又看到工艺对功耗的影响&#x…

12.SQL注入-盲注基于时间(base on time)

SQL注入-盲注基于时间(base on time) boolian的盲注类型还有返回信息的状态&#xff0c;但是基于时间的盲注就什么都没有返回信息。 输入payload语句进行睡5秒中&#xff0c;通过开发这工具查看时间&#xff0c;如图所示&#xff0c;会在5秒钟后在执行&#xff0c;因此存在基于…

面试篇-系统设计题总结

文章目录 1、设计一个抢红包系统1.1 高可用的解决方案&#xff1a;1.2 抢红包系统的设计1.3 其他 2、秒杀系统设计 这里记录一些有趣的系统设计类的题目&#xff0c;一般大家比较喜欢出的设计类面试题目会和高可用系统相关比如秒杀和抢红包等。欢迎大家在评论中评论自己遇到的题…

磁钢生产领域上下料解决方案

随着智能制造技术的不断革新&#xff0c;磁钢生产领域正逐步引入自动化生产线。然而&#xff0c;传统的人工上下料方式存在诸多问题&#xff0c;难以满足现代生产需求。富唯智能提出了一款复合机器人磁钢上下料解决方案&#xff0c;通过先进的自动化技术&#xff0c;提高生产效…

填报高考志愿,怎样正确地选择大学专业?

大学专业的选择&#xff0c;会关系到未来几年甚至一辈子的发展方向。这也是为什么很多人结束高考之后就开始愁眉苦脸&#xff0c;因为他们不知道应该如何选择大学专业&#xff0c;生怕一个错误的决定会影响自己一生。 毋庸置疑&#xff0c;在面对这种选择的时候&#xff0c;我…

Keycloak SSO 如何验证已添加的 SPN 是否生效

使用 Kerberos Ticket 验证&#xff1a; 在客户端计算机上&#xff0c;运行以下命令以获取 Kerberos Ticket&#xff1a; klist检查是否存在与 HTTP/yourdomain.com 相关的票证。如果存在&#xff0c;说明 SPN 已生效。 测试应用程序&#xff1a; 使用具有 HTTP/yourdomain.com…

windows USB 设备驱动开发-控制传输的数据包

每次在主机控制器和 USB 设备之间移动数据时&#xff0c;都会发生传输。 通常&#xff0c;USB 传输可大致分为控制传输和数据传输。 所有 USB 设备都必须支持控制传输&#xff0c;并且可以支持用于数据传输的端点。 每种类型的传输都与设备缓冲区USB 端点 的类型相关联。 控制传…

Linux 查看磁盘是不是 ssd 的方法

lsblk 命令检查 $ lsblk -d -o name,rota如果 ROTA 值为 1&#xff0c;则磁盘类型为 HDD&#xff0c;如果 ROTA 值为 0&#xff0c;则磁盘类型为 SSD。可以在上面的屏幕截图中看到 sda 的 ROTA 值是 1&#xff0c;表示它是 HDD。 2. 检查磁盘是否旋转 $ cat /sys/block/sda/q…

北京十大拆迁律师事务所排名

历史时刻在重演&#xff0c;土地征地拆迁作为城市发展中不可或缺的环节备受地方政府重视。然而&#xff0c;在土地征收过程中&#xff0c;往往因为拆迁补偿引发各种纠纷案件&#xff0c;给拆迁方和被拆迁方带来重大损失&#xff0c;侵害双方利益&#xff0c;尤其是被征收人。因…

CentOS修复OpenSSH漏洞升级到openssh 9.7 RPM更新包

在做政府和学校单位网站时&#xff0c;经常需要服务器扫描检测&#xff0c;经常被OpenSSH Server远程代码执行漏洞&#xff08;CVE-2024-6387&#xff09;安全风险通告&#xff0c;出了报告需要升级OpenSSH。 使用yum update openssh是无法更新到最新的&#xff0c;因为系统里的…

YOLOX算法实现血细胞检测

原文:YOLOX算法实现血细胞检测 - 知乎 (zhihu.com) 目标检测一直是计算机视觉中比较热门的研究领域。本文将使用一个非常酷且有用的数据集来实现YOLOX算法,这些数据集具有潜在的真实应用场景。 问题陈述 数据来源于医疗相关数据集,目的是解决血细胞检测问题。任务是通过显微…

谷粒商城学习-09-配置Docker阿里云镜像加速及各种docker问题记录

文章目录 一&#xff0c;配置Docker阿里云镜像加速二&#xff0c;Docker安装过程中的几个问题1&#xff0c;安装报错&#xff1a;Could not resolve host: mirrorlist.centos.org; Unknown error1.1 检测虚拟机网络1.2 重设yum源 2&#xff0c;报错&#xff1a;Could not fetch…

给我的 IM 系统加上监控两件套:【Prometheus + Grafana】

监控是一个系统必不可少的组成部分&#xff0c;实时&#xff0c;准确的监控&#xff0c;将会大大有助于我们排查问题。而当今微服务系统的话有一个监控组合很火那就是 Prometheus Grafana&#xff0c;嘿你别说 这俩兄弟配合的相当完美&#xff0c;Prometheus负责数据采集&…

MyBatis入门程序详解

目录 一、MyBatis概述 二、编写MyBatis入门程序 三、配置SQL提示 四、传统jdbc的劣势 一、MyBatis概述 MyBatis是一个基于Java的持久层框架&#xff0c;它内部封装了JDBC操作&#xff0c;使得开发人员可以更专注于SQL语句本身而非繁琐的JDBC操作细节。在MyBatis中&#xff0…

LLM - 词向量 Word2vec

1. 词向量是一个词的低维表示&#xff0c;词向量可以反应语言的一些规律&#xff0c;词意相近的词向量之间近乎于平行。 2. 词向量的实现&#xff1a; &#xff08;1&#xff09;首先使用滑动窗口来构造数据&#xff0c;一个滑动窗口是指在一段文本中连续出现的几个单词&#x…

逻辑这回事(八)---- 时钟与复位

时钟设计总结 时钟和复位是FPGA设计的基础&#xff0c;本章总结了一些逻辑时钟复位设计、使用中出现的问题&#xff0c;给出了设计要点&#xff0c;避免后续问题重犯。时钟和复位&#xff0c;本文都先从板级谈起&#xff0c;再到FPGA芯片级&#xff0c;最后到模块级别。仅在此…