我们在谷歌的虚拟机上遇到了一个非常奇怪的问题(类似的部署不会在本地发生(。我们有一个docker-compose部署,其中包含几个微服务。他们通过rabbitMQ进行交流。它们中的大多数还与postgres DB进行了通信(在一个VM上,我们使用容器中的数据库,在另一个VM中,我们使用google-sql服务(。当我们触发一个涉及3-4个服务和DB查询的功能时,整个流程只需不到1秒。但在一段时间的不活动后(我们没有确定确切的时间,但似乎超过了30分钟(,同样的流量需要60秒。我们观察到,当服务正在通信或有查询到DB时,正好滞后20秒。并且只有在非活动时间后的第一个请求才会发生这种情况。
当我们在我们的一个服务上观察到tcp连接时,一切似乎都很好,比如:
$ sudo nsenter -t 9389 -n netstat -tnope
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name Timer
tcp 0 0 192.168.192.10:59372 192.168.192.11:5672 ESTABLISHED 0 37791595 10732/python keepalive (38.80/0/0)
tcp 0 0 192.168.192.10:59374 192.168.192.11:5672 ESTABLISHED 0 37791599 10732/python keepalive (38.57/0/0)
tcp 0 0 192.168.192.10:59376 192.168.192.11:5672 ESTABLISHED 0 37791604 10732/python keepalive (37.94/0/0)
tcp 0 0 192.168.192.10:59402 192.168.192.11:5672 ESTABLISHED 0 37792668 10732/python keepalive (38.07/0/0)
tcp 0 0 192.168.192.10:50634 10.89.128.3:5432 ESTABLISHED 0 37793882 10732/python keepalive (38.13/0/0)
它们一直都在建立,即使问题发生了。我们试图更改keep_alive系统设置(从def7200改为60秒(,但无济于事。看起来打开的TCP连接(如rabbitMQ通道或DB连接池(确实超时了,但我们找不到它们在哪里超时-就像我们上面提到的一样,netstat没有看到连接中断。我们也在跟踪TCPDUMP,这里没有显示任何错误。我们在应用层上也没有出现错误。除了那20秒的滞后,没有什么错。我们只能找到一个证据来证实我们对TCP超时的猜测,那就是这个命令:
$ sudo nsenter -t 9389 -n netstat -s
Ip:
Forwarding: 1
1182 total packets received
0 forwarded
0 incoming packets discarded
1182 incoming packets delivered
1221 requests sent out
Icmp:
0 ICMP messages received
0 input ICMP message failed
ICMP input histogram:
0 ICMP messages sent
0 ICMP messages failed
ICMP output histogram:
Tcp:
30 active connection openings
0 passive connection openings
12 failed connection attempts
0 connection resets received
5 connections established
1068 segments received
1099 segments sent out
8 segments retransmitted
0 bad segments received
1 resets sent
Udp:
114 packets received
0 packets to unknown port received
0 packet receive errors
114 packets sent
0 receive buffer errors
0 send buffer errors
UdpLite:
TcpExt:
5 TCP sockets finished time wait in fast timer
33 delayed acks sent
Quick ack mode was activated 2 times
243 packet headers predicted
169 acknowledgments not containing data payload received
267 predicted acknowledgments
TCPLostRetransmit: 7
TCPTimeouts: 10
TCPDSACKOldSent: 2
1 connections reset due to unexpected data
1 connections aborted due to timeout
TCPRcvCoalesce: 27
TCPSpuriousRtxHostQueues: 1
TCPOrigDataSent: 391
TCPKeepAlive: 118
TCPDelivered: 407
IpExt:
InOctets: 107606
OutOctets: 107275
InNoECTPkts: 1192
在上面的统计数据中,我们可以观察到,每当出现问题时,字段计数器"TCPTimeouts"就会增长。所以,我们不知道谷歌的内部架构,但看起来tcp连接可能在一些中间层上是关闭的。因此,从应用层(连接在docker compose网络内部(来看,一切似乎都很好,但肯定是在某个地方tcp连接超时,新的连接以静默的方式创建。
我们使用的技术堆栈是:python、nameko、psql、rabbitmq。这是很普通的东西,但我想这与问题没有太大关系。
有人在谷歌的GCP上遇到过类似的问题吗?
我认为这种行为与应用程序配置与数据库服务器连接的方式有关。我发现了这个链接;限制连接的生存期有助于防止废弃的连接累积。您可以使用连接池来限制您的连接寿命"它看起来像是"0"的默认值;pool_recycle";是30分钟,这与您提供的估计值相匹配。正确调整这些设置可能有助于解决问题或找到原因。本文档还解释了为Ms-SQL Server创建连接字符串时的工作原理,请注意,情况可能并非如此,但它有助于理解它如何与任何数据库服务器一起工作。此外,他们提到的恢复正常连接后的60秒超时可能是由于本链接中描述的SQL服务器内部如何处理读取数据包。该链接是特定于MsSQL的,但是对于任何风格的SQL服务器,该行为都应该是正确的(请参阅蓝色的第二条注释(。您还可以查看其他讨论类似部署的线程。