0.废话很多,先上结论:
当双栈环境的Nginx使用域名访问公网,需要规避IPv6出访时,可以选择:
- Nginx请求DNS解析时,使其拿不到v6地址,只有v4地址可供选择(推荐);
- Nginx拿到了v6和v4的ip解析后,使操作系统优先使用v4;
- 操作系统直接禁用IPv6(不推荐);
- 中间链路有设备可以主动RST掉v6的请求,加速fallback。
1.故障现象:
微信api服务不可用,Nginx大量抛错
proxy_connect: upstream connect failed (111: Connection refused)…“CONNECT api.weixin.qq.com:443 HTTP/1.1”
connect() to [2402:4e00…1622:5363]:443 failed (101:Network is unreachable)
顾名思义,nginx请求api.weixin.qq.com:443出现问题,且第二条抛错已经明确指出ipv6地址不可达
尝试在LC上使用公网地址,直接对api.weixin.qq.com进行ping测试发现,ping6不可达
这里就基本断定nginx访问api.weixin.qq.com的ipv6地址,有问题了。但此时,并不能确定故障出在整条链路的哪一个点上。
后续在进行ping6测试发现,该域名获取到的v6地址,时通时不通,则进一步确定,故障点应该出现在公网。
2.业务访问链路介绍:
1.内部应用通过正向代理Nginx进行访问api.weixin.qq.com:443请求
2.Nginx通过resolver配置的DNS服务器,解析获取到域名对应的公网地址(这里v4和v6地址均会获得)
3.接下去Nginx服务器使用v6地址进行请求(这里根据操作系统v6优先原则),若v6不可达到,fallback机制使用v4地址进行请求)
4.拿到api.weixin.qq.com的返回后,再转给内部应用,完成正向代理。
问题就在这里,Nginx访问v6地址,请求后需要等待超时,才能fallback转为访问v4地址。(这里v6地址不可达后,大概5s左右开始使用v4地址,但只是临时disable,后面还会继续尝试v6。)
而且api.weixin.qq.com的v6地址并不是一直不可达,有时候是可以访问的。这就导致我们在LC上发现有时候v4v6的请求都存在,tmsh show sys connection cs-client-addr x.x.x.x/x: x: x: x:: x。
这样,故障现象就解释得通了:api.weixin.qq.com的aaaa记录在突然不可访问的时候,一些正在进行中的交易由于报文丢失,导致交易无法完成,同时还触发fallback机制,导致后续一部分交易响应慢。但fallback机制只是临时解决,后续Nginx仍然会继续尝试aaaa记录,依旧会出现交易慢的情况,而v6地址又时通时不通,丢失部分交易报文的现象也持续存在。
3.处理手段
在知道v6访问出现问题的情况下,我们有哪些操作可以规避v6访问呢?或者整条链路上,哪些节点是可以操作v4和v6访问的呢?
- Nginx请求DNS解析时,使其拿不到v6地址,只有v4地址可供选择(推荐);
- Nginx拿到了v6和v4的ip解析后,使操作系统优先使用v4;
- 操作系统直接禁用IPv6(不推荐);
- 中间链路有设备可以主动RST掉v6的请求,加速fallback。
3.1 Nginx只获得v4/v6的解析:
根据Nginx官网文档,默认情况下,nginx在解析时会同时查找IPv4和IPv6地址。如果不希望查找IPv4或IPv6地址,可以指定IPv4 =off(1.23.1)或IPv6 =off参数
解析只获取ipv4:resolver 221.228.255.1 114.114.114.114 valid=5 ipv6=off;
这里非常推荐这种手段,操作影响面小,速度快,而且直接解决根本问题!!!
3.2 操作系统修改v6/v4的优先级:
linux:通过vi/etc/gai.conf ,取消“preced::ffff:0:0/96 100”这一行的#注释
windows:通过修改netsh interface ipv6 set prefixpolicy ::ffff:0:0/96 60 4,将优先级调高至60(大于v6默认优先级50即可)
3.3 禁用操作系统的IPv6(不建议):
非常不建议,取消Nginx的IPv6,相当于正反向代理的全部IPv6服务全部停用,若Nginx已经提供了IPv6的服务给公网用户,那么会有大量的用户拿着IPv6的DNS缓存,无法访问!!!影响当前业务。
3.4 中间设备主动RST掉v6的请求,加速fallback:
那么到这里肯定有人要提出疑问了,整个环节中F5的LTM、LC设备扮演了如此重要的角色,怎么不能通过F5的操作,来改变v6/v4的访问呢?
正向代理接受客户端的请求,以及再帮助客户端向公网进行请求,这两部分是可以分开的。
客户端可以v4请求Nginx,Nginx再向后使用v6请求公网,这并不冲突。因此,本次故障中第一次解决手段中停了Nginx的v6监听,这是一个无效处理手段。
真正要解决的是Nginx访问公网这一段,LTM被排除在外。那这一段路径中,关联的就是LC设备,它将Nginx的ip通过SNAT转换为公网ip,进行出访。那能不能在这一段中,协助Nginx绕开v6的出访呢?
答案是可以,但很极限。
因为对LC来说,它完全不知道api.weixin.qq.com的解析,此时Nginx通过DNS解析并优选v6地址,锚定了一个v6地址后,LC改变不了Nginx的想法。
那么我们有没有手段通过加速fallback过程,来达到秒切v4的效果呢?
经过尝试,我们发现这个5秒的时间也可以通过一些手段加速,比如防火墙策略直接rst掉v6的数据包,或者通过把LC出向的v6-VS禁用,让LC对syn报文进行RST,加速Nginx从v6地址fallback到v4。
如下图所示,瞬间v4:
这里要非常感谢华讯的hydev龙哥帮助验证了fallback机制的现象,以及简单尝试加速fallback过程的可行性!
4.引申
遵循网络圣经RFC规范的情况下,当DNS获取到A记录和AAAA记录时,操作系统都会优先选择IPv6地址(AAAA记录)发起应用层的访问。这里可以看看
为了IPv4平稳过渡到IPv6的,目前业内标准的做法叫Happy Eyeballs。2012年Cisco公司提出第一版HappyEyeballs算法【RFC6555】,2017年Apple公司提出第二版HappyEyeballs算法【RFC8305】。
同时,这里也引申一下不同终端(ios、安卓、浏览器等等)在dns解析时的优先级、A/AAAA查询顺序、切换顺序。
双栈环境终端上网测试分享(双栈DNS解析优先级选择)