<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          你還不明白如何解決分布式Session?看這篇就夠了

          共 8302字,需瀏覽 17分鐘

           ·

          2022-06-28 23:30

          點(diǎn)擊關(guān)注上方“Stephen”,

          設(shè)為“置頂或星標(biāo)”,第一時間送達(dá)干貨


          平常做的項(xiàng)目都是在一臺應(yīng)用系統(tǒng),并且所有的操作都在一臺Tomcat服務(wù)器上,并不會引發(fā)Session共享的問題,所以并不會對我們的系統(tǒng)產(chǎn)生影響,但是當(dāng)我們部署多個微服務(wù)的時候,再搭配Nginx進(jìn)行負(fù)載均衡時,如果不處理分布式Session問題,我們在系統(tǒng)中訪問不同功能時就會頻繁出現(xiàn)用戶登錄的操作。

          圖解分析原因:

          前提:用戶登錄功能和圖中的商品訂單模塊、秒殺搶購模塊屬于單獨(dú)的微服務(wù)模塊

          用戶登錄成功后想要訪問圖中其他兩個模塊的功能時,由于Nginx使用默認(rèn)負(fù)載均衡策略(輪詢),這時請求會按照時間順序逐一分發(fā)到后端應(yīng)用上,也就是說用戶在Tomcat1上登錄成功之后,用戶的信息放在Tomcat1的Session里,過了一會,用戶想要進(jìn)行秒殺活動的功能操作,請求又被Nginx分發(fā)到了Tomcat2,而這時的Tomcat2上的Session里還沒有用戶信息,于是就是出現(xiàn)讓用戶重新登錄的情況,在微服務(wù)分布式項(xiàng)目中,不同的功能模塊必然會被分列成各自的微服務(wù),假設(shè)訪問一個功能都需要重新登錄一次,用戶的體驗(yàn)必然會大幅度下降!

          那如何來解決分布式Session問題呢?

          一、解決方案列舉

          1. Session復(fù)制

          優(yōu)點(diǎn):

          • 無需修改代碼,只需要修改Tomcat配置

          缺點(diǎn):

          • Session同步傳輸占用內(nèi)網(wǎng)寬帶
          • 多臺Tomcat同步性能指數(shù)級下降
          • Session占用內(nèi)存,無法有效水平擴(kuò)展

          2. 前端存儲

          優(yōu)點(diǎn):

          • 不占用服務(wù)器內(nèi)存

          缺點(diǎn):

          • 存在安全風(fēng)險
          • 數(shù)據(jù)大小受cookie限制
          • 占用外網(wǎng)寬帶

          3. Session粘滯

          優(yōu)點(diǎn):

          • 無需修改代碼
          • 服務(wù)端可以水平擴(kuò)展

          缺點(diǎn):

          • 增加新機(jī)器,會重新Hash,導(dǎo)致重新登錄
          • 應(yīng)用重新啟動后,需要重新登錄

          4. 后端集中存儲

          優(yōu)點(diǎn):

          • 安全
          • 容易水平擴(kuò)展

          優(yōu)點(diǎn):

          • 增加復(fù)雜度
          • 需要修改代碼

          二、Java代碼實(shí)現(xiàn)解決分布式Session

          1. SpringSession - Redis解決分布式Session

          添加依賴

          <!--Redis-->
          <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
          </dependency>
          <!--commons-pools2 對象池依賴-->
          <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
          </dependency>
          <!--spring session 依賴,公眾號:Java精選-->
          <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
          </dependency>

          添加Redis配置

          ## Redis配置
          spring:
            redis:
              # 服務(wù)器地址
              host: localhost
              # 端口
              port: 6379
              # 數(shù)據(jù)庫
              database: 0
              # 超時時間
              connect-timeout: 10000ms
              lettuce:
                pool:
                  # 最大連接數(shù)
                  max-active: 8
                  # 最大連接阻塞等待時間 默認(rèn) -1
                  max-wait: 10000ms
                  # 最大空閑時間 默認(rèn)8
                  max-idle: 200
                  # 最小空閑連接 默認(rèn)8
                  min-idle: 5

          業(yè)務(wù)邏輯實(shí)現(xiàn)

          /**
           * 登錄功能
           * @param loginVo
           * @return
           */

          @Override
          public RespBean doLogin(LoginVo loginVo, HttpServletRequest request, HttpServletResponse response) {

              String username = loginVo.getUserName();
              String password = loginVo.getPassword();

              User user = userMapper.selectByUserName(username);
              if (user == null){
                  throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
              }
              //判斷密碼是否正確
              if (!MDUtils.formPassToDBPass(password,user.getSalt()).equals(user.getPassword())){
                  throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
              }
              //使用UUID生成字符串代替Cookie
              String ticket = UUIDUtil.uuid();
              request.getSession().setAttribute(ticket,user);
              CookieUtil.setCookie(request,response,"userTicket",ticket);
              return RespBean.success();
          }

          視圖控制層

          /**
           * 跳轉(zhuǎn)商品列表
           * @param session
           * @param model
           * @return
           */

          @RequestMapping("/toList")
          public String toList(HttpSession session, Model model,@CookieValue("userTicket")String ticket){
              if (StringUtils.isEmpty(ticket)){
                  return "login";
              }
              User user = (User) session.getAttribute(ticket);
              if (user == null){
                  return "login";
              }
              model.addAttribute("user",user);
              return "goodsList";
          }

          登錄測試

          打開Redis管理軟件發(fā)現(xiàn)Session信息已經(jīng)添加到Redis中了

          2. Redis解決分布式Session

          導(dǎo)入依賴

          <!--Redis-->
          <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
          </dependency>
          <!--commons-pools2 對象池依賴-->
          <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
          </dependency>

          Redis配置參考 【SpringSession - Redis解決分布式Session】

          業(yè)務(wù)邏輯層

          @Override
          public RespBean doLogin(LoginVo loginVo, HttpServletRequest request, HttpServletResponse response) {

              String username = loginVo.getUserName();
              String password = loginVo.getPassword();

              User user = userMapper.selectByUserName(username);
              if (user == null){
                  throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
              }
              //判斷密碼是否正確
              if (!MDUtils.formPassToDBPass(password,user.getSalt()).equals(user.getPassword())){
                  throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
              }
              //成功Cookie
              String ticket = UUIDUtil.uuid();
              //將用戶信息存入到redis中
              redisTemplate.opsForValue().set("userTicket",ticket);
              redisTemplate.opsForValue().set("user:"+ticket,user);
              //request.getSession().setAttribute(ticket,user);
              CookieUtil.setCookie(request,response,"userTicket",ticket);
              return RespBean.success();
          }

          /**
           * 根據(jù)cookie獲取cookie
           * @param ticket
           * @return
           */

          @Override
          public User getUserByByCookie(String ticket,HttpServletRequest request,HttpServletResponse response) {
              if (StringUtils.isEmpty(ticket)){
                  return null;
              }
              User user = (User) redisTemplate.opsForValue().get("user:" + ticket);
              if (user == null){
                  CookieUtil.setCookie(request,response,"userTicket",ticket);
              }
              return user;
          }

          視圖控制層

          /**
           * 跳轉(zhuǎn)商品列表
           * @param session
           * @param model
           * @return
           */

          @RequestMapping("/toList")
          public String toList(HttpSession session, Model model,HttpServletRequest request,HttpServletResponse response){
              String ticket = (String) redisTemplate.opsForValue().get("userTicket");
              if (StringUtils.isEmpty(ticket)){
                  return "login";
              }
              //User user = (User) session.getAttribute(ticket);
              User user = userService.getUserByByCookie(ticket, request, response);
              if (user == null){
                  return "login";
              }
              model.addAttribute("user",user);
              return "goodsList";
          }

          測試成功

          查看Redis管理工具

          作者:派 大 星.

          https://blog.csdn.net/Gaowumao/article/details/124309548

          END


          關(guān)注 Stephen,一起學(xué)習(xí),一起成長。


          點(diǎn)“在看”支持下吧


          點(diǎn) 閱讀原文 可優(yōu)惠充值話費(fèi),流量,視頻會員等。

          瀏覽 61
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久偷拍片久久 | 免费一级黄色大片 | 特级西西444Ww高清大胆 | 小h片免费在线观看 | 欧美日韩免费在线视频 |