浅谈Linux ulimit以及max memory locked

刚入职,我在索引这个组,需要熟悉下之前的搜索索引模块的代码,以便后续开发。我在新申请的测试机器上编译代码部署索引这个模块就报错了。定位出现问题的地方,代码大致流程是这样子的:

1
2
3
4
5
6
7
8
9
10
if (conf->use_memlock_for_mmap) {
// add MAP_LOCKED to lock the buffer
attr_hash = (AttrIndexInfo*)mmap(NULL, fsize, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_LOCKED, fd, 0);
} else {
attr_hash = (AttrIndexInfo*)mmap(NULL, fsize, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
}

而参数里配置了use_memlock_for_mmap 选项,于是代码就走到第一个mmap逻辑处。

使用ulimit -a查看下系统属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[armsword@search-querybs1 ~]$ ulimit -a
core file size (blocks, -c) 4194304
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 256726
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1000000
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 102400
virtual memory (kbytes, -v) unlimited (注:相当于limits.conf中的as和cgroup中的memory.limit_in_bytes.)
file locks (-x) unlimited

我们知道索引程序在启动时候,需要加载倒排/正排等索引原文件,这些文件是比较大的,几十G或者过百G也是可能的,但是系统下的max locked memory对应值是64k,而mmap选项也设置了MAP_LOCKED选项,此选项的意思就是lock一段地址范围内已map的内存,相应的数据在unlock之前一直存在于物理内存中,不会被回收。对于应用程序来说,可以将内存中一些对程序性能影响较大的数据lock起来,避免非预期的页面回收或者换入/换出引起性能波动。所以将max locked memory设置为unlimited就解决问题。

linux系统提供了以下几个系统调用用于内存的lock和unlock。

1
2
3
4
5
mlock/munlock:lock/unlock一段地址范围内已map的内存
mlockall/munlockall:lock进程虚拟地址空间内已map的内存,还可以选择对于此后新map的空间是否自动lock
mmap使用MAP_LOCKED选项时表示在mmap的同时,对相应地址范围进行mlock

一般情况下,我们使用ulimit多用于提高性能,最常用的地方就是设置打开文件描述符的数量,web服务器等需要大量的文件句柄,一旦开太小,比如默认1024,在句柄使用完毕的时候,系统就频繁出现emfile错误,这时候系统很容易陷入不可用。但是如果设定太大了,又会有这样的副作用。很多服务器程序是事件派遣的,比如说用epoll,程序在启动的时候通常会根据最大的文件句柄数来预留内部的slot,一个slot貌似要占用几K的资源,如果你设定文件句柄数目太大,就可能无端的浪费了几百M内存。所以要设置一个合适的值有利于提高程序性能。

ulimit 用于限制 shell 启动进程所占用的资源,支持以下各种类型的限制,具体楼上已列出,注意下H/S选项的意义,

-H 设置硬资源限制,硬资源限制用于控制软限制。限定一旦设置只有root用户可以增加硬限制,普通用户只能减少自己的硬限制大小。
-S 设置弹性资源限制,弹性限制用于限制具体的用户或者进程。设置后普通用户可以增加,但是不能超过硬限制大小。
如果不指定-S或者-H,那么弹性资源限制和硬限制将同时设置。

作为临时限制,ulimit 可以作用于通过使用其命令登录的 shell 会话,在会话终止时便结束限制,并不影响于其他 shell 会话。而对于长期的固定限制,修改 /etc/security/limits.conf 文件即可。