【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

腾讯视频 Node.js 服务是如何支撑国庆阅兵直播高并发的?

  • 2019-10-30
  • 本文字数:3299 字

    阅读完需:约 11 分钟

腾讯视频Node.js服务是如何支撑国庆阅兵直播高并发的?

上个月,我有幸参与了腾讯视频国庆阅兵直播页面开发的相关工作,最终,累计观看 2.38 亿人次,经受住了高并发的考验。在参于 Glama 框架的开发维护及平时基础建设相关讨论实践中,对高并发有一些部分实践心得,正好老友也想了解腾讯视频这边的经验,特撰写本文,对相关经验进行梳理总结,与大家探讨。(本文作者:Lucienduan,腾讯视频 Web 前端高级工程师)


本文将从服务可用性、缓存、日志三个维度总结视频侧开发高并发 Nodejs 服务的一些经验。

一、视频前端网络结构

先介绍腾讯视频前端网络结构,网络架构如下图所示。



腾讯视频 Node.js 服务的网络示意图


流程简述如下:


1.用户首先请求 GSLB,找到最佳接入 IP,就近访问 CDN 节点;


2.CDN 缓存命中时,直接响应缓存, 如果有 CDN 缓存失效或未配缓存, 会直接回源到 TGW(Tencent Gateway), TGW 主要处理容灾、负载匀衡;


3.请求从 TGW(STGW)转发到业务层 Nginx,在 Nginx 中也会有简单的容灾策略(主要由 max_fails,fail_timeout 两个设置配置)和缓存机制,最后到达 Node 服务;


4.在 Node 中用 cluster 模板转发到对应的 worker 进程处理,worker 中会跑具体的业务, 请求对应的后台服务器。


这里 TGW 主要功能:负载均衡、容灾、IP 收敛、多通接入。


系统整体的可靠性需要各个节点相互配合,本文主要针对由前端开发的负责的模块, Node 和业务这一节点为中心从可用性, 缓存和日志发散来说高并发服务需要关注的点。

二、可用性

运维老司机说:没有绝对可靠的系统,局部故障是常态。


但通过一些方法兜底和保护,可以保证核心业务无异常。


保证业务可用首先需要保证相关的进程工作正常,进程异常时能容灾兜底。

进程守护

Node.js 主进程守护,腾讯视频这边用 shell 脚本来描述执行:


通过 crontab 命令,定时 1min 钟去检查一次进程(用 ps 指令)和端口(用 nc 指令)是否正常, 异常时重启服务。


在 Nodejs Cluster 模块,主进程会把 TCP 分配给 worker 进程处理,worker 进程主要三个问题, 僵尸进程, 内存泄露和进程异常退出。


僵尸(无响应)进程:当程序运行到死循环,就不再响应任何请求了,需要及时重启:


  • 在 Master 进程定时向 worker 进程发心跳包,当 worker 进程在一段时间多次不回包时, 杀死重启。

  • 内存监听:主要为了兜底内存泄露问题, 当 worker 进程达到阈值时, 杀死重启

  • 进程退出:进程异常退出时, 需要重启。


目前社区有比较多的工具可以实现进程守护,比如 pm2。

页面静态化/预渲染

最安全的进程是没有进程……即整个请求链中不依赖的 Node.js 服务。



静态化示意图


对于一些只有少数的几个运营同学更新数据且可用性要求极高的页面,可以直接由运营的发布动作触发页面更新的 CDN。


整个请求链环节少,无回源请求,异常的概率最低。


即使 Node.js 有多级的守护,但还是有可能进程内的分支逻辑或接口出现异常,当分支逻辑或接口异常出现时,合理的容灾策略可以提供降级服务让核心业务无影响,用户无感知。

三、三层容灾策略

如果上面守护异常,或是底层的依赖服务挂了,H5 页面有三层容灾策略。



容灾策略示意图

1. 接口容灾

接口容灾主要应对依赖的底层接口异常。当后台接口正常返回时,把数据缓存到 redis,异常时,用 redis 的旧数据兜底。

2. 页面 HTML

兜底思路与口容灾差不多,当页面渲染异常时,中间件检测到返回 5xx,同样用正常的缓存在 redis 的旧 HTML 兜底。

3. NodeJS 容灾

主要应对 NodeJS 工作异常,当 NodeJS 进程正常响应时,把静态的 HTML 推到 CDN 作为备份文件, 如果 NodeJS 返回 5xx 时, 在 Nginx 代理层重定向到静态备份文件。


从实践来看,上面的进程 worker 的守护和容灾兜底,可以很好的保证源站业务的稳定性,对于高并发业务,缓存和告警必不可少。

四、缓存

缓存在高并发的系统扮演着至关主要的角色,除了用户态、推荐等少数业务场景不能用缓存外,缓存是应对流量冲击简单有效的方式, 目前视频侧主要有三级缓存, CDN 缓存,代理层 Nginx 缓存,应用层 redis 缓存。



三级缓存示意图图片来源:《Web 前端与中间层缓存的故事》

CDN 缓存

CDN 的 OC 节点不但可以减少用户的访问延时,也可以减少源站的负载,但 Node.js 站点在用 CDN 抗量时同时需要注意两个问题。

1. 更新时间

由于 CDN 一般用于缓存静态文件或更新粒度比较小的页面,默认的缓存时间比较长,在接口上使用时需要注意更新时间,同时接口不能带有随机参数。


在 70 周年阅兵主持人页面中,轮询请求量非常大,接口用了 CDN 缓存,由于没有太关注更新时间,导致接口更新不及时, 对于自建 CDN, 需要注意 cache-control 和 last-modified 字段的更新,或是关注 status 头查看回源状态。

2. 缓存穿透、雪崩

目前自建 CDN 缓存没有缓存锁,当缓存失效到下一次缓存更新这一小段时间(一般在 40~500ms),所有的请求都回源到源站,并发比较高时,会有大量穿透到源站,底层没有保护的话可能引起雪崩, 所以需要多级缓存。


Nginx 自带缓存锁,通过简单的配置就可以解决这个问题。

Nginx 代理层缓存

Nginx 除了提供基本的缓存能力外,还提供缓存锁、缓存容错能力,


proxy_cache_use_stale 可以配置,错误, 超时,更新中和其它异常状态时, 使用旧缓存兜底和避免过多的的流量穿透到源站。


同时 proxy_cache_lock 配置,可以防止配置没有预热时,缓存的穿透的问题。


当 proxy_cache_lock 被启用时,当多个客户端请求一个缓存中不存在的文件(或称之为一个 MISS),只有这些请求中的第一个被允许发送至服务器。其他请求在第一个请求得到满意结果之后在缓存中得到文件。如果不启用 proxy_cache_lock,则所有在缓存中找不到文件的请求都会直接与服务器通信。


所以 Nginx 通过正常的配置,可以大大减少回源的请求,减轻源站的负载。

页面缓存

在应用层或框架层,可以用 redis 实现第三层缓存,这层的 redis 缓存也是 HTML 渲染异常时兜底的基础。实现思路比较简单,需要关注两个问题:


1.页面缓存版本不同步时,有无适配问题,如果需要识别版本,版本不匹配的缓存直接失效。


2.是否需要设计缓存锁来避免穿透问题,如果上层已处理(比如 Nginx),或下层能抗量流量可以忽略不加锁。


整页缓存粒度比较大,可以针对业务场景做拆分,比如针对部分推荐数据的页面拆分页面片缓存或接口缓存。


从 CDN、Nginx 到 redis,每一层的工作量、业务侵入性,粒度不一样,业务需要根据自身场景, 选用适合自己业务的缓存即可。

五、日志与告警

告警和日志,对故障早发现早处理,复盘根本原因至关重要。


目前视频除了基础平台提供的 CDN、TGW 和机器的物理资源的监控外,在用户侧和代理层, 源站均有不同维度的告警和监控。



监控示意图


1.客户端提供了前端监控和告警,提供用户侧的监控,比如页面质量,CGI 质量, 用户流水及手动上报的能力。


2.反向代理层 由 Nginx 上报监控,监控访问波动,错误量占比(4xx, 5xx)时耗时。


3.请求日志 主要记录原站的总请求数,请求失败数据及平均耗时。


4.Nodejs 进程日志 主要进程异常退出,内存泄露,僵尸进程等进程日志, 对业务稳定运行, 非常重要。


5.Node 请求流水日志 主要记录请求维度的开发自定义日志,用于问题的定位复盘, 进程状态观测。


6.模调监控 监控请求方和服务方的错误和响应时间的情况,当前模块与底层依赖模块的接口实时接口质量。


每层的监控和日志可以帮助业务快速了解业务状态,定位业务异常。


总结来说:单个用户异常,查看客户端啄木鸟流水和 Node 请求流水日志,服务大概率异常查模调和请求日志,Node 进程异常查看 代理层日志和进程日志,响应时间异常可以从客户端、代理层、源站及模调的耗时逐步分析。

六、总结

可用性永远是做框架和业务的同学需要关心重要指标,但是现状如文初所说:没有绝对可靠的系统。


除了关注 Node.js 的业务开发质量,如何在流程和架构层面避免局部异常不影响整体业务和用户体验更值得更进一步思考。腾讯视频在架构和框架的设计层面防呆,故障前进程守护,监控告警等方法避免和发现问题;故障中通过多级容灾兜底提供降级服务;故障后通过各个节点的日志定位问题改进回顾。保证质量参差不齐业务都能抗住高并发且高可用。


本文转载自公众号云加社区(ID:QcloudCommunity)。


原文链接:


https://mp.weixin.qq.com/s/WKhALCAarFNOCQylBUryfQ


2019-10-30 14:532203

评论

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

MySQL性能优化(三):深入理解索引的这点事

xcbeyond

MySQL 索引 MySQL性能优化

MySQL性能优化(五):为什么查询速度这么慢

xcbeyond

MySQL 查询优化 MySQL性能优化

计算机网络基础(二)---网络层-IP协议详解

书旅

php laravel 计算机网络 网络协议

海南七星彩网站源码结算功能开发

网站,小程序,APP开发定制

如何在 3 个小时内完成一周的工作

escray

从一盏路灯,看亿万级联接的智能之路

华为云开发者联盟

人工智能 物联网 智能设备 华为云

开源数据交换(client)

李孟聊AI

Java 大数据 flink spark 数据交换

天元MegEngine深度学习框架贡献者计划全面启动!

flashrunrun

人工智能 学习 开源 AI

API接口设计最佳实践

Man

Java 安全开发 设计实践 APi设计 接口管理

doris临时故障恢复过程时序图

刘志刚

为什么我们应该使用 Flutter?

环信

flutter

SaaS是「包治百病」的良药吗?

ToB行业头条

再强调一遍, 我为什么不建议大家接外包干私活?

非著名程序员

程序员 外包 提升认知 接私活

面试官:如何决定使用 HashMap 还是 TreeMap?

爱嘤嘤嘤斯坦

Java 算法 hashmap

静态代码检查完成代码分析和SonarQuber的初探

陈磊@Criss

啃碎并发(11):内存模型之重排序

猿灯塔

MySQL 三万字精华总结 + 面试100 问,和面试官扯皮绰绰有余(收藏系列)

大头星

Java MySQL 面试

你与30W奖金只差一个 Apache Flink 极客挑战赛的报名

Apache Flink

flink

Spring配置类深度剖析-总结篇(手绘流程图,可白嫖)

YourBatman

spring springboot @Configuration 白嫖

一致性协议算法

张瑞浩

未来的智慧城市:未来的城市生活愿景

网站,小程序,APP开发定制

案例解析丨金蝶K/3 Wise接入华为云RDS数据库SQL Server

华为云开发者联盟

MySQL 数据库 Serverless 数据 华为云

Spring循环依赖及解决方式

张sir

Java spring 循环依赖

MySQL性能优化(六):常见优化SQL的技巧

xcbeyond

MySQL MySQL性能优化 SQL优化 优化技巧

分布式存储系统doris

Thrine

JDK1.8新特性(一):JDK1.8究竟有哪些新特性呢

xcbeyond

jdk8 新特性 JDK1.8新特性

MySQL性能优化(七):MySQL执行计划,真的很重要,来一起学习吧

xcbeyond

MySQL MySQL性能优化 执行计划

课程总结

Thrine

从需求到交付——论敏捷过程中的需求管理

华为云开发者联盟

敏捷开发 团队协作 需求管理 故事 持续交付

腾讯的区块链为何败给了老干妈的“萝卜章”?

ToB行业头条

MySQL性能优化(四):如何高效正确的使用索引

xcbeyond

MySQL 索引 MySQL性能优化

腾讯视频Node.js服务是如何支撑国庆阅兵直播高并发的?_文化 & 方法_Lucienduan_InfoQ精选文章