正文
TCP Gateway 会根据服务号判断出是 Hybrid 转发服务,解包后将 Payload 直接转发至 HTTP Gateway,此 HTTP 请求对 HTTP Gateway 是透明的,HTTP Gateway 无需区分是 App 直接发来的还是 TCP Gateway 转发来的 HTTP 请求。
后端业务服务处理完成后,HTTP 响应会经 HTTP Gateway 返回给 TCP Gateway,TCP Gateway 将此 HTTP 响应作为 Payload 返回给 App 的 TCP 网络通讯层。 TCP 网络通讯层会再将该 Payload 反序列化后返回给 Hybrid 框架,最终异步回调给 Hybrid 业务调用方。整个过程对于 Hybrid 业务调用方也是透明的,它并不知道 TCP Tunnel 的存在。
采用该技术方案后,携程 App 中 Hybrid 业务的网络服务成功率提升至 99%以上,平均耗时下降 30%,如图 3 所示。
图 3 携程 App TCP 和 HTTP 效果对比图
➤
携程 App 海外网络服务优化
携程目前没有部署海外 IDC,海外用户在使用 App 时需要访问位于国内的 IDC,服务平均耗时明显高于国内用户。我们采用了名为“TCP Bypass for Oversea”的技术方案来优化主要是使用了 Akamai 的海外专属网络通道,同时在携程国内 IDC 部署了局端设备,使用专用加速通道的方式来提升海外用户体验,如图 4 所示。
图 4 携程海外网络通道署图
海外用户启动 App 后先通过 Akamai 定制域名获取 Server IP,所有网络服务优先走 Akamai 通道;如果 Akamai 通道的网络服务失败并且重试机制生效时,会改走传统 Internet 通道进行重试。相比只用传统 Internet 通道,在保持网络服务成功率不变的情况下,使用 Akamai 通道 Bypass 技术后平均服务耗时下降了 33%,如图 5 所示。
图 5 海外网络服务优化前后对比图
➤
携程 App 通信数据格式优化
携程 App 原来使用了自定义的 SOTP 协议格式,底层采用 Socket TCP 协议,为了提高服务响应加载速度,我们优化了 TCP 服务 Payload 数据的格式和序列化/反序列化算法,从自定义 SOTP 格式转换到了 Protocol Buffer 数据格式。此外对数据格式进行了 Gzip 压缩,提升效果非常明显,我们使用 PB+Gzip 后,数据大小下降了 76%,如图 6 和表 1 所示。
图 6 数据序列化大小对比效果图
表 1 数据序列化大小对比效果
基于 PB+Gzip 的优势,我们目前基本上大部分服务都已经迁移到 PB 上来。另外 Facebook 曾分享过他们使用 FlatBuffer 提高性能的实践,可以参考 Facebook 开源的 Blog。
FlatBuffer 是 Google 为游戏平台开放的一个开源项目,它是 Protocol Buffer 的一种进化方案与实现,具有不需要反序列化就能够获取到任意子元素、保持元数据的优点,不需要打包/解包。它的结构化数据都以二进制形式保存,不需要数据解析过程,数据也可以方便传递。所以在性能上很有优势,但是后续我们分析后不太适合携程的业务场景因而最终没有使用。
➤
其他网络相关优化
携程 App 引入了网络质量参数,通过网络类型和端到端 Ping 值进行计算,根据不同的网络质量改变网络服务策略:
-
调整长连接池个数:例如在 2G/2.5G Egde 网络下,会减少长连接池个数为 1(运营商会限制单个目标 IP 的 TCP 连接个数);Wi-Fi 网络下可以增加长连接池个数等机制。
-
动态调整 TCP Connection、Write、Read 的超时时间。
-
不同网络类型状态切换连接机制:例如 Wi-Fi 和移动网络、4G/3G 切换至 2G 时,客户端 IP 地址会发生变化,已经连接上的 TCP Socket 注定已经失效(每个 Socket 对应一个四元组:源 IP、源 Port、目标 IP、目标 Port),此时会自动关闭所有空闲长连接,现有网络服务也会根据状态自动重试。
受 TCP 协议重传机制来保证可靠传输的机制启发,在应用层面也引入了重试机制来提高网络服务成功率。我们发现 90%以上的网络服务失败都是由于连接失败,此时再次重试是有机会连接成功并完成服务的;同时我们发现前面提到的网络服务生命周期处于建立连接、序列化网络请求报文、发送网络请求这三个阶段失败时,都可以自动重试,因为我们可以确信请求还没有到达服务端进行处理,不会产生幂等性问题(如果存在幂等性问题,会出现重复订单等情况)。当网络服务需要重试时,会使用短连接进行补偿,而不再使用长连接。
实现了上述机制后,携程 App 网络服务成功率由原先的 95.3%+提升为如今的 99.5%+(这里的服务成功率是指端到端服务成功率,即客户端采集的服务成功数除以请求总量计算的,且不区分当前网络状况),效果显著。
➤
其他网络服务机制和技巧
携程 App 也实现了其他一些网络服务机制方便业务开发,如网络服务优先级机制,高优先级服务优先使用长连接,低优先级服务默认使用短连接;网络服务依赖机制,根据依赖关系自动发起或取消网络服务,例如主服务失败时,子服务自动取消。
开发过程中我们也发现一些移动平台上的 TCP Socket 开发技巧:
-
iOS 平台上的原生 Socket 接口创建连接并不会激活移动网络,这里原生 Socket 接口是指 POSIX Socket 接口,必须使用 CFSocket 或再上层的网络接口尝试连接时才会激活网络。因此携程 App 启动时会优先激活注册一些第三方 SDK 以及发送 HTTP 请求来激活移动网络。
-
合理设置 Socket 的几个参数:SO_KEEPALIVE 参数确保 TCP 连接保持(注:此 KeepAlive 是 TCP 中的属性,和 HTTP 的 KeepAlive 是两个场景概念),SO_NOSIGPIPE 参数关闭 SIGPIPE 事件,TCP_NODELAY 参数关闭 TCP Nagle 算法的影响。
-
由于 iOS 要求支持 IPv6-Only 网络,因此使用原生 Socket 必须支持 IPv6。
-
如果使用 select 来处理 Non-blocking/IO 操作,确保正确处理不同的返回值和超时参数。
-
保持 TCP 长连接可用性的心跳机制:对于非 IM 类应用而言,心跳机制的作用不大,因为用户会不断触发请求去使用 TCP 连接。尤其在携程业务场景下,通过数据统计发现使用心跳与否对服务耗时和成功率影响极小,因此目前已经关闭心跳机制。原先的心跳机制是 TCP 长连接池中的空闲 TCP 连接每 60 秒发送一个心跳包到 Gateway,Gateway 返回一个心跳响应包,从而让双方确认 TCP 连接有效。
➤
关于 SPDY 和 HTTP/2 协议的探讨
过去两年我们的网络服务优化工作都是基于 TCP 协议实现的,基本达到了优化目标。不过这两年来新的应用层网络协议 SPDY 和 HTTP/2 逐步迈入主流,基于 UDP 的 QUIC 协议看起来也非常有趣,值得跟进调研。