/ 中存储网

Nginx优化指南

2013-08-23 16:35:48 来源:itjs.cn
未优化前服务器的状态

[[email protected] ~ "o">] "c"># netstat -na |awk '{print $6}'| sort |uniq -c |sort -nr

490 ESTABLISHED

44 SYN_RECV

34 LAST_ACK

10 CONNECTED

5 LISTEN

3 CLOSE_WAIT

2

1 established)

1 and

1 I-Node

1 Foreign

1 7894382

1 6343

1 6250

1 6241

1 3937508

1 2837682

1 1863

理论图

放一张图,要搞清楚怎么调整参数,这张图相当重要。看不太明白不要紧,后面会详细讲到这张图

优化经验值

转一个金山张宴的贴子对/etc/sysctrl.conf的优化参数,后面会仔细介绍参数。

# Add

net.ipv4.tcp_max_syn_backlog = 65536

net.core.netdev_max_backlog =  32768

net.core.somaxconn = 32768

net.core.wmem_default = 8388608

net.core.rmem_default = 8388608

net.core.rmem_max = 16777216

net.core.wmem_max = 16777216

net.ipv4.tcp_timestamps = 0

net.ipv4.tcp_synack_retries = 2

net.ipv4.tcp_syn_retries = 2

net.ipv4.tcp_tw_recycle = 1

#net.ipv4.tcp_tw_len = 1

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_mem  "o">= 94500000 915000000 927000000

net.ipv4.tcp_max_orphans = 3276800

#net.ipv4.tcp_fin_timeout = 30

#net.ipv4.tcp_keepalive_time = 120

net.ipv4.ip_local_port_range = 1024  65535

TCP三次握手以及其中的各种状态:

SYN(Synchronize Sequence Numbers)。

同步序列编号

ACK (ACKnowledge Character)

在数据通信传输中,接收站发给发送站的一种传输控制字符。它表示确认发来的数据已经接受无误。

=================================

client发送syn至server

此时客户端的状态变为SYN_SENT

client( "nv">syn=j "o">)====>server

server收到syn,并发送syn+ack到client,

这种过程server状态由listen变为SYN_RECV,并等待客户端再次发来ack数据

client<=========server "o">(syn "o">=k,ack=j+1 "o">)

client接收到server发过来的syn+ack,并向服务端发送ACK,服务器接收后由SYN_RECV变为ESTABLISHED

client(ACK "o">(ack "o">=k+1))========>server

此种情况下,服务端在三次握手的变迁是

LISTEN->SYN_RECV ->ESTABLISHED

客户端的三次握手的变迁是

SYN_SENT ->ESTABLISHED

====================================

注意问题

一、首先server有个用来接收client发送的syn并对syn进行排队的队列,如果队列满了,新的请求不被接受。

此队列长度控制参数:

net.ipv4.tcp_max_syn_backlog

对应文件(/proc/sys/net/ipv4/tcp_max_syn_backlog ) 默认是1024

1   [[email protected] "o">] "c"># cat /proc/sys/net/ipv4/tcp_max_syn_backlog

2   1024

二、然后是SYN-ACK重传:当server向client发送syn+ack没有收到相应,server将重传,然后再重传。。。控制这个重传次数的参数是

tcp_synack_retries

对应文件(/proc/sys/net/ipv4/tcp_synack_retries )默认值是5,对应于180秒左右时间

1   [[email protected] ~ "o">] "c"># cat /proc/sys/net/ipv4/tcp_synack_retries

2   5

关于tcp_synack_retries的英文解释:

The maximum number of times a SYN/ACK segment for a passive TCP connection will be retransmitted. This number should not be higher than 255. The default value is 5.

备注:与此相对应的client的参数是:

tcp_syn_retries

The maximum number of times initial SYNs for an active TCP connection attempt will be retransmitted. This value should not be higher than 255. The default value is 5, which corresponds to approximately 180 seconds.

三、关于tcp_syncookies

SYN Cookie是对TCP服务器端的三次握手协议作一些修改,专门用来防范SYN Flood攻击的一种手段。它的原理是,在TCP服务器收到TCP SYN包并返回TCP SYN+ACK包时,不分配一个专门的数据区,而是根据这个SYN包计算出一个cookie值。在收到TCP ACK包时,TCP服务器在根据那个cookie值检查这个TCP ACK包的合法性。如果合法,再分配专门的数据区进行处理未来的TCP连接。

1   [[email protected]~ "o">] "c"># cat /proc/sys/net/ipv4/tcp_syncookies

2   1

典型syn_recv故障处理

如果服务器syn_recv的条数过多,可以采取的操作是:

减少server==>client重传syn+ack的次数。

加大syn队列长度,防止无法响应新的连接

1   echo  "s2">"net.ipv4.tcp_max_syn_backlog = 4096" >>/etc/sysctl.conf

2   echo  "s2">"net.ipv4.tcp_synack_retries = 1" >>/etc/sysctl.conf

3   sysctl -p

当受到syn攻击的时候,启用syn-cookie(默认启用,在/etc/sysctl.conf里本身就有参数配置)

1    "nb">echo 1 >/proc/sys/net/ipv4/tcp_syncookies

TCP四次握手

下面说tcp/ip的第四次握手,分析主动关闭和被动关闭两种。

A:因为如果是CLIENT端主动断掉当前连接,那么双方关闭这个TCP连接共需要四个packet:

setup

Client     --->   FIN(M)   --->   Server

client发送一个FIN给server,(说它不跟你玩了),client由ESTABLISHED->FIN_WAIT1

Client    <---  ACK(M+1 "o">)  <---   Server

SER VER收到fin后发送ack确认(拿出两人信物),状态由ESTABLISHED->close_wait

client收到server的ack确认,只是改变状态ESTABLISHED->FIN_WAIT1->FIN_WAIT2,继续等server发送数据。

Client  <--  FIN(N "o">)    <--  Server

server继续发送FIN到client(好就不玩了吧),状态ESTABLISHED->close_wait->LAST_ACK,等待client发送ack做最后的确认

Client  -->  ACK(N+1 "o">)  -->  Server

client收到FIN,马上发送ack确认,状态ESTABLISHED->FIN_WAIT1->FIN_WAIT2->TIME_WAIT[2MSL超时]->closed

server收到ack确认,状态ESTABLISHED->close_wait->LAST_ACK->CLOSED.

keepalive_timeout

client关闭连接很好想,有点要搞清楚的是,server端什么时候会发起丢掉连接的操作:

有些是应用程序控制的。nginx.conf为例

keepalive_timeout  0;

[[email protected] ~ "o">]# curl -I http://www.XXX.com

Connection: close

keepalive_timeout  600;

[[email protected] ~ "o">]# curl -I http://www.XXX.com

Connection: keep-alive

这种规定了连接时间的,到了时间连接会断掉。

如果没有规定的,则按照系统keepalived定时器的设置进行,具体参数如下:

[[email protected] ~ "o">]# sysctl -a|grep tcp_keepalive

net.ipv4.tcp_keepalive_intvl = 75

net.ipv4.tcp_keepalive_probes = 9

net.ipv4.tcp_keepalive_time = 30

连接两端一直没发送数据,间隔半分钟,后开始第一次探测,间隔75秒后第二次探测,探测9次,最后放弃连接。

四种状况其实最后一种没什么意义,能考虑到下面三种就行了

1 client正常,每进行一次通讯,net.ipv4.tcp_keepalive_time重置一次。

2 一直到7200+75*9后也无法获取client反馈信息,则认为client已经关闭并终止连接(连接超时)

3 client重启, 收到探测后返回一个复位(RST)信息。server收到后终止连接(连接被对方复位)

典型timewait故障处理

一、网站服务器访问速度变慢,查看网站服务器连接,看到连接至数据库的连接中出现大量time_wait,多达400个。分析是网站服务器定时任务做大量读取数据库操作的时候产生的。

此情况出现在client.

根据上面讲的,time_wait对应2MSL超时,什么是2MSL?,是在client在四次握手的时候最后发送了ack确认给服务器后必然经过的一个时间。TIME_WAIT状态的目的是为了防止最后client发出的ack丢失,让server处于LAST_ACK超时重发FIN。配置2MSL时间长短的服务器参数,但这里不是优化的重要参数,我们需要的是Time_wait的连接可以重用,并且能迅速关闭。

2MSl的解释:

MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为tcp报文(segment)是ip数据报(datagram)的数据部分,具体称谓请参见《数据在网络各层中的称呼》一文,而ip头中有一个TTL域,TTL是time to live的缩写,中文可以译为“生存时间”,这个生存时间是由源主机设置初始值但不是存的具体时间,而是存储了一个ip数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减1,当此值为0则数据报将被丢弃,同时发送ICMP报文通知源主机。RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。

5

6       2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,当TCP的一端发起主动关闭,在发出最后一个ACK包后,即第3次握手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。

7

8       TTL与MSL是有关系的但不是简单的相等的关系,MSL要大于等于TTL。

1   [[email protected] ~ "o">] "c"># sysctl -a | grep time | grep wait

2   net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait = 120

3   net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait = 60

4   net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait = 120

关于 ip_ct_tcp_timeout_time_wait

1   3.7.15. ip_ct_tcp_timeout_time_wait

2

3   The ip_ct_tcp_timeout_time_wait variable defines the timeout value of the TIME-WAIT state as defined by RFC 793. This is the final state possible in a TCP connection. When a connection is closed in both directions, the server and client enters the TIME-WAIT state, which is used so that all stale packets have time to enter the client or server. One example of the usage of this may be if packets are reordered during transit between the hosts and winds up in a different order at either side. In such a case, the timewindow defined in the ip_ct_tcp_timeout_time_wait variable is used so that those packets may reach their destinations anyways. When the timeout expires, the conntrack entry is destroyed and we enter the state CLOSED, which means that there is no conntrack data at all for the connection in question.

4

5   The default value of the ip_ct_tcp_timeout_time_wait variable is set to 120 seconds, or 2 minutes. You should generally want to keep this value if you know that you live on a connection that is slow and that often reorders the packets in question. If this value is too low you will often experience corrupt downloads or missing data in downloaded data, you should definitely avoid tuning this value down in such a case, and you may most definitely consider raising the timeout of this value in such case. If you never experience such behaviour or any other problems like that, you may most probably lower this value so that conntrack entries die faster, and hence recycle the conntrack entry space faster.

6   3.7.15.3.7.15. ip_ct_tcp_timeout_time_wait

如何解决?

控制重用和迅速回收的参数是net.ipv4.tcp_tw_reuse和net.ipv4.tcp_tw_recycle。

这两个参数的具体英文解释和作用等我查到了再补充,网上讲的也不怎么清楚。

net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0

net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0。

1   echo  "s2">"net.ipv4.tcp_tw_reuse = 1" >>/etc/sysctl.conf

2   echo  "s2">"net.ipv4.tcp_tw_recycle = 1" >>/etc/sysctl.conf

3   sysctl -p

出现FIN_WAIT_2状态

现象描述

服务器端运行服务9090的c,或java程序用killall -9 服务名 kill掉后,出现

FIN_WAIT_2状态,新的服务无法启动。因为这个状态占据了服务端口。时间默认1分钟。

1   [[email protected] ~ "o">] "c"># sysctl -a | grep time | grep fin

2   net.ipv4.tcp_fin_timeout = 60

主要就是服务端主动发起关闭,此时服务端相当于一个client,在最后等对方发送最后一个FIN的却一直等不到,直至超时,控制这个超时的时间参数是tcp_fin_timeout

tcp_fin_timeout(0S)

How many seconds to wait  "k">for a final FIN packet before the socket is forcibly closed. This is strictly a violation of the TCP specification, but required to prevent denial-of-service (DoS) attacks. The default value in 2.4 kernels is 60, down from 180 in 2.2.

备注:TCP_LINGER2(tcp socket编程选项 "o">)

The lifetime of orphaned FIN_WAIT2 state sockets. This option can be used to override the system wide sysctl tcp_fin_timeout on this socket. This is not to be confused with the socket (7) level option SO_LINGER. This option should not be used in code intended to be portable.

1   echo  "s2">"net.ipv4.tcp_fin_timeout = 30"  >>/etc/sysctl.conf

2   sysctl -p

3    "c">#echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout 

此外,还有控制tcp发送缓冲区,接收缓冲区大小的设置,能够使用端口范围的设置。

1   [[email protected]~ "o">] "c"># cat /proc/sys/net/ipv4/ip_local_port_range

2   32768   61000

这个是本地连接外地端口时开的动态端口,个人觉得默认就够了。如果有很频繁的要连接外面端口,可以设大。

1    "c">#echo "5000 65535" > /proc/sys/net/ipv4/ip_local_port_range

2   echo  "s2">"net.ipv4.ip_local_port_range = 5000    65000" >> /etc/sysctl.conf

3   sysctl -p

总结经验值

net.ipv4.tcp_keepalive_time = 300

net.ipv4.tcp_syncookies = 1

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_tw_recycle = 1

net.ipv4.ip_local_port_range = 5000    65000