1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        分布式session的幾種解決方案,你中意哪種?

        共 4515字,需瀏覽 10分鐘

         ·

        2021-05-17 12:08

        點擊上方 Java旅途選擇 設(shè)為星標

        優(yōu)質(zhì)文章,每日送達




        我發(fā)現(xiàn)了一個商城,我還沒有登錄,就可以往購物車中添加商品,加了好幾件后,我準備付款,需要我先去登錄,登錄完之后付款。

        現(xiàn)在很多商城,都會要求用戶先去登錄,登錄之后再往購物車中添加商品,這樣用戶、購物車、商品,三個對象之間就有了綁定關(guān)系。

        而針對我最開始說的那種情況,其實就是基于session做的,客戶端往購物車中添加第一個商品的時候,發(fā)送一個請求,服務(wù)收到請求之后,創(chuàng)建session,然后返回當前session對應(yīng)的一個JessionId,瀏覽器存儲在cookie中,客戶端往購物車添加第二個商品時,攜帶JessionId,服務(wù)端收到請求后,更新session。瀏覽器關(guān)閉后,cookie失效,JessionId也就丟失了,需要重新往購物車中添加商品,默認情況下,session有效期為30分鐘。

        在分布式環(huán)境下,session就會出現(xiàn)問題了,假如服務(wù)端部署在兩個服務(wù)器AB上。第一次往購物車添加商品時,請求落在了服務(wù)器A上,服務(wù)器A創(chuàng)建了一個session,并返回JessionId,第二次往購物車添加商品時,請求落在了服務(wù)器B上,請求攜帶的JesssionId在服務(wù)器B上并不會找到對應(yīng)的session。這時候服務(wù)器B就會創(chuàng)建一個新的session,并返回對應(yīng)的JessionId,客戶端發(fā)現(xiàn)第一次添加的商品丟失了。。。

        接下來,一起來學習分布式環(huán)境下session一致性是如何實現(xiàn)的。

        一、客戶端存儲

        既然分布式環(huán)境中,一個客戶端的多個請求可能會落在多個服務(wù)器上,那么我們是否可以改變策略,直接將session信息存儲在客戶端?可以的,服務(wù)器將session信息直接存儲到cookie中,這樣就保證了session的一致性,但是并不推薦這樣去做,因為將一些信息存儲在cookie中,相當于就把這些信息暴露給了客戶端,存在嚴重的安全隱患。

        缺點

        • 安全性存在問題
        • cookie對于數(shù)據(jù)類型及數(shù)據(jù)大小有所限制

        二、session復制

        將服務(wù)器A的session,復制到服務(wù)器B,同樣將服務(wù)器B的session也復制到服務(wù)器A,這樣兩臺服務(wù)器的session就一致了。像tomcat等web容器都支持session復制的功能,在同一個局域網(wǎng)內(nèi),一臺服務(wù)器的session會廣播給其他服務(wù)器。

        缺點

        同一個網(wǎng)段內(nèi)服務(wù)器太多,每個服務(wù)器都會去復制session,會造成服務(wù)器內(nèi)存浪費。

        三、session黏性

        利用Nginx服務(wù)器的反向代理,將服務(wù)器A和服務(wù)器B進行代理,然后采用ip_hash的負載策略,將客戶端和服務(wù)器進行綁定,也就是說客戶端A第一次訪問的是服務(wù)器B,那么第二次訪問也必然是服務(wù)器B,這樣就不存在session不一致的問題了。

        缺點

        如果服務(wù)器A宕機了,那么客戶端A和客戶端B的session就會出現(xiàn)丟失。

        四、session集中管理

        這種方式就是將所有服務(wù)器的session進行統(tǒng)一管理,可以使用redis等高性能服務(wù)器來集中管理session,而且spring官方提供的spirng-session就是這樣處理session的一致性問題。這也是目前企業(yè)開發(fā)用到的比較多的一種分布式session解決方案。

        五、spring-session實戰(zhàn)

        Spring提供了處理分布式session的解決方案——Spring Session。Spring Session提供了用于管理用戶會話的API和實現(xiàn)。

        Spring Session提供了對redis,mongodb,mysql等常用的存儲庫的支持,Spring Session提供與HttpSession的透明整合,這意味著開發(fā)人員可以使用Spring Session支持的實現(xiàn)切換HttpSession實現(xiàn)。還是原來的配方,產(chǎn)生了不一樣的味道!

        Spring Session添加了一個SessionRepositoryFilter的過濾器,用來修改包裝請求和響應(yīng),包裝后的請求為SessionRepositoryRequestWrapper,調(diào)用getSession()方法的時候?qū)嶋H上就是調(diào)用Spring Session實現(xiàn)了的session。

        Spring Session使用非常簡單,添加了相關(guān)依賴后,直接操作HttpSession就可以實現(xiàn)效果。

        第一步:添加Spring Sessionredis的相關(guān)依賴

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        第二步:配置redis相關(guān)信息

        spring:
          redis:
            # redis庫
            database: 0
            # redis 服務(wù)器地址
            host: localhost
            # redis 端口號
            port: 6379
            # redis 密碼
            password:
          # session 使用redis存儲  
          session:
            store-type: redis

        第三步:項目中使用session

        public String sessionTest(HttpServletRequest request){

            HttpSession session = request.getSession();
            session.setAttribute("key","value");
            return session.getAttribute("key").toString();
        }

        redis中每個session存儲了三條信息。

        • 第一個存儲這個Session的id,是一個Set類型的Redis數(shù)據(jù)結(jié)構(gòu)。這個k中的最后的1439245080000值是一個時間戳,根據(jù)這個Session過期時刻滾動至下一分鐘而計算得出。

        • 第二個用來存儲Session的詳細信息,包括Session的過期時間間隔、最近的訪問時間、attributes等等。這個k的過期時間為Session的最大過期時間 + 5分鐘。如果默認的最大過期時間為30分鐘,則這個k的過期時間為35分鐘。

        • 第三個用來表示Session在Redis中的過期,這個k-v不存儲任何有用數(shù)據(jù),只是表示Session過期而設(shè)置。這個k在Redis中的過期時間即為Session的過期時間間隔。

        處理一個session為什么要存儲三條數(shù)據(jù),而不是一條呢!對于session的實現(xiàn),需要監(jiān)聽它的創(chuàng)建、過期等事件,redis可以監(jiān)聽某個key的變化,當key發(fā)生變化時,可以快速做出相應(yīng)的處理。

        但是Redis中帶有過期的key有兩種方式:

        • 當訪問時發(fā)現(xiàn)其過期
        • Redis后臺逐步查找過期鍵

        當訪問時發(fā)現(xiàn)其過期,會產(chǎn)生過期事件,但是無法保證key的過期時間抵達后立即生成過期事件。

        spring-session為了能夠及時的產(chǎn)生Session的過期時的過期事件,所以增加了:

        spring:session:sessions:expires:726de8fc-c045-481a-986d-f7c4c5851a67spring:session:expirations:1620393360000

        spring-session中有個定時任務(wù),每個整分鐘都會查詢相應(yīng)的spring:session:expirations:整分鐘的時間戳中的過期SessionId,然后再訪問一次這個SessionId,即spring:session:sessions:expires:SessionId,以便能夠讓Redis及時的產(chǎn)生key過期事件——即Session過期事件。

        參考

        https://www.cnblogs.com/sxw123/p/13803478.html



        < END >


        往期精選:

        老大讓我優(yōu)化數(shù)據(jù)庫,我上來就分庫分表,他過來就是一jio

        帶你走進程序員們一天的生活!

        每月第一天,尋找這10位小伙伴

        終于有人能把TCP/IP 協(xié)議講的明明白白了

        瀏覽 39
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            让人看了下面流水的视频 | 摸少妇的奶她呻吟不断爽视频 | 91人妻熟女一区二区AⅤ蜜桃 | 性爱网站免费观看 | 丝袜足交诱惑 | 北条麻妃av无码 国产精品久久久国产盗摄 一区二区三区四区在线看 深交午夜精品久久久 | 动漫理伦片在线版观看 | 羞羞影院午夜男女爽爽在线播放 | 日韩欧美二 | 人妻天天爽|