LINUX系統程式設計 SWAP原理以及和資料庫(MYSQL ORACLE)關係

luckyfriends發表於2016-12-21
作為一位DBA長期以來一直受到一些關於SWAP使用的問題,比如如下問題:
1、為了我 free 中buffer/cache明明還有空間為什麼SWAP使用了?
2、哪個(些)程式使用了最多的SWAP?
3、如果在ORACLE或者MYSQL避免使用SWAP?
4、為什麼要使用直接路徑繞過作業系統緩衝(O_DIRECT)?
5、ORACLE 11G使用tmpfs虛擬檔案系統,記憶體可能被SWAP出嗎?
6、設定/proc/sys/vm/swappiness為0後有什麼風險?


本文參考<<深入理解liunx核心>><<LINUX系統程式設計手冊>>結合資料庫希望給出
比較明瞭的答案,但是由於涉及內容較深特別是系統知識,而作者也沒有詳細
研究過LINUX核心和實現,只是從API呼叫者和DBA的角度來看,難免有概念不準
或者有誤的地方,望指出共同討論。如果特別有興趣請自行參考<<深入理解liunx核心>>
類似書籍。

1、LINUX 高速頁面緩衝與資料庫BUFFER的關係
為了闡明這些問題,不得不從LINUX頁高速緩衝說起,在資料庫中我們都知道有
一塊非常大的緩衝區用於存放最近訪問的資料,如ORACLE的BUFFER_CACHE、INNODB
的innodb_buffer_pool_size,這片區域至關重要,直接影響到資料庫物理讀取的可能性。
所以一般資料庫指導意見都為系統實體記憶體的60%以上(當然ORACLE 還有share_pool
一般ORACLE建議memory_target包含SGA+PGA為系統記憶體60%以上),而在LINUX OS看來
資料軟體只是使用者態的匿名頁空間,既然如此重要LINUX OS當然也是如此,他也
有這樣一部分記憶體為核心態頁快取記憶體,LINUX 採用一種比較粗狂的分配方式,只要
資料讀取(還有預讀-區域性性原理)它就會進行快取,它只受限於2個方面
--實體記憶體大小
--使用者態空間佔用記憶體大小
(LINUX系統程式設計13章)
這樣做是因為這樣能夠大大加快READ(),WIRTE()呼叫的速度,如果使用者態程式沒有自己的
快取的時候,那麼熱資料快取在LINUX頁高速緩衝中,那麼下次讀取的時候速度大大加快
那麼就資料庫而言資料塊可能存在於:
DISK DATA PAGE-->KERNAL BUFFER/CACHE PAGE--->USER(DATABASE) BUFFER PAGE
這樣一個順序,這裡是我自己的理解,因為我程式設計的時候也時常自己分配一塊記憶體區域
(malloc族函式)
如果這個時候稍加思考,我們可以看到資料頁可能存在於2個地方一個是KERNEL一個是
USER(DATABASE) BUFFER,前者是LINUX OS級別的,後者是DATABASE級別的。在LINUX中
我們透過FREE可以檢視到
[root@testmy ~]# free
             total       used       free     shared    buffers     cached
Mem:       4052856    2009000    2043856          0     146404    1327484
-/+ buffers/cache:     535112    3517744
Swap:      8388600          0    8388600

第一行:從OS的角度看記憶體使用
TOTAL:總的記憶體大小
USED :LINUX來看使用的空間,使用者態記憶體(比如資料庫記憶體)+核心態高速緩衝區
FREE :剩餘的記憶體大小 4052856-2009000
BUFFERS和CACHED:一起說明了核心佔用的大小
SHRED:共享記憶體大小,應該存在於使用者態
第二行:從使用者態的角度來看記憶體使用
used:使用者態記憶體(比如資料庫記憶體)
free:應用程式可能可以使用的大小,第一行的 UESD - (buffers+cached)

--其實如果要看記憶體剩餘空間,這兩個FREE都是隻有部分參考價值。
另外如果要說buffers和cache的區別,這一點在深入LINUX核心 P607頁有相關
的說明,實際上在核心2.4.10後就沒有區別了,所以進行描述。
關於核心態、使用者態可以參考:
http://blog.itpub.net/7728585/viewspace-2129073/
的部分觀點和配圖

2、為什麼資料庫可以採用O_DIRECT開啟檔案模式(linux open() api flag)
--資料庫軟體有自己的記憶體塊的管理方法,不需要核心態高速緩衝區,這樣有浪費記憶體
  空間的風險。如上:
DISK DATA PAGE-->KERNAL BUFFER/CACHE PAGE--->USER(DATABASE) BUFFER PAGE
我們去掉了>KERNAL BUFFER/CACHE PAGE,直接從DIS DATA PAGE--> USER BUFFER PAGE
--資料庫軟體有自己的記憶體塊的管理方法,不需要核心態高速緩衝區,這樣讓READ(),
  WRITE()操作有KERNAL BUFFER/CACHE PAGE這一層額外的開銷
  關於這一點可以參考
  http://blog.itpub.net/7728585/viewspace-2129558/
  的部分觀點和配圖加以理解

3、記憶體不足頁回收
   我們知道LINUX記憶體分配使用夥伴演算法,在LINUX這種粗狂的記憶體分配方式下,一般來說
這種情況下實體記憶體遲早會全部對映完。這個時候就需要一種制度或者說是演算法來進行頁
回收,這就是LINUX的PFRA演算法
  關於那些頁可以回收,還是看一下深入LINUX核心第17章:
  Swappable  Anonymous pages in User Mode address spaces
             Mapped pages of tmpfs filesystem (e.g.,pages of IPC sharedmemory)
             
  Syncable   Mapped pages in User Mode address spaces Pages included in the 
             page cache and containing data of disk files Block device buffer 
             pages Pages of some disk caches(e.g., the inode cache)
             
  Discardable  Unused pages included in memory caches (e.g., slab allocator caches)
             Unused pages of the dentry cache
  
  實際上這裡我們明顯看到一個重點使用者態的匿名頁,匿名頁包含了程式了堆和棧空間,
那麼資料庫的自己分配的記憶體明顯是堆記憶體,這些空間是可以被交換(swap)的,而核心
太快取記憶體的頁一般為可同步和可丟棄頁。
  接下來釋放記憶體的原則:
  1、首先釋放沒有任何程式使用的核心態快取記憶體頁
  2、使用者態程式的所有頁是可以回收和交換的
  3、回收共享頁
  4、根據LRU演算法回收核心態快取記憶體中的頁,優先換出乾淨頁,因為不需要
     寫磁碟。
  這裡還透露一個ORACLE 11G中使用tmpfs虛擬檔案系統也是會被SWAP到交換分割槽的。
4、交換(swap)和交換傾向
   交換分割槽用於擴充實際記憶體的大小,但是他是存在於物理磁碟,它速度可想而知,
也成了DBA非常關注的一個部分,因為一旦使用SWAP那麼資料庫的效能可想而知。
   前面我們已經描述了使用者態記憶體空間都是可以交換的包括tmpfs虛擬檔案系統,
相反核心態快取記憶體頁反而是不會進入SWAP空間的,他只是在記憶體不足的情況下
進行同步和回收。
   那麼接下來要說一下交換傾向(深入LINUX核心 P688):
   交換傾向=對映比率/2+負荷值+交換值
--對映比率:使用者態記憶體實際實體記憶體佔用總實體記憶體大小的比重 
很明顯是:
-/+ buffers/cache:     535112    3517744 這裡的535112/4052856
如果比重大則說明使用者態記憶體佔用實體記憶體更大,如果比較小則說明核心態高速緩衝頁
佔用更大。
  顯然這裡 /2,即使最多也就是50%,也就是50 當然不可能。
-- 負荷值:詳細參考深入LINUX核心,一般不可能為50,知道這一點已經足夠做出推論
           了。
-- 交換值(SWAPPINESS):使用者可以設定的,預設為60,sysctl -a|grep swappiness可以看到

  如果交換傾向大於等於100時,記憶體緊張的時候,頁才從使用者態記憶體進行交換出去,
然後釋放,如果設定交換值(SWAPPINESS)=0,那麼對映比率/2+負荷值不可能大於等於
100,這就不可能讓使用者態記憶體交換出去,對於資料庫當然是各種buffer_cache,這是
對資料庫有利的。
如何修改:
--永久修改
修改 /etc/sysctl.conf 加上:
  vm.swappiness=0
sysctl -p生效
--臨時修改
echo 0 > /proc/sys/vm/swappiness

這裡我們也不得不在看下
[root@testmy ~]# free
             total       used       free     shared    buffers     cached
Mem:       4052856    2009000    2043856          0     146404    1327484
-/+ buffers/cache:     535112    3517744

這裡的兩個free值,前文說過第一個free是OS來看的,第二個是app應用來看的,實際上
他們只有參考價值而沒有絕對的含義,因為實際的記憶體空閒應該是2043856,但是這個值
在一般的安裝資料庫應用的LINUX作業系統中為0,第二列3517744,包含了buffer+cached
的核心態高速緩衝頁,雖然核心態高速緩衝頁可以回收和同步,但是由於交換傾向的存在
而且並不是有的核心態高速緩衝區頁都能回收和同步,在安裝有資料庫應用的LINUX操作
系統中,一般來說這一列值非常大,但是偶爾也有使用SWAP的情況。其實使用SWAP如果不
存在SWAP的換出換入,資料庫也不會慢。


5、OOM(out of memory)
    如果交換區已經滿了,並且沒有核心態快取記憶體可以回收和同步,那麼就會啟用OOM
來刪除程式,輸入LINUX核心一書用外科醫生為病人截肢來比喻,非常恰當,雖然不
情況但是已經沒有退路。
    那麼如果我們設定了swappiness=0,那麼用不了交換區滿,因為使用者態記憶體比如資料
佔用記憶體不能使用交換區,感覺這個時候交換已經沒用了。這就是一個潛在的風險,但是
對於資料庫軟體來說,頻繁大量的使用SWAP換入換出和DOWN機沒什麼區別,我就遇到過
大量使用SWAP交換區換出換入頁的ORACLE(10GR2)資料庫基本動不了的,等待事件為
shared pool、libarycache,最後使用巨頁進行解決。
   我在ORACLE METALINK上也找到這樣一個文章
The confusion about vm.swappiness comes from the fact that in older Red Hat kernels, 
a value of 0 for vm.swappiness resulted in the minimal amount of swapping to avoid 
an out of memory condition. In newer kernels (as of RHEL kernel 2.6.32-303), a value 
of 0 will completely disable swap, but a value of 1 will provide the minimal amount 
of swapping to avoid an out of memory condition.

My general recommendation is to set vm.swappiness to a value of 1 for a dedicated 
MySQL server.  There is not much practical difference between a value of 0 and a 
value of 1 on older kernels, but 1 is the safe setting to avoid an OOM condition 
on newer kernels (assuming that some swap space is available, of course).

   我們可以看到設定為swappiness=0確實加大了OOM的風險,它建議為1最小化swap

6、資料庫伺服器的交換設定


--設定O_DIRECT,依賴資料庫自身記憶體,減少記憶體中資料的冗餘浪費記憶體,減少SWAP使用的可能


  MYSQL適用 innodb_flush_method = O_DIRECT
  
  ORACLE謹慎使用 filesystemio_options=SETALL,DIRECTIO 可能有存在BUG,使用前務必檢視
  metalink,看看版本是否有bug
  實際ORACLE 11G很多大表的全表掃描都是使用
  Direct Path Read的方式減少了對資料庫本身和核心高速緩衝頁的衝擊
  
--設定vm.swappiness=0(或者1),根據交換傾向讓使用者態記憶體不交換,如果如此作者認為如果未設定
  O_DIRECT那麼應該保證有足夠的記憶體,那麼資料庫記憶體最好不要超過實體記憶體的50%(請各位指點),
  避免出現OOM問題。
  
  MYSQL適用 
  ORACLE查詢METALINK沒有相關說明,原理上可以使用


--設定巨頁
  ORACLE 適用,注意11gMEMORY_TARGET使用tmpfs和巨頁有衝突我在ORACLE10G中設定過
 
  MYSQL  可以使用,但是沒用過


--除了buffer以外其他和記憶體相關的引數是否過大
 mysql:sort_buffer tmp_table_size join_buffer_size等
 oracle:分開SGA和PGA,PGA是否得當

--最簡單的各位同仁多買點實體記憶體吧,實體記憶體也不貴了

最後來回答開始的問題
1、為了我 free 中buffer/cache明明還有空間為什麼SWAP使用了?
   參考部分4   
2、哪個(些)程式使用了最多的SWAP?
   top後按F選擇p然後回車會出現SWAP供查詢 
   /proc/pid/stats 包含了swap使用量,可以使用程式遍歷排序
   
3、如果在ORACLE或者MYSQL避免使用SWAP?
   參考部分6
4、為什麼要使用直接路徑繞過作業系統緩衝(O_DIRECT)?
   參考部分2
5、ORACLE 11G使用tmpfs虛擬檔案系統,記憶體可能被SWAP出嗎?
   參考部分3
6、設定/proc/sys/vm/swappiness為0後有什麼風險?
   參考部分5
   
參考:
<<深入理解liunx核心>> 15 16 17
<LINUX系統程式設計手冊> 13
ORACLE METALINK

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14710393/viewspace-2131121/,如需轉載,請註明出處,否則將追究法律責任。

相關文章