一金融公司客戶核心交易系統的新版即將上線,隨著試運行網點的增多,數據庫服務器突然出現內存使用量陡增的狀況。事件第一次出現時,初步查看發現Oracle數據庫內存SGA、PGA使用量並未出現異常。隨後操作系統的交換空間SWAP達到20多GB,系統緩慢到無法登陸無法操作,最終只能重啟處理。經過反復分析,沒有在日志中查找到原因。於是我們降低了Oracle對操作系統內存的用量。
半月後,內存使用量又有上升趨勢,我們快速介入進行了觀察。
此時發現數據庫服務器操作系統對內存使用偏高,約有20G。查看/proc/meminfo,一一比對,發現PageTables項過大,達到16GB。
原因分析:
Page Table是進程使用的內存虛擬地址和實際的內存物理地址的映射表,也就是記錄上圖當中那些箭頭的位置。Linux下默認內存每頁面為4KB,所以當內存很大,進程很多時,這張映射表會非常大,又完全存在於內存中。
解決的方法是在操作系統中采用大內存頁面(Huge Page,1個頁面2MB)技術,內存映射表由每記錄處理4KB上升為每記錄處理2MB。每條映射管理的內存塊的大小增大500倍,則映射數下降為1/500,使用的內存量也將下降到1/500,從GB級下降到MB級。大頁面內存的使用需要程序的支持,Oracle數據庫中,大頁面內存完全用於SGA。
Oracle建議在大SGA(12G以上),高連接數(1000個以上)的系統中使用Huge Page,但是Huge Page和Oracle 11g的AMM不兼容。因此需要取消memory_target、memory_max_target的設置。分別設置sga和pga。這樣內存中Page Table的使用量就可以由幾十G下降到幾十M了。
處理過程:
1、 修改數據庫參數
[oracle@uaflsdb02 ~]$ sqlplus / as sysdba
SQL> alter system reset memory_target scope=spfile;
SQL> alter system reset memory_max_target scope=spfile;
2、 查看數據庫參數,計算大頁面的需求數
[oracle@uaflsdb02 ~]$ sqlplus / as sysdba
SQL> show parameter sga
查看到sga為32GB。大頁面每頁面有2MB,32GB/2MB=16384。因此至少需要16384個大頁面。取大頁面數稍大於需求量,並取整為17000。
3、 設置大頁面數為17000
[root@uaflsdb01 ~]$ vim /etc/sysctl.conf
# 添加以下一行
vm.nr_hugepages = 17000
4、 設置memlock參數
[root@uaflsdb01 ~]# vim /etc/security/limits.conf
# 添加以下兩行,memlock參數稍小於內存總量即可,按KB算
* soft memlock 60000000
* hard memlock 60000000
5、 關閉數據庫,重啟服務器,再打開數據庫,查看修改生效情況與效果
[oracle@uaflsdb02 ~]$ free -m
total used free shared buffers cached
Mem: 64509 38118 26391 0 126 1296
-/+ buffers/cache: 36694 27814
Swap: 66399 0 66399
# 剩余內存有27GB
[root@uaflsdb02 ~]# grep Huge /proc/meminfo
HugePages_Total: 17000
HugePages_Free: 14452
HugePages_Rsvd: 13837
HugePages_Surp: 0
Hugepagesize: 2048 kB
# 大頁面已啟用
[root@uaflsdb02 ~]# free -m
total used free shared buffers cached
Mem: 64509 37152 27356 0 11 717
-/+ buffers/cache: 36424 28085
Swap: 66399 478 65921
# 空閒內存有28GB
[root@uaflsdb02 ~]# grep PageTables /proc/meminfo
PageTables: 73256 kB
# PageTables內存使用量由16GB下降到72MB。
6、 查看數據庫狀況,驗證應用系統業務操作,發現完全正常
7、 至此,本調整成功完成。
後續分析:
這套系統為什麼會出現如此高的Page Table使用量呢?這是由Oracle的服務器進程過多,SGA過大引起的,一個進程映射到32GB的內存需要32GB/4KB=8M個映射條目,在64bit的系統上約消耗24MB的內存,那麼1000個進程就會消耗24GB的內存,這是非常大的使用量。
而對於一般應用而言,是不需要1000個並發操作的,數據庫對1000個並發操作也無法承擔,那麼在設計應用時,應盡量避免過高連接數的設計,使用數據庫時,啟用少量連接並進行重用。
而連接數實在無法控制的時候,則可使用本文介紹的大內存頁面方式,降低Page Table內存的使用量。