程序因为 tcp window full hang 住的一次排查过程
目录
文章简介:程序因为 tcp window full hang 住的一次排查过程
背景
生产出了问题,被拉来救场。
业务流程是 server1 会从 kafka1 中消费数据,重新整理数据后通过 tcp 发送给 logstash,logstash 再将数据发送给下游的 kafka2;为了确保不丢数据,logstach 开了某种幂等插件。
问题现象是,kafka1 中有 1000 条数据,tcp 确认发送成功 500 条,剩下的 500 条数据未发送或者发送失败了;kafka2 中未收到数据;
debug 过程
首先从源头看 server 1 中 tcp 是未发送还是发送失败了。从日志中未发现发送失败的日志。
从程序中的 goroutine 调用栈可以确认,程序卡在 syscall write 27 minutes,怀疑 tcp 连接出了问题;
在 logstash 这个机器上 ss 查看连接状态,可以看到,logstash 没有将 socket 中的数据 copy 到用户空间。
Recv-Q:
The count of bytes not copied by the user program connected to this socket.
man 8 netstat
查看 logstash 发现发送到 kafka 失败了:
看下抓包,可以看到再 keepalive + zerowindow,确认为 tcp read buf 已经满了,tcp 无法继续发送新的数据,golang 的 socket.write 只能死等。
解决
修复 kafka TopicAuthorizationException: not authorized to aceess topics, 业务即恢复。
综上
- tcp write 的成功,不意味着数据真的被接收到,如果业务需要确保下游被接收到,需要有业务 ack 机制;
- 改进方案可以考虑添加一个 kafka topic 或者中间添加一个 mq,整体数据流变更为 kafka1 -> server1 -> mq -> kafka2