我使用 gRPC 在 Java(在主机上运行)和 Python(在我的 Guest VM 上运行)之间进行通信。我的软件在启动时使用 libvirt 设置一些 VM。我使用 DHCP 范围指定我的网络,如下所示:
<network>
...
<ip address='192.168.122.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.122.128' end='192.168.122.254'/>
<host mac="00:16:3e:77:e2:ed" ip="192.168.122.128"/>
<host mac="00:16:3e:3e:a9:1a" ip="192.168.122.129"/>
...
</dhcp>
</ip>
...
</network>
一切设置完毕,虚拟机开始运行后,我会为每个虚拟机创建快照。现在,软件的工作流程如下:打开 gRPC 接口,使用上面指定的 IP 为客户虚拟机获取 mac 地址,设置正确的时间(现在的时间,由于快照和没有互联网访问而有所不同),做一些工作,然后恢复快照并重复。
在虚拟机上的 Python 代码中,我每 5 秒向主机发送一次 ping 消息(类似于心跳)。大多数情况下,这都运行正常,我会在 Java 代码中在主机上收到消息。但是,有时我会在 3 分钟内不再在主机上收到消息(之后我会抛出自定义超时异常)。Python 代码中没有错误或无限循环,Java 端也没有收到任何异常。所以问题一定出在其他地方。
在检查这种奇怪行为的原因时,我发现了 DHCP 租约时间。我的虚拟机从通过 libvirt 配置的 DHCP 范围中获取其 IP(见上文)。DHCP 租约设置为 1 小时后到期。有趣的是,心跳消息的这种超时通常发生在(如果发生,并非总是发生)我制作初始快照并从中恢复后约 1 小时。我的问题是否与 DHCP 租约续订过程有关,其中虚拟机突然处于不再具有其初始 IP 的状态?例如,我打开与 192.168.122.128 的 gRPC 连接,获取心跳消息,突然由于 DHCP 租约到期,IP 发生变化,并且 gRPC 无法传递任何进一步的消息?如果这可能是问题所在,我该怎么做?
我还运行了一个自定义测试,在该测试中,我打开与虚拟机的 gRPC 连接,然后手动更改虚拟机上的 IP 地址,然后将其更改回其原始 IP。然后我观察到完全相同的行为:3 分钟后我收到超时异常,因为在我手动更改后没有再收到任何心跳消息。因此,我强烈感觉到虚拟机上的 IP 以某种方式发生了更改,这可能与即将到期的 DHCP 租约有关,这会干扰 gRPC 连接。
这可能是问题所在,还是可能是完全不同的东西导致了 gRPC 连接出现问题?我能做些什么来解决这个问题?任何帮助或进一步的阐述都将不胜感激。
答案1
我很确定大多数 gRPC 卡住的情况都可以追溯到 DHCP 租约时间续订。我还怀疑,一般来说,当 DHCP 服务器在任何时间点都无法访问时,gRPC 连接就会卡住(我通过手动设置系统时间和从命令行调用来测试这一点ipconfig /renew
。然后我首先遇到 DHCP 超时,但之后它工作正常。但结果是 gRPC 卡住了,即使我再次获得了相同的 IP)。由于我仍然不完全了解 DHCP 租约续订的行为以及查询 DHCP 服务器及其超时的一般事项,我决定不再摆弄它。我决定对我的 VM 快照使用静态 IP(禁用 DHCP)。如果有人遇到同样的问题,您可能想尝试一下。希望它有所帮助。