@Tmacy
2016-12-02T11:23:56.000000Z
字数 4315
阅读 1711
linux
优化
假设有这样一种情况,当一台 Linux 主机上同时登陆了 10 个人,在系统资源无限制的情况下,这 10 个用户同时打开了 500 个文档,而假设每个文档的大小有10M,这时系统的内存资源就会受到巨大的挑战。而实际应用的环境要比这种假设复杂的多,例如在一个嵌入式开发环境中,各方面的资源都是非常紧缺的,对于开启文件描述符的数量,分配堆栈的大小,CPU时间,虚拟内存大小等,都有非常严格的要求。
资源的合理限制和分配,不仅仅是保证系统可用性的必要条件,也与系统上软件运行的性能有着密不可分的联系。ulimit可以起到很大的作用,它是一种简单并且有效的实现资源限制的方式。
ulimit用于限制shell启动进程占用的资源,支持各种类型的限制:
DeepinServer 15
#ulimit -a
core file size (blocks, -c) #core文件最大值
data seg size (kbytes, -d) #数据段最大值
scheduling priority (-e) #最大调度优先级
file size (blocks, -f) #创建文件最大值
pending signals (-i) #信号可以被挂起的最大数
max locked memory (kbytes, -l) #最大可加锁的内存
max memory size (kbytes, -m) #最大常驻内存
open files (-n) #使用文件描述符上限
pipe size (512 bytes, -p) #管道缓冲区最大数量
POSIX message queues (bytes, -q) #POSIX信号队列最大值
real-time priority (-r) #最大实时优先级
stack size (kbytes, -s) #栈的最大值
cpu time (seconds, -t) #cpu使用时间最大上限
max user processes (-u) #用户线程最大值
virtual memory (kbytes, -v) #虚拟内存上限
file locks (-x) #文件锁上限
ulimit 命令的格式为:ulimit [options] [limit]
除了上列的几个资源限制参数,ulimit还有几个参数
-H : 设置硬资源,一旦设置不能再增加
例如:ulimit -Hs 64
限制硬资源,线程栈大小为64k。
-S :设置软资源限制,设置后可以增加,但是不能超过硬资源
例如:ulimit -Sn 32
限制软资源,32个文件描述符
-a 显示当前所有的limit 信息
我们可以通过一下几种方式来使用ulimit
1.在用户的启动脚本中
如果用户使用的是 bash,就可以在用户的目录下的 .bashrc 文件中,加入 ulimit – u 64,来限制用户最多可以使用 64 个进程。此外,可以在与 .bashrc 功能相当的启动脚本中加入 ulimt。
2.在应用程序的启动脚本中
如果用户要对某个应用程序 myapp 进行限制,可以写一个简单的脚本 startmyapp:
ulimit - s 512
myapp
3.直接在控制台输入
# ulimit -p 256
限制管道的缓冲区为256k
ulimit作为对资源使用限制的一种工具,是有其所用范围的。它限制的对象是单个用户,还是单个进程,还是整个系统呢?
ulimit实际上限制的是当前shell进程以及其派生的子进程,对另一个shell终端包括其子进程都没有影响。
针对具体用户的资源加以限制的方法是修改系统的/etc/security/limits.conf文件。该文件不仅能限制用户的资源使用,还能制定组的资源使用情况。该文件的每一行都是对限定的描述,格式如下
<domain> <type> <item> <value>
domain 表示用户或者组的名字,还可以使用 * 作为通配符。Type 可以有两个值,soft 和 hard。
Item 则表示需要限定的资源,可以有很多候选值,如 stack,cpu,nofile 等等,分别表示最大的堆栈大小,占用的 cpu时间,以及打开的文件数。通过添加对应的一行描述,则可以产生相应的限制
* hard nofile 100
表示任意用户所能创建的最大文件数是100
有时候,我们需要对整个系统的资源做总的限制,这时候我们需要修改/proc下的配置文件。/proc下包含了很多系统当前状态的配置文件。例如:/proc/sys/kernel/pid_max,/proc/sys/net/ipv4/ip_local_port_range 等等。大部分从文件名称就可以猜出限制资源的种类,我们可以根据需要针对修改。
1.限制 shell 的内存使用
root@10-13-3-180:~# echo "test ulimit" > test
root@10-13-3-180:~# ulimit -d 1000 -m 1000 -v 10000
root@10-13-3-180:~# ls -l test
ls: error while loading shared libraries: libpcre.so.3: failed to map segment from shared object: Cannot allocate memory
-m 设置常驻内存最大值
-d 设置数据段最大值
-v 设置虚拟内存最大值
上面的命令,我们已经把当前 shell 所能使用的最大内存限制在 1000KB 以下,导致ls命令运行失败。可以看到报错信息是无法分配内存,也就表示ulimit已经成功限制了系统资源。
2.限制创建文件大小
在没有限制的情况下,我们复制一个新的test文件:
root@10-13-3-180:~# ls -l test
-rw-r----- 1 root root 6711 Mar 15 15:03 test
root@10-13-3-180:~# cat test > newTest
root@10-13-3-180:~# ls -l newTest
-rw-r--r-- 1 root root 6711 Mar 15 15:04 newTest
之后,我们设置ulimit -f 5,单位是blocks(1024 bytes)
root@10-13-3-180:~# ulimit -f 5
root@10-13-3-180:~# cat test > new
File size limit exceeded (core dumped)
提示文件大小超出限制。我们查看new文件,大小为5120
root@10-13-3-180:~# ls -l new
-rw-r--r-- 1 root root 5120 Mar 15 15:06 new
关于block size的问题:
通常Linux的“block size”指的是1024 bytes,Linux用1024-byte blocks 作为buffer cache的基本单位。但linux的文件系统的block却不一样。例如ext3系统,block size是4096。使用tune2fs可以查看带文件系统的磁盘分区的相关信息,包括block size。
tune2fs -l /dev/sda1
1.硬件上的 block size, 应该是"sector size",linux的扇区大小是512byte
2.有文件系统的分区的block size, 是"block size",大小不一,可以用工具查看
3.没有文件系统的分区的block size,也叫“block size”,大小指的是1024 byte
4.Kernel buffer cache 的block size, 就是"block size",大部分PC是1024
3.限制socket数量
对于一个 C/S 模型中的 server 程序来说,它会为多个 client 程序请求创建多个 socket 端口给与响应。如果恰好有大量的 client 同时向 server 发出请求,那么此时 server 就会需要创建大量的 socket 连接。但在一个系统当中,往往需要限制单个 server程序所能使用的最大 socket 数,以供其他的 server 程序所使用。
我们发现,在ulimit的选项中没有限制socket的选项。但是socket是文件,我们可以利用限制文件描述符来起到限制socket的作用。
查看当前进程打开的文件描述符:
root@10-13-3-180:~# ls /proc/3639/fd/ -l
total 0
lrwx------ 1 root root 64 Mar 15 14:59 0 -> /dev/null
lrwx------ 1 root root 64 Mar 15 14:59 1 -> /dev/null
lrwx------ 1 root root 64 Mar 15 15:36 10 -> /dev/ptmx
lrwx------ 1 root root 64 Mar 15 14:59 2 -> /dev/null
lrwx------ 1 root root 64 Mar 15 14:59 3 -> socket:[82797]
lrwx------ 1 root root 64 Mar 15 14:59 4 -> socket:[83076]
lr-x------ 1 root root 64 Mar 15 14:59 5 -> pipe:[83079]
l-wx------ 1 root root 64 Mar 15 15:36 6 -> pipe:[83079]
lrwx------ 1 root root 64 Mar 15 15:36 7 -> /dev/ptmx
lrwx------ 1 root root 64 Mar 15 15:36 9 -> /dev/ptmx
4.限制堆栈数量
使用 -s(单位KB)来对线程的堆栈大小进行限制,从而减少整个多线程程序的内存使用,增加可用线程的数量。
我们所遇到的问题是系统对我们的多线程程序有如下的限制:
ulimit -v 200000
这意味着我们的程序最多只能使用不到 200MB 的虚拟内存。由于我们的程序是一个多线程程序,程序在运行时会根据需要创建新的线程,这势必会增加总的内存需求量。一开始我们对堆栈大小的限制是 1024 (本例子中使用 1232 来说明):
ulimit -s 1232
当我们的程序启动后,通过 pmap来查看其内存使用情况,可以看到多个占用 1232KB 的数据段,这些就是程序所创建的线程所使用的堆栈。
每当一个新的线程被创建时都需要新分配一段大小为 1232KB 的内存空间,而我们总的虚拟内存限制是 200MB,所以如果我们需要创建更多的线程,那么一个可以改进的方法就是减少每个线程的固定堆栈大小,这可以通过 ulimit – s 来实现:
ulimit -s 512
我们将堆栈大小设置为 512KB,这时再通过 pmap 查看一下我们的设置是否起作用:
从上面的信息可以看出,我们已经成功的将线程的堆栈大小改为 512KB 了,这样在总内存使用限制不变的情况下,我们可以通过本小节介绍的方法来增加可以创建的线程数,从而达到改善程序的多线程性能。