系統吃swap問題排查

目錄

背景

問題

分析并解決

1.控制線程數

2.更換IO組件

3.Linux進程信息文件分析

總結加餐

參考文檔

背景

隔壁業務組系統是簡單的主從結構,寫索引的服務(主)叫primary, 讀索引并提供搜索功能的服務(從)叫replica。業務線同步數據并不是平滑的,在同步數據時primary瞬間負載上升,磁盤寫IO增加,這是合理的。

primary 寫完索引,會馬上觸發索引的同步操作,因此,瞬間的磁盤讀IO增加以及網絡流量的增加都是合理的。

問題

在節假日高峰期前期,團隊增加了50%的replica服務器,這造成了primary的同步壓力進一步增加,觀測系統監控,發現了“吃swap”的現象,這就不合理了,需要分析優化。

這里簡單解釋下“吃swap”:

在計算機系統中,"吃swap"指的是系統開始使用交換空間(swap space)來補充物理內存(RAM)的不足。交換空間是一塊預留在磁盤上的區域,用于存儲那些當前不常用的內存數據。當物理內存不足時,操作系統會將一些數據從內存中移到交換空間,以騰出內存給其他需要的進程。

具體來說,“吃swap”通常表示以下幾種情況:

  1. 內存不足:系統的物理內存已經被用完,導致操作系統不得不使用交換空間來存儲數據。
  2. 性能下降:因為磁盤的讀寫速度遠低于內存的讀寫速度,當系統頻繁訪問交換空間時,性能會顯著下降。用戶可能會注意到系統變得響應緩慢。
  3. 高負載場景:在高負載場景下,如大量的索引寫入和同步操作,內存需求突然增加,導致系統不得不使用swap。

以上描述的情況下,primary服務器在索引寫入和同步操作的高負載下,內存不足,導致操作系統開始頻繁使用swap,從而出現“吃swap”的現象。這是不合理的,因為頻繁使用swap會顯著降低系統性能,影響整體服務的響應速度和穩定性。因此,需要通過優化措施來減少對swap的依賴,提高系統的性能。

分析并解決

1.控制線程數

參考以前的經驗,replica 有個索引備份功能,在晚上4點會備份本地索引文件(30G)到指定目錄
這個操作就會造成瞬間IO的增加以及負載的升高,因此最初我們判斷這是索引復制太快,導致的內存耗盡和負載增加。我們嘗試通過控制primary服務線程池的大小,來放慢索引復制的速度。

經過壓測發現,線程很小(5個)的情況,載峰值有所降低,但是吃swap的問題仍然存在。

結論:primary采用的gRPC框架,通過控制線程池大小來放慢索引復制的速度在gRPC框架中并不奏效,因為gRPC的異步調用機制允許高并發執行,獨立于線程數量。有效的優化策略需要針對異步調用特性和具體負載情況進行調整,而不僅僅是控制線程數。

2.更換IO組件

Lucene提供了兩種磁盤訪問方式MMapDirectory和NIODirectory,因為mmap方式會大量使用堆外內存,因此我們懷疑是堆外內存失控導致的系統內存不足,經過更換Directory,發現吃swap問題仍然存在。

Apache Lucene 是一個高性能、可伸縮的信息檢索庫,用于全文搜索和索引。Lucene 提供了多種方式來訪問磁盤存儲的索引數據,主要包括 MMapDirectoryNIODirectory

結論:mmap雖然會使用堆外內存,但是linux應該是可以控制好堆外內存的回收的。

3.Linux進程信息文件分析

我們分析了linux下的 /proc/$pid/status文件,VmSwap是swap占用情況,VmHWM是歷史內存占用。以及java進程當前的內存占用情況 sudo -u tomcat jhsdb jmap --heap --pid $pid

發現java進程的歷史內存占用很高,而當前內存占用并不高(所以排除了內存泄漏),各個進程都有占用swap的現象,說明是java進程在某個時刻(文件傳輸)耗盡了內存,導致其他進程吃swap,而那個時刻過后,java進程是可以回收內存的。所以推測是索引文件傳輸過程中,某些buffer設置不合理導致的。

經過代碼排查 ,發現gRPG(高度異步)在讀取索引文件時需要多次判斷serverCallStreamObserver.isReady(),如果只判斷一次isReady,就把所以數據寫入響應流,就會占用大量系統緩沖區。官方推薦的是一種callback機制,示例代碼如下:

final?InputStream input = ...

serverCallStreamObserver.setOnReadyHandler(new?Runnable() {

????int?upto =?0;?// 傳輸偏移,需要反復使用

????final?long?size = file.length();

????public?void?run() {?// 這里會根據緩沖區狀態多次被觸發執行,因此這個Runnable是有狀態的

?? ? ? ?while?(upto < size && serverCallStreamObserver.isReady()) {

?? ? ? ? ? ??response.onNext(...);?//寫入緩沖區

?????????????upto += chunk;

????????}

????}

});

serverCallStreamObserver.setOnCancelHandler(() -> input.close());

serverCallStreamObserver.setOnCloseHandler(() -> input.close());

  • 緩沖區管理不當:原始代碼在判斷 serverCallStreamObserver.isReady() 一次后,立即寫入所有數據,導致系統緩沖區被大量占用,內存迅速耗盡。
  • 回調機制:通過設置 serverCallStreamObserver.setOnReadyHandler 回調函數,確保只有在緩沖區準備好時才寫入數據。這樣可以避免一次性寫入過多數據,導致內存占用過高。
  • 狀態管理:使用 upto 變量跟蹤傳輸偏移量,每次 isReady 時僅寫入一部分數據,緩解系統緩沖區的壓力。
  • 資源釋放:通過 setOnCancelHandlersetOnCloseHandler 確保在取消或關閉時正確關閉輸入流,避免資源泄漏。

這種寫法會比較反直覺,通過回調函數關閉InputStream看上去沒有finally去關閉安全,好處是緩沖區壓力小,最終問題解決。

總結加餐

以上描述的問題的根本原因在于 gRPC 在文件傳輸過程中緩沖區管理不當,導致內存占用過高。通過引入官方推薦的回調機制和合理的狀態管理,成功解決了該問題。因此在日常開發中,涉及到文件寫入與讀取時,還是需要多關注一下流的關閉與打開與緩沖區buffer的使用是否合理。

Linux將物理內存分為內存段,叫做頁面。交換是指內存頁面被復制到預先設定好的硬盤空間(叫做交換空間)的過程,目的是釋放這份內存頁面。物理內存和交換空間的總大小是可用的虛擬內存的總量。我們知道swap space是磁盤上的一塊區域,可以是一個分區,也可以是一個文件,或者以它們的組合方式出現。簡單點說,當系統物理內存吃緊時,Linux系統會將內存中不常訪問的數據保存到 swap 上,這樣系統就有更多的物理內存為其他進程服務,而當系統需要訪問swap上存儲的內容時,系統會再將 swap 上的數據加載到內存中,這就是我們常說的swap outswap in了。那么配置多大的 Swap 比較合適?

  • 當物理內存小于1G且不需要休眠時,設置和內存同樣大小的swap空間即可;當需要休眠時,建議配置兩倍物理內存的大小,但最大值不要超過兩倍內存大小。
  • 當物理內存大于1G且不需要休眠時,建議大小為sqrt(RAM),其中RAM為物理內存大小;當需要休眠時,建議大小是RAM+round(sqrt(RAM)),但最大值不要超過兩倍內存大小。
  • 如果兩倍物理內存大小的swap空間還不夠用,建議增加內存而不是增加swap

此外,在一篇參考文獻中看到如下這段話:

?如果頻繁的訪問 swap 的話,怎么優化 swap 都沒用,跟內存比還是低幾個數量級,性能還是下降的厲害,如果不頻繁訪問 swap 的話,優化 swap 又有啥意義呢?所以其實優化 swap 性能的實際意義不大。

參考文檔

https://zhuanlan.zhihu.com/p/467976849

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

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

相關文章

離散化及其在 Pandas 中的實現方法

目錄 1.什么是離散化&#xff1f; 2.離散化類型 3.示例代碼 3.1連續變量離散化 3.2定性變量離散化 4.運行結果 4.1連續變量離散化 4.2定性變量離散化 1.什么是離散化&#xff1f; 離散化是將連續數據或分類數據轉換為離散類別的過程&#xff0c;方便后續的數據分析和機…

static的理論學習

在說到static之前&#xff0c;需要先明確變量類型&#xff1a; 而在聊到變量類型之前我們可以將變量的兩個屬性好好學一學 變量的兩個屬性 作用域&#xff08;scope&#xff09;&#xff1a; 從內存的角度來看&#xff0c;就是變量存放在棧&#xff08;stack&#xff09;中&…

在 JavaScript 中,??(雙問號運算符)和 ?.(可選鏈運算符)區別

在 JavaScript 中&#xff0c;??&#xff08;雙問號運算符&#xff09;和 ?.&#xff08;可選鏈運算符&#xff09;是兩種不同的運算符&#xff0c;用于處理不同的情況&#xff1a; 雙問號運算符 (??): ?? 運算符是空值合并運算符&#xff08;Nullish Coalescing Oper…

Android C++系列:Linux進程(一)

1. 進程概念 我們知道,每個進程在內核中都有一個進程控制塊(PCB)來維護進程相關的信 息,Linux內核的進程控制塊是task_struct結構體。現在我們全面了解一下其中都有哪 些信息。 進程id。系統中每個進程有唯一的id,在C語言中用pid_t類型表示,其實就是一個非 負整數。進程的…

TypeError: Cannot read properties of null (reading ‘nextSibling‘)

做項目用的Vue3Vite, 在畫靜態頁面時&#xff0c;點擊菜單跳轉之后總是出現如下報錯&#xff0c;百思不得其解。看了網上很多回答&#xff0c;也沒有解決問題&#xff0c;然后試了很多方法&#xff0c;最后竟然發現是template里邊沒有結構的原因。。。 原來我的index.vue是這樣…

android.bp 編譯 順序

在Android平臺上&#xff0c;.bp 文件是用來定義Android編譯系統中的編譯規則的。Android編譯系統是基于Blueprint的&#xff0c;.bp 文件中定義的規則決定了如何編譯和打包應用程序。 在Android編譯系統中&#xff0c;.bp 文件中的規則通常是按照它們在文件中的順序來執行的。…

ELK+Filebeat+Kafka+Zookeeper

本實驗基于ELFK已經搭好的情況下 ELK日志分析 架構解析 第一層、數據采集層 數據采集層位于最左邊的業務服務器集群上&#xff0c;在每個業務服務器上面安裝了filebeat做日志收集&#xff0c;然后把采集到的原始日志發送到Kafkazookeeper集群上。第二層、消息隊列層 原始日志發…

conda和pip

1.眾所周知&#xff0c;pip的確是python官方&#xff08;PyPA&#xff09;推薦的Python軟件包安裝管理工具&#xff0c;在安裝Python軟件包時&#xff0c;第一反應應該是pip。正是由于pip是Python官方推薦的“正統”工具&#xff0c;所以pip只專注于Python軟件包之間的依賴&…

Matlab手搓線性回歸-非正規方程法

原理&#xff1a;wxb&#xff0c;x是輸入&#xff0c;求得的結果與真實值y求均方誤差。 采用鏈式法則求導 參數更新&#xff0c;梯度下降法&#xff08;批量梯度下降&#xff09; 隨機生成數據&#xff1a; m100&#xff1b;生成100個數據&#xff0c;并添加隨機噪聲 clear; …

基于flask的貓狗圖像預測案例

&#x1f4da;博客主頁&#xff1a;knighthood2001 ?公眾號&#xff1a;認知up吧 &#xff08;目前正在帶領大家一起提升認知&#xff0c;感興趣可以來圍觀一下&#xff09; &#x1f383;知識星球&#xff1a;【認知up吧|成長|副業】介紹 ??如遇文章付費&#xff0c;可先看…

二次元轉向SLG,B站游戲的破圈之困

文 | 螳螂觀察 作者 | 夏至 2023年是B站游戲的滑鐵盧&#xff0c;盡管這年B站的游戲營收還有40多億&#xff0c;但相比去年大幅下降了20%&#xff0c;整整少了10億&#xff0c;這是過去5年來的最大跌幅&#xff0c;也是陳睿接管B站游戲業務一年以來&#xff0c;在鼻子上碰的第…

鴻蒙語言基礎類庫:【@ohos.process (獲取進程相關的信息)】

獲取進程相關的信息 說明&#xff1a; 本模塊首批接口從API version 7開始支持。后續版本的新增接口&#xff0c;采用上角標單獨標記接口的起始版本。開發前請熟悉鴻蒙開發指導文檔&#xff1a;gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md點擊或者復制轉到。…

昇思13天

ResNet50遷移學習 ResNet50遷移學習總結 背景介紹 在實際應用場景中&#xff0c;由于訓練數據集不足&#xff0c;很少有人會從頭開始訓練整個網絡。普遍做法是使用在大數據集上預訓練得到的模型&#xff0c;然后將該模型的權重參數用于特定任務中。本章使用遷移學習方法對Im…

放棄華為OD,選擇最合適而不是最難得

時間不知不覺邁入了七月&#xff0c;五月嘗試去重新找一份工作&#xff0c;但釋放出來的崗位太少了&#xff0c;難得有進華為OD的機會&#xff0c;還是比較核心的部門&#xff0c;但思來想起&#xff0c;還是放棄了。 如果想去&#xff0c;是很有機會的&#xff0c;一路過關斬…

imx6ull/linux應用編程學習(13) CMAKE

什么是cmake&#xff1f; cmake 工具通過解析 CMakeLists.txt 自動幫我們生成 Makefile&#xff0c;可以實現跨平臺的編譯。cmake 就是用來產生 Makefile 的工具&#xff0c;解析 CMakeLists.txt 自動生成 Makefile&#xff1a; cmake 的使用方法 cmake 就是一個工具命令&am…

怎么將aac文件弄成mp3格式?把aac改成MP3格式的四種方法

怎么將aac文件弄成mp3格式&#xff1f;手頭有一些aac格式的音頻文件&#xff0c;但由于某些設備或軟件不支持這種格式&#xff0c;你希望將它們轉換成更為通用的MP3格式。而且音頻格式的轉換在現在已經是一個常見且必要的操作。aac是一種相對較新的音頻編碼格式&#xff0c;通常…

大模型增量預訓練新技巧-解決災難性遺忘

大模型增量預訓練新技巧-解決災難性遺忘 機器學習算法與自然語言處理 2024年03月21日 00:02 吉林 以下文章來源于NLP工作站 &#xff0c;作者劉聰NLP NLP工作站. AIGC前沿知識分享&落地經驗總結 轉載自 | NLP工作站 作者 | 劉聰NLP 目前不少開源模型在通用領域具有不錯…

G1 和 CMS

1、CMS CMS&#xff08;Concurrent Mark Sweep&#xff0c;并發標記清除&#xff0c;是為了解決早期垃圾收集器在執行垃圾回收時導致應用程序暫停時間過長的問題而設計的。 CMS的工作流程主要包括以下幾個階段&#xff1a; 初始標記&#xff08;Initial Mark&#xff09;&…

一體化運維監控平臺:賦能各行業用戶運維升級

在當今數字化轉型的大潮中&#xff0c;企業IT系統的復雜性和規模不斷攀升&#xff0c;對運維團隊提出了前所未有的挑戰。如何高效、精準地監控和管理IT基礎設施&#xff0c;確保業務連續性和穩定性&#xff0c;成為所有企業關注的焦點。美信&#xff0c;自2007年成立以來&#…

el-scrollbar實現自動滾動到底部(AI聊天)

目錄 項目背景 實現步驟 實現代碼 完整示例代碼 項目背景 chatGPT聊天消息展示滾動面板&#xff0c;每次用戶輸入提問內容或者ai進行流式回答時需要不斷的滾動到底部確保展示最新的消息。 實現步驟 采用element ui 的el-scrollbar作為聊天消息展示組件。 通過操作dom來實…