B站端侧DCDN容灾演练实践

一、 背景

网络请求的质量是互联网产品一切交互的前提,尤其对于B站这种大流量业务场景,动静态资源的快速、可靠分发是提供优质用户体验的关键。因此大量的静态资源缓存在边缘节点,供不同区域的用户就近访问;动态资源基于智能选路技术,从众多回源线路中择优进行传输。享受全局动态加速的同时,DCDN的稳定性变得至关重要。

二、演练探索

2.1 演练目标

在整个DCDN加速过程中DNS解析扮演着最重要的角色之一,DNS一般默认使用运营商的 LocalDNS,然而LDNS有着容易被劫持、DNS调度不准确等问题。业界成熟的方案是使用 HTTPDNS,与传统的DNS解析方式不同,集成 HTTPDNS 的客户端可以绕过 LocalDNS,直接向 HTTPDNS 服务发送DNS查询请求,服务端根据所属运营商和地区等综合信息,经过服务评分模块,确保用户请求被引导到最优的边缘节点。当然,出于容灾考虑,依然保留LocalDNS作为备选。

图1:DCDN加速过程

市面上固然有一些成熟的商业HTTPDNS服务供选择,但面对B站庞大的用户基数和不断增长的业务体量,早在22年B站就已经完成了自建HTTPDNS的道路。一次完整的网络请求大致包括,连接管理、DNS解析、IP选取汰换、域名调度策略、CDN加速等,各模块承担着不同的重要作用。面对如此复杂的网络请求链路,端到端验证不同网络状况、不同调度策略下,其容灾方案的高可用性尤为重要。

2.2 演练场景

带着上述目的,最初我们通过mock的方式进行摸排,对HTTPDNS 服务接口请求的状态码、响应内容中的域名、v4\v6 IP(单个错误、多个错误、部分错误)分别进行拦截篡改,观测客户端表现及其对应日志。整理出客户端网络请求的大致链路如下,将重点的演练方向聚焦在以下几点:

  • DNS cache & TTL:客户端 DNS 本地缓存是否存在,TTL 过期时间多久

  • HTTPDNS:自建、商业 HTTPDNS 流量分配,HTTPDNS 服务状态

  • DCDN:节点服务状态、IP 是否有效

  • 客户端域名降级策略:什么情况会触发域名降级,需要多久,哪些域名会降级?降级成功后的请求域名是否一直不变

图2:客户端网络请求整体链路

随着演练的深入,我们遇到了一系列困难,比如多路连接复用、代理转发的干扰,无法进行持续拦截,同时我们还需要注入更丰富的故障类型,如SSL证书错误、CDN节点异常、域名无法解析等故障。经过调研业界的技术方案,缺乏对端上完整的网络请求链路、动静态资源加速效果、各环节对应的超时重试、域名降级等容灾策略的有效测试方法。存在测试场景不够丰富、模拟故障注入困难、连接复用的干扰等问题。同时由于测试场景的复杂性,在日常工作开展过程中,需要持续投入人力,反复操作进行定向容灾演练,测试效率低、人力成本较高。

为了能够有效解决上述问题,我们联合SRE团队本地搭建了一套 HTTPDNS 自建服务,首先通过修改客户端配置的方式,将网络请求直接指向自建服务。在自建服务器上,我们可以根据自己的需要,修改各域名返回的节点IP或状态、替换域名证书等。除了演练场景的构造,我们还通过关键帧、稳定区间划分等方式,对端侧各网络请求阶段页面加载耗时、异常场景的故障根因进行自动记录和分析,比如模拟动静态资源业务接口建连超时,识别出最终的dns_provider、请求域名、页面渲染加载过程的具体耗时等关键信息。

三、 演练方案

3.1 整体设计

最终我们选定如下方案,对日常的网络库版本迭代、CDN调度策略、超时重试降级逻辑等进行保障,整体的演练方案由以下部分组成:

  • 通过自动化脚本进入各核心域名对应场景,经网络库SDK发起网络请求

  • 修改客户端配置,拦截网络请求指向自建 HTTPDNS 服务

  • 模拟各故障类型,包括服务自身异常、CDN单、多节点异常、SSL证书错误、域名无法解析、封禁、劫持等问题

  • 拿到最终解析出来的 IP,发起业务请求建连,观测客户端渲染过程,自动记录并拆帧,分析各阶段耗时、空窗、持续加载等异常场景

  • 对解析结果进行缓存与建连优化,对客户端 & HTTPDNS 服务进行关键日志分析

图3:端侧DCDN自动化容灾演练方案

3.2 演练实践

DCDN 已覆盖 B站数十个业务域,包括安卓、iOS、web等各端。我们通过构建模拟真实用户行为的自动化测试脚本,对各业务的核心域名发起网络请求,覆盖各不同终端,记录并观测客户端表现,上传行为日志。在客户端的配置文件中记录需要拦截的业务域名,将请求转发至自建的域名解析服务,并向该服务注入各种类型故障,包括服务自身状态异常(4XX、5XX等)、CDN节点状态异常(单节点状态异常、多节点状态异常)、iPv4、iPv6错误、SSL证书错误、TTL超时等。

图4:模拟CDN节点 5xx 类错误

对于异常结果的判定,对客户端资源加载结果、各阶段耗时等的感知和分析。通常来说业界的主要方案是对资源标签添加错误回调、埋点日志分析,亦或是肉眼的直观感受等,但上述方法在时效性、侵入性、易用性方面都有一些缺陷,如何选择一种既不侵入业务,又能得到即时反馈的低成本、可持续实现方案。通过调研,最终我们选择对客户端渲染过程进行自动拆帧,划分为多个稳定区间,每一个区间前后都以关键帧进行切割,在完成稳定区间分割处理后,利用预先训练好的分类模型,基于SVM分析方法进行归类。同时记录每帧对应的时间戳,最终计算得到每个阶段的耗时。图5为视频拆帧和稳定区间归类脚本流程示意图。

图5:拆帧和稳定区间归类脚本示意图

这里以打开哔哩哔哩APP首页为例,整个过程会被划分为如下阶段:

  • 启动APP,展示品牌广告
  • 发起业务请求建连
  • 动态资源:如API接口、数据库交互等数据返回
  • 静态资源:如图片、网页、压缩包文件等

将上述视频文件进行拆帧分析,进行稳定区间的分割处理,计算相邻的两帧之间的峰值信噪比(PSNR)或结构相似性指数(SSIM),可以根据SSIM 或 PSNR计算出差异度(如:差异度=1-SSIM)。将计算得到的差异度与预设阈值进行比较,若比较结果为差异度大于或等于预设差异度阈值,则执行阶段稳定区间的分割处理,每一个阶段稳定区间前后都以关键帧进行标记,并记录两个关键帧的时间戳。得到稳定区间后,再结合阶段稳定区间的起始帧和截止帧的时间戳来计算得到对应的阶段耗时。

图6:阶段划分

图7:阶段耗时

为了减少两个关键帧之间因微小变化,而错误地将一个连续的稳定区间分割成多个部分,还可以提供一个预设补偿阈值,允许一定程度内的波动而不立即视为新的稳定区间开始。因此,可以根据预设补偿阈值对所述差异度进行补偿处理,例如,计算差异度与预设补偿阈值的和,求和结果即为补偿处理后的差异度。然后,将补偿处理后的差异度与预设差异度阈值进行比较。若比较结果为,补偿处理后的差异度大于或等于预设差异度阈值,则执行阶段稳定区间的分割处理。如此一来,有助于减少因微小变化导致的误判,确保只有当变化足够显著时,才会识别为一个新的稳定阶段。

在本案例中,影响稳定区间分割的参数是预设差异度阈值(threshold)和预设补偿阈值(offset),其中threshold参数越高,则稳定的阈值门槛越高,越难被判定为稳定帧;offset则是补偿值,将前后相似的两帧进行合并。因此,需要根据实际的被测场景,进行参数调优,找到最合适的threshold和offset。

3.3 演练结果&收益

故障场景下客户端的明显故障表现为,空窗、无内容或持续加载等。通过该方案,我们只需要根据被测场景,预先设定好网络请求不同阶段,页面显著变化的关键帧、稳定区间分割的补偿参数,就可以自动记录并分析故障场景下的客户端表现信息、其阶段稳定区间划分及所对应的阶段耗时。故障恢复时间期间,是否对用户体验有损等,比如:

  • 自建HTTPDNS:服务状态4xx、5xx类错误时,是否会立刻主动降级商业HTTPDNS
  • CDN节点状态:
  • 单个 or 多个节点,4xx、5xx类错误时:业务接口请求会报错,是否有降级逻辑,耗时多久
  • SSL错误:业务接口请求失败后是否会立刻域名降级恢复,耗时多久
  • 域名解析不到如何处理,是否能主动干预,迅速剔除

通过多次演练,我们对先前的一些推测点进行了验证,理清了客户端网络请求的整体链路及其降级容灾策略,并发现了一些潜在的风险和可进一步优化的点,比如:

  • 端侧CDN域名:客户端静态资源CDN请求域名,一次冷启生命周期内不应发生变化, 可以按设备维度固定
  • 域名降级逻辑:部分域名降级配置比例不合理,可能会导致同一域名未命中降级策略的部分请求无法容灾自恢复
  • 端侧降级重试超时控制策略:返回的部分CDN 节点异常时,应综合考虑ip降级重试、域名降级重试、全局超时控制等组合策略,保障各类极端网络故障下用户体验都能快速止损恢复

演练中发现的一系列问题优化上线后,在随后的一次网络故障中,我们观测到虽然A机房流量下跌30%,B机房流量快速切量上涨,几乎同时完成了切量,用户对本次故障基本无感。客户端网络请求错误率快速收敛,从侧面印证了我们的努力有效改善了用户使用B站的体验。

四、 总结和展望

对端侧网络请求动态加速过程有了一个清晰的认知后,预期还有一些可尝试优化的技术方案,让资源的首次加载更加稳定有效,为不同区域的用户动态提供最优的 DCDN 域名列表和节点IP

  • 端侧IP动态排序:根据端侧IP策略使用记录(成功、失败、耗时等维度)进行优先级排序,建连错误次数多的策略在排序优先级上进行降权操作,与之相对应的,建连成功率高性能好的策略优先级提高。
  • 端侧域名动态计算:域名降级逻辑,目前会根据容灾域名列表配置依次进行重试,如果某A域名下的CDN节点大范围异常,端侧依然会使用该域名返回的DNS解析结果,并对其所有IP进行重试,这样就会导致不必要的重试成本,根据域名可用性动态调整域名顺序并对结果进行输出。

回顾本次演练,面对复杂的用户网络环境、机房稳定性等挑战,为保障用户良好的使用体验,我们能做得还很多,长路漫漫,道阻且长。

-End-

作者丨虚空、春申

相关推荐
WebInfra17 小时前
🔥 Midscene 重磅更新:支持 AI 驱动的 Android 自动化
android·前端·测试
用户7858298243061 天前
Selenium3.0 平台级自动化测试框架综合实战(完结)
测试
用户7858298243061 天前
Selenium3+Pytest+Allure 落地 Python Web 自动化测试
测试
felix19911 天前
pytest-dsl: 用自然语言编写自动化测试,让测试代码不再难懂
测试
越学不动啦4 天前
十、自动化函数+实战
运维·软件测试·自动化·测试
Hy小杨4 天前
压测JMeter经验分享文档-Concurrency Thread Group
测试
waves浪游4 天前
自动化测试常用函数
测试用例·bug·测试
邹老师的小课堂4 天前
Windows环境下,Jenkins+Gitee的CICD
windows·gitee·jenkins·测试·cicd
Z_z在努力5 天前
【软件测试】bug 篇
bug·测试