分类: LINUX
2014-04-04 20:03:53
Linux内核中和内存相关的2个系统参数的设置:
想要通过修改linux内存管理相关的参数设置来观察其对内存数据库的读写性能的影响,首先要了解一些linux内存管理相关的重要参数,先了解两个,如下。
介绍一些前提基础:
在非一致性内存访问(NUMA)情况下,CPU访问不同位置的内存,代价是不一样的。在多CPU情况下,对每个CPU来说都有本地内存和远端内存之分,访问本地内存的代价要比访问远端内存的代价小。
内存节点(node):内存节点主要是依据CPU访问代价的不同而划分的。在多CPU环境下,本地内存和远端内存就是不同的节点。而且,就算在单CPU环境下,访问所有的内存的代价都是一样的,依然存在内存节点的概念,只是此时只有一个内存节点而已,内核中用struct pg_data_t来描述内存分区。
内存分区(zone):linux会对内存节点做进一步的划分,再将一个内存节点划分为不同的区。内核中以struct zone来描述内存分区。通常一个节点分为DMA,Normal, HighMem三个内存区。
DMA内存区:直接内存访问区,通常是物理内存起始的16MB,主要被一些外设使用,使得外围设备和主内存之间直接传输它们的I/O数据,而不需要系统CPU的参与。
Normal内存区:从16MB-896MB内存区。
HighMem内存区:896MB以后的内存区。
对一个内存节点来说,优先从HighMem分配,再从Normal或者DMA分配。
页框:linux采用的是页式内存管理,页是物理内存管理的基本单位,每个内存分区是由大量的页框组成的,内核中用struct page来描述一个页框。关于内存节点,内存区(zone)以及page的关系如下图所示:
注:其中zone_mem_map是一个页框的数组,它记录了一个内存分区的所有页框的使用情况。
1.min_free_kbyte:代表系统中必须保留的可用空闲内存的最小值。
在系统初始化时会根据内存大小计算一个默认值,计算规则是:
min_free_kbytes = sqrt(lowmem_kbytes * 16) = 4 * sqrt(lowmem_kbytes)(注:lowmem_kbytes即可认为是系统内存大小)计算出来的值有最小最大限制,最小为128K,最大为64M。
(1)每个zone区中都存在一套这三个参数,其中从小到大的顺序依次是watermark[min],watermark[low],watermark[high].
(2)当系统中空闲内存低于watermark[low]时,开始启用内核守护线程kswapd进行内存页面回收(每个zone中都会有一个kswapd),直到该zone的空闲内存页数量达到watermark[high]之后才停止回收行为。如果上层申请内存的速度太快,导致空闲内存降至watermark[min]以下,内核就会进行direct reclaim(直接回收),也就是说直接在应用程序的上下文中进行页面回收,再用回收来的内存满足内存申请。所以,当有这样的情况发生时就会阻塞应用程序的执行,会带来一定的响应延迟,甚至可能会触发OOM(Out Of Memory,内存溢出)。因为watermark[min]以下的内存空间是留给系统特殊使用的,所以不会给用户态程序用。
前面说道 min_free_kbyte主要是用于计算watermark[min/low/high]的。具体的计算方法就是:
所以中间的buffer量为 high - low = low - min = per_zone_min_free_pages * 1/4
因为min_free_kbytes = 4* sqrt(lowmem_kbytes),也可以看出中间的buffer量也是跟内存的增长速度成开方关系。
关于每个zone中的watermark[min/low/high]可以通过查看/proc/zoneinfo的内容获得:
min_free_kbytes大小的影响:
就像前面说的,min_free_kbyte设置的越大,watermark就会越高,同时三个水平标志之间的内存量页会相应的增加,这就会导致较早的启动kswapd线程进行页回收,而且回收上来的内存页会比较多(直到watermark[high]才会停止),这就使得系统会预留过多的空闲内存,而在一定程度上导致了应用程序可用内存量的减少。min_free_kbyte设置的过小,则会导致系统的预留内存过小。极端情况下设置min_free_kbytes接近内存大小时,留给应用程序的内存就会太少而可能会频繁地导致OOM的发生。
min_free_kbytes设的过小,则会导致系统预留内存过小。kswapd回收的过程中也会有少量的内存分配行为(会设上PF_MEMALLOC)标志,这个标志会允许kswapd使用预留内存;另外一种情况是被OOM选中杀死的进程在退出过程中,如果需要申请内存也可以使用预留部分。这两种情况下让他们使用预留内存可以避免系统进入deadlock状态。
2.lowmem_reserve_ratio
(1)这个参数的作用是在各个zone之间预留一些空间,以防止高端zone在没有内存的情况下过度使用低端zone的内存资源。一般一个node的机器有三个zone:DMA,Normal, HighMem.低端内存DMA很小,有自己的特殊作用,比如发生DMA时只能分配DMA zone的低端内存,所以,要遵循尽量能使用高端内存时不使用低端内存,同时防止高端内存分配不足的时候抢占稀有的低端内存。
(2)计算方法:
内核利用/proc/zoneinfo中的protection数组计算每个zone的预留页数,计算出来也是数组形式,可以在上面第1个参数讲解中看到。在进行内存分配时,这些预留页数值和watermark相加,一起来决定现在的内存是否满足分配请求,或者空闲内存是否过少需要启动回收机制。比如内核文档/Documentation/sysctl/vm.txt中给出了这样一个例子:
如果一个normal区(index = 2)的页申请来试图分配DMA区的内存,且现在使用的判断标准是watermark[low]时,内核计算出page_free = 1355,而watermark + protection[2] = 3 + 2004 = 2007 > page_free,则认为空闲内存太少而不予以分配。如果分配请求本就来自DMA zone,则 protection[0] = 0会被使用,而满足分配申请。zone[i] 的 protection[j] 计算规则如下:
当在normal区分配了大量内存的时候,可用的低端内存可能就不够了,一些系统操作可能会失败并提示“EAGAIN”等的错误信息。在上面的lowmem_reserve_ratio中显示normal区保留了32页,假如想在常规区保留64页,则改写lowmem_reserve_ratio参数的值来实现:
vm.lowmem_reserve_ratio = 256 64 32
然后执行下列命令使之生效:
linux内存回收机制如何被触发:
当某个进程针对页面发出请求时,系统内核会首先检查首选项NUMA(非一致内存访问)区是否有足够的空余内存,以及是否存在1%以上的可回收的页面。这个百分比可以调节,并由vm.min_unmaped_ratio sysctl来决定。可回收页面属于由文件支持的页面(即与页面缓存存在映射关系的文件所产生的页面),但目前并未被映射到任何进程中的那些页面。在/proc/meminfo中,可以很清楚地看到,所谓"可回收页面(reclaimable pages)"就是那些"活动(文件)+非活动(文件)-被映射"(Active(file)+Inactive(file)-Mapped)的内容。
系统内核如何判断多少空闲内存才够用呢?
内存会使用区“水平标记(watermarks)”,通过/proc/sys/vm/min_free_kbytes中的值来判断。同时它们也会检查/proc/sys/vm/lowmem_reserve_ratio中的值:
特定主机内经过计算的值会保存在/proc/zoneinfo当中,并带有如下面所示的“低/中/高”(low/min/high)标签:
内核会在区内存空闲页面的数量低于水平标志时执行页面回收,当空闲页面的数量高于“低”水平标记后,页面回收操作就会中止。(注意:这一计算过程针对的是各个独立区(zone):即使其他区仍然拥有足够的空闲内存,只要当前区被触发,回收机制就会执行)。
参考:
13.5/Documentation/sysctl/vm.txt
http://kernel.taobao.org/index.php/Kernel_Documents/mm_sysctl(淘宝内核组)