07月02日(电源)插座通信
大家好,今天小六子来为大家解答以下的问题,关于,电源)插座通信这个很多人还不知道,现在让我们一起来看看吧!
1、从tcp socket通讯原理可以看到,在连接断开“四次挥手”过程中,只有被动close的一方才会出现CLOSE_WAIT和LAST_ACK,或者说如果发起close动作的看作client端,那出现CLOSE_WAIT和LAST_ACK就是server端。
2、只要收到client端发出FIN包,server端就是CLOSE_WAIT状态,这个状态意味着可能在关闭连接之前还有许多数据要发送,如果没有数据要发送,那server就要回复一个FIN给cilent,然后server端就变成LAST_ACK,client收到server的FIN包后,正常会立即回复ACK,server只要收到ACK后连接就断开了。
3、下面我们结合案例谈谈CLOSE_WAIT和LAST_ACK。
4、案例分析:某系统的应用支持人员反馈,文件传输服务14029端口异常,业务被堵塞。
5、我们登入系统检查,除文件传输服务交易处理缓慢,其他类型的交易均未受影响,也就是说该服务器有多个对外服务端口,只有一个端口异常。
6、与应用开发人员沟通过后,反馈应用没有实施过变更。
7、同时应用开发人员反映这类业务全部是从公网接入的,我们登入F5设备,将公网接入业务渐出后,交易并发请求量下降,文件传输服务端口堵塞现象逐渐缓解,但从F5重新渐入公网业务后,问题重现。
8、从异常时收集的数据分析,14029服务端口约有3000个连接,其中大多数连接处于CLOSE_WAIT和LAST_ACK状态。
9、这么多的CLOSE_WAIT和LAST_ACK说明通讯阶段肯定不正常,看到这里,大家都怀疑问题出现网络层面了吧,这里先不回答,先结合上面介绍的TCP原理中的CLOSE_WAIT和LAST_ACK思考一下,现在问题仅反映出大量CLOSE_WAIT和LAST_ACK,连接建立阶段未出现异常,说明什么呢?继续查看网络通讯报文。
10、异常时段的网络报文如下:从网络报文看,连接释放前大致正常,为什么说大致正常,client和server有来有往,也无重传等异常现象,但是,交互一次经常有20多秒,所以只能说大致正常。
11、在一笔交易完成后,开始断开连接,问题出现了,client端发出了FIN包,server立刻回复ACK,然后经过20多秒的等待后,又发送了长度为7的数据,再回复了FIN包,然后出现网络重传FIN包。
12、 对于网络重传,乍一看以为是网络通讯丢包,但仔细一推敲,其他时间不丢包,为什么只在连接释放阶段丢包,没有道理啊。
13、就此,我们和网络技术专家进行了沟通,得到的答复是:在通讯阶段,大量客户端超时发出连接关闭请求,也就是client发出了FIN包,server端服务进程处理超时未能及时响应关闭连接请求,超过10秒触发防火墙安全保护机制,连接关闭应答包(FIN)被防火墙抛弃,以至于出现大量FIN包重传的现象。
14、答复就是说网络没问题,是应用程序超时了。
15、网络丢包问题排除了,那么问题可能就出在了应用程序上了,但应用程序的问题在哪里呢?我们回顾了前面的整个分析过程,有两个疑点和应用相关,一是通讯报文中客户端和服务端两端交互延时很大,经常出现20多秒时差;二是大量客户端发出断链请求。
16、带着疑问,我们和应用开发人员进行沟通,进一步了解了交易的整个流程,很快第二个疑点就明确了,正常情况下,交易都是由农行端关闭,不会由公网客户端关闭,除非交易超时,从现象上看肯定出现了大量的客户端交易超时。
17、同时从应用开发人员提供的交易流程分析,每一笔交易,分8次输出日志,也就是说一笔交易记录8次日志,对日志文件操作了8次。
18、既然应用分步记录日志,那日志肯定能反映交易每一步的时间差,也就是说交易超时应用日志中能直接看出来。
19、打开日志文件,发现日志文件中几乎很难看一笔完整的、顺序的日志,这是由于应用进程池多个进程并行写日志所致。
20、这么重要的线索,怎么能随便放弃。
21、为此我们根据日志中的时间戳以及进程号的规律专门编写了一个脚本负责遍历和排序近一周的应用日志,几个小时后,令人振奋的结果出来了,排序后的日志对每一笔交易时间记录很详细,大多数时间,每一笔交易都在一秒内完成,一到交易高峰,交易时间开始延迟,短的延迟2~3秒,长的延迟几十秒甚至上百秒,从日志可以推断出这个问题一直存在,只是反映出来程度轻重不同而已。
22、分析到这一步,应该是明确了应用程序存在问题,但应用程序的问题究竟是什么呢?有了方向,我们在业务高峰针对应用进程开启了truss跟踪,truss对交易的过程和底层调用非常详细记录如下:交易中共有8次对于该日志的写入,以其中一次日志文件操作过程(kopen-kwrite-close)为例,其耗时达到1.1s以上。
23、一笔交易完成,时间基本耗费都在10多秒。
24、同时段,还有其他多个14029端口相关进程对于此日志并发操作,引起整笔中绝大多数都在进行该日志文件操作。
25、从Truss信息中可以看到交易打开日志还是采用同步方式。
26、35782920: 48955803: 0.1007: kfork() = 1887454218874542: kfork() (returning as child ...) = 018874542: 31785117: 0.1086: _getpid() = 1887454235782920: 48955803: 0.1088: semget(1674622889, 1, 0)18874542: 31785117: 0.1088: thread_setmystate(0x00000000, 0x2FF21920) = 300942464 = 018874542: 31785117: 0.1091: _thread_self() = 3178511718874542: 31785117: 0.1094: thread_setmystate(0x2FF21608, 0x2FF21910) = 018874542: 31785117: 0.1096: thread_setmymask_fast(0x00000000, 0x00000000, 0x00000000, 0xD051C880, 0x00000000, 0x11E5009D, 0x11E5009D, 0xF0256118) = 0x0000000018874542: 31785117: 0.1104: thread_unlock(0x2003F750) = 018874542: 31785117: 8.0003: kopen("/ho22938062: 44761355: 8.0009: kopen("/home/beics/log/Fil = 83997862: 75104323: 8.0018: kopen= 0 = 8 = 917170888: 63897901: 8.0034: close(9)16849568808: 53805667: 8.0037: kopen("/home/beics/log/FileSvr.20140604", O_RDWR|O_SYNC|O_APPE= 0 = 9 = 932965182: 51970655: 8.0039: kopen("/home/beics/log/FileSvr.20140604", O_RDWR|O_SYNC|O_APPEND)35521118: 45220353: 8.0065: kopen("/home/beics/log/FileSvr.20140604", O_RDWR|O_SYNC|O_APPEND) = 8 = 98454202: 21954581: 8.0049: kopen("/home/beics/log/FileSvr.20140604", O_RDWR|O_SYNC|O_APPEND) = 915991212: 14877101: 8.0080: _erecv(7, 0x2FF21630, 7, 256, 0x00000000) = 76488658: 81134209: kwrite(8, 0x2FF208C4, 56) = 5618874542: 31785117: kwrite(8, 0x2FF20B14, 53) = 5318874542: [ 1 6 : 2 3 : 0 4 | 0 0 1 8 8 7 4 5 4 2 | ] ????[ 1 0 . *18874542: . *. * ] ??????: Q U I T分析到这里,相信大家知道怎么回事了,truss中多个线程并行操作,时间延迟了,信息都是乱的。
27、所以,经过最终分析结论如下:由于交易过于频繁的、且使用同步方式对一个日志文件进行打开和写入操作,而这些文件操作都是串行操作,交易之间相互竞争记录日志,导致交易处理时间延长、处理效率下降。
28、至于异常时系统层面看到的大量CLOSE_WAIT 和LAST_ACK,应该比较好理解,由于交易进程处理变慢,服务端接收到客户端发出的FIN包仍然在发送数据(响应前面的请求)所致,所以能看到很多CLOSE_WAIT;而LAST_ACK状态,是由于交易超时情况下,触发了防火墙安全机制,服务端回复的FIN被丢弃所致。
29、解决方案及建议:应用开发人员在我们的建议下,对应用程序进行了优化,将打开文件方式改成异步方式,并改进了日志记录方法,每笔交易分步记入日志改成先缓冲、交易完成后一次性记入日志文件方式,降低操作日志文件的频率,减少文件操作竞争。
30、优化完成后,该问题彻底解决。
31、socket通讯异常问题排查和处置难度大,系统层和应用层都也难以快速进行应急处置。
32、建议架构上尽量采用集群模式,实现应用负载均衡,有效地规避应用"单点"风险,提升应用的高可用性。
33、对于自行开发的socket通讯系统,应用与TCP通讯关联紧密,异常处理机制都依赖应用实现,要详尽考虑外部环境的各种复杂异常情况,确实是非常困难的事情,就如一些业内经验丰富开发人员所说的,标准的socket通讯程序,3分功能代码,7分异常处置,如果缺乏这份决心,建议还是采用比较成熟的通讯中间件产品来实现通讯处理。
本文分享完毕,希望对你有所帮助。