第16章 服务器调制、调试和测试
16.1 最大文件描述符数
系统分配给应用进程的文件描述符数量是有限制的,所以我们必须关闭那些已经不再使用的文件描述符,以释放它们占用的资源,比如作为守护进程运行的服务器就应该总是关闭标准输入、标准输出、标准错误这3个文件描述符。
Linux对应用进程能打开的最大文件描述符数量有两个层次的限制:用户级限制和系统级限制。用户级限制指目标用户运行的所有进程总共能打开的文件描述符数;系统级限制指所有用户总共能打开的文件描述符数。
以下命令可查看用户级文件描述符限制:
ulimit -n
我们可通过一下方式将用户级文件描述符限制设为max-file-number,以2048为例:
ulimit -SHn 2048
但这种设置是临时的,只在当前session中有效,为永久修改用户级文件描述符数限制,可在/etc/security/limits.conf
文件中加入以下两项:
* hard nofile 2048
* soft nofile 2048
*第一行是硬限制,第二行是软限制。是通配符,表示所有用户。
如果要修改系统级文件描述符数限制,可用以下命令:
sysctl -w fs.file-max=2048
但该命令也是临时更改系统限制,要永久更改系统级文件描述符数限制,需要在/etc/sysctl.conf
文件中添加以下项:
fs.file-max=2048
然后执行sysctl -p
命令,该Linux系统上的命令用于重新加载系统内核参数设置。
16.2 调整内核参数
几乎所有内核模块,包括内核核心模块和驱动程序,都在/proc/sys
目录下提供了某些配置文件以供用户调整模块的属性和行为。通常一个配置文件对应一个内核参数,文件名就是参数的名字,文件内容就是参数的值。我们可通过命令sysctl -a
查看所有这些内核参数。
16.2.1 /proc/sys/fs
目录下的部分文件
/proc/sys/fs
目录下的内核参数都与文件系统相关
对服务器程序来说,有以下重要参数:
- 1.
/proc/sys/fs/file-max
:系统级文件描述符数限制,修改它是临时性修改,与以上所述临时修改系统级文件描述符数的限制效果相同。一般修改完该文件后,需要把/proc/sys/fs/inode-max
设置为新/proc/sys/fs/file-man
值的3~4倍,否则可能导致i节点数不够用。 - 2.
/proc/sys/fs/epoll/max-user_watches
:一个用户能够往epoll
内核事件表中注册的事件总量。它是某用户打开的所有epoll
实例总共能监听的事件数目,而不是单个epoll
实例能监听的事件数目。往epoll
内核事件表中注册一个事件,在32位系统上大概消耗90字节的内核空间,在64位系统上则消耗160字节的内核空间。这个内核参数限制了epoll
使用的内核内存总量。
16.2.2 /proc/sys/net
目录下的部分文件
内核中网络模块的相关参数都位于/proc/sys/net
目录下,其中和TCP/IP协议相关的参数主要位于以下3个子目录中:core、ipv4、ipv6,以下是和服务器性能相关的部分参数:
-
1./proc/sys/net/core/somaxconn:指定listen函数监听队列里,能建立完整连接从而进入ESTABLISHED状态的socket的最大数目。
-
2./proc/sys/net/ipv4/tcp_max_syn_backlog:指定listen函数监听队列里,能够转移至ESTABLISHED或SYN_RCVD状态的socket的最大数目。
-
3./proc/sys/net/ipv4/tcp_wmem:它包含3个值,分别指定一个socket的TCP写缓冲区的最小值、默认值、最大值。
-
4./proc/sys/net/ipv4/tcp_rmem:它包含3个值,分别指定一个socket的TCP读缓冲区的最小值、默认值、最大值。
-
5./proc/sys/net/ipv4/tcp_syncookies:指定是否打开TCP同步标签(syncookie),同步标签通过启动cookie来防止一个监听socket因不停地重复接收来自同一个地址的连接请求(同步报文段),而导致listen函数监听队列溢出(所谓的SYN风暴)。
除了通过直接修改文件的方式来修改这些系统参数外,我们也可使用sysctl命令来修改它们,这两种修改方式都是临时的,永久的修改方法是在/etc/sysctl.conf文件中加入相应网络参数及其数值,并执行sysctl -p使之生效。
16.3 gdb调试
16.3.1 用gdb调试多进程程序
如果一个进程通过fork系统调用创建了子进程,gdb会继续调试原来的进程,子进程则正常运行,以下方式可调试子进程:
- 单独调试子进程
子进程本质上来说也是一个进程,因此我们可通过通用的gdb调试方法来调试它,例如,我们可先运行服务器,然后找到子进程的PID,再将其附加(attach)到gdb调试器上,具体操作如下:
上图中,b命令表示设置断点,格式为b filename:linenumber
;c命令的作用是继续程序的执行,直到遇到下一个断点或程序正常结束;bt命令的作用是打印当前程序的函数调用堆栈(backtrace),显示当前执行路径中各个函数的调用关系和调用帧信息。
- 使用调试器选项follow-fork-mode
gdb调试器的选项follow-fork-mode允许我们选择程序在执行fork系统调用后是继续调试父进程还是调试子进程,其用法如下:
上图中,mode的可选值是parent和child,分别表示调试父进程和子进程,使用前面的例子,这次使用follow-fork-mode选项来调试子进程,具体过程如下:
16.3.2 用gdb调试多线程程序
gdb有一组命令可辅助多线程程序的调试,以下是其中一些常用的命令:
-
1.info threads:显示当前可调式的所有线程。gdb会为每个线程分配一个ID,我