我正在尝试使用 cgroups 来限制具有大量 RAM(128 GB 或更多)的服务器上用户进程的内存使用量。我们想要实现的是为操作系统和根进程保留大约 6GB 的 RAM,其余部分留给用户。我们希望确保始终有可用内存,并且我们不希望服务器频繁交换。
如果限制设置得足够低(<16GB),则此方法可行。cgred 将用户进程正确分配给正确的 cgroup,一旦达到限制,oom 将终止占用大量内存的进程。
当我们将限制设置得更高时,问题就会出现。然后,如果某个进程使用的 RAM 超过 16G,即使内存使用量仍远低于限制,并且有足够的 RAM 可用,服务器也会开始交换。
是否存在任何设置或某种最大值来限制我们可以在 cgroups 下授予访问权限的内存量?
以下是更多信息:
我使用以下代码来模拟用户进程占用内存的情况。代码在链接列表中跟踪已分配的内存,因此可以从程序内部使用和访问内存,而不是仅使用 malloc 保留内存(每次都覆盖指针)。
/* grabram.c 的内容 */
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
struct testlink {
void *ram;
struct testlink *next;
};
int main (int argc, char *argv[]) {
int block=8192;
char buf[block];
void *ram=NULL;
FILE *frandom;
int nbproc,i;
pid_t pID;
struct testlink *pstart, *pcurr, *pnew;
if (argc < 2) {
//nbproc = 1 by default
nbproc=1;
} else {
if (sscanf(argv[1], "%d", &nbproc) != 1) {
/* it is an error */
printf("Failed to set number of child processes\n");
return -1;
}
}
// open /dev/urandom for reading
frandom = fopen("/dev/urandom", "r");
if ( frandom == NULL ) {
printf("I can't open /dev/urandom, giving up\n");
return -1;
}
fread(&buf, block, 1, frandom);
if ( ferror(frandom) ) {
// we read less than 1 byte, get out of the loop
printf("Error reading from urandom\n");
return -1;
}
fclose (frandom);
// pID=0 => child pID <0 => error, pID > 0 => parent
for (i=1; i<nbproc; i++){
pID = fork();
// break out of the loop if a child
if (pID == 0)
break;
// exit if fork fails
if (pID < 0) {
printf("fork() failed, dying \n");
return -1;
}
}
pstart = (struct testlink*)malloc(sizeof(struct testlink));
pstart->ram=NULL;
pstart->next=NULL;
pcurr = pstart;
while ( 1==1 ) {
ram = (void *)malloc(block);
if (ram == NULL) {
printf("can't allocate memory\n");
return -1;
}
memcpy(ram, &buf, block);
// store allocated blocks of ram in a linked list
// so no one think we are not using them
pcurr->ram = ram;
pnew = (struct testlink*)malloc(sizeof(struct testlink));
pnew->ram=NULL;
pnew->next=NULL;
pcurr->next=pnew;
pcurr=pnew;
}
return 0;
}
到目前为止我尝试设置以下可调参数:
vm.overcommit_memory
vm.overcommit_ratio
vm.swappiness
vm.dirty_ratio
vm.dirty_background_ratio
vm.vfs_cache_pressure
这些 sysctl 设置似乎都没有任何效果。即使将 swappiness 设置为 0、禁用过量使用等,上述代码一旦超过 16GB 限制,服务器也会开始交换。我甚至尝试关闭交换,但无济于事。即使没有交换,kswapd 仍会触发,性能会下降。
最后是cgconfig.conf文件的相关内容
mount {
cpuset = /cgroup/computenodes;
cpu = /cgroup/computenodes;
memory = /cgroup/computenodes;
}
#limit = 120G
group computenodes {
# set memory.memsw the same so users can't use swap
memory {
memory.limit_in_bytes = 120G;
memory.memsw.limit_in_bytes = 120G;
memory.swappiness = 0;
# memory.use_hierarchy = 1;
}
# No alternate memory nodes if the system is not NUMA
# On computenodes use all available cores
cpuset {
cpuset.mems="0";
cpuset.cpus="0-47";
}
}
最后我们使用Centos 6,内核2.6.32。
谢谢
答案1
**注:为后代取消删除**
你的问题在这里
# No alternate memory nodes if the system is not NUMA
# On computenodes use all available cores
cpuset {
cpuset.mems="0";
cpuset.cpus="0-47";
}
}
你只使用一内存节点。您需要设置此项才能使用全部记忆节点。
我也认为下面的内容也适用,除非您了解下面的内容,否则您仍然会看到问题。因此留给后人看。
这个问题基本上归结于所使用的硬件。内核有一个启发式方法来确定此开关的值。这会改变内核确定 NUMA 系统上的内存压力的方式。
zone_reclaim_mode:
Zone_reclaim_mode allows someone to set more or less aggressive approaches to
reclaim memory when a zone runs out of memory. If it is set to zero then no
zone reclaim occurs. Allocations will be satisfied from other zones / nodes
in the system.
This is value ORed together of
1 = Zone reclaim on
2 = Zone reclaim writes dirty pages out
4 = Zone reclaim swaps pages
zone_reclaim_mode is set during bootup to 1 if it is determined that pages
from remote zones will cause a measurable performance reduction. The
page allocator will then reclaim easily reusable pages (those page
cache pages that are currently not used) before allocating off node pages.
It may be beneficial to switch off zone reclaim if the system is
used for a file server and all of memory should be used for caching files
from disk. In that case the caching effect is more important than
data locality.
Allowing zone reclaim to write out pages stops processes that are
writing large amounts of data from dirtying pages on other nodes. Zone
reclaim will write out dirty pages if a zone fills up and so effectively
throttle the process. This may decrease the performance of a single process
since it cannot use all of system memory to buffer the outgoing writes
anymore but it preserve the memory on other nodes so that the performance
of other processes running on other nodes will not be affected.
Allowing regular swap effectively restricts allocations to the local
node unless explicitly overridden by memory policies or cpuset
configurations.
为了让您对这里发生的事情有个大概的了解,内存被分成多个区域,这在 RAM 与特定 CPU 绑定的 NUMA 系统上特别有用。在这些主机中,内存位置可能是影响性能的重要因素。例如,如果内存组 1 和 2 分配给物理 CPU 0,则 CPU 1 可以访问这些内存,但代价是锁定 CPU 0 无法访问的内存,这会导致性能下降。
在 Linux 上,分区反映了物理机的 NUMA 布局。每个区域大小为 16GB。
在区域回收开启的情况下,内核选择在完整区域 (16 GB) 中回收 (将脏页写入磁盘、逐出文件缓存、交换内存),而不是允许进程在另一个区域分配内存(这会影响该 CPU 的性能)。这就是为什么您会注意到 16GB 之后进行交换。
如果你关闭这个值应该改变内核的行为,不是积极地回收区域数据,而是从另一个节点分配。
zone_reclaim_mode
尝试通过运行系统来关闭它sysctl -w vm.zone_reclaim_mode=0
,然后重新运行测试。
请注意,在这种关闭配置下运行的长时间运行的高内存进程zone_reclaim_mode
会随着时间的推移变得越来越昂贵。
如果您允许大量不同的 CPU 上运行的大量不同进程都使用大量内存来使用任何具有可用页面的节点,则可以有效地将主机的性能提升到类似于只有 1 个物理 CPU 的性能。