5. 连接建立@tcp调优
Last updated
Was this helpful?
Last updated
Was this helpful?
[toc]
syn-cookies: 是否要使用syn-cookie
synack_retries: 决定重新发几次SYN,ACK包
max-syn-backlog: syn队列长度, 允许更多的等待连接
somaxconn: syn队列/accept队列的长度
如上图所示, 你的连接在建立之后, accept正式启用之前, 一直存在这两个队列里, 而这两个队列是有长度限制的, 很显然, 如果你的程序处理不过来(accept不过来), 很容易就会导致这两个队列溢出, 通过如下手段改善溢出问题
正常情况下, 如果半连接队列溢出了, 服务端会直接忽略掉这个SYN包, 让客户端以为自己的SYN包没有发出, 但除此之外还有syn-cookies参数也会参与这个过程
我们之前提过存在一种情况, 就是有人会故意挤占你的syn队列, 在上面我们说服务器会忽略这个SYN包, 导致别的客户端无法访问. syn-cookies是专门防御这种攻击的办法, 在syn-cookies开启以后:
如果现在SYN队列没有满: 按照正常方法处理
如果现在SYN队列已满: 我们会把(源地址/端口+目的地址/端口)哈希成一个整数, 并用这个整数作为(SYN,ACK)包响应回去, 然而接下来这个连接并不会进入队列, 而是直接释放. 稍后客户端, 如果是真的他就会发出最后一个ACK包, 这时候我们再计算一下这个哈希值, 确认是之前链接的返回包, 就进入连接状态
溢出确实不好, 但溢出以后会发生什么呢? 查看net.ipv4.tcp_abort_on_overflow
, 参数, 这个参数决定了全连接队列满了以后怎么处理:
如果是1: 直接RST, 客户端那边收到reset by peer
为0: 好, 现在第二个参数登场, 就是synack_retry参数发挥作用
如果是0, 也会回 (SYN,ACK) 包, 收到了这个包的客户端立刻回复了三次握手中的最后一个ACK包, 美滋滋以为连接已经建立了, 但是很不幸, 这个包会被服务器直接忽略, 你无法进入全连接队列了, 你只能在半连接队列里继续呆着了.
而服务器装傻, 他一边忽略这个包, 一边又在问: "我最后一个ACK包去哪了", 然后他不停的发 (SYN,ACK) 催客户端重发ACK, 第二个参数synack_retry 就决定了这句话要问几遍: 现在如果客户端真的回了ACK, 那么服务器会重新尝试看看他能不能挤进全连接队列. 默认5次, 每次间隔时长递增, 最终会消耗3分钟
设想一个场景, 如果客户端回完ACK, 兴奋的以为自己连接已经建立了, 于是开始发数据, 接下来会发生什么? (你压根就不在全连接队列里, 自然也没有人会来accept/read你), 实际上压根没人理你, 超时以后等你主动FIN
这种场景跟sync-flood有关吗? 其实有的, 如果有人专门消磨你这三分钟, 故意挤占你的半连接队列呢? 这减少重试次数, 比如最多重问一次, 一次不回复就算作sync-flood, 直接关闭连接
keepalive: 发送频率, 默认是两小时一发
fastopen:
理论上的传输耗时 = 传输数据耗时 + TTL (其中TTL是指浪费在路由器跳跃上的时间, 这一项可以通过Ping得到) , 我们举例说明: 如果你的带宽是"千兆", 一秒钟能发送"100 MegaBits(Mb)"的数据, 那就是"100 MegaBytes(MB)"的数据, 这种情况下:
如果你想发送1MB的数据: 需要 1/100 秒 + TTL
如果是同机房发送, 不走路由器, TTL等于0, 消耗 10ms
如果跨机房发送, TTL是4ms, 那就是10+4 = 14毫秒
如果你想发送4MB的数据. 需要4/100秒+TTL = 40(同)/44(跨)毫秒