关于goneaway及499

关于上面现象的分析如下

         问题描述:

                  接口偶发性出现接口耗时过长的情况

 

         根源:

                   “sockets的快速回收”机制被启动

 

简单代码+数据分析:

1.      经简单分析,耗时主要出现在连接数据库的方法:mysql_connect

2.      耗时基本为3s(3.001s,2.999s,3.000s)

 

进一步分析:

         由于耗时出现在php的mysql_connect函数上,从代码上基本上可以确认非业务逻辑问题;

         可能情况:

         1、Mysql_connect具体实现问题

                   经查看具体代码,未发现有异常。

         2、网络抖动

                   经抓包确认且不大可能为稳定为3秒,非此问题;

         3、DNS解析

                   经分析直接绑定HOST与DNS解析对比,确认非此问题;

         4、LVS抖动

                   根据出现时间,与LVS监控对比,确认非此问题

         5、mysql服务器配置或者mysql配置存在问题

         待分析

         ……

         最终确认:

         Mysql服务器配置问题,启动了“sockets的快速回收”机制

         根据运维和DBA对app机器即(Client端)到mysql服务(Server端)的tcp日志抓包中出现了passive connection rejected because of time stamp,且抓到了syn数据包,这个即标识tcp请求一次握手成功

 

 

为说明此问题,需要补充以下知识点:

(1)       公司的机器部署架构

大部分公司用LVS做负载均衡,通常是前面一台LVS,后面多台后端服务器,它便转发给后端服务器

(2)       TCP协议中的三次握手

(3)  “sockets的快速回收”机制

a)      目的:sockets快速回收

b)      行为解释:可以缓存每个连接最新的时间戳,后续请求中如果时间戳小于缓存的时间戳,即视为无效,相应的数据包会被丢弃。

c)      涉及参数:tcp_timestamps和tcp_tw_recycle

i.       tcp_timestamps默认为1,tcp_tw_recycle默认为0

ii.      当tcp_timestamps与tcp_tw_recycle同时为1时,表示此机制开启

 

结论分析:

在有LVS做负载均衡的情况下,,对于后端服务器来说,请求的源地址就是LVS的地址((nat模式才会修改源地址,我们用的都是dr模式)),加上端口会复用,

所以从后端服务器的角度看,原本不同客户端的请 求经过LVS的转发,就可能会被认为是同一个连接,于是后面的数据包就被丢弃了。

具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK

                  

后续思考:

1、

既然必须同时激活tcp_timestamps和tcp_tw_recycle才会触发这种现象,那只要禁止 tcp_timestamps,同时激活tcp_tw_recycle,

就可以既避免丢包问题,又降低TIME_WAIT连接数量。如果服务器并不 依赖于RFC1323,那么这种方法应该也是可行的,不过最好多做测试,以防有其他的副作用。

2、为什么是3s?

建立连接时SYN超时,如果server端接到了clien发的SYN后回了SYN-ACK后client掉线了,

server端没有收到client回来的ACK,那么,这个连接处于一个中间状态,即没成功,也没失败。

于是,server端如果在一定时间内没有收到的TCP会重发SYN-ACK。在Linux下,默认重试次数为5次,

重试的间隔时间从1s开始每次都翻售,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s,

第5次发出后还要等32s都知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 2^6 -1 = 63s,

TCP才会把断开这个连接。但跟运维沟通之后我们的重试机制时间间隔为3s。

3、安全起见,通常要禁止tcp_tw_recycle,至于TIME_WAIT连接过多的问题,可以通过激活tcp_tw_reuse来缓解

 

以上分析如有纰漏,麻烦指正,谢谢!

 

下面原创:

使用PHP作为常驻进程解决问题的时候,我们会遇到这样的问题,数据库(mysql)连接的时间是有限的,常驻脚本的一般会设置set_time_out,这样子项目中会出现一些db gone away的问题。如何解决这一问题主要涉及几点:

①数据库连接可以商讨使用长连接,但是长连接是否一致有效呢。这个取决于数据库的配置。该处受限于两个参数

wait_timeout

interactive_timeout

详细的可以查看该博主的博客:https://www.cnblogs.com/ivictor/p/5979731.html

这两个参数表示的是我们脚本与程序建立连接之后  如果间隔配置参数的秒数之后没有发起任何查询请求,数据库则会关闭该连接,进而出现gone away的问题。

解决的办法我们可以这样每隔范围内的时间  我们可以进行一次数据的无效查询,比如 select id from table where id=1,这样子我们就可以保持与数据库之间的心跳。

②使用短链接的情况下  我们可以每隔一段时间重新获取数据库连接,抛弃原来的链接。个人觉得最好使用这种方式,这种形式我认为还得加上①中保持心跳方法。

 

另外网上也有几种解决改问题的方法,如https://blog.p2hp.com/archives/4442

posted on 2017-01-23 16:39  爱搁浅  阅读(167)  评论(0编辑  收藏  举报