目录
1、linux内核参数注释
2、两种修改内核参数方法
3、内核优化参数生产配置
参数解释由网络上收集整理,常用优化参数对比了网上多个实际应用进行表格化整理,使查看更直观。
学习linux也有不少时间了,每次优化linux内核参数时,都是在网上拷贝而使用,甚至别人没有列出来的参数就不管了,难道我就不需要了吗?
参考文章:
linux内核TCP相关参数解释
http://os.chinaunix.net/a2008/0918/985/000000985483.shtml
linux内核参数优化
http://blog.chinaunix.net/uid-29081804-id-3830203.html
linux内核调整和内核参数详解
http://blog.csdn.net/cnbird2008/article/details/4419354
1、linux内核参数注释
以下表格中红色字体为常用优化参数
根据参数文件所处目录不同而进行分表整理
下列文件所在目录:/proc/sys/net/ipv4/
名称 默认值 建议值 描述
tcp_syn_retries 5 1 对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃。不应该大于255,默认值是5,对应于180秒左右时间。。(对于大负载而物理通信良好的网络而言,这个值偏高,可修改为2.这个值仅仅是针对对外的连接,对进来的连接,是由tcp_retries1决定的)
tcp_synack_retries 5 1 对于远端的连接请求SYN,内核会发送SYN + ACK数据报,以确认收到上一个 SYN连接请求包。这是所谓的三次握手( threeway handshake)机制的第二个步骤。这里决定内核在放弃连接之前所送出的 SYN+ACK 数目。不应该大于255,默认值是5,对应于180秒左右时间。
tcp_keepalive_time 7200 600 TCP发送keepalive探测消息的间隔时间(秒),用于确认TCP连接是否有效。
防止两边建立连接但不发送数据的攻击。
tcp_keepalive_probes 9 3 TCP发送keepalive探测消息的间隔时间(秒),用于确认TCP连接是否有效。
tcp_keepalive_intvl 75 15 探测消息未获得响应时,重发该消息的间隔时间(秒)。默认值为75秒。 (对于普通应用来说,这个值有一些偏大,可以根据需要改小.特别是web类服务器需要改小该值,15是个比较合适的值)
tcp_retries1 3 3 放弃回应一个TCP连接请求前﹐需要进行多少次重试。RFC 规定最低的数值是3
tcp_retries2 15 5 在丢弃激活(已建立通讯状况)的TCP连接之前﹐需要进行多少次重试。默认值为15,根据RTO的值来决定,相当于13-30分钟(RFC1122规定,必须大于100秒).(这个值根据目前的网络设置,可以适当地改小,我的网络内修改为了5)
tcp_orphan_retries 7 3 在近端丢弃TCP连接之前﹐要进行多少次重试。默认值是7个﹐相当于 50秒 - 16分钟﹐视 RTO 而定。如果您的系统是负载很大的web服务器﹐那么也许需要降低该值﹐这类 sockets 可能会耗费大量的资源。另外参的考tcp_max_orphans。(事实上做NAT的时候,降低该值也是好处显著的,我本人的网络环境中降低该值为3)
tcp_fin_timeout 60 2 对于本端断开的socket连接,TCP保持在FIN-WAIT-2状态的时间。对方可能会断开连接或一直不结束连接或不可预料的进程死亡。默认值为 60 秒。
tcp_max_tw_buckets 180000 36000 系统在同时所处理的最大 timewait sockets 数目。如果超过此数的话﹐time-wait socket 会被立即砍除并且显示警告信息。之所以要设定这个限制﹐纯粹为了抵御那些简单的 DoS 攻击﹐不过﹐如果网络条件需要比默认值更多﹐则可以提高它(或许还要增加内存)。(事实上做NAT的时候最好可以适当地增加该值)
tcp_tw_recycle 0 1 打开快速 TIME-WAIT sockets 回收。除非得到技术专家的建议或要求﹐请不要随意修改这个值。(做NAT的时候,建议打开它)
tcp_tw_reuse 0 1 表示是否允许重新应用处于TIME-WAIT状态的socket用于新的TCP连接(这个对快速重启动某些服务,而启动后提示端口已经被使用的情形非常有帮助)
tcp_max_orphans 8192 32768 系统所能处理不属于任何进程的TCP sockets最大数量。假如超过这个数量﹐那么不属于任何进程的连接会被立即reset,并同时显示警告信息。之所以要设定这个限制﹐纯粹为了抵御那些简单的 DoS 攻击﹐千万不要依赖这个或是人为的降低这个限制。如果内存大更应该增加这个值。(这个值Redhat AS版本中设置为32768,但是很多防火墙修改的时候,建议该值修改为2000)
tcp_abort_on_overflow 0 0 当守护进程太忙而不能接受新的连接,就象对方发送reset消息,默认值是false。这意味着当溢出的原因是因为一个偶然的猝发,那么连接将恢复状态。只有在你确信守护进程真的不能完成连接请求时才打开该选项,该选项会影响客户的使用。(对待已经满载的sendmail,apache这类服务的时候,这个可以很快让客户端终止连接,可以给予服务程序处理已有连接的缓冲机会,所以很多防火墙上推荐打开它)
tcp_syncookies 0 1 只有在内核编译时选择了CONFIG_SYNCOOKIES时才会发生作用。当出现syn等候队列出现溢出时象对方发送syncookies。目的是为了防止syn flood攻击。
tcp_stdurg 0 0 使用 TCP urg pointer 字段中的主机请求解释功能。大部份的主机都使用老旧的 BSD解释,因此如果您在 Linux 打开它﹐或会导致不能和它们正确沟通。
tcp_max_syn_backlog 1024 16384 对于那些依然还未获得客户端确认的连接请求﹐需要保存在队列中最大数目。对于超过 128Mb 内存的系统﹐默认值是 1024 ﹐低于 128Mb 的则为 128。如果服务器经常出现过载﹐可以尝试增加这个数字。警告﹗假如您将此值设为大于 1024﹐最好修改include/net/tcp.h里面的TCP_SYNQ_HSIZE﹐以保持TCP_SYNQ_HSIZE*16(SYN Flood攻击利用TCP协议散布握手的缺陷,伪造虚假源IP地址发送大量TCP-SYN半打开连接到目标系统,最终导致目标系统Socket队列资源耗尽而无法接受新的连接。为了应付这种攻击,现代Unix系统中普遍采用多连接队列处理的方式来缓冲(而不是解决)这种攻击,是用一个基本队列处理正常的完全连接应用(Connect()和Accept() ),是用另一个队列单独存放半打开连接。这种双队列处理方式和其他一些系统内核措施(例如Syn-Cookies/Caches)联合应用时,能够比较有效的缓解小规模的SYN Flood攻击(事实证明)
tcp_window_scaling 1 1 该文件表示设置tcp/ip会话的滑动窗口大小是否可变。参数值为布尔值,为1时表示可变,为0时表示不可变。tcp/ip通常使用的窗口最大可达到 65535 字节,对于高速网络,该值可能太小,这时候如果启用了该功能,可以使tcp/ip滑动窗口大小增大数个数量级,从而提高数据传输的能力(RFC 1323)。(对普通地百M网络而言,关闭会降低开销,所以如果不是高速网络,可以考虑设置为0)
tcp_timestamps 1 1 Timestamps 用在其它一些东西中﹐可以防范那些伪造的 sequence 号码。一条1G的宽带线路或许会重遇到带 out-of-line数值的旧sequence 号码(假如它是由于上次产生的)。Timestamp 会让它知道这是个 ‘旧封包’。(该文件表示是否启用以一种比超时重发更精确的方法(RFC 1323)来启用对 RTT 的计算;为了实现更好的性能应该启用这个选项。)
tcp_sack 1 1 使用 Selective ACK﹐它可以用来查找特定的遗失的数据报— 因此有助于快速恢复状态。该文件表示是否启用有选择的应答(Selective Acknowledgment),这可以通过有选择地应答乱序接收到的报文来提高性能(这样可以让发送者只发送丢失的报文段)。(对于广域网通信来说这个选项应该启用,但是这会增加对 CPU 的占用。)
tcp_fack 1 1 打开FACK拥塞避免和快速重传功能。(注意,当tcp_sack设置为0的时候,这个值即使设置为1也无效)[这个是TCP连接靠谱的核心功能]
tcp_dsack 1 1 允许TCP发送"两个完全相同"的SACK。
tcp_ecn 0 0 TCP的直接拥塞通告功能。
tcp_reordering 3 6 TCP流中重排序的数据报最大数量。 (一般有看到推荐把这个数值略微调整大一些,比如5)
tcp_retrans_collapse 1 0 对于某些有bug的打印机提供针对其bug的兼容性。(一般不需要这个支持,可以关闭它)
tcp_wmem:mindefaultmax 4096
16384
131072 8192
131072
16777216 发送缓存设置
min:为TCP socket预留用于发送缓冲的内存最小值。每个tcp socket都可以在建议以后都可以使用它。默认值为4096(4K)。
default:为TCP socket预留用于发送缓冲的内存数量,默认情况下该值会影响其它协议使用的net.core.wmem_default 值,一般要低于net.core.wmem_default的值。默认值为16384(16K)。
max: 用 于TCP socket发送缓冲的内存最大值。该值不会影响net.core.wmem_max,"静态"选择参数SO_SNDBUF则不受该值影响。默认值为 131072(128K)。(对于服务器而言,增加这个参数的值对于发送数据很有帮助,在我的网络环境中,修改为了51200 131072 204800)
tcp_rmem:mindefaultmax 4096
87380
174760 32768
131072
16777216 接收缓存设置
同tcp_wmem
tcp_mem:mindefaultmax 根据内存计算 786432
1048576 1572864 low: 当TCP使用了低于该值的内存页面数时,TCP不会考虑释放内存。即低于此值没有内存压力。(理想情况下,这个值应与指定给 tcp_wmem 的第 2 个值相匹配 - 这第 2 个值表明,最大页面大小乘以最大并发请求数除以页大小 (131072 * 300 / 4096)。 )
pressure: 当TCP使用了超过该值的内存页面数量时,TCP试图稳定其内存使用,进入pressure模式,当内存消耗低于low值时则退出pressure状态。 (理想情况下这个值应该是 TCP 可以使用的总缓冲区大小的最大值 (204800 * 300 / 4096)。 )
high: 允许所有tcp sockets用于排队缓冲数据报的页面量。(如果超过这个值,TCP 连接将被拒绝,这就是为什么不要令其过于保守 (512000 * 300 / 4096) 的原因了。 在这种情况下,提供的价值很大,它能处理很多连接,是所预期的 2.5 倍;或者使现有连接能够传输 2.5 倍的数据。 我的网络里为192000 300000 732000)
一般情况下这些值是在系统启动时根据系统内存数量计算得到的。
tcp_app_win 31 31 保留max(window/2^tcp_app_win, mss)数量的窗口由于应用缓冲。当为0时表示不需要缓冲。
tcp_adv_win_scale 2 2 计算缓冲开销bytes/2^tcp_adv_win_scale(如果tcp_adv_win_scale > 0)或者bytes-bytes/2^(-tcp_adv_win_scale)(如果tcp_adv_win_scale BOOLEAN>0)
tcp_low_latency 0 0 允许 TCP/IP 栈适应在高吞吐量情况下低延时的情况;这个选项一般情形是的禁用。(但在构建Beowulf 集群的时候,打开它很有帮助)
tcp_westwood 0 0 启用发送者端的拥塞控制算法,它可以维护对吞吐量的评估,并试图对带宽的整体利用情况进行优化;对于 WAN 通信来说应该启用这个选项。
tcp_bic 0 0 为快速长距离网络启用 Binary Increase Congestion;这样可以更好地利用以 GB 速度进行操作的链接;对于 WAN 通信应该启用这个选项。
ip_forward 0 - NAT必须开启IP转发支持,把该值写1
ip_local_port_range:minmax 32768
61000 1024
65000 表示用于向外连接的端口范围,默认比较小,这个范围同样会间接用于NAT表规模。
ip_conntrack_max 65535 65535 系统支持的最大ipv4连接数,默认65536(事实上这也是理论最大值),同时这个值和你的内存大小有关,如果内存128M,这个值最大8192,1G以上内存这个值都是默认65536
所处目录/proc/sys/net/ipv4/netfilter/
文件需要打开防火墙才会存在
名称 默认值 建议值 描述
ip_conntrack_max 65536 65536 系统支持的最大ipv4连接数,默认65536(事实上这也是理论最大值),同时这个值和你的内存大小有关,如果内存128M,这个值最大8192,1G以上内存这个值都是默认65536,这个值受/proc/sys/net/ipv4/ip_conntrack_max限制
ip_conntrack_tcp_timeout_established 432000 180 已建立的tcp连接的超时时间,默认432000,也就是5天。影响:这个值过大将导致一些可能已经不用的连接常驻于内存中,占用大量链接资源,从而可能导致NAT ip_conntrack: table full的问题。建议:对于NAT负载相对本机的 NAT表大小很紧张的时候,可能需要考虑缩小这个值,以尽早清除连接,保证有可用的连接资源;如果不紧张,不必修改
ip_conntrack_tcp_timeout_time_wait 120 120 time_wait状态超时时间,超过该时间就清除该连接
ip_conntrack_tcp_timeout_close_wait 60 60 close_wait状态超时时间,超过该时间就清除该连接
ip_conntrack_tcp_timeout_fin_wait 120 120 fin_wait状态超时时间,超过该时间就清除该连接
文件所处目录/proc/sys/net/core/
名称 默认值 建议值 描述
netdev_max_backlog
1024 16384 每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目,对重负载服务器而言,该值需要调高一点。
somaxconn
128 16384 用来限制监听(LISTEN)队列最大数据包的数量,超过这个数量就会导致链接超时或者触发重传机制。
web应用中listen函数的backlog默认会给我们内核参数的net.core.somaxconn限制到128,而nginx定义的NGX_LISTEN_BACKLOG默认为511,所以有必要调整这个值。对繁忙的服务器,增加该值有助于网络性能
wmem_default
129024 129024 默认的发送窗口大小(以字节为单位)
rmem_default
129024 129024 默认的接收窗口大小(以字节为单位)
rmem_max
129024 873200 最大的TCP数据接收缓冲
wmem_max 129024 873200 最大的TCP数据发送缓冲
2、两种修改内核参数方法:
1、使用echo value方式直接追加到文件里如echo “1” >/proc/sys/net/ipv4/tcp_syn_retries,但这种方法设备重启后又会恢复为默认值
2、把参数添加到/etc/sysctl.conf中,然后执行sysctl -p使参数生效,永久生效
3、内核生产环境优化参数
这儿所列参数是老男孩老师生产中常用的参数:
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl =15
net.ipv4.tcp_retries2 = 5
net.ipv4.tcp_fin_timeout = 2
net.ipv4.tcp_max_tw_buckets = 36000
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_orphans = 32768
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_wmem = 8192 131072 16777216
net.ipv4.tcp_rmem = 32768 131072 16777216
net.ipv4.tcp_mem = 786432 1048576 1572864
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.ip_conntrack_max = 65536
net.ipv4.netfilter.ip_conntrack_max=65536
net.ipv4.netfilter.ip_conntrack_tcp_timeout_established=180
net.core.somaxconn = 16384
net.core.netdev_max_backlog = 16384
对比网上其他人的生产环境优化参数,需要优化的参数基本差不多,只是值有相应的变化。具体优化值要参考应用场景,这儿所列只是常用优化参数,是否适合,可在上面查看该参数描述,理解后,再根据自己生产环境而设。
其它相关linux内核参数调整文章:
Linux内核参数优化
http://flandycheng.blog.51cto.com/855176/476769
优化linux的内核参数来提高服务器并发处理能力
http://www.ha97.com/4396.html
nginx做web服务器linux内核参数优化
http://blog.csdn.net/force_eagle/article/details/6725243
Nginx做web服务器Linux内核参数优化
Nginx提供web服务时Linux内核参数调整是必不可少的,其中在优化方面就需要我们格外的注意。在下面就是对Linux内核参数优化的详细介绍,希望大家有所收获。
关于Linux内核参数的优化:
net.ipv4.tcp_max_tw_buckets = 6000
timewait的数量,默认是180000。
net.ipv4.ip_local_port_range = 1024 65000
允许系统打开的端口范围。
net.ipv4.tcp_tw_recycle = 1
启用timewait快速回收。
net.ipv4.tcp_tw_reuse = 1
开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接。
net.ipv4.tcp_syncookies = 1
开启SYN Cookies,当出现SYN等待队列溢出时,启用cookies来处理。
net.core.somaxconn = 262144
web应用中listen函数的backlog默认会给我们内核参数的net.core.somaxconn限制到128,而Nginx内核参数定义的NGX_LISTEN_BACKLOG默认为511,所以有必要调整这个值。
net.core.netdev_max_backlog = 262144
每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
net.ipv4.tcp_max_orphans = 262144
系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤儿连接将即刻被复位并打印出警告信息。这个限制仅仅是为了防止简单的DoS攻击,不能过分依靠它或者人为地减小这个值,更应该增加这个值(如果增加了内存之后)。
net.ipv4.tcp_max_syn_backlog = 262144
记录的那些尚未收到客户端确认信息的连接请求的最大值。对于有128M内存的系统而言,缺省值是1024,小内存的系统则是128。
net.ipv4.tcp_timestamps = 0
时间戳可以避免序列号的卷绕。一个1Gbps的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种“异常”的数据包。这里需要将其关掉。
net.ipv4.tcp_synack_retries = 1
为了打开对端的连接,内核需要发送一个SYN并附带一个回应前面一个SYN的ACK。也就是所谓三次握手中的第二次握手。这个设置决定了内核放弃连接之前发送SYN+ACK包的数量。
net.ipv4.tcp_syn_retries = 1
在内核放弃建立连接之前发送SYN包的数量。
net.ipv4.tcp_fin_timeout = 1
如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。 对端可以出错并永远不关闭连接,甚至意外当机。缺省值是60秒。2.2 内核的通常值是180秒,你可以按这个设置,但要记住的是,即使你的机器是一个轻 载的WEB服务器,也有因为大量的死套接字而内存溢出的风险,FIN- WAIT-2的危险性比FIN-WAIT-1要小,因为它最多只能吃掉1.5K内 存,但是它们的生存期长些。
net.ipv4.tcp_keepalive_time = 30
当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时。
高并发服务器内核优化!!!
用vim打开配置文件:#vim /etc/sysctl.conf
在这个文件中,加入下面的几行内容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
输入下面的命令,让内核参数生效:#sysctl -p
简单的说明上面的参数的含义:
net.ipv4.tcp_syncookies = 1
#表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1
#表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1
#表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭;
net.ipv4.tcp_fin_timeout
#修改系統默认的 TIMEOUT 时间。
在经过这样的调整之后,除了会进一步提升服务器的负载能力之外,还能够防御小流量程度的DoS、CC和SYN攻击。
此外,如果你的连接数本身就很多,我们可以再优化一下TCP的可使用端口范围,进一步提升服务器的并发能力。依然是往上面的参数文件中,加入下面这些配置:
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 5000
#这几个参数,建议只在流量非常大的服务器上开启,会有显著的效果。一般的流量小的服务器上,没有必要去设置这几个参数。
net.ipv4.tcp_keepalive_time = 1200
#表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。
net.ipv4.ip_local_port_range = 10000 65000
#表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为10000到65000。(注意:这里不要将最低值设的太低,否则可能会占用掉正常的端口!)
net.ipv4.tcp_max_syn_backlog = 8192
#表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_max_tw_buckets = 6000
#表示系统同时保持TIME_WAIT的最大数量,如果超过这个数字,TIME_WAIT将立刻被清除并打印警告信息。默 认为180000,改为6000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量,但是对于 Squid,效果却不大。此项参数可以控制TIME_WAIT的最大数量,避免Squid服务器被大量的TIME_WAIT拖死。
内核其他TCP参数说明:
net.ipv4.tcp_max_syn_backlog = 65536
#记录的那些尚未收到客户端确认信息的连接请求的最大值。对于有128M内存的系统而言,缺省值是1024,小内存的系统则是128。
net.core.netdev_max_backlog = 32768
#每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
net.core.somaxconn = 32768
#web应用中listen函数的backlog默认会给我们内核参数的net.core.somaxconn限制到128,而nginx定义的NGX_LISTEN_BACKLOG默认为511,所以有必要调整这个值。
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216 #最大socket读buffer,可参考的优化值:873200
net.core.wmem_max = 16777216 #最大socket写buffer,可参考的优化值:873200
net.ipv4.tcp_timestsmps = 0
#时间戳可以避免序列号的卷绕。一个1Gbps的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种“异常”的数据包。这里需要将其关掉。
net.ipv4.tcp_synack_retries = 2
#为了打开对端的连接,内核需要发送一个SYN并附带一个回应前面一个SYN的ACK。也就是所谓三次握手中的第二次握手。这个设置决定了内核放弃连接之前发送SYN+ACK包的数量。
net.ipv4.tcp_syn_retries = 2
#在内核放弃建立连接之前发送SYN包的数量。
#net.ipv4.tcp_tw_len = 1
net.ipv4.tcp_tw_reuse = 1
开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接。
net.ipv4.tcp_wmem = 8192 436600 873200
TCP写buffer,可参考的优化值: 8192 436600 873200
net.ipv4.tcp_rmem = 32768 436600 873200
TCP读buffer,可参考的优化值: 32768 436600 873200
net.ipv4.tcp_mem = 94500000 91500000 92700000
同样有3个值,意思是:
net.ipv4.tcp_mem[0]:低于此值,TCP没有内存压力。
net.ipv4.tcp_mem[1]:在此值下,进入内存压力阶段。
net.ipv4.tcp_mem[2]:高于此值,TCP拒绝分配socket。
上述内存单位是页,而不是字节。可参考的优化值是:786432 1048576 1572864
net.ipv4.tcp_max_orphans = 3276800
#系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。
如果超过这个数字,连接将即刻被复位并打印出警告信息。
这个限制仅仅是为了防止简单的DoS攻击,不能过分依靠它或者人为地减小这个值,
更应该增加这个值(如果增加了内存之后)。
net.ipv4.tcp_fin_timeout = 30
#如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。对端可以出错并永远不关闭连接,甚至意外当机。缺省值是60秒。2.2 内核的通常值是180秒,你可以按这个设置,但要记住的是,即使你的机器是一个轻载的WEB服务器,也有因为大量的死套接字而内存溢出的风险,FIN- WAIT-2的危险性比FIN-WAIT-1要小,因为它最多只能吃掉1.5K内存,但是它们的生存期长些。
经过这样的优化配置之后,你的服务器的TCP并发处理能力会显著提高。以上配置仅供参考,用于生产环境请根据自己的实际情况。
Linux
Table of Contents
• 1. vmlinuz
• 2. TCP IO
• 2.1. create connection
• 2.2. packet reception
• 2.3. packet transmission
• 2.4. congestion control
• 3. kernel panic
• 4. Disk IO
• 5. 程序返回值问题
• 6. dp8网卡问题
• 7. 修改资源限制
• 8. CPU温度过高
• 9. sync hangup
• 10. 更换glibc
• 11. 允许不在tty上执行sudo
• 12. ssh proxy
• 13. 修改最大打开文件句柄数
• 14. apt-get hang
• 15. 使用自选锁来实现信号量
1 vmlinuz
vmlinuz是可引导的、压缩的内核。“vm”代表“Virtual Memory”。Linux 支持虚拟内存,不像老的操作系统比如DOS有640KB内存的限制。Linux能够使用硬盘空间作为虚拟内存,因此得名“vm”。vmlinuz是可执行 的Linux内核,它位于/boot/vmlinuz,它一般是一个软链接。vmlinux是未压缩的内核,vmlinuz是vmlinux的压缩文件。
vmlinuz的建立有两种方式。一是编译内核时通过“make zImage”创建,然后通过:“cp /usr/src/linux-2.4/arch/i386/linux/boot/zImage /boot/vmlinuz”产生。zImage适用于小内核的情况,它的存在是为了向后的兼容性。二是内核编译时通过命令make bzImage创建,然后通过:“cp /usr/src/linux-2.4/arch/i386/linux/boot/bzImage /boot/vmlinuz”产生。bzImage是压缩的内核映像,需要注意,bzImage不是用bzip2压缩的,bzImage中的bz容易引起 误解,bz表示“big zImage”。 bzImage中的b是“big”意思。
zImage(vmlinuz)和bzImage(vmlinuz)都是用gzip压缩的。它们不仅是一个压缩文件,而且在这两个文件的开头部分内 嵌有gzip解压缩代码。所以你不能用gunzip 或 gzip –dc解包vmlinuz。内核文件中包含一个微型的gzip用于解压缩内核并引导它。两者的不同之处在于,老的zImage解压缩内核到低端内存(第一 个640K),bzImage解压缩内核到高端内存(1M以上)。如果内核比较小,那么可以采用zImage或bzImage之一,两种方式引导的系统运 行时是相同的。大的内核采用bzImage,不能采用zImage。
2 TCP IO
http://www.ece.virginia.edu/cheetah/documents/papers/TCPlinux.pdf
2.1 create connection
下面摘自 “Linux TCP队列相关参数的总结”:
简单看下连接的建立过程,客户端向server发送SYN包,server回复SYN+ACK,同时将这个处于SYN_RECV状态的连接保存到半 连接队列。客户端返回ACK包完成三次握手,server将ESTABLISHED状态的连接移入accept队列,等待应用调用accept()。可以 看到建立连接涉及两个队列:
• 半连接队列,保存SYN_RECV状态的连接。队列长度由net.ipv4.tcp_max_syn_backlog设置。
• accept队列,保存ESTABLISHED状态的连接。队列长度为min(net.core.somaxconn, backlog). # listen(sockfd, backlog)
另外,为了应对SYN flooding(即客户端只发送SYN包发起握手而不回应ACK完成连接建立,填满server端的半连接队列,让它无法处理正常的握手请 求),Linux实现了一种称为SYN cookie的机制,通过net.ipv4.tcp_syncookies控制,设置为1表示开启。简单说SYN cookie就是将连接信息编码在ISN(initial sequence number)中返回给客户端,这时server不需要将半连接保存在队列中,而是利用客户端随后发来的ACK带回的ISN还原连接信息,以完成连接的建 立,避免了半连接队列被攻击SYN包填满。对于一去不复返的客户端握手,不理它就是了。
2.2 packet reception
整个流程大致如下:
• linux里面使用sk_buff数据结构来描述packet.
• NIC检测到packet到达,从Kernel Memory(sk_buffs)分配sk_buff数据结构,调用DMA Engine将packet放到sk_buff数据结构里面 #note: NIC检测有packet到达和有packet发送,都不是触发而是主动poll的方式来完成的
• 将sk_buff并且加入rx_ring这个ring_buffer里面。如果rx_ring满了的话那么将packet丢弃。
• 当DMA Engine完成处理之后, NIC通过向CPU发起中断 通知kernel进行处理。
• kernel将这个packet传递给IP层进行处理。IP层需要将信息组装成为ip packet。如果ip packet是tcp的话那么放到socket backlog里面。如果socket backlog满了的话那么将ip packet丢弃。 copy packet data to ip buffer to form ip packet #note: 这个步骤完成之后IP layer就可以释放sk_buffer结构
• tcp layer从socket backlog里面取出tcp packet, copy ip packet tcp recv buffer to form tcp packet
• tcp recv buffer交给application layer处理, copy tcp recv buffer to app buffer to form app packet
• 其中内核参数有
• /proc/sys/net/ipv4/tcp_rmem # tcp recv buffer大小
• /proc/sys/net/core/netdev_max_backlog # 图中socket backlog大小,和accept系统调用的backlog区分开。
下面这些是从文章摘取出来的
• Linux TCP队列相关参数的总结
• https://www.suse.com/documentation/sles11/book_sle_tuning/data/sec_tuning_network_buffers.html
Linux在2.6.17以后增加了recv Buffer自动调节机制,recv buffer的实际大小会自动在最小值和最大值之间浮动,以期找到性能和资源的平衡点,因此大多数情况下不建议将recv buffer手工设置成固定值。
当 net.ipv4.tcp_moderate_rcvbuf设置为1时,自动调节机制生效,每个TCP连接的recv Buffer由下面的3元数组指定:net.ipv4.tcp_rmem = (min, default, max). 最初recv buffer被设置为,同时这个缺省值会覆盖net.core.rmem_default的设置。随后recv buffer根据实际情况在最大值和最小值之间动态调节。在缓冲的动态调优机制开启的情况下,我们将net.ipv4.tcp_rmem的最大值设置为 BDP(Bandwidth-Delay Product)。
当net.ipv4.tcp_moderate_rcvbuf被设置为0, 或者设置了socket选项SO_RCVBUF,缓冲的动态调节机制被关闭。recv buffer的缺省值由net.core.rmem_default设置,但如果设置了net.ipv4.tcp_rmem,缺省值则被覆盖。可以通过系 统调用setsockopt()设置recv buffer的最大值为net.core.rmem_max。在缓冲动态调节机制关闭的情况下,建议把缓冲的缺省值设置为BDP。
发送端 缓冲的自动调节机制很早就已经实现,并且是无条件开启,没有参数去设置。如果指定了tcp_wmem,则net.core.wmem_default被 tcp_wmem的覆盖。send Buffer在tcp_wmem的最小值和最大值之间自动调节。如果调用setsockopt()设置了socket选项SO_SNDBUF,将关闭发送 端缓冲的自动调节机制,tcp_wmem将被忽略,SO_SNDBUF的最大值由net.core.wmem_max限制。
2.3 packet transmission
整个流程大致如下:
• application layer将数据copy到tcp send buffer里面,如果空间不够的话那么就会出现阻塞。 copy app buffer to tcp send buffer as app packet
• tcp layer等待tcp send buffer存在数据或者是需要做ack的时候,组装ip packet推送到IP layer copy tcp send buffer to ip send buffer as tcp packet
• IP layer从kernel memory申请sk_buffer,将ip data包装成为packet data,然后塞到qdisc(txqueuelen控制队列长度)里面(指针)。如果队列满的话那么就会出现阻塞,反馈到tcp layer阻塞。copy ip send buffer to packet data as ip packet
• NIC driver如果检测到qdisc有数据的话,调用NIC DMA Engine将packet发送出去。发送完成之后NIC向CPU发起中断释放packet data内存到Kernel Memory
• 其中内核参数有:
• /proc/sys/net/ipv4/tcp_wmem 这个和rmem非常类似
• #note: 与上面类比,相关参数还有net.core.wmem_default和net.core.wmem_max.
#note: 在wangyx的帮助下, qdisc队列长度参数txqueuelen这个配置在ifconfig下面找到了. txqueuelen = 1000.
➜ ~ ifconfig
eth0 Link encap:Ethernet HWaddr 12:31:40:00:49:d1
inet addr:10.170.78.31 Bcast:10.170.79.255 Mask:255.255.254.0
inet6 addr: fe80::1031:40ff:fe00:49d1/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:13028359 errors:0 dropped:0 overruns:0 frame:0
TX packets:9504902 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2464083770 (2.4 GB) TX bytes:20165782073 (20.1 GB)
Interrupt:25
下面摘自: Linux TCP队列相关参数的总结
QDisc(queueing discipline )位于IP层和网卡的ring buffer之间。我们已经知道,ring buffer是一个简单的FIFO队列,这种设计使网卡的驱动层保持简单和快速。而QDisc实现了流量管理的高级功能,包括流量分类,优先级和流量整形 (rate-shaping)。可以使用tc命令配置QDisc。
QDisc的队列长度由txqueuelen设置,和接收数据包的队列长度由内核参数net.core.netdev_max_backlog控制所不同,txqueuelen是和网卡关联
2.4 congestion control
• 初始状态是slow start
• cwnd(congestion window) 拥塞窗口,表示一次最多发送的数据包多少。
• ssthresh(slow start threshold) 慢速启动阈值。
• MSS(maximum segment size) 最大分节大小,和传输网络的MTU相关。
• 为什么多 TCP 连接分块下载比单连接下载快?
3 kernel panic
4 Disk IO
• Linux IO Stack Diagram
• Linux Storage Stack Diagram
5 程序返回值问题
首先看下面一段Java程序
/* coding:utf-8
- Copyright © dirlt
*/
public class X{
public static void main(String[] args) {
System.exit(1);
}
}
然后这个Java程序被Python调用,判断这个打印值
#!/usr/bin/env python
#coding:utf-8
#Copyright © dirlt
import os
print os.system(‘java X’)
返回值不为1而是256,对此解释是这样的
a 16-bit number, whose low byte is the signal number that killed the process, and whose high byte is the exit status (if the signal number is zero); the high bit of the low byte is set if a core file was produced.
但是下面这段Python程序,使用echo $?判断返回值为0而不是256
#!/usr/bin/env python
#coding:utf-8
#Copyright © dirlt
code=256
exit(code)
6 dp8网卡问题
当时dp8的网络流量从一个非常大的值变为非常小的值,检查/proc/net/netstat,以下几个统计数值dp8和其他机器差距较大(相差1-2个数量级):
• TCPDirectCopyFromPrequeue
• TCPHPHitsToUser
• TCPDSACKUndo
• TCPLossUndo
• TCPLostRetransmit
• TCPFastRetrans
• TCPSlowStartRetrans
• TCPSackShiftFallback
之后在dmesg上面发现如下线索:
dp@dp8:~$ dmesg | grep eth0
[ 15.635160] eth0: Broadcom NetXtreme II BCM5716 1000Base-T (C0) PCI Express f
[ 15.736389] bnx2: eth0: using MSIX
[ 15.738263] ADDRCONF(NETDEV_UP): eth0: link is not ready
[ 37.848755] bnx2: eth0 NIC Copper Link is Up, 100 Mbps full duplex
[ 37.850623] ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[ 1933.934668] bnx2: eth0: using MSIX
[ 1933.936960] ADDRCONF(NETDEV_UP): eth0: link is not ready
[ 1956.130773] bnx2: eth0 NIC Copper Link is Up, 100 Mbps full duplex
[ 1956.132625] ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[4804526.542976] bnx2: eth0 NIC Copper Link is Down
[4804552.008858] bnx2: eth0 NIC Copper Link is Up, 100 Mbps full duplex
日志 [4804552.008858] bnx2: eth0 NIC Copper Link is Up, 100 Mbps full duplex 表明dp8上的网卡速度被识别成100 Mbps了。
可能的原因如下:
• 网线、水晶头质量太差或老化、水晶头没压好,从而导致网线接触不良或短路等,可以重新压水晶头或更换网线,建议用质量可靠的六类网线六类水晶头
• 本地连接―右键―属性―配置―高级―速度和双工,这里设置错误,改为自动感应或1000Mbps全双工即可
• 网卡所接的交换机或路由器等硬件设备出现故障,或者这些设备是百兆的(千和百连在一起,千变百向下兼容)
• 电磁场干扰有时也会变百兆,所以说网线尽量别与电线一起穿管(论坛会员tchack友情提供)
我们的网线都是由 世xx联 提供的,质量应该不错,有两种情况需要优先排除。
• 网线问题(测试方法:换根网线试试)
• 交换机dp8连接的口坏了(测试方法:把dp8的网线换一个交换机的口)
7 修改资源限制
临时的修改方式可以通过ulimit来进行修改,也可以通过修改文件/etc/security/limits.conf来永久修改
hadoop - nofile 102400
hadoop - nproc 40960
8 CPU温度过高
这个问题是我在Ubuntu PC上面遇到的,明显的感觉就是运行速度变慢。然后在syslog里面出现如下日志:
May 2 18:24:21 umeng-ubuntu-pc kernel: [ 1188.717609] CPU1: Core temperature/speed normal
May 2 18:24:21 umeng-ubuntu-pc kernel: [ 1188.717612] CPU0: Package temperature above threshold, cpu clock throttled (total events = 137902)
May 2 18:24:21 umeng-ubuntu-pc kernel: [ 1188.717615] CPU2: Package temperature above threshold, cpu clock throttled (total events = 137902)
May 2 18:24:21 umeng-ubuntu-pc kernel: [ 1188.717619] CPU1: Package temperature above threshold, cpu clock throttled (total events = 137902)
May 2 18:24:21 umeng-ubuntu-pc kernel: [ 1188.717622] CPU3: Package temperature above threshold, cpu clock throttled (total events = 137902)
9 sync hangup
• kill -KILL fails to kill process : http://lists.freebsd.org/pipermail/freebsd-questions/2008-September/182821.html
• Linux-Kernel Archive: Bug: sync’s hangup forever in call_rwsem_down_read_failed : http://lkml.indiana.edu/hypermail/linux/kernel/1011.2/04099.html
10 更换glibc
• linux - How to recover after deleting the symbolic link libc.so.6? - Stack Overflow : http://stackoverflow.com/questions/12249547/how-to-recover-after-deleting-the-symbolic-link-libc-so-6
@2013-05-23 https://docs.google.com/a/umeng.com/document/d/12dzJ3OhVlrEax3yIdz0k08F8tM8DDQva1wdrD3K49PI/edit 怀疑glibc版本存在问题,在dp45上操作但是出现问题。
我的操作顺序计划是这样的:
- 将dp20的glibc copy到自己的目录下面/home/dp/dirlt/libc-2.11.so
- 将dp45的glibc backup. mv /lib64/libc-2.12.so /lib64/libc-2.12.bak.so(补充一点,就是在lib64下面还有软链接 libc.so.6 -> libc-2.12.so,这个文件应该是被程序查找使用的)
- cp /home/dp/dirlt/libc-2.11.so /lib64/libc-2.12.so
但是进行到2之后就发现cp不可用了,并且ls等命令也不能够使用了。原因非常简单,就是因为2之后libc.so.6没有对应的文件了,而cp,ls这些基本的命令依赖于这个动态链接库。
~ $ ldd /bin/cp
linux-vdso.so.1 => (0x00007fff9717f000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f5efb804000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f5efb5fc000)
libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x00007f5efb3f3000)
libattr.so.1 => /lib/x86_64-linux-gnu/libattr.so.1 (0x00007f5efb1ee000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5efae2f000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5efac2a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5efba2d000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f5efaa0d000)
@2013-08-03
A copy of the C library was found in an unexpected directory | Blog : http://blog.i-al.net/2013/03/a-copy-of-the-c-library-was-found-in-an-unexpected-directory/
上面的链接给出了升级glibc的方法
• sudo su - root # 首先切换到root账号下面
• mv libc.so librt.so /root # 将glibc等相关的so移动到root账号下面,主要不要移动软连接文件。
• LD_PRELOAD=/root/libc.so:/root/librt.so bash # 这个时候如果执行bash是找不到glibc等so了,所以需要使用LD_PRELOAD来预先加载
• apt-get install # 在这个bash下面使用apt-get来安装和升级glibc.
11 允许不在tty上执行sudo
修改/etc/sudoers文件,注释掉
Defaults requiretty
12 ssh proxy
http://serverfault.com/questions/37629/how-do-i-do-multihop-scp-transfers
• 目的机器是D,端口是16021,用户是x
• 跳板机器是T,端口是18021,用户是y
• client需要和x@D以及y@T建立信任关系
• 方法A
• 从T上和D建立链接并且配置转发端口p, 所有和T:p的数据交互都会转发到D:16021
• 在T上执行 ssh -L “*:5502:D:16021” x@D # 转发端口是5502
• -o ServerAliveInterval=60 # 我才想单位应该是s。这样每隔60s可以和server做一些keepalive的通信,确保长时间没有数据通信的情况下,连接不会断开。
• ssh -p 5502 x@T 或者 scp -P 5502 x@T:
• 方法B
• scp可以指定proxyCommand配合D上nc命令完成
• scp -o ProxyCommand=“ssh -p 18021 y@T ‘nc D 16021’” x@D:
13 修改最大打开文件句柄数
• http://blog.csdn.net/superchanon/article/details/13303705
• http://unix.stackexchange.com/questions/127777/how-to-configure-the-process-open-file-limit-of-a-user
• https://www.kernel.org/doc/Documentation/sysctl/fs.txt
首先需要修改系统上限
• /proc/sys/fs/file-max # 所有进程打开文件句柄数上限
• /proc/sys/fs/nr_open # 单个进程打开文件句柄数上限
• /proc/sys/fs/file-nr # 系统当前打开文件句柄数
然后修改用户(进程)使用上限
• /etc/security/limits.conf
• ulimit
14 apt-get hang
在使用ubuntu的apt-get时候,可能会出现一些异常的状况,我们直接终止了apt-get。但是这个时候apt-get软件本身出于一个不正常的状态,导致之后不能够启动apt-get。如果观察进程的话会出现下面一些可疑的进程
dp@dp1:~$ ps aux | grep “apt”
root 3587 0.0 0.0 36148 22800 ? Ds Oct08 0:00 /usr/bin/dpkg --status-fd 50 --unpack --auto-deconfigure /var/cache/apt/archives/sgml-data_2.0.4_all.deb
root 9579 0.0 0.0 35992 22744 ? Ds Oct19 0:00 /usr/bin/dpkg --status-fd 50 --unpack --auto-deconfigure /var/cache/apt/archives/iftop_0.17-16_amd64.deb
root 25957 0.0 0.0 36120 22796 ? Ds Nov05 0:00 /usr/bin/dpkg --status-fd 50 --unpack --auto-deconfigure /var/cache/apt/archives/iftop_0.17-16_amd64.deb /var/cache/apt/archives/iotop_0.4-1_all.deb
dp 30586 0.0 0.0 7628 1020 pts/2 S+ 08:59 0:00 grep --color=auto apt
这些进程的父进程都是init进程,并且状态是uninterruptible sleep,给kill -9也没有办法终止,唯一的办法只能reboot机器来解决这个问题。关于这个问题可以看stackoverflow上面的解答 How to stop ‘uninterruptible’ process on Linux? - Stack Overflow http://stackoverflow.com/questions/767551/how-to-stop-uninterruptible-process-on-linux
• Simple answer: you cannot. Longer answer: the uninterruptable sleep means the process will not be woken up by signals. It can be only woken up by what it’s waiting for. When I get such situations eg. with CD-ROM, I usually reset the computer by using suspend-to-disk and resuming.
• The D state basically means that the process is waiting for disk I/O, or other block I/O that can’t be interrupted. Sometimes this means the kernel or device is feverishly trying to read a bad block (especially from an optical disk). Sometimes it means there’s something else. The process cannot be killed until it gets out of the D state. Find out what it is waiting for and fix that. The easy way is to reboot. Sometimes removing the disk in question helps, but that can be rather dangerous: unfixable catastrophic hardware failure if you don’t know what you’re doing (read: smoke coming out).
15 使用自选锁来实现信号量
typedef struct sema
{
lock_t lock;
int count;
queue q;
} sema_t;
void init_sema(sema_t* sema, int init_cnt)
{
init_lock(&sema->lock);
init_queue(&sema->q);
sema->count=init_cnt;
}
void p(sema_t* sema)
{
lock(&sema->lock);
sema->count–;
if (sema->count < 0) {
q.push(current_process_context());
unlock(&sema->lock);
swtch(); // switch to another process.
return;
}
unlock(&sema->lock);
}
void v(sema_t* sema)
{
lock(&sema->lock);
sema->count++;
if (sema->count <= 0) {
pcs_ctx* ctx = q.pop();
unlock(&sema->lock);
enqueue(&running_queue, ctx);
return ;
}
unlock(&sema->lock);
}