能ping通但是网络不通,是它们在搞鬼( 三 )


有 , 将它们两条路径的成本设置成一样 , 那它们就成了等价路由 , 然后中间的路由器开启ECMP特性 , 就可以同时利用这两条链路了 。带宽就从原来的1千兆变成了2千兆 。数据就可以在两条路径中随意选择了 。

能ping通但是网络不通,是它们在搞鬼

文章插图
 
利用ECMP可以同时使用两条链路
但这也带来了另外一个问题 。加剧了数据包乱序 。
原来我只使用一条网络路径 , 数据依次发出 , 如无意外 , 也是依次到达 。
现在两个数据包走两条路径 , 先发的数据包可能后到 。这就乱序了 。
那么问题又又来了 。
乱序会有什么问题?
对于我们最最最常使用的TCP协议来说 , 它是个可靠性网络的协议 , 这里提到的可靠 , 不仅是保证数据要能送到目的地 , 还要保证数据顺序要跟原来发送端的一样 。
实现也很简单 , TCP为每个数据包(segment)做上编号 。数据到了接收端后 , 根据数据包编号发现是乱序数据包 , 就会扔到乱序队列中对数据包进行排序 。如果前面的数据包还没到 , 哪怕后面的数据包先到了 , 也得在乱序队列中一直等 , 到齐后才能被上层拿到 。
举个例子 , 发送端发出三个数据包 , 编号1,2,3 , 假设在传输层2和3先到了 , 1还没到 。那此时应用层是没办法拿到2和3的数据包的 , 必须得等1来了之后 , 应用层才能一次性拿到这三个包 。因为这三个包原来可能表示的是一个完整的消息 , 少了1, 那么消息就不完整 , 应用层拿到了也毫无意义 。
像这种 , 由于前面的数据丢失导致后面的数据没办法及时给到应用层的现象 , 就是我们常说的TCP队头阻塞 。
能ping通但是网络不通,是它们在搞鬼

文章插图
 
乱序队列等待数据包的到来
乱序发生时2和3需要待在乱序队列中 , 而乱序队列其实用的也是接收缓冲区的内存 , 而接收缓冲区是有大小限制的 。通过下面的命令可以看到接收缓冲区的大小 。
# 查看接收缓冲区 $ sysctl.NET.ipv4.tcp_rmem net.ipv4.tcp_rmem = 4096(min) 87380(default) 6291456(max) # 缓冲区会在min和max之间动态调整
乱序的情况越多 , 接收缓冲区的内存就被占用的越多 , 对应的接收窗口就会变小 , 那正常能收的数据就变少了 , 网络吞吐就变差了 , 也就是性能变差了 。
因此 , 我们需要尽量保证所有同一个TCP连接下的所有TCP包都走相同路径 , 这样才能最大程度避免丢包 。
ECMP的路径选择策略
当初开启ECMP就是为了提升性能 , 现在反而加重了乱序 , 降低了TCP传输性能 。
这怎么能忍 。
为了解决这个问题 , 我们需要有一个合理的路径选择策略 。为了避免同一个连接里的数据包乱序 , 我们需要保证同一个连接里的数据包 , 都走同样的路径 。
这好办 。我们可以通过连接的五元组(发送方的IP和端口 , 接收方的IP和端口 , 以及通信协议)信息定位到唯一一条连接 。
能ping通但是网络不通,是它们在搞鬼

文章插图
 
五元组
然后对五元组信息生成哈希键 , 让同一个哈希键的数据走同一条路径 , 问题就完美解决了 。
能ping通但是网络不通,是它们在搞鬼

文章插图
 
五元组映射成hash键
能ping通但是网络不通,是它们在搞鬼

文章插图
 
根据五元组选择ECMP路径


推荐阅读