<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?看這篇就夠了!

          共 8404字,需瀏覽 17分鐘

           ·

          2022-06-20 22:19

          Hollis的新書(shū)限時(shí)折扣中,一本深入講解Java基礎(chǔ)的干貨筆記!

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

          圖解分析原因:

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

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

          那如何來(lái)解決分布式Session問(wèn)題呢?

          一、解決方案列舉

          1. Session復(fù)制

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

          • 無(wú)需修改代碼,只需要修改Tomcat配置

          缺點(diǎn):

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

          2. 前端存儲(chǔ)

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

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

          缺點(diǎn):

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

          3. Session粘滯

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

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

          缺點(diǎn):

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

          4. 后端集中存儲(chǔ)

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

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

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

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

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

          1. SpringSession - Redis解決分布式Session

          添加依賴(lài)

          <!--Redis-->
          <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
          </dependency>
          <!--commons-pools2 對(duì)象池依賴(lài)-->
          <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
          </dependency>
          <!--spring session 依賴(lài),公眾號(hào):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ù)庫(kù)
              database: 0
              # 超時(shí)時(shí)間
              connect-timeout: 10000ms
              lettuce:
                pool:
                  # 最大連接數(shù)
                  max-active: 8
                  # 最大連接阻塞等待時(shí)間 默認(rèn) -1
                  max-wait: 10000ms
                  # 最大空閑時(shí)間 默認(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";
          }

          登錄測(cè)試

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

          2. Redis解決分布式Session

          導(dǎo)入依賴(lài)

          <!--Redis-->
          <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
          </dependency>
          <!--commons-pools2 對(duì)象池依賴(lài)-->
          <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();
              //將用戶(hù)信息存入到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";
          }

          測(cè)試成功

          查看Redis管理工具

          作者:派 大 星.

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



          我的新書(shū)《深入理解Java核心技術(shù)》已經(jīng)上市了,上市后一直蟬聯(lián)京東暢銷(xiāo)榜中,目前正在6折優(yōu)惠中,想要入手的朋友千萬(wàn)不要錯(cuò)過(guò)哦~長(zhǎng)按二維碼即可購(gòu)買(mǎi)~


          長(zhǎng)按掃碼享受6折優(yōu)惠


          往期推薦

          一次簡(jiǎn)單的 JVM 調(diào)優(yōu),拿去寫(xiě)到簡(jiǎn)歷里


          高并發(fā)下如何防重?


          入職就想run的公司特征




          有道無(wú)術(shù),術(shù)可成;有術(shù)無(wú)道,止于術(shù)

          歡迎大家關(guān)注Java之道公眾號(hào)


          好文章,我在看??

          瀏覽 55
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  亚洲t v| 免费成人性爱网站 | 久爱一区二区 | 色哟哟——国产精品 | 日韩三级乱伦 |