每天學習一點點之 Tomcat 是如何清除過期 Session 的

今天使用一種很臨時的方案解決 Session 泄漏的問題:縮短 Session 的過期時間。這種方法雖然簡單,但卻非常有效。然而,這引發了一個問題:我們應該將過期時間設置為多短呢?在 Spring Boot 中,最短的過期時間是 60 秒。如果你配置的值小于 60 秒,系統會將其默認設置為 60 秒。這是由 org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getSessionTimeoutInMinutes 方法決定的:

	private long getSessionTimeoutInMinutes() {Duration sessionTimeout = getSession().getTimeout();if (isZeroOrLess(sessionTimeout)) {return 0;}return Math.max(sessionTimeout.toMinutes(), 1);}

這時候組內有同學說,過短的過期時間是否會影響服務的性能,例如,是否需要更頻繁地刪除 Session

為了解答這個問題,我們需要理解 “Tomcat 是如何清除 Session 的”,以及 “Tomcat 中 Session 的更新機制是否會受到 Session 過期時間設置的長短的影響”。

其實根據經驗,結合 Redis 刪除過期 Key,以及 ThreadLocal 清除過期 entry 等存在類似場景的框架,過期清除機制無非就是兩種策略,以及一些細微的處理差異:

  • 惰性刪除:只在數據被訪問時才檢查和刪除過期的數據
    • 每次只檢查當前數據
    • 順帶檢查周邊數據
  • 定期刪除:后臺定時進行掃描
    • 全量掃描
    • 隨機掃描

我相信 Tomcat 的處理方式也不會脫離這兩種策略。帶著這個思考,那么接下來就源碼分析一下 Tomcat 到底是如何清除過期 Session 的。

關于 Session,Tomcat 提供了一個常用的函數 org.apache.catalina.session.StandardSession#isValid,用于判斷 Session 是否有效。如果 Session 已經無效,該函數會調用 org.apache.catalina.session.StandardSession#expire(boolean) 使 Session 過期(移除)。這表明 Tomcat 對 Session 的處理采用了惰性刪除機制。

Tomcat 提供了幾種不同的 Session 持久化策略,主要通過實現不同的 ManagerStore 來實現:

  1. 內存持久化:這是 Tomcat 的默認策略,由 StandardManager 實現。所有的 Session 都保存在內存中。當 Tomcat 重啟或者出現故障時,所有的 Session 信息都會丟失。
  2. 文件持久化:由 PersistentManagerFileStore 實現。不活躍的 Session 會被保存到文件系統中,從而釋放內存。當 Session 再次變得活躍時,可以從文件系統中恢復。
  3. 數據庫持久化:由 PersistentManagerJDBCStore 實現。不活躍的 Session 會被保存到數據庫中。這種策略適合于需要在多個 Tomcat 實例之間共享 Session 的情況。
  4. 分布式 Session:在一個 Tomcat 集群中,可以通過實現 ClusterableSessionDeltaManagerBackupManager 來實現 Session 的復制或者備份,從而實現 Session 的分布式管理。

本文關注的是內存持久化策略,即 StandardManager。它有一個函數 org.apache.catalina.session.ManagerBase#processExpires,該函數遍歷所有的 Session,對每個 Session 判斷是否過期。如果發現 Session 已失效,就會讓 Session 過期:

    public void processExpires() {long timeNow = System.currentTimeMillis();Session sessions[] = findSessions();int expireHere = 0;if (log.isDebugEnabled()) {log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);}for (Session session : sessions) {if (session != null && !session.isValid()) {expireHere++;}}long timeEnd = System.currentTimeMillis();if (log.isDebugEnabled()) {log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) +" expired sessions: " + expireHere);}processingTime += (timeEnd - timeNow);}

既然懷疑這個函數可能存在定時調度,其實有一個小技巧,在這個函數上打一個斷點,看是否可能觸發,果然沒一會就觸發了:

在這里插入圖片描述

根據 stack trace,這個函數是由 ContainerBackgroundProcessor 執行的。

在這里插入圖片描述

Tomcat 啟動時會執行 threadStart 方法,該方法基于 java.util.concurrent.ScheduledExecutorService 啟動一個定時任務,backgroundProcessorDelay 參數可以控制啟動后多久開始執行,backgroundProcessorDelay 控制多久執行一次。

    /*** Start the background thread that will periodically check for session timeouts.*/protected void threadStart() {if (backgroundProcessorDelay > 0 &&(getState().isAvailable() || LifecycleState.STARTING_PREP.equals(getState())) &&(backgroundProcessorFuture == null || backgroundProcessorFuture.isDone())) {if (backgroundProcessorFuture != null && backgroundProcessorFuture.isDone()) {// There was an error executing the scheduled task, get it and log ittry {backgroundProcessorFuture.get();} catch (InterruptedException | ExecutionException e) {log.error(sm.getString("containerBase.backgroundProcess.error"), e);}}backgroundProcessorFuture = Container.getService(this).getServer().getUtilityExecutor().scheduleWithFixedDelay(new ContainerBackgroundProcessor(), c,backgroundProcessorDelay, TimeUnit.SECONDS);}}

這表明 Tomcat 對 Session 的處理也有定期刪除機制。

總結

在 Tomcat 中,Session 的管理采用了惰性刪除和定期刪除兩種策略:

  • 惰性刪除是通過 org.apache.catalina.session.StandardSession#isValid 方法實現的,每次在判斷 Session 是否有效的時候,如果 Session 已經無效,就會讓 Session 過期(移除)
  • 在內存持久化策略中在內存持久化策略中,定期刪除是通過 org.apache.catalina.session.ManagerBase#processExpires 方法實現的,該方法會定期遍歷所有的 Session,對每個 Session 判斷是否過期,如果發現 Session 已失效,就會讓 Session 過期

在 Tomcat 中,Session 的更新機制并不會直接受到 Session 過期時間設置的長短的影響,但是,如果 Session 的數量過多,可能導致 Session 清理操作的效率降低。因為在每次 Session 清理操作時,都需要遍歷所有的 Session,檢查每個 Session 是否過期,如果過期就將其移除。如果 Session 的數量過多,那么這個過程就會消耗更多的時間和資源。

因此,雖然 Session 的過期時間設置不會直接影響 Session 的更新機制,但是 Session 的數量過多確實會對 Session 的更新效率和系統性能產生影響。為了保持系統的高效運行,應該盡量控制 Session 的數量,避免 Session 的數量過多。

歡迎關注公眾號:
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/163229.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/163229.shtml
英文地址,請注明出處:http://en.pswp.cn/news/163229.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

實在智能攜“TARS大模型”入選“2023中國數據智能產業AI大模型先鋒企業”

近日,由數據猿與上海大數據聯盟聯合主辦的“2023企業數智化轉型升級發展論壇”在上海圓滿收官。 論壇頒獎典禮上,《2023中國數據智能產業AI大模型先鋒企業》等六大榜單正式揭曉,旨在表彰在AI領域為數智化升級取得卓越成就和突出貢獻的企業&am…

解決“使用 CNKI 保存時發生錯誤。改為嘗試用 DOI 保存。”【Bug Killed】

文章目錄 簡介解決辦法跟新本地Zotero中茉莉花插件的非官方維護中文翻譯器更新網頁插件Zetero Connector中的Transtors 結語參考資料 簡介 使用Chrome ? Zotero Connector保存中國知網(CNKI)的參考文獻到本地的Zotero時無法正常保存,出現使…

Altium Designer學習筆記8

創建原理圖元件: 畫出原理圖: 根據規則書畫出原理圖: 根據規則書畫出封裝圖: 參照: 確認下過孔的內徑和外徑的最小允許值。

Vatee萬騰的數字時代探險:vatee科技力量的未來洞悉

在數字化的時代潮流中,Vatee萬騰以其強大的科技力量,正在進行一場前所未有的數字時代探險。 Vatee萬騰的數字時代探險源于其對未來的洞悉。通過深度研究和前瞻性思考,他們將科技力量與未來趨勢相結合,勾勒出數字時代的新藍圖&…

springboot注解@NotNull,@NotBlank,@Valid自動判定空值

一.前言 使用springboot搭建項目時,我們都是采用的Restful風格接口,這里面問題來了,當前端調用接口或者是其他項目調用時,傳入參數時我們不能單一靠調用方來控制參數的準確性,自己也要一些參數進行判斷,進行非空之類的…

露營管理系統預約小程序效果如何

旅游經濟已經復蘇,并且市場規模增速加快,近一年來遠途/周邊游客戶增多,不少旅游景區在節假日常常面對客流爆滿現象。同時露營作為近幾年突然火熱的項目,其需求也是日漸上升。 然而在高需求的同時,我們也看到露營經營痛…

【數組棧】實現

目錄 棧的概念及其結構 棧的實現 數組棧 鏈式棧 棧的常見接口實現 主函數Test.c 頭文件&函數聲明Stack.h 頭文件 函數聲明 函數實現Stack.c 初始化SLInit 擴容Createcapacity 壓棧STPush 出棧STPop 棧頂元素STTop 判斷棧是否為空STempty 棧內元素個數STSzi…

Mysql中join on中的like使用

1、使用mysql中的函數CONCAT(str1,str2,…) 返回結果為連接參數產生的字符串。如有任何一個參數為NULL ,則返回值為 NULL。 SELECT * FROM Table1 INNER JOIN Table2 ON Table1.col LIKE CONCAT(%, Table2.col, %) 2、放棄使用join語句 SELECT * FROM Table1, T…

使用sqlserver備份還原,復制遷移數據庫

文章目錄 前言一、備份數據庫二、還原數據庫三、其他 前言 當初學sqlserver復制數據庫的時候,老師只教了右鍵數據庫生成sql腳本,沒說數據庫非常大的時候咋搞啊,分離數據庫復制一份后在附加上去太危險了 百度一下備份還原數據庫針對小白的資料…

docker安裝mysql及主從配置

創建mysql配置文件:my.cnf 主庫配置: [client] ## 默認編碼格式 default-character-setutf8mb4 [mysqld] ## 設置server-id,同一局域網中需要唯一 server-id101 ## 設置編碼格式 character-set-serverutf8mb4 ## 允許最大連接數 max_conne…

Redis key鍵

Redis 是一種鍵值(key-value)型的緩存型數據庫,它將數據全部以鍵值對的形式存儲在內存中,并且 key 與 value 一一對應。這里的 key 被形象的稱之為密鑰,Redis 提供了諸多操作這把“密鑰”的命令,從而實現了…

財報解讀:電商GMV增長30%后,快手將堅守本地生活?

快手逐漸講好了其高質量成長的故事。 根據財報,快手三季度業績超出預期,其中,營收279.5億元,同比增長20.8%;調整后凈利潤31.7億元,同比扭虧為盈。 而聯系市場環境來看,三季度廣告、電商市場較…

超詳細的pytest玩轉HTML報告:修改、漢化和優化

前言 Pytest框架可以使用兩種測試報告,其中一種就是使用pytest-html插件生成的測試報告,但是報告中有一些信息沒有什么用途或者顯示的不太好看,還有一些我們想要在報告中展示的信息卻沒有,最近又有人問我pytest-html生成的報告&a…

javascript Math相關計算取值屬性方法

*向上取整【只要有小數就+1】 Math.ceil(3.14); // 4 *向下取整【有小數就舍棄】 Math.floor(3.14); // 3 parseInt(3.14); // 3 // 常用于字符串類型的數字轉為十進制的數據 四舍五入【小數點后部分】 Math.round(11.5)); //12 Math.round(-11.5)); //-11 取兩數…

6-使用nacos作為注冊中心

本文講解項目中集成nacos,并將nacos作為注冊中心使用的過程。本文不涉及nacos的原理。 1、項目簡介 以一個演示項目為例,項目包含三個服務,調用及依賴如下圖: 由圖中可以看出,coupon-customer-serv為服務的消費者&a…

基于element自動表格

需求是根據JSON文件生成表格,包含配置和自動props屬性以及過濾器; 數據示例: 表格設置: /*** 表格表頭信息* chineseToPinYin: 這是封裝的根據中文漢字轉換為拼音的方法* prop: 表頭字段名* filter: 數據過濾器* label: 表頭顯示…

最長連續序列【中等】

leetcode鏈接 給定一個未排序的整數數組 nums ,找出數字連續的最長序列(不要求序列元素在原數組中連續)的長度。 請你設計并實現時間復雜度為 O(n) 的算法解決此問題。 示例 1:輸入:nums [100,4,200,1,3,2] 輸出&am…

『new Date 在 IOS 失效 の bug』

問題:new Date()在安卓下正常,在IOS下顯示不出來。 原因:在IOS下,new Date(“2000-2-22 00:10”),返回的是undefined,因為IOS不支持這種類型格式。 解決:更換下格式:new Date(“2000/2/22”) …

類初始化,類加載,類加載器

類初始化,類加載,類加載器 1. 類加載1.1. 類的加載1.2. 類的鏈接1.2.1. 驗證1.2.2. 準備1.2.3. 解析 2. 類加載器2.1. 類加載器分為四種:前三種為虛擬機自帶的加載器。2.2. 類加載有三種方式:2.3. **JVM類加載機制**2.4. 雙親委派…