NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

构建通用 WebSocket 推送网关的设计与实践

  • 2021-03-07
  • 本文字数:3601 字

    阅读完需:约 12 分钟

构建通用WebSocket推送网关的设计与实践

HTTP 协议是一种无状态的、基于 TCP 的请求/响应模式的协议,请求只能由客户端发起、服务端进行响应。在大多数场景,这种请求/响应的 Pull 模式已经可以满足需求。但在某些情形,例如消息推送、通知等应用场景,需要实时将数据同步到客户端,这就要求服务端支持主动 Push 数据。


服务端推送技术历史悠久,经历了短轮询、长轮询的发展,一定程度上能够解决问题,但也存在着不足,例如时效性、资源浪费等。HTML5 标准带来的 WebSocket 规范基本结束了这一局面,成为目前服务端推送技术的主流方案。


在系统中集成 WebSocket 十分简单,相关讨论与资料很丰富。但如何实现一个通用的 WebSocket 推送网关尚未有成熟的方案。目前的云服务厂商主要关注 iOS 和安卓等移动端推送,也缺少对 WebSocket 的支持。本文介绍了我们基于 Netty 实现 WebSocket 长连接网关时的一些思考和经验。

1 爱奇艺号 WebSocket 使用现状

爱奇艺号是爱奇艺内容创作、分发和变现的平台,涵盖自媒体、网大、网剧、儿童、知识、纪录片等多个业务,是爱奇艺内容生态的重要组成。爱奇艺号作为前台系统,对用户体验有较高要求,直接影响着创作者的创作热情。目前,爱奇艺号有多个业务场景中用到了 WebSocket 推送技术,包括:


  • 用户评论。实时的将评论消息推送到浏览器。

  • 实名认证。合同签署前需要对用户进行实名认证,用户扫描二维码后进入第三方的认证页面,认证完成后异步通知浏览器认证的状态。

  • 活体识别。类似实名认证,当活体识别完成后,异步将结果通知浏览器。


在实际的业务开发中,我们发现,WebSocket 推送技术在使用中存在以下问题:首先,WebSocket 技术栈不统一,既有基于 Netty 实现的,也有基于 Web 容器实现的,给开发和维护带来困难;其次,WebSocket 实现分散在在各个工程中,与业务系统强耦合,如果有其他业务需要集成 WebSocket,面临着重复开发的窘境,浪费成本、效率低下;第三,WebSocket 是有状态协议的,客户端连接服务器时只和集群中一个节点连接,数据传输过程中也只与这一节点通信。


因此,WebSocket 集群需要解决会话共享的问题。如果只采用单节点部署,虽然可以避免这一问题,但无法水平扩展支撑更高负载,有单点的风险;最后,缺乏监控与报警,虽然可以通过 Linux 的 Socket 连接数大致评估 WebSocket 长连接数,但数字并不准确,也无法得知用户数等具有业务含义的指标数据;无法与现有的微服务监控整合,实现统一监控和报警。

2 长连接网关的设计与实现

为了解决以上问题,我们实现了统一的 WebSocket 长连接网关,具备如下特点:


1. 集中实现长连接管理和推送能力。统一技术栈,将长连接作为基础能力沉淀,便于功能迭代和升级维护。


2. 与业务解耦。将业务逻辑与长连接通信分离,使业务系统不再关心通信细节,也避免了重复开发,浪费研发成本。


3. 使用简单。提供 HTTP 推送通道,方便各种开发语言的接入。业务系统只需要简单的调用,就可以实现数据推送,提升研发效率。


4. 分布式架构。实现多节点的集群,支持水平扩展应对业务增长带来的挑战;节点宕机不影响服务整体可用性,保证高可靠。


5. 多端消息同步。允许用户使用多个浏览器或标签页同时登陆在线,保证消息同步发送。


6. 多维度监控与报警。自定义监控指标与现有微服务监控系统打通,出现问题时可及时报警,保证服务的稳定性。

2.1. 技术选型

在众多的 WebSocket 实现中,从性能、扩展性、社区支持等方面考虑,最终选择了 Netty。Netty 是一个高性能、事件驱动、异步非阻塞的网络通信框架,在许多知名的开源软件中被广泛使用。


WebSocket 是有状态的,无法像直接 HTTP 以集群方式实现负载均衡,长连接建立后即与服务端某个节点保持着会话,因此集群下想要得知会话属于哪个节点,有两种方案,一种是使用类似微服务的注册中心来维护全局的会话映射关系,一种是使用事件广播由各节点自行判断是否持有会话,两种方案对比如表 1 所示。

方案

优点

缺点

注册中心

会话映射关系清晰,集群规模较大时更合适

实现复杂,强依赖注册中心,有额外运维成本

事件广播

实现简单更加轻量

节点较多时,所有节点均被广播,资源浪费

表 1:WebSocket 集群方案


综合考虑实现成本与集群规模,选择了轻量级的事件广播方案。实现广播可以选择基于 RocketMQ 的消息广播、基于 Redis 的 Publish/Subscribe、基于 ZooKeeper 的通知等方案,其优缺点对比如表 2 所示。从吞吐量、实时性、持久化、实现难易等方面考虑,最终选择了 RocketMQ。


方案

优点

缺点

基于RocketMQ

吞吐量高、高可用、保证可靠

实时性不如Redis

基于Redis

实时性高、实现简单

不保证可靠

基于ZooKeeper

实现简单

写入性能较差,不适合频繁写入场景

表 2:广播的实现方案对比

2.2. 系统架构

网关的整体架构如图 1 所示。



图 1:WebSocket 长连接网关架构

网关的整体流程如下:


1. 客户端与网关任一节点握手建立起长连接,节点将其加入到内存维护的长连接队列。客户端定时向服务端发送心跳消息,如果超过设定的时间仍没有收到心跳,则认为客户端与服务端的长连接已断开,服务端会关闭连接,清理内存中的会话。

2. 当业务系统需要向客户端推送数据时,通过网关提供的 HTTP 接口将数据发向网关。

3. 网关在接收到推送请求后,将消息写入 RocketMQ。

4. 网关作为消费者,以广播模式消费消息,所有节点都会接收到消息。

5. 节点接收到消息后判断推送的消息目标是否在自己内存中维护的长连接队列里,如果存在则通过长连接推送数据,否则直接忽略。


网关以多节点方式构成集群,每节点负责一部分长连接,可实现负载均衡,当面对海量连接时,也可以通过增加节点的方式分担压力,实现水平扩展。同时,当节点出现宕机时,客户端会尝试重新与其他节点握手建立长连接,保证服务整体的可用性。

2.3. 会话管理

长连接建立起来后,会话维护在各节点的内存中。SessionManager 组件负责管理会话,内部使用了哈希表维护了 UID 与 UserSession 的关系;UserSession 代表用户维度的会话,一个用户可能会同时建立多个长连接,因此 UserSession 内部同样使用了一个哈希表维护 Channel 与 ChannelSession 的关系。为了避免用户无限制的创建长连接,UserSession 在内部的 ChannelSession 超过一定数量后,会将最早建立的 ChannelSession 关闭,减少服务器资源占用。SessionManager、UserSession、ChannelSession 的关系如图 2 所示。



图 2:SessionManager 组件

2.4. 监控与报警

为了了解集群建立了多少长连接、包含了多少用户,网关提供了基本的监控与报警能力。网关接入了 Micrometer,将连接数与用户数作为自定义指标暴露,供 Prometheus 进行采集,实现了与现有的微服务监控系统打通。在 Grafana 中方便地查看连接数、用户数、JVM、CPU、内存等指标数据,了解网关当前的服务能力与压力。报警规则也可以在 Grafana 中配置,当数据异常时触发奇信(内部报警平台)报警。

2.5. 性能压测

压测选择两台配置为 4 核 16G 的虚拟机,分别作为服务器和客户端。压测时选择为网关开放了 20 个端口,同时建立 20 个客户端,每个客户端使用一个服务端端口建立起 5 万连接,可以同时创建百万个连接。连接数与内存使用情况如图 3 所示。



图 3:百万级连接

给百万个长连接同时发送一条消息,采用单线程发送,服务器发送完成的平均耗时在 10s 左右,如图 4 所示。


图 4:服务器推送耗时

一般同一用户同时建立的长连接都在个位数。以 10 个长连接为例,在并发数 600、持续时间 120s 条件下压测,推送接口的 TPS 大约在 1600+,如图 5 所示。



图 5 :长连接 10、并发 600、持续时间 120s 的压测数据

当前的性能指标已满足爱奇艺号的实际业务场景,可支持未来的业务增长。

3 业务案例

为了更生动的说明优化效果,文章最后,我们也以封面图添加滤镜效果为例,介绍一个爱奇艺号使用 WebSocket 网关的案例。


爱奇艺号自媒体发表视频时,可选择为封面图添加滤镜效果,引导用户提供提供更优质的封面。当用户选择一个封面图后,会提交异步的后台处理任务。当异步任务处理完成后,通过 WebSocket 将不同滤镜效果处理后的图片返回给浏览器,业务场景如图 6 所示。



图 6:爱奇艺号视频封面图滤镜


从研发效率方面考虑,如果在业务系统中集成 WebSocket,至少需要 1-2 天的开发时间;如果直接使用网关的推送能力,只需要简单的接口调用就实现了数据推送,开发时间降低到分钟级别,研发效率大大提高。从运维成本方面考虑,业务系统不再含有与业务逻辑无关的通信细节,代码的可维护性更强,系统架构变得更加简单,运维成本大大降低。

4 写在最后

WebSocket 是目前实现服务端推送的主流技术,恰当使用能够有效提供系统响应能力,提升用户体验。通过 WebSocket 长连接网关可以快速为系统增加数据推送能力,有效减少运维成本,提高开发效率。


长连接网关的价值在于它封装了 WebSocket 通信细节,与业务系统解耦,使得长连接网关与业务系统可独立优化迭代,避免重复开发,便于开发与维护。其次,网关提供了简单易用的 HTTP 推送通道,支持多种开发语言接入,便于系统集成和使用。另外,网关采用了分布式架构,可以实现服务的水平扩容、负载均衡与高可用。最后,网关集成了监控与报警,当系统异常时能及时预警,保证服务的健康和稳定。

 

目前,WebSocket 长连接网关已在爱奇艺号图片滤镜结果通知、MCN 电子签章等多个业务场景中得到应用。未来还有许多方面需要探索,例如消息的重发与 ACK、WebSocket 二进制数据的支持、多租户的支持等。我们也会不断优化、丰富功能,带给开发者更好的使用体验。


本文转载自:爱奇艺技术产品团队(ID:iQIYI-TP)

原文链接:构建通用WebSocket推送网关的设计与实践

2021-03-07 08:004811

评论 3 条评论

发布
用户头像
该方案只降低了节点的连接数,但每个节点订阅全量信息,对系统资源消耗更大。维护全局注册关系也并不是特别复杂,核心是一致性哈希和注册表。
2023-07-13 22:09 · 浙江
回复
用户头像
由于多个consumer消费偏移量不一致,客户端重连时可能重复消费同一条消息,这个问题是怎么解决的
2021-06-17 11:26
回复
后端自己维护消费状态
2023-07-13 22:03 · 浙江
回复
没有更多了
发现更多内容

Spring Boot Serverless 实战系列 | 性能调优

阿里巴巴云原生

阿里云 Serverless 架构 云原生

企业为什么要做应用多活?

阿里巴巴云原生

阿里云 云原生 容灾

《MySQL入门很轻松》第4章:数据表中能存放的数据类型

乌龟哥哥

数据库 2月月更

独家下载!阿里云云原生携 10+ 技术专家带来《云原生与云未来的新可能》

阿里巴巴云原生

阿里云 Kubernetes 云原生 电子书

国内唯一!阿里云容器服务进入 Forrester 领导者象限

阿里巴巴云原生

阿里云 云原生 容器平台

一篇文章讲懂prometheus

流沙

云原生 监控 Prometheus

http请求中的payload

喀拉峻

网络安全

阿里云容器服务差异化 SLO 混部技术实践

阿里巴巴云原生

阿里云 Kubernetes 云原生 混部技术

云原生落地大爆发,企业和开发者如何把握先机?

阿里巴巴云原生

阿里云 云原生 ACK ACK Anywhere

人人都是 Serverless 架构师 | 现代化 Web 应用开发实战

阿里巴巴云原生

阿里云 Serverless 云原生

给面试加点硬菜:延迟任务场景,该如何提高吞吐量和时效性!

小傅哥

小傅哥 架构设计 Redis 6.0 任务系统

Linux系统编程-进程间通信(mmap内存映射)

DS小龙哥

2月月更 mmap内存映射

SSH远程连接命令执行没反应不报错问题解决(-bash: fork: retry: Resource temporarily unavailable.[资源暂时不可用])

山河已无恙

SSH Linxu 2月月更

Kotlin语法手册(三)

寻找生命中的美好

android kotlin 安卓

DGIOT 工业物联网开源平台简介

dgiot

物联网 2月月更 2月日更 dgiot dgiot物联网

Spring Boot Serverless 实战 | Serverless 应用的监控与调试

阿里巴巴云原生

阿里云 Serverless 云原生

如何快速构建服务发现的高可用能力

阿里巴巴云原生

阿里云 开源 微服务 云原生

专访 OpenKruise 负责人:现在的云原生应用自动化发展到什么程度了?

阿里巴巴云原生

阿里云 开源 云原生

平安保险基于 SPI 机制的 RocketMQ 定制化应用

阿里巴巴云原生

阿里云 云原生 消息队列 开源云工具

为什么start方法不能重复调用?而run方法却可以?

王磊

Java 面试

从冬奥看中国科技(三):数字人的觉醒与进化

脑极体

【附赠PPT】 KubeMeet 成都站回顾:让云原生应用交付和管理变得更简单!

阿里巴巴云原生

阿里云 Kubernetes 云原生 活动 开源项目

运营给产品送的情人节礼物是?

阿里云弹性计算

产品运营 情人节 轻量征文 用户投稿

Go 语言Web开发很简单:使用模板将视图与逻辑分离

宇宙之一粟

Go 语言 Web应用开发 2月月更

剑指Offer——企业级项目中分层的含义与依据及多态的优势

No Silver Bullet

封装 offer 继承 多态 2月月更

Serverless 架构开发手册 — “人人都是 Serverless 架构师”先导篇

阿里巴巴云原生

阿里云 Serverless 架构 云原生

如何利用 AHAS 保障 Web 服务稳如磐石?

阿里巴巴云原生

阿里云 高可用 云原生 AHAS

KubeDL HostNetwork:加速分布式训练通信效率

阿里巴巴云原生

阿里云 云原生 分布式训练 KubeDL

计算机网络面试知识点

yuexin_tech

面试 计算机网络

微信朋友圈高性能架构方案

Geek_36cc7c

详细讲解mybatis的执行流程

编程江湖

mybatis

构建通用WebSocket推送网关的设计与实践_架构_爱奇艺技术产品团队_InfoQ精选文章