# 服务器不支持IPv6引起的网络连接超时
8月26日中午接到QA信息,部分用户反馈中配保网络连接巨慢,由于身边没有真机,不能进行场景复现。临时提供web服务解决用户问题。
8月27日进行真机测试,在移动网络的环境下,复现问题。在Android的帮助下review代码,未发现异常代码。怀疑是某个配置/DNS解析问题导致,随即搜集了一些资料 (opens new window)。但由于有其他优先级较高任务未深入。
8月28日再次debug,隐约发现有一处异常
okhttp3.internal.connection.RouteException: java.net.SocketTimeoutException: failed to connect to mobileapi.qipeipu.com/64:ff9b::79c9:1078 (port 443) from /2409:8955:4d0:6097:a263:657:3094:6c08 (port 42236) after 10000ms
由于网络知识匮乏,当时怀疑是DNS解析出错,后去向运维求证,得知服务器不支持IPv6。
[Online Ping IPv6 (opens new window)]
IPv6 Ping Output:
PING mobileapi.qipeipu.com(64:ff9b::79c9:1078 (64:ff9b::79c9:1078)) 32 data bytes
--- mobileapi.qipeipu.com ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3000ms
---- Finished ------
定位到问题,给出临时解决方案。
- 设置
- 更多(无线和网络)/移动网络
- 接入点名称
- 选择默认的接入点
- 【APN协议】和【APN漫游协议】设置成IPv4
- 保存
8月29日搜索相关资料
http://square.github.io/okhttp/3.x/okhttp/okhttp3/Dns.html (opens new window)
在Android同事的帮助下,实现了DNS解析选择器。
public class DnsSelector implements Dns {
...
addresses = Dns.SYSTEM.lookup(hostname);
switch (mode) {
case IPV6_FIRST:
Collections.sort(addresses, IPv6FirstComparator);
break;
case IPV4_FIRST:
Collections.sort(addresses, IPv4FirstComparator);
break;
case IPV6_ONLY:
List<InetAddress> newInet6Addresses = new ArrayList<>();
for (InetAddress inetAddress : addresses) {
if (Inet6Address.class.isInstance(inetAddress)) {
newInet6Addresses.add(inetAddress);
}
}
addresses = newInet6Addresses;
break;
case IPV4_ONLY:
List<InetAddress> newInet4Addresses = new ArrayList<>();
for (InetAddress inetAddress : addresses) {
if (Inet4Address.class.isInstance(inetAddress)) {
newInet4Addresses.add(inetAddress);
}
}
addresses = newInet4Addresses;
break;
}
return addresses;
}
...
}
当天下午修复上线。
后续的思考:
为什么Sentry没有监听到网络连接异常?
答:Sentry默认只会捕捉应用崩溃异常,需自己实现caught其他异常的方法。
为什么用户只反馈慢而没出现网络网络错误提示?(干扰问题定位)
答:由于okhttp的重试机制 (opens new window),默认的如果连接到路由有超时会尝试下一条路线(如果有的话)。
# 问题出现原因
- 服务器不支持IPv6
- 路由连接时间过长(10s)
# 总结
定位这个bug的花费大量时间的主要原因是
- 没有深度debug,认定问题不会出现在okhttp上。
- 由于有其他任务没有跟app组深度协作定位问题,个人知识面窄。