不要在linux上启用net.ipv4.tcp_tw_recycle参数 本文为翻译英文BLOG《Coping with the TCP TIME-WAIT state on busy Linux servers》,但并非完整的翻译,译者CFC4N对原文理解后,进行了调整,增加了相关论点论据,跟原文稍有不同。翻译的目的,是为了加深自己知识点的记忆,以及分享给其他朋友,或许对他们也有帮助。文章比较长,没耐心请点关闭。 不要启用 net.ipv4.tcp_tw_recycle linux 内核文档中,对net.ipv4.tcp_tw_recycle的描述并不是很明确。 tcp_tw_recycle (Boolean; default: disabled; since Linux 2.4)[译者注:来自linux man tcp的描述] Enable fast recycling of TIME-WAIT sockets. Enabling this option is not recommended since this causes problems when working with NAT (Network Address Translation). 启用TIME-WAIT状态sockets的快速回收,这个选项不推荐启用。在NAT(Network Address Translation)网络下,会导致大量的TCP连接建立错误。 与其功能相似的参数net.ipv4.tcp_tw_reuse,手册里稍微有点描述,如下: tcp_tw_reuse (Boolean; default: disabled; since Linux 2.4.19/2.6) Allow to reuse TIME-WAIT sockets for new connections when it is safe from protocol viewpoint. It should not be changed without advice/request of technical experts. //从协议设计上来看,对于TIME-WAIT状态的sockets重用到新的TCP连接上来说,是安全的。(用于客户端时的配置) 这里的注释说明非常的少,我们发现,网上很多linux参数调整指南都建议把这些参数net.ipv4.tcp_tw_recycle 设置1「启用」,用于快速减少在TIME-WAIT状态TCP连接数。 但是,在TCP(7)手册中,参数net.ipv4.tcp_tw_recycle 非常蛋疼,尤其是在普通用户家中,有多台设备,或者网吧、公司等多台设备,共用同一个NAT设备环境下,TW回收选项是很有问题的面向公共服务器作为它不会把手连接两台不同的计算机上,这问题很难发现,无从下手。 Enable fast recycling of TIME-WAIT sockets. Enabling this option is not recommended since this causes problems when working with NAT (Network Address Translation). 启用TIME-WAIT状态sockets的快速回收,这个选项不推荐启用。在NAT(Network Address Translation)网络下,会导致大量的TCP连接建立错误。如果没有技术大神的指点的话,千万不要去改动他。 下文将给予更详细的解释,希望可以纠正互联网上错误的观点,尤其是转载比较多的内容,搜索时,往往排在前面,使用者往往接触到的都是不严谨的或者是错误的知识点。 正如此文,在 net.ipv4.tcp_tw_recycle 控制参数中,尽管很多地方写的是ipv4,但对ipv6同样实用。此外,我们这里聊的是Linux TCP协议栈,在linux上可能会受到Netfilter影响,稍微有差异。 关于TCP连接的TIME-WAIT状态,它是为何而生,存在的意义是什么? 让我们回忆一下,什么是TCP TIME-WAIT状态?如下图 这图中的流程不是很好理解,再看一张流程更清晰的图 当TCP连接关闭之前,首先发起关闭的一方会进入TIME-WAIT状态,另一方可以快速回收连接。 可以用ss -tan来查看TCP 连接的当前状态 TIME-WAIT状态的作用 对于TIME-WAIT状态来说,有两个作用 一、人尽皆知的是,防止上一个TCP连接的延迟的数据包(发起关闭,但关闭没完成),被接收后,影响到新的TCP连接。(唯一连接确认方式为四元组:源IP地址、目的IP地址、源端口、目的端口),包的序列号也有一定作用,会减少问题发生的几率,但无法完全避免。尤其是较大接收windows size的快速(回收)连接。RFC1137解释了当TIME-WAIT状态不足时将会发生什么。如果TIME-WAIT状态连接没有被快速回收,会避免什么问题呢?请看下面的例子: 缩短TIME-WAIT的时间后,延迟的TCP 包会被新建立的TCP连接接收。 二、另外一个作用是,当最后一个ACK丢失时,远程连接进入LAST-ACK状态,它可以确保远程已经关闭当前TCP连接。如果没有TIME-WAIT状态,当远程仍认为这个连接是有效的,则会继续与其通讯,导致这个连接会被重新打开。当远程收到一个SYN 时,会回复一个RST包,因为这SEQ不对,那么新的连接将无法建立成功,报错终止。 如果远程因为最后一个ACK包丢失,导致停留在LAST-ACK状态,将影响新建立具有相同四元组的TCP连接。 RFC 793中强调TIME-WAIT状态必须是两倍的MSL时间(max segment lifetime),在linux上,这个限制时间无法调整,写死为1分钟了,定义在include/net/tcp.h 曾有人提议将TCP TIME-WAIT时间改为一个可以自定义配置的参数,但被拒绝了,其实,这对TCP规范,对TIME-WAIT来说,是利大于弊的。 那么问题来了 我们来看下,为什么这个状态能影响到一个处理大量连接的服务器,从下面三个方面来说: 新老连接(相同四元组)在TCP连接表中的slot复用避免 内核中,socket结构体的内存占用 额外的CPU开销 而ss -tan state time-wait|wc -l的结果,并不能说明这些问题。 Connection table slot连接表槽 处于TIME-WAIT状态的TCP连接,在链接表槽中存活1分钟,意味着另一个相同四元组(源地址,源端口,目标地址,目标端口)的连接不能出现,也就是说新的TCP(相同四元组)连接无法建立。 对于web服务器来说,目标地址、目标端口都是固定值。如果web服务器是在L7层的负载均衡后面,那么源地址更是固定值。在LINUX上,作为客户端时,客户端端口默认可分配的数量是3W个(可以在参数net.ipv4.up_local_port_range上调整)。 这意味着,在web服务器跟负载均衡服务器之间,每分钟只有3W个端口是处于established状态,也就大约500连接每秒。 如果TIME-WAIT状态的socket出现在客户端,那这个问题很容易被发现。调用connect()函数会返回EADDRNOTAVAIL,程序也会记录相关的错误到日志。 如果TIME-WATI状态的socket出现在服务端,问题会非常复杂,因为这里并没有日志记录,也没有计数器参考。不过,可以列出服务器上当前所有四元组连接的数量来确认 解决办法是,增加四元组的范围,这有很多方法去实现。(以下建议的顺序,实施难度从小到大排列) 修改net.ipv4.ip_local_port_range参数,增加客户端端口可用范围。 增加服务端端口,多监听一些端口,比如81、82、83这些,web服务器前有负载均衡,对用户友好。 增加客户端IP,尤其是作为负载均衡服务器时,使用更多IP去跟后端的web服务器通讯。 增加服务端IP。 当然了,最后的办法是调整net.ipv4.tcp_tw_reuse和net.ipv4.tcp_tw_recycle。但不到万不得已,千万别这么做,稍后再讲。 内存 保持大量的连接时,当多为每一连接多保留1分钟,就会多消耗一些服务器的内存。举个栗子,如果服务器每秒处理了1W个新的TCP连接,那么服务器将会存货1W/s*60s = 60W个TIME-WAIT状态的TCP连接,那这将会占用多大的内存么?别担心,少年,没那么多。 首先,从应用的角度来看,一个TIME-WAIT状态的socket不会消耗任何内存:socket已经关了。在内核中,TIME-WAIT状态的socket,对于三种不同的作用,有三个不同的结构。 一、“TCP established hash table”的连接存储哈希表(包括其他非established状态的连接),当有新的数据包发来时,是用来定位查找存活状态的连接的。 该哈希表的bucket都包括在TIME-WAIT连接列表以及正在活跃的连接列表中(netstat -antp命令的结果中,没PID的TIME_WAIT状态连接,跟有PID的活跃连接两种)。 该哈希表的大小,取决于操作系统内存大小。在系统引导时,会打印出来,dmesg日志中可以看到。 这个数值,有可能被kernel启动参数thash_entries(设置TCP连接哈希表的最大数目)的改动而将其覆盖。 在TIME-WAIT状态连接列表中,每一个元素都是一个tcp_timewait_sock结构体,其他状态的连接都是tcp_sock结构体。 二、“death row”连接列表,是用来终止TIME-WAIT状态的连接的,这会在他们过期之前,开始申请。它占用的内存空间,跟在连接哈希表中的一样。这个结构体hlist_node tw_death_node是inet_timewait_sock的一个成员,如上代码的倒数第二行。 三、端口绑定的哈希表,用来存储绑定端口跟其他参数,用来确保当前端口没有被使用的,比如在listen监听时的指定端口,或者连接其他socket时,系统动态分配的端口。该哈希表的大小跟连接哈希表大小一样。 每个元素都是inet_bind_socket结构体。每个绑定的端口都会有一个元素。对于web服务器来说,它绑定的是80端口,其TIME-WAIT连接都是共享同一个entry的。另外,连接到远程服务器的本地连接,他们的端口都是随机分配的,并不共享其entry。 所以,我们只关心结构体tcp_timewait_sock跟结构体inet_bind_socket所占用的空间大小。每一个连到远程,或远程连到本地的一个TIME-WAIT状态的连接,都有一个tcp_timewait_sock结构体。还有个结构体inet_bind_socket,只会在连到远程的连接会存在,远程连过来的连接没这个结构体。 tcp_timewait_sock结构体的大小只有168 bytes,inet_bind_socket结构体为48bytes: 所以,当服务器上有4W个连进来的连接进入TIME-WAIT状态时,才用了10MB不到的内存。如果服务器上有4W个连接到远程的连接进入TIME-WAIT状态时,才用了2.5MB的内存。再来看下slabtop的结果,这里测试数据是5W个TIME-WAIT状态的连接结果,其中4.5W是连接到远程的连接: 命令执行结果原样输出,一个字符都没动。TIME-WAIT状态的连接占用内存非常的小。如果你的服务器上要处理每秒成千上万的新建TCP连接,你可能需要多一点的内存才能 正确无误的跟客户端做数据通信。但TIME-WAIT状态连接的内存占用,简直可以无视。 CPU 在CPU这边,查找一个空闲端口的操作,还是蛮珍贵的。这由inet_csk_get_port() 函数,加锁,遍历整个空闲端口列表实现。这个哈希表里条目数量大通常不是问题,如果服务器上存在大量连接到远程TIME-WAIT状态的连接(比如FPM连redis、memcache之类),都会同享相同的profile,这个特性会非常快的按照顺序找到一个新的空闲端口。 其他解决办法 如果你读了上面的章节后,仍对TIME-WAIT状态的连接存有疑问,那么接着看吧: 禁用socket延迟关闭「译者注1:以ubuntu 12.04为例,linger结构体定义在:/usr/src/linux-headers-3.2.0-23/include/linux/socket.h」 禁用net.ipv4.tcp_tw_reuse 禁用net.ipv4.tcp_tw_recycle 当close被调用时,SOCKET需要延迟关闭(lingering),在内核buffers中的残留数据将会发送到远程地址,同时,socket会切换到TIME-WAIT状态。如果禁用此选项,则调用close之后,底层也会关闭,不会将Buffers中残留数据未发送的数据继续发送。 不过呢,应用程序可以选择禁用socket lingering延迟关闭行为。关于socket lingering 延迟关闭,下面两个行为简单描述一下: 第一种情况,close函数后,并不会直接终止该四元组连接序号,而是在buffers任何残留数据都会被丢弃。该TCP连接将会收到一个RST的关闭信号,之后,服务端将立刻销毁该(四元组)连接。 在这种做法中,不会再有TIME-WAIT状态的SOCKET出现。第二种情况,如果当调用close函数后,socket发送buffer中仍然有残留数据,此进程将会休眠,直到所有数据都发送完成并确认,或者所配置的linger计时器过期了。非阻塞socket可以设置不休眠。如上,这些过程都都在底层发生,这个机制确保残留数据在配置的超时时间内都发送出去。 如果数据正常发送出去,close包也正常发送,那么将会转换为TIME-WAIT状态。其他异常情况下,客户端将会收到RST的连接关闭信号,同时,服务端残留数据会被丢弃。 这里的两种情况,禁用socket linger延迟关闭不是万金油。但在HAproxy,Nginx(反代)场景中,在TCP协议上层的应用上(比如HTTP),比较合适。同样,也有很多无可厚非的理由不能禁用它。 net.ipv4.tcp_tw_reuse TIME-WAIT状态是为了防止不相关的延迟请求包被接受。但在某些特定条件下,很有可能出现,新建立的TCP连接请求包,被老连接(同样的四元组,暂时还是TIME-WAIT状态,回收中)的连接误处理。RFC 1323 实现了TCP拓展规范,以保证网络繁忙状态下的高可用。除此之外,另外,它定义了一个新的TCP选项--两个四字节的timestamp fields时间戳字段,第一个是TCP发送方的当前时钟时间戳,而第二个是从远程主机接收到的最新时间戳。 启用net.ipv4.tcp_tw_reuse后,如果新的时间戳,比以前存储的时间戳更大,那么linux将会从TIME-WAIT状态的存活连接中,选取一个,重新分配给新的连接出去的TCP连接。 连出的TIME-WAIT状态连接,仅仅1秒后就可以被重用了。 如何确通讯安全性? TIME-WAIT的第一个作用是避免新的连接(不相关的)接收到重复的数据包。由于使用了时间戳,重复的数据包会因为timestamp过期而丢弃。 第二个作用是确保远程端(远程的不一定是服务端,有可能,对于服务器来说,远程的是客户端,我这里就用远程端来代替)是不是在LAST-ACK状态。因为有可能丢ACK包丢。远程端会重发FIN包,直到 放弃(连接断开) 等到ACK包 收到RST包 如果 FIN包接及时收到,本地端依然是TIME-WAIT状态,同时,ACK包也会发送出去。 一旦新的连接替换了TIME-WAIT的entry,新连接的SYN包会被忽略掉(这得感谢timestramps),也不会应答RST包,但会重传FIN包。 FIN包将会收到一个RST包的应答(因为本地连接是SYN-SENT状态),这会让远程端跳过LAST-ACK状态。 最初的SYN包将会在1秒后重新发送,然后完成连接的建立。看起来没有啥错误发生,只是延迟了一下。 另外,当连接被重用时,TWrecycled计数器会增加的。「译者注:见/proc/net/netstat 中TWrecycled的值」 net.ipv4.tcp_tw_recycle 这种机制也依赖时间戳选项,这也会影响到所有连接进来和连接出去的连接。「译者注:linux上tcp_timestamps默认开启」 TIME-WAIT状态计划更早的过期:它将会在超时重发(RTO)间隔后移除(底层会根据当前连接的延迟状况根据RTT来计算RTO值,上篇《PHP-FPM中backlog参数变更的一些思考》也有提到过,比较复杂的算法)。可以执行ss指令,获取当前存活的TCP连接状态,查看这些数据。「译者注:linux指令ss的结果中rto,rtt值单位均为ms」 Linux将会放弃所有来自远程端的timestramp时间戳小于上次记录的时间戳(也是远程端发来的)的任何数据包。除非TIME-WAIT状态已经过期。 当远程端主机HOST处于NAT网络中时,时间戳在一分钟之内(MSL时间间隔)将禁止了NAT网络后面,除了这台主机以外的其他任何主机连接,因为他们都有各自CPU CLOCK,各自的时间戳。这会导致很多疑难杂症,很难去排查,建议你禁用这个选项。另外,对方上TCP的LAST-ACK状态是体现本机net.ipv4.tcp_tw_recycle的最好数据。 总结 最合适的解决方案是增加更多的四元组数目,比如,服务器可用端口,或服务器IP,让服务器能容纳足够多的TIME-WAIT状态连接。在我们常见的互联网架构中(NGINX反代跟NGINX,NGINX跟FPM,FPM跟redis、mysql、memcache等),减少TIME-WAIT状态的TCP连接,最有效的是使用长连接,不要用短连接,尤其是负载均衡跟web服务器之间。尤其是链家事件中的PHP连不上redis。 在服务端,不要启用net.ipv4.tcp_tw_recycle,除非你能确保你的服务器网络环境不是NAT。在服务端上启用net.ipv4.tw_reuse对于连接进来的TCP连接来说,并没有任何卵用。 在客户端(尤其是服务器上,某服务以客户端形式运行时,比如上面提到的nginx反代,连接着redis、mysql的FPM等等)上启用net.ipv4.tcp_tw_reuse,还算稍微安全的解决TIME-WAIT的方案。再开启net.ipv4.tcp_tw_recycle的话,对客户端(或以客户端形式)的回收,也没有什么卵用,反而会发生很多诡异的事情(尤其是FPM这种服务器上,相对nginx是服务端,相对redis是客户端)。 最后引用一下W. Richard Stevens在《UNIX网络编程》的一句话 The TIME_WAIT state is our friend and is there to help us (i.e., to let old duplicate segments expire in the network). Instead of trying to avoid the state, we should understand it. 译者:存在即合理,勇敢面对,而不是逃避。 译者注: 译者根据原文做了翻译,并增加了相关论点论据,跟原文稍有不同。 linux的netstat命令ss命令的结果中,前者是TIME_WAIT之类,分个字符是下划线,而后者是TIME-WAIT的中划线。 残酷的案例: Clients behind NAT/Stateful FW will get dropped, 99.99999999% of time should never be enabledTuning TCP and nginx on ec2中30页内容 参考资料: Tuning TCP and nginx on ec2 -p30 TIME_WAIT and its design implications for protocols and scalable client server systems tcp_tw_recycle和tcp_timestamps导致connect失败问题 记一次TIME_WAIT网络故障 打开tcp_tw_recycle引起的一个问题 Transmission Control Protocol 2017年10月更新 在linux 4.1内核中,net.ipv4.tcp_tw_recycle参数将被移除。net.ipv4.tcp_tw_recycle has been removed from Linux 4.12. The tcp_tw_recycle was already broken for connections behind NAT, since the per-destination timestamp is not monotonically increasing for multiple machines behind a single destination address. After the randomization of TCP timestamp offsets in commit 8a5bd45f6616 (tcp: randomize tcp timestamp offsets for each connection), the tcp_tw_recycle is broken for all types of connections for the same reason: the timestamps received from a single machine is not monotonically increasing, anymore. Remove tcp_tw_recycle, since it is not functional. Also, remove the PAWSPassive SNMP counter since it is only used for tcp_tw_recycle, and simplify tcp_v4_route_req and tcp_v6_route_req since the strict argument is only set when tcp_tw_recycle is enabled. 2015-07-27 +7 11 0
nginx、php-fpm默认配置与性能–TCP socket还是unix domain socket 前几天看到一篇博客,提到php所在服务器在大并发情况下,频繁创建TCP短连接,而其所在服务器的2MSL时间过长,导致没有端口可用,系统无法创建TCP socket,而大量报错。博主在后面给的解决方案是减少2MSL的时间,尽快清除TIME_WAIT状态的TCP连接,回收端口。同时,文章结尾写了不用长连接的理由,但这真的是最好的解决办法吗?有其他办法可以更好的做法吗? 类似经历 之所以多这篇文章兴趣这么高,是因为在前段时间,末学也经历了一件类似的优化历程,先简短的描述下我们的服务器架构。如图 想必看到这幅架构图的同学,都比较熟悉吧,也比较简单。“最前面”的nginx 反代负责与玩家的http请求通讯,这里是长连接。在其与后端游戏大区通讯时,使用了短连接,也就是意味着,每处理用户的一个http请求,都要重新与后端的nginx建立一次TCP(http)请求,后端nginx处理完之后就关闭。后端的nginx与php在同一台服务器上,通讯配置如下: 在这个架构图中,反代承担这承上启下的作用,前面是用户,后面是web app服务器,长连接用户,短连接后端。若用户数在1W人,1W人与反代的连接,在反代服务器上都用80端口。但这1W人的每一个请求,反代都要重新使用服务器的端口与后端nginx的80创建tcp socket,来处理请求。若2MSL时间为1分钟以上,同时,玩家两次请求间隔很短,想我们游戏的服务器,两次请求间隔大约5秒(甚至2-3秒)。那么反代的端口,5秒用1W个,10秒2W,15秒3W,20秒4W,25秒5W,30秒6W!!!,前面已经用掉的端口还没被回收掉。那么将会有很多的用户请求被nginx反代接收之后,因没有端口资源而无法与后端nginx创建tcp连接。。。以游戏的其中一个大区为例: 关于这个问题,末学在新浪微博上请教过其他大牛,其中tengine负责人淘叔度前辈以及@120斤的大青蛙前辈告诉我,nginx将在1.1.4版本开始支持ngx_http_upstream_keepalive,3月1号左右,是1.1.16 dev版本,我们的运维团队稍微由于几天,之后在部分小区的服务器上适用了1.1.16,效果不错,Nginx反代上与目标服务器的80端口的TCP连接中处于ESTABLISHED状态的非常多,TIME_WAIT的几乎没有,很稳定。我们几乎计划为了这个性能的提升,决定用dev版了。接着nginx1.2Stable version也出来了,那么也就用这个版本了。至于反代上nginx与后端app server建立TCP连接个数,也就是端口数(满载情况下,维持ESTABLISHED状态)的为nginx worker_processes * ((upstream1 server * keepalive参数数量) + (upstream2 server * keepalive参数数量) + ...),并不多。 如上,端口占用数少了,那么还有其他有点吗?先看一副 socket创建,监听、数据接收发送、关闭与客户端连接的socket流程图: 如上图,nginx反代跟后端nginx的形式跟php-fpm与mysqld socket的模型一样的。 nginx反代跟php-fpm 相对来说,就是客户端,这种做法,他们的每个新socket 请求的发起,都会跟着左边的流程走一遍,一遍又一遍。。。。每次的socket创建,端口等资源申请,与服务端的三次握手,关闭时的四次握手,端口的回收。。。。 改用长连接之后,如下图: 只有php-fpm(或者nginx反代)的子进程分别与mysqld创建1次TCP连接,之后都是send、recv数据的事情了,端口占用也是为数不多的几个(每个fpm子进程将与mysqld维持一个TCP长连接)。 同样,后端服务器的nginx与php-fpm的通讯也是如此,只是请求两没有反代那么大。区别就是IP地址是回环地址127.0.0.1。 既然是回环地址,那么两个服务都是在同一台机器上跑的,既然是同一台机器,为何不用进程间通讯的socket--unix domain socket呢? socket是神马?摘抄一段描述: Socket 可以被定义描述为两个应用通信通道的端点。一个 Socket 端点可以用 Socket 地址来描述, Socket 地址结构由 IP 地址,端口和使用协议组成( TCP or UDP )。http协议可以通过socket实现,socket在传输层上实现。从这个角度来说,socket介于应用层和传输层之间。但是socket作为一种进程通信机制,操作系统分配唯一一个socket号,是依赖于通信协议的,但是这个通信协议不仅仅是 tcp或udp,也可以是其它协议。 在同一台服务器上,用tcp socket与unix domain socket有什么区别? 如图所示,对于进程间通讯的两个程序,unix domain socket的流程不会走到TCP 那层,直接以文件形式,以stream socket通讯。如果是TCP socket,则需要走到IP层。 对于非同一台服务器上,TCP socket走的就更多了。 至于localhost\127.0.0.1以及网络IP他们之间的区别,无意中找到一篇博客写的是以mysql作为验证,来说明localhost不走TCP/IP层,跟127.0.0.1不一样。末学认为他理解错了。他的理由如下 (以下截图均在linux上,windows的没有unix domain socket) mysql连接本机时,不加-h参数: mysql连接本机时,加-h参数且值是localhost: mysql连接本机时,加-h参数且值是127.0.0.1: 那位同学从mysql工具的使用方法、与结果的区别,来理解推导localhost与127.0.0.1的区别,这从方向上就存在问题,我更相信,这是mysql这个程序自己的行为,遇到-h参数没加,或者-h参数的值不是IP形式,且my.cnf里指定mysql的socket路径时,则直接使用unix domain socket来连接服务器,当然,这也是我的猜测,没有去验证,大家听听就好,别相信。 鉴于末学对以上的理解,将服务器的架构配置变更如下 至此,优化还为完毕,若php-fpm与mysql使用mysql_pconnect的话,那么php-fpm的子进程生成模式最好用static模式,若为dynamic模式,可能会出现mysql连接数被占满的情况,这也跟mysql服务的连接超时时间有关,适当调整也容易避免。 不过,我们目前还没用mysql_pconnect,主要原因是我们的代码中,有些事务处理开启之后,对于代码的失败处理,忘记写回滚语句,在短连接的情况下,这个连接的销毁,哪怕客户端没提交ROLLBACK或者COMMIT指令,mysql会自动回滚之前的事务。但使用长连接之后,不同请求会使用同一个MYSQL连接句柄,每个事务开启都会禁用MYSQL的自动提交,即SET AUTOCOMMIT=0语句,这语句会提交之前的事务。对于我们代码忘记写回滚,而直接返回结果的情况下,这是会出大问题的,也是我们目前唯一没有使用MYSQL_pconnect的原因。(计划近期找到没有写回滚语句的代码,修复,继续使用mysql_pconnect) 其实还有,我们php-fpm使用了APC来缓存php file,以及 变量数据等,这些也是有优化的地方(如果有时间的话,则待续)。 回过头来再理解下文章开头那位同学给的解决办法,我仍不能从他给的理由中,理解长连接的缺点,哪怕是解决了TIME_WAIT的问题,但每次创建TCP socket ,连接到服务器时三次握手,关闭TCP socket时的四次握手 这些也是开销。当然,缩短2MSL的时间,也是更好利用服务器资源的一个好方法。 最后,我们调整优化的服务器架构图如下: 好像有点偏离这篇文章的标题了,其实我更想说我不能理解为啥nginx跟php-fpm给的默认配置中,都是TCP socket通讯的,为啥不默认给unix domain socket的默认配置呢?如果说为了方便非同一台服务器时的情况,但给的默认IP也是回环地址呀。 而且,nginx给默认配置中,对于uri请求中的php文件的处理,匹配规则还是老的,之前发生因为NGINX与PHP的配置而导致的安全问题,虽然不是nginx的错,但nginx也可给出更严谨的范例,但仍没有。 值得欣慰的是,在UBUNTU 12.4中,nginx的默认配置有了很大的改进,不管是匹配uri的规则,还是nginx与php-fpm的交互方式: PS:末学只是个web程序员,这些只是末学学习研究如上知识的总结,理解上难免有错,各位请海涵。 2012-05-31 +18 22 0