一、引言
下图示为手淘网络协议演进关键节点。2015年为优化标准TLS/1.2握手慢问题,我们自行研制上线了轻量级私有加密协议Slight SSL来优化握手与加密问题,在没有重放攻击风险时允许将会话协商和数据加密放在一个TCP报文中来实现0-RTT,目前手淘线上流量HTTP2+SlightSSL也是主要承载者。与此同时过往问题排查/业务接入/业务诉求面临一些疑难或者无法满足诉求问题,诸如 "WI-FI下长链全失败降级短链https可以成功,切换到4G网长链正常使用(SlightSSL私有协议被wifi防火墙断开)"、"你们计划支持TLS1.3吗?"、"我们域名接入服务端不支持部署SlightSSL"等;另一方面随着QUIC RFC9000、HTTP3 RFC9114正式发布,将手淘网络协议演进到HTTP3/QUIC不管是解决Slight SSL私有协议在业务上痛点,还是为了提高网络传输性能提升用户体验,同时也是当下网络协议向前演进的大势所趋。私有化协议带来高效网络体验的同时,归纳起来问题主要集中在以下三点:
- 私有化的协议意味着更定制,需要端到端的部署支持(侵入性)
- 不支持TLS1.3
- 偶有网络中间设备因私有协议同时断开两端连接
二、TNET能力演进
TNET 全称 TAOBAO NET,是在手淘无线化发展和演进中,逐步形成的一套底层网络基础能力库。目前承载了手淘 90%+的业务HTTPs数据流量(少量域名AMDC未配置长链协议),作为集团网络服务在端侧落地的基石,是端上到服务端的长链通道端侧入口,同时也是端上网络相关中间件的底层基础。经过演进完善目前对上层提供丰富可组合的协议搭配,内部对不同协议进行实现&抽象适配,对外接口上提供统一的接口,外层只需要在建联时传入不同组合协议类型即可,做到真正意义上的简单易用。目前内部功能上主要有两大块:
- 一块由SPDY/HTTP2/HTTP3/Custom/HTTP3/Tunnel对上层满足HTTP网络请求/上传私有协议通道/ACCS消息网络通道能力(其中标准TLS主要为海外等部分不支持SlightSSL部署业务使用,标准HTTP2目前采用分支维护未合入手淘主干,原因主要基于手淘集成下包大小考虑,手淘下SlightSSL即满足业务要求且性能更高)
- 另一块为提供自实现DNS解析/traceroute/MTU探测/ICMP PING探测/IPv4&IPv6协议栈探测能力,主要偏网络工具属性满足上层对网络诊断/探测能力的支持,以及部分对原生DNS接口失败情况下系统能力的补充。
三、HTTP3/QUIC协议升级提性能
端云升级技术改造方案
XQUIC作为手淘自研IETF QUIC标准的协议库具备完全自主可控快速演进的优势,关于XQUIC协议库的设计部分组内同事已有多篇文档进行详细的介绍不再重复,感兴趣的可通过本文尾部的相关文章链接查看。回到端上TNET网络库来说,通过适配XQUIC库全面升级增加支持七层HTTP3协议和四层QUIC协议,同时对外屏蔽掉各协议实现上的差异,上层只需建联时选择不同的协议类型即可,满足多种业务场景下不同诉求。
端侧降级&快恢
端上会先从amdc拉取一组策略 (amdc可以理解为一个扩展的httpdns域名解析服务,不仅会返回域名对应的ip,还有支持协议等扩展属性),这时amdc会同时下发http3&http2协议(端上优先使用http3,同时下发http2协议是为确保有兜底长链协议),拿到http3协议后会先进行udp连通性探测规避udp受限问题,只有当前网络环境探测通过后的才会新建HTTP3长链,关于探测部分文章后面会有介绍。
升级效果
大盘升级进度&效果
前年在手淘重点联路完成IPv4流量部分的HTTP3升级覆盖,去年随着Aserver主站内网QUIC IPv6链路改造完成,我们将导购/交易/短视频/上传链路原先走TCP+IPv6这部分流量也全部切到QUIC,目前手淘里这几个重点场景已完成全部覆盖升级。效果上大盘/业务AB数据显示HTTP3/QUIC在这些不同类型业务场景下都取得显著提升,助力业务实现好网(传输速率/均值耗时)更好,弱网(长尾耗时&成功率)更优,为用户带来更顺滑的网络体验。除此之外,阿里集团内其他如菜鸟、手猫、AliExpress等APP也复用我们方案进行HTTP3升级覆盖,拿到更优网络体验的业务收益数据。以下是手淘上收益提升情况:
- 导购场景:网络总耗时均值/P99降低22%/33%,一秒完成率提升1.2pt;
- 交易场景:网络总耗时均值/P99降低23%/32%,一秒完成率提升0.55pt;
- 上传场景:视频/图片 上传速率提升7.7%/21%,成功率提升0.18pt;
- 短视频下载:网络总耗时均值/P99降低15%/16%,下载速率提升18%;
典型业务场景效果
互动场景中断率
在互动业务下AB实验数据显示升级HTTP3实验桶可有效降低互动中断UV数/流失UV数。Android HTTP3 AB实验桶中断UV数/中断流失UV数分别降低 24.02%/22.89%,IOS端实验桶分别降低20.91%/18.57%。
购物车&详情
今年手淘购物车改版后为用户下单带来了便捷,但同时也面临网络传输体验上耗时长的业务痛点问题,通过切换到HTTP3后从业务大盘耗时均值下降明显,给业务带来更多可能。如下图所示为HTTP3升级推量后接口大盘耗时变化趋势。其他详情/首页等接口也有类似表现,这正是由于升级后传输性能的提升所带来。
落地问题&优化
UDP穿透性问题
因部分运营商和网络中间设备可能存在将udp包丢弃的策略,这将拉低大盘建联成功率并导致降级率显著变高,往往需要等建联超时后才会降级重试成功,这显然会增加重试耗时导致不好用户体验。
对此我们设计了udp联通性探测,在启动阶段或者络环境发生切换时会触发异步探测,该探测结果会根据网络环境持久化到本地,在探测结果过期后会重新触发探测更新。这样确保了即使udp不通情况下,对上层业务体验也不会有劣化影响,而在探测通的环境下使用HTTP3/QUIC将为用户带来更优的用户体验,线上全国大盘的udp穿透性探测成功率数据平均值一开始在95%左右,经过对UDP质量差的VIP治理/下线历史不支持UDP端口特殊调度配置/运营商对某些UDP IP网段去黑名单处理,目前全国udp探测成功率均值提升到98%。
UDP端口NET-rebind问题
在TCP下五元组便唯一确定一条连接,过往我们SLB和CDN LVS的负载均衡分发基础算法都是基于5元组来实现,这在TCP下可以很好的满足要求。升级为QUIC协议后基于五元组转发对连接迁移(Connection Migration)和 多路径(Multipath QUIC)的能力就无法支持,因为在这两类场景下5元组都会发生变化。比较理想的是基于CID进行一致性hash转发,这也是QUIC协议设计之初便与5元组解耦考虑,关于基于CID分发感兴趣的可以查看草案QUIC-LB。回到我们落地由于涉及到SLB/LVS基建改造周期较长,受此影响一开始在单路落地我们基于5元组转发(舍弃掉连接迁移能力)进行业务应用,这在大多数情况下已经满足要求但也面临一些问题。NAT 网关针对 UDP 的 Session 存活时间普遍较短,在移动端因为用户切后台空闲情况下容易发生UDP端口NET-rebind问题,这时通过5元组转发下将无法分发到目标服务器,便会出现因为找不到连接上下文而导致连接中断即使当前网络正常。
如下图所示,客户端QUIC连接Q首先从NET设备源出口端口1被SLB转发到Server A上,连接Q从客户端到Server A链路双向转发传输正常;某个时刻如果连接Q对应的UDP Session空闲(如用户切后台)超过NET设备保活时间,APP与出口端口1之间映射将失效;等用户回前台触发发包后,NET设备重新建立起APP到出口端口2的新映射,此时客户端上来的包将被SLB转发到另一台Server机器C上,而在C机器上是找不到QUIC连接Q对应的上下文,这时会回复RESET导致连接中断,从我们数据看华为机型比例高于其他厂商。问题已经清楚通过CID转发来确保端口NET-rebind前后路由的一致性,当Servre端检测到新的5元组后触发连接迁移便可得到解决。
0RTT比例提升
在首次建连握手时,服务端会给客户端返回Session ticket和传输参数,客户端在Session ticket缓存有效期内,下一次握手即可在client-hello之后直接发送加密数据。同时Session ticket自动到期失效后可以退回1-RTT更新,在减少握手延迟的前提下,相较于公钥预置的方案更优,兼顾前向安全性。手淘上目前在完成首次1RTT建联后,我们会将Session ticket和传输参数存储在安全保镖中以确保缓存的安全性。在项目上线初期,提升效果并不那么理想,网络总耗时相较于H2提升约15%左右,分析数据在首包耗时方面与H2几乎保持持平这显然不符合预期,通过数据看0RTT连接比例一开始只有40%左右,经过优化缓存有效率后0RTT比例由40%提升到了65%(该比例还有进一步提升空间,短视频场景0RTT比例目前在80%+),网络总耗时相较H2的提升由15%提高到了20%左右。
业务非加密诉求
对于一些短视频业务,响应大小相比RPC场景更大,且基本都是明文传输对加密诉求弱,更关注视频拉流的速率。为此我们在XQUIC中实现了加密/明文协商能力,在握手完成后如果协商结果为明文传输,则后续包都不再进行加密,这可有效降低server端/客户端加解密的处理开销,进而提升性能。
XQUIC协议栈性能优化
除前面优化外我们还对协议栈进行深度优化,就XQUIC库本身协议处理性能提升85.93%,对比nginx-quic在处理性能上也有15.62%的提升。
图3.8 XQUIC库协议栈优化对比数据
XQUIC库处理模型
下图是XQUIC协议栈最简化模型:对于发送方而言,XQUIC会把一段有序字节流封装成QUIC报文发送出去,对于接收方来说,是把一个个无序的QUIC报文组装成一段有序的字节流。
整体性优化
我们思考下优化CPU开销的核心是什么?为了回答这个问题,我们先想想CPU上跑的是什么?没错,就是指令集。那么指令集是怎么来的呢?它是由汇编语言生成的。汇编语言是怎么来的呢?他是由高级编程语言生成的。因此,我们至少可以想到以下三个方面可以优化:
- 编程语言:也就是你的代码,选择一个合适的编程语言,然后想办法写的性能高一点
- 编译
- 编译优化,可以开的编译优化选项都开起来
- 编译器,选择一个高性能的编译器
- 指令集:这个我们能做的比较少,服务端一般都是X86
- 组包优化:回到上面的问题,优化CPU开销的核心是什么?本质上就是减少完成一个功能所需的指令数。注意看XQUIC的简化模型,每收到一个QUIC报文,都需要一系列的函数操作,最终输出一段流。相反的,每发送一段流,都需要调用一系列函数,最终输出一个个QUIC报文。我们要完成的功能就是把一段流传输给对端,我们可以优化处理每个包的一系列函数的性能,但是减少函数调用次数是不是来的更高效。减少QUIC报文数能大幅提升性能,在协议允许的范围内尽量填满每一个报文。
局部性优化
- 能不能不调
- 避免无效计算
- 避免重复计算 :每次加解密包都创建加解密上下文,并且初始化密钥 -> 握手完成时或者密钥改变时创建加解密上下文,并且初始化密钥
- 能不能少调
- 减少内存拷贝:业务拷贝到H3层再拷贝到传输层 -> 业务拷贝到传输层
- 尽早退出循环:特别是遍历的列表很长时
- 优化函数性能
- 空间换时间 :huffman解码表 用4K数组存储,每次解码4bits -> 用64K数组存储,每次解码16bits
- 函数内联
- 分支预测 :likely()/unlikely()
四、集团全链路压测协议升级
amazon全链路平台升级HTTP3
在手淘客户端导购&交易场景HTTP3大规模放量后,随之而来的大促全链路压测流量模型中协议占比也发生改变,全链路压测需同时支持HTTP2+HTTP3协议,对此我们对集团全链路压测引擎amazon平台进行一次大的改造升级支持HTTP3协议压测。
不同于HTTP2基于TCP的已经过多年大促&压测多轮验证过的稳定链路,HTTP3基于UDP的全新链路在大促脉冲下的表现则显得缺少大促经验,确实通过压测前验证助力我们提前发现UDP新链路下一些问题,针对解决后最终确保双十一大促HTTP3平稳顺利。碰到的问题主要有:
- 1、udp_hash查找性能差问题:在quic连接数多的情况下,系统udp_hash查找的性能会急剧下降,易打满系统软中断而无法及时处理超时。内核对该问题进行过优化,4.19之前内核版本需要打patch,4.19及之后的版本已自带,该查找优化需通过设置socket option 来启用,为此我们升级内核版本到4.19。
setsockopt(s, SOL_UDP, 200, (const void *) &value, sizeof(int)
- 2、内核对udp丢包问题:升级4.19内核后在pps高的情况下又碰到udp丢包问题,原因在于4.19内核对udp内存存在限制。具体原理:
1. 对每个UDP session内核会把使用的内存计数,并累积到一定值(与rcvbuf正相关)才释放 2. 内核会记录所有UDP的的内存计数和,当这个计数和大于限制值(与umem正相关 )时 ,将会丢弃所有的UDP报文。
不难看出该问题会导致我们单机长链数和应对突增流量的受限,为此我们两个优化参数调节方向:
1、增加umem值 2、缩小recvbuf值。
五、 正在进行
HTTP3覆盖图片域名
当前我们完成导购、交易、短视频、上传链路的全量升级覆盖,图片域名的升级覆盖还在逐步灰度覆盖中。
HTTP3 over MPQUIC规模化应用
MPQUIC改造涉及到客户端、SLB、Aserver等基建的升级,目前RPC链路端到端整条链路已经改造完成。手淘Android已正式上线目前处在规模化放量阶段,能力上提供两种可选模式(长尾补偿模式和多路并行加速模式),从灰度数据看加速模式下MPQUIC相比单路QUIC还有8%进一步速率提升,目前XQUIC实现的MPQUIC已对外开源。CDN链路MPQUIC支持改造Server端和LVS正在进行中。