>>環境信息:
操作系統版本: CTyunOS release 2 22.06.1
內核版本: 4.19.90-2102.2.0.0064.ctl2.x86_64
數據庫初始版本: 5.7.39, for Linux (x86_64)
>>問題梳理
1,2022.11 創建安裝實例
3臺物理機64C768G,8set1主2從
部署完成后,業務未上線,監控無異常
1,2024.02 參照《MySQL加載Jemalloc庫的排查手段及說明(含arm版)》修復jemalloc
修復后,頻繁出現Out of memory導致的實例重啟(空閑內存充足)
2,關閉numa,協調主機排查其他軟硬件
問題依舊
3,2022.06.25 關閉jemalloc
堆棧信息大量內存和libjemalloc相關信息,測試關閉jemalloc
OOM重啟不再出現,mysqld進程內存泄漏且free較大情況下swap耗盡
4,2024208.09 嘗試升級至5.7.46(默認開啟jemalloc)
仍然頻繁出現Out of memory導致的實例重啟
5,2022.08.10 調整jemalloc配置為系統庫文件
無效,仍然頻繁出現Out of memory導致的實例重啟
6,2022.08.11 嘗試升級最新版本至5.7.49
暫無異常,繼續觀察
系統頻繁重啟,目前已經替換最新的包,擔心再次oom及排查之前oom的原因,今天上午10點找DBA分析排查,暫未找到原因。
2. 原因分析
從錯誤日志中看出,出錯都是在內存分配時,在jemalloc下的 throw_bad_castv 拋出 bad_alloc 異常
提示關注下虛擬內存后,同事找出頻繁 core 的實例與穩定實例間,系統配置 vm.max_map_count 有所不同。
7. 觀察發現,開啟jemalloc后雖然物理內存無泄漏,但是虛擬內存仍然存在泄漏現象
通過pmap -x <msyql pid>查看進程使用內存的詳細信息
$ pmap -x 739642|grep anon|wc -l --開啟jemalloc
24773
$ pmap -x 2876664|grep anon|wc -l --未使用jemalloc
2602
開啟J版內存回收的mysqld有大量的anon(匿名內存塊),雖然物理內存釋放,但是內存映射區仍然保留,且不斷增加
懷疑是內存映射區耗盡導致
8. 調整vm.max_map_count 驗證
vm.max_map_count默認為65530 ,上次升級5.7.49后曾優化過內核設置vm.max_map_count=262144,所以升級后至今未觸發重啟
為驗證,調小vm.max_map_count,超過內存映射區的mysqld立即重啟
以上,mysqld 頻繁OOM原因為mysqld進程映射有大量的anon(匿名內存塊)導致進程內存映射區耗盡導致
對于開啟jemalloc后,mysqld進程映射大量的anon(匿名內存塊),虛擬內存泄漏問題仍需進一步分析
找到一個文章分析,與問題完全吻合:
大概意思是,連續的mmap是會合并為一個記錄,count還是1,但連續的區域中間部分munmap了,就會分開成兩個區域,count增多。意思是碎片化過多了,導致系統限制新映射區創建。
結合用戶提供的 maps 文件,可看到用戶映射區記錄的映射是連續的地址空間,并且使用(rw-p)和釋放的(---p) 梅花間竹地存在,符合連續分配后,釋放不再使用內存,導致碎片過多情況。
3. 解決方案
調大 max_map_count 可以簡單粗暴的解決這個問題。最終結果,將默認數值65530 調大到 262144