内容简介:如下图. server docker restart后, client端写入的日志丢失, 并且无报错.因为不支持时序图, 把时序图代码嵌入在代码里.
问题
问题简述
如下图. server docker restart后, client端写入的日志丢失, 并且无报错.
因为不支持时序图, 把时序图代码嵌入在代码里.
```sequence client->server: log_data client->server: log_data server->server: docker restart server->client: fin client->server: log_data loss without error ```
tcp state diagram
问题定位过程
为什么卡在CLOSE_WAIT.
看tcp状态转换图, 可以看到client收到了fin, 一直没有recv, 一直卡在CLOSE_WAIT. 和实际的代码是吻合的.
那么, 为什么在server docker restart 引发CLOSE_WAIT后, client发消息仍然不报错呢?
因为:
- tcp协议允许client在收到fin后, 继续发送消息.
- server 在docker restart后 ip 改变, client还是往原来的ip发送消息, 没有主机通知client rst, 导致消息在系统buffer里积压.
积压信息如下:
root@9eeaefa7fe57:/# netstat -nap | grep 27017 | grep 10.0.0 tcp 1 402 10.0.0.186:62281 10.0.0.16:27017 CLOSE_WAIT 4308/server root@9eeaefa7fe57:/# netstat -nap | grep 27017 | grep 10.0.0 tcp 1 70125 10.0.0.186:62281 10.0.0.16:27017 CLOSE_WAIT 4308/server
此时, 在elixir socket接口层面来看, 不管socket的状态, 还是发送, 都是ok的.
iex(client@client.)25> socket |> :inet.port
{:ok, 57395}
iex(client@client.)26> socket |> :gen_tcp.send("aaa")
:ok
如果主动close, 则会进入LAST_ACK状态
iex(client@client.)27> socket |> :gen_tcp.close() :ok
root@9eeaefa7fe57:/# netstat -nap | grep 27017 | grep 10.0.0 tcp 1 70126 10.0.0.186:62281 10.0.0.16:27017 LAST_ACK -
CLOSE_WAIT的恢复
如果代码还是只发不收. 是检测不到CLOSE_WAIT的. 显然, 应用层心跳是一个解决方案. 那么, 不使用心跳, 只发不收的情况下, 什么时候才能检测到错误呢?
- send buffer 满
- todo 深究tcp keepalive, 不使用 keepalive情况下的 tcp 最大链接空闲时间.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Golang实现平滑重启(优雅重启)
- SOFAMosn 无损重启/升级
- nginx-平滑重启
- Unbuntu 自动重启MySQL
- Zabbix监控Windows进程重启
- Golang代码修改后自动重启
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Design systems
Not all design systems are equally effective. Some can generate coherent user experiences, others produce confusing patchwork designs. Some inspire teams to contribute to them, others are neglected. S......一起来看看 《Design systems》 这本书的介绍吧!