写点什么

百度 App 网络深度优化系列(番外篇):IPv6 下 Happy Eyeballs 的最佳实践

2019 年 12 月 25 日

百度App网络深度优化系列(番外篇):IPv6下Happy Eyeballs的最佳实践

一、前言

IPv6 是当下如火如荼的话题,由于 IPv4 地址的耗尽,所以 IPv6 的切换已经势在必行。但在 IPv6 的初期,由于基础建设还不完善,IPv6 可能会出现连通性或可靠性的问题,那我们该如何从 IPv4 平稳过渡到 IPv6 呢?


目前业内标准的做法叫 Happy Eyeballs,什么叫 Happy Eyeballs 呢?就是不会因为 IPv4 或 IPv6 的故障问题,导致用户的眼球一直在等待加载或者出错,这就是 Happy Eyeballs 名字的由来。


二、背景

Happy Eyeballs 解决的核心问题是,复杂环境下 v4 和 v6 IP 选取的问题,它是一套整体解决方案,对于域名查询的处理,地址的排序,连接的尝试等方面均做出了规定。


Happy Eyeballs 有 v1 版本 RFC6555(Cisco 提出来的)和 v2 版本 RFC8305(Apple 提出来的)。具体的协议规范可参考资料【1】和【2】。我们从百度 App 对于 Happy Eyeballs 的实践出发,剖析下百度 App 是如何实现 Happy Eyeballs 的。


三、最佳实践

百度 App 的 Happy Eyeballs 最佳实践,如下图所示。



Happy Eyeballs 最佳实践


最佳实践包括自有业务和核心组件(图片组件,音视频组件,WebView 组件)底层网络库的流量接管。


网络库包括 FFmpeg 的网络模块(实现了 RFC8305 的 Happy Eyeballs),okhttp(实现了 RFC6555 的 Happy Eyeballs),统一网络库 cronet(实现了 RFC6555 的 Happy Eyeballs)。下面我们来看下这三个网络库的 Happy Eyeballs 的实现机制。


1.FFmpeg 的 Happy Eyeballs 实现机制

我们从域名查询的处理、地址的排序、连接的尝试三个方面来说明。



FFmpeg Happy Eyeballs 实现机制


域名查询的处理,FFmpeg 主要流量走的是 localDNS,会将 v4 和 v6 地址一并查询回来,DNS query 中 A 记录表示 v4 查询,Type 是 1,AAAA 记录表示 v6 查询,Type 是 28。具体协议可以参考下面两图。



IPv4 的 Query



IPv6 的 Query


地址的排序,如果查询回来是多个 v4 和 v6 的地址,会将查询结果保存在 addrinfo 这个结构体里,它是一个链表结构,会将这个链表交替排序,v6 在前,v4 在后,比如查询回来的是[第一个 v4 地址,第二个 v4 地址,第一个 v6 地址,第二个 v6 地址],排序之后变成[第一个 v6 地址,第一个 v4 地址,第二个 v6 地址,第二个 v4 地址]。


连接的尝试,立即连接 v6 地址,FFmpeg 可以让使用者设置连接超时时间,会将这个超时时间和 200ms(这是 RFC8305 建议的值)进行取小操作,如果在较小值以内 v6 建连成功,则结束,若以外将发起下一个 v4 连接,与此同时关闭当前的 v6 连接。延迟发送的 v4 连接将重复上面的操作,如果成功则结束,如果超时将发起下一个 v6 连接,与此同时关闭当前的 v4 连接。直到没有 ip 地址。


2.cronet 的 Happy Eyeballs 实现机制

我们从域名查询的处理、地址的排序、连接的尝试三个方面来说明。



cronet Happy Eyeballs 实现机制


域名查询的处理,百度 App 的 cronet 主要流量走的是 HTTPDNS,HTTPDNS 请求会将一个域名的 v4 地址和 v6 地址同时返回。


地址的排序,cronet 开启 Happy Eyeballs 有两个条件,一是查询结果第一个地址是 v6 的,二是查询结果里包含 v4 和 v6 的地址。cronet 会优先将 v6 地址放入结果列表,保证了第一点。


连接的尝试,立即连接 v6 地址并开启一个延迟 300ms(这是 RFC6555 建议的值)发起 v4 的建连任务,如果在 300ms 以内 v6 建连成功,延迟任务直接终止,流程结束。若以外会将结果列表进行 rotate,按顺序将列表里的第一个 v4 地址旋转到第一个,发起 v4 连接,此时将开启一个竞争模式,当 v4 开始建立连接和建连成功后,都会去检查 v6 是否成功,只要 v6 在竞争模式内建连成功,则使用 v6 的连接,v6 没有建连成功,则使用 v4 连接。


3.okhttp 的 Happy Eyeballs 实现机制


okhttp Happy Eyeballs 实现机制


百度 App 依照 cronet 的实现细节,遵循 RFC6555 的规范,实现了 okhttp 版本的 Happy Eyeballs,由于实现细节和 cronet 类似,所以就不在这里进行讲解。主体流程如上图,通过 okhttp 的请求并发控制模块(核心定义了最大线程数 64 个和单域名的最大并发数 5 个),再来到核心拦截器模块,包括对于 Header 和 Cookie 处理的拦截器,对于 Cache 处理的拦截器,对于连接处理的拦截器,在连接处理的拦截器里首先是从连接池获取连接,获取不到就会新创建连接,Happy Eyeballs 的实现就会加到这里。


4.WKWebView 的 Happy Eyeballs 实现

在某些场景下 WKWebView 没有被 cronet 网络库进行接管,所以还需要依赖苹果自身的 Happy Eyeballs 机制,在这里就不多赘,感兴趣的同学可以参考资料【3】,苹果的工程师会详细讲解如何实现 Happy Eyeballs 的机制以及 Happy Eyeballs 下走 v6 的测试结果。


四、结语

IPv6 的进程是任重而道远的,Happy Eyeballs 做为从 v4 过渡到 v6 的重要规范必然会起到它应有的使命,详尽了解它并使用它应该是每个相关工程师的职责,希望本次番外篇对大家有帮助,感谢大家的辛苦阅读。


参考资料

[1]https://tools.ietf.org/html/rfc6555


[2]https://tools.ietf.org/html/rfc8305


[3]https://mailarchive.ietf.org/arch/msg/v6ops/DYiI9v_O66RNbMJsx0NsatFkubQ


[4]https://git.ffmpeg.org/gitweb/ffmpeg.git/commit/9b4c3f5aadf54ffd2a6e15746b1fd736379883c4


作者介绍:


蔡锐,9 年移动端开发经验,在百度先后主导过订制 ROM 领域、多屏互动领域、Hybrid 跨平台领域等多个技术领域的开发,目前担任百度 App 的客户端资深工程师,参与基础技术的研究,专攻动态化、性能和网络优化方向。获得 2019 软件绿色联盟最佳人气讲师、2019ArchSummit 大前端专题明星讲师。


相关文章:


百度App网络深度优化系列(一):DNS优化


百度App网络深度优化系列(二):连接优化


百度App网络深度优化系列(三):弱网优化


2019 年 12 月 25 日 08:041339

评论

发布
暂无评论
发现更多内容

去掉美颜和滤镜后的数字货币

亨利笔记

比特币 区块链 数字货币 DCEP libra

详解iOS性能优化,安装包瘦身

Usama Bin Laden

ios 源码分析 性能优化 性能 原理

系统的伸缩性以及扩展性设计

Janenesome

读书笔记 程序员 架构

[读书随笔]从哲学上的问题分类看TDD

老狗

哲学 TDD

JAVA小抄-000-初始

NoNoGirl

Java

在InfoQ上开博的第一天

罗琦

开博 文章链接

赚钱的6个层次

品牌运营|陆晓明

创业 技术人 赚钱思维 层次 商机

新人工作的时候遇到问题怎么办

波波

学习 编程 职场 新人

基于vue(element ui) + ssm + shiro 的权限框架

吴邪

在今天种下一棵树

陈医僧Ethan

感悟 育儿

瞎琢磨先生の好物推荐(软件/网站)

瞎琢磨先生

python面向对象的魔法方法详解

半面人

Python

年轻人的世界

boyzcl

年轻人 系列

关于「后浪」,ta 们在说什么?

boyzcl

年轻人 系列 后浪

信仰

小天同学

人生 个人成长 思考 读书感悟 信仰

关于沟通成本的一些认知

大鱼读书

项目管理 软件开发

我的编程之路-1(启蒙)

顿晓

编程 入门 启蒙 经历 故事

从每个Python文件快速得到项目根目录的绝对路径

良少

Python 路径 绿色

Redis源码之常用数据结构和函数

心平气和

redis

Hello World !

ATGU:阿宝哥

Java Hello World ! Info

开张咯~

李绍俊

生活 随想

开通InfoQ写作平台测试

ytl

瞎琢磨先生の常用的 linux 命令

瞎琢磨先生

Linux Shell

对你来说,阅读是另一种生活的方式吗?

叶小鍵

准备重读测试驱动开发

escray

学习 CSD 认证实战营

LeetCode 1396. Design Underground System

liu_liu

LeetCode

UITableView 手势延迟导致subview无法完成两次绘制

AlienJunX

技术人赚钱的9个路线

品牌运营|陆晓明

副业 赚钱 技术人 码农 生财有术

关于CodeReview的一些思考

Yezhiwei

我也曾对架构师的力量一无所知

曲水流觞TechRill

Redis学习笔记(基础命令)

编程随想曲

redis

2021年全国大学生计算机系统能力大赛操作系统设计赛 技术报告会

2021年全国大学生计算机系统能力大赛操作系统设计赛 技术报告会

百度App网络深度优化系列(番外篇):IPv6下Happy Eyeballs的最佳实践-InfoQ