通过http请求超时观察tcp链接问题

项目中写了一个中间件使用http传语音包的功能: 首先 从websocket中读取语音流包,然后向http server上传语音流, 生产端会每100ms写一个二进制语音流包, 中间件上传完50ms(等http server 响应)后再从websocket中读取 再上传(得用tcp链接), 那么这个上传过程可能会因为少量请求响应超过100ms,最终影响 用于ASR转写的语音流 整体滞后;
单从上传的角度看解决这个滞后问题,可以只上传然后不等待对接服务的响应,当然这样做会引入其它问题,
这里所指的是http1.1

                            -request timeout 10ms->
websocket <--r/w--> proxy                           asr(http)
                            <-response 50ms-

Svg Video Icon
这里是记录视频click here to watch the demo video

比如 怎么只上传然后不等待对接服务的响应呢? 虽然一般不这样做 #

在golang的http timeout中, transport timeout 或者 http client配置的timeout,这两者设置得过小比如10ms,只要保证大于单次 roundtrip time,数据能够让http server接到即可

比如 http timeout后,底层的tcp链接会直接关闭,而且是client主动关闭,会存在大量TIME_WAIT的链接,怎么解决? #

答案是 net.ipv4.tcp_tw_reuse, 从官方文档可知,处于TIME_WAIT状态下tcp链接可以重新走三次使用port,如图中用tcpdump抓包显示,每一次请求会走三次握手,还有服务端口返回响应会被拒收rst掉(往已经关闭的链接上发package会收到rst,比如这里的server端,或者没有进程监听的端口上发起建立链接请求);(net.ipv4.tcp_tw_recycle 就不建议使用了特别是对于server主动关闭tcp的情况,而且从linux kernal 4.4开始已经把这个配置参数去掉了)



http client发起大量的短链接对http server有什么影响? #

一个是 tcp 的sync queue或者accpet queue会被占满导致后续的链接请求被drop掉如图所示,这有点类似于DDoS攻击, 服务端可以把sync队列调大来一定程序上解决这个问题

debug以及一些优化tcp链接配置笔记 #

netstat -anp|grep TIME

sysctl -a|grep net.ipv4.tcp_tw

vi /etc/sysctl.conf

net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1

/sbin/sysctl -p

2022-04-26