LINUX系统编程SWAP原理以及和数据库(MYSQLORACLE)关系

作为一位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内核和实现,只是从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
13
ORACLE METALINK


当前名称:LINUX系统编程SWAP原理以及和数据库(MYSQLORACLE)关系
网页URL:http://myzitong.com/article/ijeoep.html