Jack Jiang

我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
posts - 422, comments - 13, trackbacks - 0, articles - 0

本文由蘑菇街前端开发工程师“三体”分享,原题“蘑菇街云端直播探索——启航篇”,有修订。

1、引言

随着移动网络网速的提升与资费的降低,视频直播作为一个新的娱乐方式已经被越来越多的用户逐渐接受。特别是最近这几年,视频直播已经不仅仅被运用在传统的秀场、游戏类板块,更是作为电商的一种新模式得到迅速成长。

本文将通过介绍实时视频直播技术体系,包括常用的推拉流架构、传输协议等,让你对现今主流的视频直播技术有一个基本的认知。

学习交流:

本文已同步发布于:http://www.52im.net/thread-3922-1-1.html

2、蘑菇街的直播架构概览

目前蘑菇街直播推拉流主流程依赖于某云直播的服务。

云直播提供的推流方式有两种:

  • 1)一是通过集成SDK的方式进行推流(用于手机端开播);
  • 2)另一种是通过RTMP协议向远端服务器进行推流(用于PC开播端或专业控台设备开播)。

除去推拉流,该云平台也提供了云通信(IM即时通讯能力)和直播录制等云服务,组成了一套直播所需要的基础服务。

3、推拉流架构1:厂商SDK推拉流

如上题所示,这一种推拉流架构方式需要依赖腾讯这类厂商提供的手机互动直播SDK,通过在主播端APP和用户端APP都集成SDK,使得主播端和用户端都拥有推拉流的功能。

这种推拉流架构的逻辑原理是这样的:

  • 1)主播端和用户端分别与云直播的互动直播后台建立长连接;
  • 2)主播端通过UDT私有协议向互动直播后台推送音视频流;
  • 3)互动直播后台接收到音视频流后做转发,直接下发给与之建立连接的用户端。

这种推拉流方式有几点优势:

  • 1)只需要在客户端中集成SDK:通过手机就可以开播,对于主播开播的要求比较低,适合直播业务快速铺开;
  • 2)互动直播后台仅做转发:没有转码,上传CDN等额外操作,整体延迟比较低;
  • 3)主播端和用户端都可以作为音视频上传的发起方:适合连麦、视频会话等场景。

4、推拉流架构2:旁路推流

之前介绍了通过手机SDK推拉流的直播方式,看起来在手机客户端中观看直播的场景已经解决了。

那么问题来了:如果我想要在H5、小程序等其他场景下观看直播,没有办法接入SDK,需要怎么处理呢?

这个时候需要引入一个新的概念——旁路推流。

旁路推流指的是:通过协议转换将音视频流对接到标准的直播 CDN 系统上。

目前云直播开启旁路推流后,会通过互动直播后台将音视频流推送到云直播后台,云直播后台负责将收到音视频流转码成通用的协议格式并且推送到CDN,这样H5、小程序等端就可以通过CDN拉取到通用格式的音视频流进行播放了。

目前蘑菇街直播旁路开启的协议类型有HLS、FLV、RTMP三种,已经可以覆盖到所有的播放场景,在后续章节会对这几种协议做详细的介绍。

5、推拉流架构3:RTMP推流

随着直播业务发展,一些主播逐渐不满足于手机开播的效果,并且电商直播需要高保真地将商品展示在屏幕上,需要通过更加高清专业的设备进行直播,RTMP推流技术应运而生。

我们通过使用OBS等流媒体录影程序,对专业设备录制的多路流进行合并,并且将音视频流上传到指定的推流地址。由于OBS推流使用了RTMP协议,因此我们称这一种推流类型为RTMP推流。

我们首先在云直播后台申请到推流地址和秘钥,将推流地址和秘钥配置到OBS软件当中,调整推流各项参数,点击推流以后,OBS就会通过RTMP协议向对应的推流地址推送音视频流。

这一种推流方式和SDK推流的不同之处在于音视频流是直接被推送到了云直播后台进行转码和上传CDN的,没有直接将直播流转推到用户端的下行方式,因此相比SDK推流延迟会长一些。

总结下来RTMP推流的优势和劣势比较明显。

优势主要是:

  • 1)可以接入专业的直播摄像头、麦克风,直播的整体效果明显优于手机开播;
  • 2)OBS已经有比较多成熟的插件,比如目前蘑菇街主播常用YY助手做一些美颜的处理,并且OBS本身已经支持滤镜、绿幕、多路视频合成等功能,功能比手机端强大。

劣势主要是:

  • 1)OBS本身配置比较复杂,需要专业设备支持,对主播的要求明显更高,通常需要一个固定的场地进行直播;
  • 2)RTMP需要云端转码,并且本地上传时也会在OBS中配置GOP和缓冲,延时相对较长。

6、高可用架构方案:云互备

业务发展到一定阶段后,我们对于业务的稳定性也会有更高的要求,比如当云服务商服务出现问题时,我们没有备用方案就会出现业务一直等待服务商修复进度的问题。

因此云互备方案就出现了:云互备指的是直播业务同时对接多家云服务商,当一家云服务商出现问题时,快速切换到其他服务商的服务节点,保证业务不受影响。

直播业务中经常遇到服务商的CDN节点下行速度较慢,或者是CDN节点存储的直播流有问题,此类问题有地域性,很难排查,因此目前做的互备云方案,主要是备份CDN节点。

目前蘑菇街整体的推流流程已经依赖了原有云平台的服务,因此我们通过在云直播后台中转推一路流到备份云平台上,备份云在接收到了直播流后会对流转码并且上传到备份云自身的CDN系统当中。一旦主平台CDN节点出现问题,我们可以将下发的拉流地址替换成备份云拉流地址,这样就可以保证业务快速修复并且观众无感知。

7、视频直播数据流解封装原理

介绍流协议之前,先要介绍我们从云端拿到一份数据,要经过几个步骤才能解析出最终需要的音视频数据。

如上图所示,总体来说,从获取到数据到最终将音视频播放出来要经历四个步骤。

第一步:解协议。

协议封装的时候通常会携带一些头部描述信息或者信令数据,这一部分数据对我们音视频播放没有作用,因此我们需要从中提取出具体的音视频封装格式数据,我们在直播中常用的协议有HTTP和RTMP两种。

第二步:解封装。

获取到封装格式数据以后需要进行解封装操作,从中分别提取音频压缩流数据和视频压缩流数据,封装格式数据我们平时经常见到的如MP4、AVI,在直播中我们接触比较多的封装格式有TS、FLV。

第三步:解码音视频。

到这里我们已经获取了音视频的压缩编码数据。

我们日常经常听到的视频压缩编码数据有H.26X系列和MPEG系列等,音频编码格式有我们熟悉的MP3、ACC等。

之所以我们能见到如此多的编码格式,是因为各种组织都提出了自己的编码标准,并且会相继推出一些新的议案,但是由于推广和收费问题,目前主流的编码格式也并不多。

获取压缩数据以后接下来需要将音视频压缩数据解码,获取非压缩的颜色数据和非压缩的音频抽样数据。颜色数据有我们平时熟知的RGB,不过在视频的中常用的颜色数据格式是YUV,指的是通过明亮度、色调、饱和度确定一个像素点的色值。音频抽样数据通常使用的有PCM。

第四步:音视频同步播放。

最后我们需要比对音视频的时间轴,将音视频解码后的数据交给显卡声卡同步播放。

PS:如果你对上述流程还不太理解,建议进一步阅读以下系列文章:

  1. 移动端实时音视频直播技术详解(一):开篇
  2. 移动端实时音视频直播技术详解(二):采集
  3. 移动端实时音视频直播技术详解(三):处理
  4. 移动端实时音视频直播技术详解(四):编码和封装
  5. 移动端实时音视频直播技术详解(五):推流和传输
  6. 移动端实时音视频直播技术详解(六):延迟优化

另外:有关音视频编解码技术的文章,也可以详细学习以下文章:

  1. 视频编解码之:《理论概述》、《数字视频介绍》、《编码基础》、《预测技术介绍
  2. 认识主流视频编码技术H.264
  3. 如何开始音频编解码技术的学习
  4. 音频基础及编码原理入门
  5. 常见的实时语音通讯编码标准
  6. 实时视频编码H.264的特点与优势》、《视频编码H.264、VP8的前世今生
  7. 详解音频编解码的原理、演进和应用选型》、《零基础,史上最通俗视频编码技术入门

8、视频直播传输协议1:HLS

首先介绍一下HLS协议。HLS是HTTP Live Streaming的简写,是由苹果公司提出的流媒体网络传输协议。

从名字可以明显看出:这一套协议是基于HTTP协议传输的。

说到HLS协议:首先需要了解这一种协议是以视频切片的形式分段播放的,协议中使用的切片视频格式是TS,也就是我们前文提到的封装格式。

在我们获取TS文件之前:协议首先要求请求一个M3U8格式的文件,M3U8是一个描述索引文件,它以一定的格式描述了TS地址的指向,我们根据M3U8文件中描述的内容,就可以获取每一段TS文件的CDN地址,通过加载TS地址分段播放就可以组合出一整段完整的视频。

使用HLS协议播放视频时:首先会请求一个M3U8文件,如果是点播只需要在初始化时获取一次就可以拿到所有的TS切片指向,但如果是直播的话就需要不停地轮询M3U8文件,获取新的TS切片。

获取到M3U8后:我们可以看一下里面的内容。首先开头是一些通用描述信息,比如第一个分片序列号、片段最大时长和总时长等,接下来就是具体TS对应的地址列表。如果是直播,那么每次请求M3U8文件里面的TS列表都会随着最新的直播切片更新,从而达到直播流播放的效果。

HLS这种切片播放的格式在点播播放时是比较适用的,一些大的视频网站也都有用这一种协议作为播放方案。

首先:切片播放的特性特别适用于点播播放中视频清晰度、多语种的热切换。比如我们播放一个视频,起初选择的是标清视频播放,当我们看了一半觉得不够清晰,需要换成超清的,这时候只需要将标清的M3U8文件替换成超清的M3U8文件,当我们播放到下一个TS节点时,视频就会自动替换成超清的TS文件,不需要对视频做重新初始化。

其次:切片播放的形式也可以比较容易地在视频中插入广告等内容。

在直播场景下,HLS也是一个比较常用的协议,他最大的优势是苹果大佬的加持,对这一套协议推广的比较好,特别是移动端。将M3U8文件地址喂给video就可以直接播放,PC端用MSE解码后大部分浏览器也都能够支持。但是由于其分片加载的特性,直播的延迟相对较长。比如我们一个M3U8有5个TS文件,每个TS文件播放时长是2秒,那么一个M3U8文件的播放时长就是10秒,也就是说这个M3U8播放的直播进度至少是10秒之前的,这对于直播场景来说是一个比较大的弊端。

HLS中用到的TS封装格式,视频编码格式是通常是H.264或MPEG-4,音频编码格式为AAC或MP3。

一个ts由多个定长的packtet组成,通常是188个字节,每个packtet有head和payload组成,head中包含一些标识符、错误信息、包位置等基础信息。payload可以简单理解为音视频信息,但实际上下层还有还有两层封装,将封装解码后可以获取到音视频流的编码数据。

9、视频直播传输协议2:HTTP-FLV

HTTP-FLV协议,从名字上就可以明显看出是通过HTTP协议来传输FLV封装格式的一种协议。

FLV是Flash Video的简写,是一种文件体积小,适合在网络上传输的封包方式。FlV的视频编码格式通常是H.264,音频编码是ACC或MP3。

HTTP-FLV在直播中是通过走HTTP长连接的方式,通过分块传输向请求端传递FLV封包数据。

在直播中,我们通过HTTP-FLV协议的拉流地址可以拉取到一段chunked数据。

打开文件后可以读取到16进制的文件流,通过和FLV包结构对比,可以发现这些数据就是我们需要的FLV数据。

首先开头是头部信息:464C56转换ASCII码后是FLV三个字符,01指的是版本号,05转换为2进制后第6位和第8位分别代表是否存在音频和视频,09代表头部长度占了几个字节。

后续就是正式的音视频数据:是通过一个个的FLV TAG进行封装,每一个TAG也有头部信息,标注这个TAG是音频信息、视频信息还是脚本信息。我们通过解析TAG就可以分别提取音视频的压缩编码信息。

FLV这一种格式在video中并不是原生支持的,我们要播放这一种格式的封包格式需要通过MSE对影视片的压缩编码信息进行解码,因此需要浏览器能够支持MSE这一API。由于HTTP-FLV的传输是通过长连接传输文件流的形式,需要浏览器支持Stream IO或者fetch,对于浏览器的兼容性要求会比较高。

FLV在延迟问题上相比切片播放的HLS会好很多,目前看来FLV的延迟主要是受编码时设置的GOP长度的影响。

这边简单介绍一下GOP:在H.264视频编码的过程中,会生成三种帧类型:I帧、B帧和P帧。I帧就是我们通常说的关键帧,关键帧内包括了完整的帧内信息,可以直接作为其他帧的参考帧。B帧和P帧为了将数据压缩得更小,需要由其他帧推断出帧内的信息。因此两个I帧之间的时长也可以被视作最小的视频播放片段时长。从视频推送的稳定性考虑,我们也要求主播将关键帧间隔设置为定长,通常是1-3秒,因此除去其他因素,我们的直播在播放时也会产生1-3秒的延时。

10、视频直播传输协议3:RTMP

RTMP协议实际可以与HTTP-FLV协议归做同一种类型。

他们的封包格式都是FlV,但HTTP-FLV使用的传输协议是HTTP,RTMP拉流使用RTMP作为传输协议。

RTMP是Adobe公司基于TCP做的一套实时消息传输协议,经常与Flash播放器匹配使用。

RTMP协议的优缺点非常明显。

RTMP协议的优点主要是:

  • 1)首先和HTTP-FLV一样,延迟比较低;
  • 2)其次它的稳定性非常好,适合长时间播放(由于播放时借用了Flash player强大的功能,即使开多路流同时播放也能保证页面不出现卡顿,很适合监控等场景)。

但是Flash player目前在web端属于墙倒众人推的境地,主流浏览器渐渐都表示不再支持Flash player插件,在MAC上使用能够立刻将电脑变成烧烤用的铁板,资源消耗很大。在移动端H5基本属于完全不支持的状态,兼容性是它最大的问题。

11、视频直播传输协议4:MPEG-DASH

MPEG-DASH这一协议属于新兴势力,和HLS一样,都是通过切片视频的方式进行播放。

他产生的背景是早期各大公司都自己搞自己的一套协议。比如苹果搞了HLS、微软搞了 MSS、Adobe还搞了HDS,这样使用者需要在多套协议封装的兼容问题上痛苦不堪。

于是大佬们凑到一起,将之前各个公司的流媒体协议方案做了一个整合,搞了一个新的协议。

由于同为切片视频播放的协议,DASH优劣势和HLS类似,可以支持切片之间多视频码率、多音轨的切换,比较适合点播业务,在直播中还是会有延时较长的问题。

12、如何选择最优的视频直播传输协议

视频直播协议选择非常关键的两点,在前文都已经有提到了,即低延时和更优的兼容性。

首先从延时角度考虑:不考虑云端转码以及上下行的消耗,HLS和MPEG-DASH通过将切片时长减短,延时在10秒左右;RTMP和FLV理论上延时相当,在2-3秒。因此在延时方面HLS ≈ DASH > RTMP ≈ FLV。

从兼容性角度考虑:HLS > FLV > RTMP,DASH由于一些项目历史原因,并且定位和HLS重复了,暂时没有对其兼容性做一个详尽的测试,被推出了选择的考虑范围。

综上所述:我们可以通过动态判断环境的方式,选择当前环境下可用的最低延迟的协议。大致的策略就是优先使用HTTP-FLV,使用HLS作为兜底,在一些特殊需求场景下通过手动配置的方式切换为RTMP。

对于HLS和HTTP-FLV:我们可以直接使用 hls.js 和 flv.js 做做解码播放,这两个库内部都是通过MSE做的解码。首先根据视频封装格式提取出对应的音视频chunk数据,在MediaSource中分别对音频和视频创建SourceBuffer,将音视频的编码数据喂给SourceBuffer后SourceBuffer内部会处理完剩下的解码和音视频对齐工作,最后MediaSource将Video标签中的src替换成MediaSource 对象进行播放。

在判断播放环境时我们可以参照flv.js内部的判断方式,通过调用MSE判断方法和模拟请求的方式判断MSE和StreamIO是否可用:

// 判断MediaSource是否被浏览器支持,H.264视频编码和Acc音频编码是否能够被支持解码

window.MediaSource && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"');

如果FLV播放不被支持的情况下:需要降级到HLS,这时候需要判断浏览器环境是否在移动端,移动端通常不需要 hls.js 通过MSE解码的方式进行播放,直接将M3U8的地址交给video的src即可。如果是PC端则判断MSE是否可用,如果可用就使用hls.js解码播放。

这些判读可以在自己的逻辑里提前判断后去拉取对应解码库的CDN,而不是等待三方库加载完成后使用三方库内部的方法判断,这样在选择解码库时就可以不把所有的库都拉下来,提高加载速度。

13、同层播放如何解决

电商直播需要观众操作和互动的部分比起传统的直播更加多,因此产品设计的时候很多的功能模块会悬浮在直播视频上方减少占用的空间。这个时候就会遇到一个移动端播放器的老大难问题——同层播放。

同层播放问题:是指在移动端H5页面中,一些浏览器内核为了提升用户体验,将video标签被劫持替换为native播放器,导致其他元素无法覆盖于播放器之上。

比如我们想要在直播间播放器上方增加聊天窗口,将聊天窗口通过绝对定位提升z-index置于播放器上方,在PC中测试完全正常。但在移动端的一些浏览器中,video被替换成了native播放器,native的元素层级高于我们的普通元素,导致聊天窗口实际显示的时候在播放器下方。

要解决这个问题,首先要分多个场景。

首先在iOS系统中:正常情况下video标签会自动被全屏播放,但iOS10以上已经原生提供了video的同层属性,我们在video标签上增加playsinline/webkit-playsinline可以解决iOS系统中大部分浏览器的同层问题,剩下的低系统版本的浏览器以及一些APP内的webview容器(譬如微博),用上面提的属性并不管用,调用三方库iphone-inline-video可以解决大部分剩余问题。

在Android端:大部分腾讯系的APP内置的webview容器用的都是X5内核,X5内核会将video替换成原生定制的播放器已便于增强一些功能。X5也提供了一套同层的方案(该方案官方文档链接已无法打开),给video标签写入X5同层属性也可以在X5内核中实现内联播放。不过X5的同层属性在各个X5版本中表现都不太一样(比如低版本X5中需要使用X5全屏播放模式才能保证MSE播放的视频同层生效),需要注意区分版本。

在蘑菇街App中,目前集成的X5内核版本比较老,在使用MSE的情况下会导致X5同层参数不生效。但如果集成新版本的X5内核,需要对大量的线上页面做回归测试,成本比较高,因此提供了一套折中的解决方案。通过在页面URL中增加一个开关参数,容器读取到参数以后会将X5内核降级为系统原生的浏览器内核,这样可以在解决浏览器视频同层问题的同时也将内核变动的影响范围控制在单个页面当中。

14、相关文章

[1] 移动端实时音视频直播技术详解(四):编码和封装

[2] 移动端实时音视频直播技术详解(五):推流和传输

[3] 实现延迟低于500毫秒的1080P实时音视频直播的实践分享

[4] 浅谈开发实时视频直播平台的技术要点

[5] 直播系统聊天技术(七):直播间海量聊天消息的架构设计难点实践

[6] 从0到1:万人在线的实时音视频直播技术实践分享(视频+PPT) [附件下载]

[7] 实时视频编码H.264的特点与优势

[8] 视频编码H.264、VP8的前世今生

[9] 零基础,史上最通俗视频编码技术入门

[10] 视频编解码之编码基础

[11] 零基础入门:实时音视频技术基础知识全面盘点

[12] 实时音视频面视必备:快速掌握11个视频技术相关的基础概念

[13] 写给小白的实时音视频技术入门提纲

本文已同步发布于:http://www.52im.net/thread-3922-1-1.html

posted @ 2022-05-31 15:26 Jack Jiang 阅读(283) | 评论 (0)编辑 收藏

     摘要: 本文作者张彦飞,原题“聊聊TCP连接耗时的那些事儿”,有少许改动。1、引言对于基于互联网的通信应用(比如IM聊天、推送系统),数据传递时使用TCP协议相对较多。这是因为在TCP/IP协议簇的传输层协议中,TCP协议具备可靠的连接、错误重传、拥塞控制等优点,所以目前在应用场景上比UDP更广泛一些。相信你也一定听闻过TCP也存在一些缺点,能常都是老生常谈的开销要略大。但是各路技...  阅读全文

posted @ 2022-05-26 16:10 Jack Jiang 阅读(153) | 评论 (0)编辑 收藏

     摘要: 本文作者“Carson”,现就职于腾讯公司,原题“高效保活长连接:手把手教你实现自适应的心跳保活机制”,有较多修订和改动。1、引言当要实现IM即时通讯聊天、消息推送等高实时性需求时,我们一般会选择长连接的通信方式。而真正当实现长连接方式时,会遇到很多技术问题,比如最常见的长连接保活问题。今天,我将通过本篇文章,手把手教大家实现一套可自适应的心跳保活机...  阅读全文

posted @ 2022-05-18 15:09 Jack Jiang 阅读(199) | 评论 (0)编辑 收藏

本文由ELab技术团队分享,原题“探秘HTTPS”,有修订和改动。

1、引言

对于IM开发者来说,IM里最常用的通信技术就是Socket长连接和HTTP短连接(通常一个主流im会是这两种通信手段的结合)。从通信安全的角度来说,Socket长连接的安全性,就是基于SSL/TLS加密的TCP协议来实现的(比如微信的mmtls,见《微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解);而对于HTTP短连接的安全性,也就是HTTPS了。

到底什么是HTTPS?为什么要用HTTPS?今天就借此机会,跟大家一起深入学习一下HTTPS的相关知识,包括HTTP的发展历程、HTTP遇到的问题、对称与非对称加密算法、数字签名、第三方证书颁发机构等概念。

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

本文已同步发布于:http://www.52im.net/thread-3897-1-1.html

2、系列文章

本文是IM通讯安全知识系列文章中的第9篇,此系列总目录如下:

3、写在前面

说到HTTPS,那就得回到HTTP协议。

对于HTTP协议,大家肯定都熟得不能再熟了。那么HTTPS和HTTP的区别大家了解吗?

对于这个经典的面试题,大部分人会这么回答:

  • 1)HTTPS比HTTP多了一个S(Secure):也就是说HTTPS是安全版的HTTP;
  • 2)端口号不同:HTTP使用80端口,HTTPS使用443端口;
  • 3)加密算法:HTTPS用的是非对称加密算法。

上面的回答能给几分?等看完本文我们可以再回头来看下这个回答。

那么,HTTPS是如何实现安全的短连接数据传输呢?想彻底搞明白这个问题,还是要从HTTP的发展历程说起 ......

4、HTTP协议回顾

4.1 基础常识

HTTP是Hypertext Transfer Protocal 的缩写,中文全称是超文本传输协议(详见《深入浅出,全面理解HTTP协议)。

通俗了解释就是:

  • 1)超文本是指包含但不限于文本外的图片、音频、视频等多媒体资源;
  • 2)协议是通信双方约定好的数据传输格式以及通信规则。

HTTP是TCP/IP协议簇的最高层——应用层协议:

▲ 上图引用自《深入浅出,全面理解HTTP协议

浏览器和服务器在使用HTTP协议相互传递超文本数据时,将数据放入报文体内,同时填充首部(请求头或响应头)构成完整HTTP报文并交到下层传输层,之后每一层加上相应的首部(控制部分)便一层层的下发,最终由物理层将二进制数据以电信号的形式发送出去。

HTTP的请求如下图所示:

▲ 上图引用自《深入浅出,全面理解HTTP协议

HTTP报文结构如下:

4.2 发展历程

HTTP的发展历程如下:

由HTTP的发展历程来看,最开始版本的HTTP(HTTP1.0)在每次建立TCP连接后只能发起一次HTTP请求,请求完毕就释放TCP连接。

我们都知道TCP连接的建立需要经过三次握手的过程,而每次发送HTTP请求都需要重新建立TCP连接,毫无疑问是很低效的。所以HTTP1.1改善了这一点,使用长连接的机制,也就是“一次TCP连接,N次HTTP请求”。

HTTP协议的长连接和短连接,实质上是 TCP 协议的长连接和短连接。

在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。

PS:对于IM开发者来说,为了与Socket长连接通道区分,通常认为HTTP就是“短连接”虽然这个“短连接”不一定真的“短”)。

HTTP1.0若要开启长连接,需要加上Connection: keep-alive请求头。有关HTTP协议的详细发展历程可阅读《一文读懂HTTP协议的历史演变和设计思路》一文。

4.3 安全问题

随着HTTP越来越广泛的使用,HTTP的安全性问题也逐渐暴露。

回忆一下多年前遍地都是的运营商劫持,当你访问一个本来很正常的网页,但页面上却莫名其妙出现了一些广告标签、跳转脚本、欺骗性的红包按钮,甚至有时候本来要下载一个文件,最后下载下来却变成了另外一个完全不同的东西,这些都是被运营商劫持了HTTP明文数据的现象。

下图就是似曾相识的运营商劫持效果图:

PS:关于运营商劫持问题,可以详细阅读《全面了解移动端DNS域名劫持等杂症:原理、根源、HttpDNS解决方案等》。

HTTP主要有以下3点安全性问题:

 

归纳一下就是:

  • 1)数据保密性问题:因为HTTP无状态,而且又是明文传输,所有数据内容都在网络中裸奔,包用户括身份信息、支付账号与密码。这些敏感信息极易泄露造成安全隐患;
  • 2)数据完整性问题:HTTP数据包在到达目的主机前会经过很多转发设备,每一个设备节点都可能会篡改或调包信息,无法验证数据的完整性;
  • 3)身份校验问题:有可能遭受中间人攻击,我们无法验证通信的另一方就是我们的目标对象。

因此,为了保证数据传输的安全性,必须要对HTTP数据进行加密。

5、常见的加密方式

5.1 基本情况

常见的加密方式分为三种:

  • 1)对称加密;
  • 2)非对称加密;
  • 3)数字摘要。

前两种适合数据传输加密,而数字摘要不可逆的特性常被用于数字签名。

接下来,我们逐一简要学习一下这三种常见的加密方法。

5.2 对称加密

对称加密也称为密钥加密或单向加密,就是使用同一套密钥来进行加密和解密。密钥可以理解为加密算法。

对称加密图示如下:

广泛使用的对称加密有:

对称加密算法的优缺点和适用场景:

  • 1)优点:算法公开、简单,加密解密容易,加密速度快,效率高;
  • 2)缺点:相对来说不算特别安全,只有一把钥匙,密文如果被拦截,且密钥也被劫持,那么,信息很容易被破译;
  • 3)适用场景:加解密速度快、效率高,因此适用于大量数据的加密场景。由于如何传输密钥是较为头痛的问题,因此适用于无需进行密钥交换的场景,如内部系统,事先就可以直接确定密钥。

PS:可以在线体验对称加密算法,链接是:http://www.jsons.cn/textencrypt/

小知识:base64编码也属于对称加密哦!

5.3 非对称加密

非对称加密使用一对密钥(公钥和私钥)进行加密和解密。

非对称加密可以在不直接传递密钥的情况下,完成解密,具体步骤如下:

  • 1)乙方生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的;
  • 2)甲方获取乙方的公钥,然后用它对信息加密;
  • 3)乙方得到加密后的信息,用私钥解密。

以最典型的非对称加密算法RSA为例,举个例子:

想要彻底搞懂RSA,需要了解数论的知识,全部推导过程RSA加密算法。简单介绍思路:使用两个超大质数以及其乘积作为生成公钥和私钥的材料,想要从公钥推算出私钥是非常困难的(需要对超大数因式分解为两个很大质数的乘积)。目前被破解的最长RSA密钥是768个二进制位。也就是说,长度超过768位的密钥,还无法破解(至少没人公开宣布)。因此可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全。

非对称加密算法的优缺点和适用场景:

  • 1)优点:强度高、安全性强于对称加密算法、无需传递私钥导致没有密钥泄露风险;
  • 2)缺点:计算量大、速度慢;
  • 3)适用场景:适用于需要密钥交换的场景,如互联网应用,无法事先约定密钥。

实践应用过程中,其实可以与对称加密算法结合:

  • 1)利用非对称加密算法安全性较好的特点来传递对称加密算法的密钥。
  • 2)利用对称加密算法加解密速度快的特点,进行数据内容比较大的加密场景的加密(如HTTPS)。

PS:对于IM开发者来说,《探讨组合加密算法在IM中的应用》一文值得一读。

5.4 如何选择?

1)如果选择对称加密:

HTTP请求方使用对称算法加密数据,那么为了接收方能够解密,发送方还需要把密钥一同传递到接收方。在传递密钥的过程中还是可能遭到嗅探攻击,攻击者窃取密钥后依然可以解密从而得到发送的数据,所以这种方案不可行。

2)如果选择非对称加密:

接收方保留私钥,把公钥传递给发送方。发送方用公钥来加密数据,接收方使用私钥解密数据。攻击者虽然不能直接获取这些数据(因为没有私钥),但是可以通过拦截传递的公钥,然后把自己的公钥传给发送方,再用自己的私钥对发送方发送数据进行解密。

整个过程通信双方都不知道中间人的存在,但是中间人能够获得完整的数据信息。

3)两种加密方法的混合:

先使用非对称加密算法加密并传递对称加密的密钥,然后双方通过对称加密方式加密要发送的数据。看起来没什么问题,但事实是这样吗?

中间人依然可以拦截公钥的传递,并以自己的公钥作为替换,治标不治本。

想要治本,就要找到一个第三方公证人来证明公钥没有被替换,因此就引出了数字证书的概念,这也是下一节将分享的内容。

6、数字证书

6.1 CA机构

CA就是 Certificate Authority,即颁发数字证书的机构。

作为受信任的第三方,CA承担公钥体系中公钥的合法性检验的责任。

证书就是源服务器向可信任的第三方机构申请的数据文件。这个证书除了表明这个域名是属于谁的,颁发日期等,还包括了第三方证书的私钥。

服务器将公钥放在数字证书中,只要证书是可信的,公钥就是可信的。

下面两图是飞书域名的证书中部分内容的信:

6.2 数字签名

摘要算法:一般用哈希函数来实现,可以理解成一种定长的压缩算法,它能把任意长度的数据压缩到固定长度。这好比是给数据加了一把锁,对数据有任何微小的改动都会使摘要变得截然不同。

通常情况下:数字证书的申请人(服务器)将生成由私钥和公钥以及证书请求文件(Certificate Signing Request,CSR)组成的密钥对。CSR是一个编码的文本文件,其中包含公钥和其他将包含在证书中的信息(例如:域名、组织、电子邮件地址等)。密钥对和CSR生成通常在将要安装证书的服务器上完成,并且 CSR 中包含的信息类型取决于证书的验证级别。与公钥不同,申请人的私钥是安全的,永远不要向 CA(或其他任何人)展示。

生成 CSR 后:申请人将其发送给 CA,CA 会验证其包含的信息是否正确,如果正确,则使用颁发的私钥对证书进行数字签名,然后将签名放在证书内随证书一起发送给申请人。

在SSL握手阶段:浏览器在收到服务器的证书后,使用CA的公钥进行解密,取出证书中的数据、数字签名以及服务器的公钥。如果解密成功,则可验证服务器身份真实。之后浏览器再对数据做Hash运算,将结果与数字签名作对比,如果一致则可以认为内容没有收到篡改。

对称加密和非对称加密是公钥加密、私钥解密, 而数字签名正好相反——是私钥加密(签名)、公钥解密(验证),如下图所示。

限于篇幅,关于数字证书的内容本文就不再赘述,想详细了解的可以阅读:

7、为什么要使用HTTPS

图解HTTP》一书中提到HTTPS就是身披SSL外壳的HTTP。

7.1 SSL

SSL 在1999年被更名为TLS

所以说:HTTPS 并不是一项新的应用层协议,只是 HTTP 通信接口部分由 SSL 和 TLS 替代而已。

具体就是:HTTP 会先直接和 TCP 进行通信,而HTTPS 会演变为先和 SSL 进行通信,然后再由 SSL 和 TCP 进行通信。

SSL是一个独立的协议,不只有 HTTP 可以使用,其他应用层协议也可以使用,比如FTP、SMTP都可以使用SSL来加密。

7.2 HTTPS请求流程

HTTPS请求全流程如下图:

如上图所示:

  • 1)用户在浏览器发起HTTPS请求,默认使用服务端的443端口进行连接;
  • 2)HTTPS需要使用一套CA 数字证书,证书内会附带一个服务器的公钥Pub,而与之对应的私钥Private保留在服务端不公开;
  • 3)服务端收到请求,返回配置好的包含公钥Pub的证书给客户端;
  • 4)客户端收到证书,校验合法性,主要包括是否在有效期内、证书的域名与请求的域名是否匹配,上一级证书是否有效(递归判断,直到判断到系统内置或浏览器配置好的根证书),如果不通过,则显示HTTPS警告信息,如果通过则继续;
  • 5)客户端生成一个用于对称加密的随机Key,并用证书内的公钥Pub进行加密,发送给服务端;
  • 6)服务端收到随机Key的密文,使用与公钥Pub配对的私钥Private进行解密,得到客户端真正想发送的随机Key;
  • 7)服务端使用客户端发送过来的随机Key对要传输的HTTP数据进行对称加密,将密文返回客户端;
  • 8)客户端使用随机Key对称解密密文,得到HTTP数据明文;
  • 9)后续HTTPS请求使用之前交换好的随机Key进行对称加解密。

7.3 HTTPS到底解决了什么问题

HTTPS确实解决了HTTP的三个安全性问题:

  • 1) 保密性:结合非对称加密和对称加密实现保密性。用非对称加密方式加密对称加密的秘钥,再用对称加密方式加密数据;
  • 2) 完整性:通过第三方CA的数字签名解决完整性问题;
  • 3) 身份校验:通过第三方CA的数字证书验证服务器的身份。

7.4 HTTPS优缺点

最后我们总结一下HTTPS的优缺点:

可以看到:HTTPS的确是当今安全传输HTTP的最优解,但他并不是完美的,仍会有漏洞。

8、参考资料

[1] 深入浅出,全面理解HTTP协议

[2] HTTP协议必知必会的一些知识

[3] 从数据传输层深度解密HTTP

[4] 一文读懂HTTP协议的历史演变和设计思路

[5] 你知道一个TCP连接上能发起多少个HTTP请求吗?

[6] 如果这样来理解HTTPS,一篇就够了

[7] 一分钟理解 HTTPS 到底解决了什么问题

[8] 你知道,HTTPS用的是对称加密还是非对称加密?

[9] HTTPS时代已来,打算更新你的HTTP服务了吗?

[10] 一篇读懂HTTPS:加密原理、安全逻辑、数字证书等

[11] 全面了解移动端DNS域名劫持等杂症:原理、根源、HttpDNS解决方案等

(本文已同步发布于:http://www.52im.net/thread-3897-1-1.html

posted @ 2022-05-13 16:27 Jack Jiang 阅读(124) | 评论 (0)编辑 收藏

关于MobileIMSDK

MobileIMSDK 是一套专为移动端开发的原创开源IM通信层框架:

  • 历经8年、久经考验;
  • 超轻量级、高度提炼,lib包50KB以内;
  • 精心封装,一套API同时支持UDP、TCP、WebSocket三种协议(可能是全网唯一开源的);
  • 客户端支持 iOSAndroid标准JavaH5小程序(开发中..)、Uniapp(开发中..);
  • 服务端基于Netty,性能卓越、易于扩展;:point_left:
  • 可与姊妹工程 MobileIMSDK-Web 无缝互通实现网页端聊天或推送等;:point_left:
  • 可应用于跨设备、跨网络的聊天APP、企业OA、消息推送等各种场景。

关于RainbowChat

► 详细产品介绍:http://www.52im.net/thread-19-1-1.html
► 版本更新记录:http://www.52im.net/thread-1217-1-1.html
► 全部运行截图:Android端iOS端
► 在线体验下载:专业版(TCP协议)专业版(UDP协议)      (关于 iOS 端,请:点此查看

 

RainbowChat是一套基于开源IM聊天框架 MobileIMSDK 的产品级移动端IM系统。RainbowChat源于真实运营的产品,解决了大量的屏幕适配、细节优化、机器兼容问题(可自行下载体验:专业版下载安装)。

* RainbowChat可能是市面上提供im即时通讯聊天源码的,唯一一款同时支持TCP、UDP两种通信协议的IM产品(通信层基于开源IM聊天框架  MobileIMSDK 实现)。

v8.1 版更新内容

此版更新内容:

(1)Android端主要更新内容【新增“扫一扫”等功能及优化!】:

  • 1)[新增]“扫一扫”界面及完整功能(支持扫码加好友、加群);
  • 2)[新增]“我的二维码”界面及完整功能;
  • 3)[新增]“群聊二维码”界面及完整功能;
  • 4)[升级]升级okhttp库至4.9.3;
  • 5)[优化]其它小优化。

(2)服务端主要更新内容:

  • 1)[优化]针对扫码加群等功能的相关修改。

此版主要新增功能运行截图更多截图点此查看):

posted @ 2022-05-11 17:49 Jack Jiang 阅读(133) | 评论 (0)编辑 收藏

     摘要: 一、前言MobileIMSDK 是什么?MobileIMSDK  是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、标准Java平台,服务端基于Netty编写。工程地址是:1)Gitee码云地址:https://www.oschina.net/p/mobilei...  阅读全文

posted @ 2022-05-05 15:15 Jack Jiang 阅读(174) | 评论 (0)编辑 收藏

本文由融云技术团队原创分享,原题“IM 消息数据存储结构设计”,内容有修订。

1、引言

在如今的移动互联网时代,IM类产品已是我们生活中不可或缺的组成部分。像微信、钉钉、QQ等是典型的以 IM 为核心功能的社交产品。另外也有一些应用虽然IM功能不是核心,但IM能力也是其整个应用极其重要的组成部分,比如在线游戏、电商直播等应用。

在IM技术应用场景越来越广泛的前提下,对即时通讯IM技术的学习和掌握就显的越来越有必要。

在IM庞大的技术体系中,消息系统无疑是最核心的,而消息系统中,最关键的部分是消息的分发和存储,而离线消息和历史消息又是这个关键环节中不可回避的技术要点。

本文将基于IM消息系统的技术实践,分享关于离线消息和历史消息的正确理解,以及具体的技术配合和实践,希望能为你的离线消息和历史消息技术设计带来最佳实践灵感。

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

本文同步发布于:http://www.52im.net/thread-3887-1-1.html

2、相关文章

技术相关文章:

  1. 什么是IM系统的可靠性?
  2. 闲鱼IM的在线、离线聊天数据同步机制优化实践
  3. 闲鱼亿级IM消息系统的可靠投递优化实践
  4. 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等
  5. IM消息送达保证机制实现(二):保证离线消息的可靠投递
  6. 我是如何解决大量离线消息导致客户端卡顿的

融云技术团队分享的其它文章:

  1. 融云安卓端IM产品的网络链路保活技术实践
  2. 全面揭秘亿级IM消息的可靠投递机制
  3. 解密融云IM产品的聊天消息ID生成策略
  4. 万人群聊消息投递方案的思考和实践
  5. 基于WebRTC的实时音视频首帧显示时间优化实践
  6. 融云IM技术分享:万人群聊消息投递方案的思考和实践

3、IM消息投递的一般做法

在通常的IM消息系统中,对于实时消息、离线消息、历史消息大概都是下面这样的技术思路。

对于在线用户:消息会直接实时发送到在线的接收方,消息发送完成后,服务器端并不会对消息进行落地存储。

而对于离线的用户:服务器端会将消息存入到离线库,当用户登录后,从离线库中将离线消息拉走,然后服务器端将离线消息删除。

这样实现的缺点就是消息不持久化,导致消息无法支持消息漫游,降低了消息的可靠性。

PS:实际上,这其实也不能算是缺点,因为一些场景下存储历史消息并不是必须的,所谓的消息漫游能力也不是必备的,比如微信。

而在我们设计的消息系统中,服务器只要接收到了发送方发上来的消息,在转发给接收方的同时也会在离线数据库及历史消息库中进行消息的落地存储,而历史消息的落地也就能支持消息漫游等相关功能了。

4、什么是离线消息和历史消息?

关于离线消息和历史消息,在技术上,我们是这样定义。

1)离线消息:

离线消息就是用户(即接收方)在离线过程中收到的消息,这些消息大多是用户比较关心的消息,具有一定的时效性。

以我们的系统经验来说,我们的离线消息默认只保存最近七天的消息。

用户(即接收方)在下次登录后会全量获取这些离线消息,然后在客户端根据聊天会话进行离线消息的UI展示(比如显示一个未读消息气泡等)。

PS:用户离线的可能性在技术上其实是由很多种情况组成的,比如对方不在线、对方网络断掉了、对方手机崩溃了、服务器发送时出错了等等,严格来讲——只要无法实时发送成的消息,都算“离线消息”。

2)历史消息:

历史消息存储了用户所有的聊天消息,这些消息包括发出的消息以及接收到的消息。

在客户端获取历史消息时,通常是按照会话进行分页获取的。

以我们的系统经验来说,历史消息的存储时间我们设计默认为半年,当然这个时间可以按实际的产品运营规则来定,没有硬性规定。

5、IM消息的发送及存储流程

以下是我们系统整体的消息发送及存储流程:

 如上图所示:当用户发送聊天消息到服务器端后,首先会进入到消息系统中,消息系统会对消息进行分发以及存储。

这个过程中:对于在线的接收方,会选择直接推送消息。但是遇到接收方不在线或者是消息推送失败的情况下,也会有另外的消息获取方式,比如接收方会主动向服务器拉取未收到的消息。但是接收方何时来服务器拉取消息以及从哪里拉取是未知的,所以消息存入到离线库的意义也就在这里。

消息系统存储离线的过程中,为了不影响整个系统的更为平稳,我们使用了MQ消息队列进行IO解偶,所以聊天消息实际上是异步存入到离线库中的(通过MQ进行慢IO解偶,这其实也是惯常做法)。

在分发完消息后:消息服务会同步一份消息数据到历史消息服务中,历史消息服务同样会对消息进行落地存储。

对于新的客户端设备:会有同步消息的需求(所谓的消息漫游能力),而这也正是历史消息的主要作用。在历史消息库中,客户端是可以拉取任意会话的全量历史消息的。

6、IM离线消息、历史消息在存储逻辑上的区别

6.1 概述

通过上面的图中能清晰的看到:

  • 1)离线消息我们存储介质选用的是 Redis
  • 2)历史消息我们选用的是 HBase

对于为什么选用不同的存储介质,其实我们考虑的是离线消息和历史消息不同的业务场景和读写模式。

下面我们重点介绍一下离线消息和历史消息存储的区别。

6.2 离线消息存储模式——“扩散写”

离线消息的存储模式我们用的是扩散写。

如上图所示:每个用户都有自己单独的收件箱和发件箱:

  • 1)收件箱存放的是需要向这个接收端同步的所有消息;
  • 2)发件箱里存放的是发送端发出的所有消息。

以单聊为例:聊天中的两人会话中,消息会产生两次写,即发送者的发件箱和接收端的收件箱。

而在群的场景下:写入会被更加的放大(扩散),如果群里有 N 个人,那一条群消息就会被扩散写 N 次。

小结一下:

  • 1)扩散写的优点是:接收端的逻辑会非常清晰简单,只需要从收件箱里读取一次即可,大大降低了同步消息所需的读的压力;
  • 2)扩散写的缺点是:写入会被成指数地放大,特别是针对群这种场景。

6.3 历史消息存储模式——“扩散读”

历史消息的存储模式我们用的是扩散读。

因为历史消息中,每个会话都保存了整个会话的全量消息。在扩散读这种模式下,每个会话的消息只保存一次。

对比扩散写模式,扩散读的优点和缺点如下:

  • 1)优点是:写入次数大大降低,特别是针对群消息,只需要存一次即可;
  • 2)缺点是:接收端接收消息非常的复杂和低效,因为这种模式客户端想拉取到所有消息就只能每个会话同步一次,读就会被放大,而且可能会产生很多次无效的读,因为有些会话可能根本没有新消息。

6.4 小结

在 IM 这种应用场景下,通常会用到扩散写这种消息同步模型,一条消息产生一条,但是可能会被读多次,是典型的读多写少的场景。

一个优化好的IM系统,必须从设计上平衡读写压力,避免读或者写任意一个维度达到天花板。

当然扩散写这种模式也有其弊端,比如万人群,会导致一条消息,写入了一万次。

综合来讲:我们需要根据自己的业务场景做相应设计选择,以我们的IM系统为例,就是是根据了离线和历史消息的不同场景选择了写扩散和读扩散的组合模式。适合的才是最好的,没有必要死搬硬套理论。

7、IM客户端的拉取消息逻辑

7.1 离线消息拉取逻辑

对于IM客户端而言,离线消息的获取针对的是自己的整个离线消息,包括所有的会话(直白了说,就是上线时拉取此次离线过程中的所有未收取的离线消息)。

离线消息的获取是自上而下的方式(按时间序),我们的经验是一次获取 200 条(PS:如果离线消息过多,会分页多次拉取,拉取1“次”可以理解为拉取1“页”)。

在客户端拉取离线消息的信令中,需要带上当前客户端缓存的消息的最大时间戳。

通过上节的图我们应该知道,离线消息我们存储的是一个线性结构(指的是按时间顺序),Server 会根据这个时间戳向下查找离线消息。当重装或者新安装 App 时,客户端的“当前客户端缓存的消息的最大时间戳”可以传 0 上来。

Server 也会缓存客户端拉取到的最后一条消息的时间戳,然后根据业务场景,客户端类型等因素来决定从哪里开始拉取,如果没有拉取完 Server 会在拉取消息的应答中带相应的标记位,告诉客户端继续拉取,客户端循环拉取,直到所有离线消息拉完。

7.2 历史消息拉取逻辑

历史消息的获取通常针对的是单一会话。

在拉取过程中,需要向服务端提交两个参数:

  • 1)对方的 ID(如果是单聊的话就是对方的 UserID,如果是群则是群组ID);
  • 2)当前会话的最前面消息的时间戳(即当前会话最老一条消息的时间戳)。

Server据这两个参数,可以定位到这个客户端的此会话,然后一次获取 20 条历史消息。

消息的拉取时序上采用的是自下而上的方式(也就是时间序逆序),即从最后面往前翻。只要有消息,客户端可以一直向前翻,手动触发获取会话的历史消息。

上面的拉取逻辑,在IM界面功能上通常对应的是下拉或点击“加载更多”,比如这样:

8、本文小结

本文主要分享了IM中有关离线消息和历史消息的正确,主要包括离线消息和历史消息的区别,以及二者在存储、分发、拉取逻辑方面的最佳践等。如对文中内容有异议,欢迎留言讨论。

9、参考资料

[1] 一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

[2] 一套原创分布式即时通讯(IM)系统理论架构方案

[3] 从零到卓越:京东客服即时通讯系统的技术架构演进历程

[4] 一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等

[5] 闲鱼亿级IM消息系统的架构演进之路

[6] 闲鱼亿级IM消息系统的可靠投递优化实践

[7] 闲鱼亿级IM消息系统的及时性优化实践

[8] 基于实践:一套百万消息量小规模IM系统技术要点总结

[9] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

[10] 理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨

[11] 零基础IM开发入门(一):什么是IM系统?

本文同步发布于:http://www.52im.net/thread-3887-1-1.html

posted @ 2022-04-19 14:56 Jack Jiang 阅读(205) | 评论 (0)编辑 收藏

本文由网易云信技术团队分享,原题“如何保障一场千万级大型直播?”,有修订和改动。

1、引言

本文以TFBOYS“日光旅行”七周年这场直播演唱会为案例,为你分享大型直播系统后端架构设计的方方面面,包括:基本架构、稳定性保障、安全性障、监控报警、应急预案等技术范畴。

案例中的这次演唱会采用了在线实时互动及演唱会现场的多场景导播切换,提供了主机位和三个艺人专属机位流,同时每个机位流实时转码四个清晰度档位,用户可以根据喜好选择自己想看的内容。这场演唱会最高同时在线人数达78.6万,打破线上付费演唱会世界记录。

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

本文同步发布于:http://www.52im.net/thread-3875-1-1.html

2、本文作者

费曼:网易智企服务端开发工程师。硕士毕业于华中科技大学电信系,2016年加入网易云信,热衷于大规模分布式系统和音视频相关技术,爱好文学、体育和电影。

3、架构方面

3.1 基本

 

上图是该次TFBOYS在线演唱会的直播媒体架构简图。

可以看出一场大型活动直播涵盖的技术方案点非常庞杂,本节接下来的内容我们将以推拉流链路、全局智能调度、流量精准调度以及单元化部署,对这套直播方案做一个展开介绍。

3.2 推拉流链路

 

如上图所示,直播技术架构,分为几大部分:

  • 1)视频直播中心(LMS——Live Manage Service):负责直播流的逻辑管理和操作控制,包括存储和下发实时转码、加密等媒体处理的配置信息;
  • 2)实时互动直播服:由连麦互动和直播两部分组成,主播和连麦者的音视频数据在互动直播高性能服务器合成为一道流后推流到直播流媒体服务器;
  • 3)直播源站服务(LSS——Live Source Service):网易云信自建的直播流媒体服务器节点,结合全局智能调度系统,提供第一公里的最佳链路选择,同时融合支持接入多家CDN厂商;
  • 4)媒体处理服务(MPS——Media Processing Service):提供实时水印、实时转码、媒体数据加密等强大的流媒体处理能力;
  • 5)融合CDN与全局智能调度(GSLB——Golabal Server Load Balancing):提供敏捷智能的CDN调度策略和分配算法,结合全链路、端到端的流媒体控制,来达到最终端侧优良的用户体验;
  • 6)客户端SDK:提供推流、拉流以及上下行的调度能力,便于用户快速接入使用网易云信平台一站式的音视频解决方案。

3.3 融合CDN与智能调度

这是一个端到端的服务,通过平台的SDK执行一个类似HTTPDNS的调度,来做到真正根据用户IP做就近的接入。

针对国内相对复杂的运营商网络环境,在直播上行方面通过BGP网络以及与相关运营商在网络接入方面的合作,能够更加精准地控制网络链路的选择。

而对于下行,也提供了播放端的SDK接入,通过端到端的调度策略就近选择合适的下行链路。

调度的准确性以及最终效果,依赖及时准确的数据支撑。

我们有一个全链路、立体的数据监控体系,一方面利用CDN上的一些实时日志,另一方面结合自建节点、客户端侧上报收集链路上探测的数据,然后整合做一个实时计算来支撑整个调度的策略。

融合CDN方案,通过调度、监控、高可用等技术和手段来解决CDN网络方面的问题。但是对于技术人员来说,就和在使用一个传统的CDN网络一样没有大的差异,这些技术细节对技术人员透明无感知。

3.4 流量精准调度

大型演唱会直播活动,尤其是正式开播时的进场阶段,突发流量峰值会非常高,这就需要实时精准的智能调度策略。

融合CDN的智能调度包含两大部分:CDN分配调度和节点调度。

节点调度:比较常见的是DNS协议解析调度和IP调度(302/HTTPDNS)。前者由于DNS协议原因,调度生效时间较慢,而后者则可以做到请求级别的调度,也就是支持任意比例的负载均衡,更加及时精准。在我们的智能调度的场景里,正常情况下会遵循IP调度,在IP调度解析失败时,客户端上会启动loacl DNS解析逻辑,两者的结合确保了调度的精准和稳定可靠。

Don't put all your eggs in one basket.

“永远不要将鸡蛋放在同一个篮子里”。

从风险管控的角度来说:大型活动保障的CDN厂商资源,通常没法通过一家CDN资源进行满足。融合CDN方案则是将多家CDN厂商进行整合与流量分配调度。

通常在一次大型直播中,多家CDN厂商提供的容量(区域带宽、最高带宽)、质量会各不相同。我们则是通过动态调整调度比例,在确保不超过最大带宽的前提下,精确化按比例分配流量,以及尽可能地确保体验。

我们设计了一套针对CDN厂商的打分算法:影响因子包含当前带宽、保底带宽、最大带宽、带宽预测、带宽质量。

算法遵循以下原则:

  • 1)没超保底的带宽,比超过保底的带宽,得分更高;
  • 2)没超保底的时候,剩余保底和剩余总带宽越大,得分更高;
  • 3)超过保底的时候,剩余总带宽越大、质量越好,得分更高。

各CDN的分数之比决定了调度比例,CDN打分算法是在持续地迭代更新计算,最大化分配使用各家CDN的带宽,然后再分配各家CDN厂商的保障之外的资源。同时优先选择质量较好的厂家,避免单价CDN厂商超分配。

3.5 单元化部署

上面所说,在大型直播活动中,短时间大量涌入的用户请求,对以全局智能调度服务为主的相关非媒体流链路应用,也提出了更高的并发处理挑战。

除了上行的推流链路我们做了主备两个单元的部署,非媒体数据链路上的服务也采用了单元化的部署方案。

在此部署方案下,可用性做到任意单元机房故障,不影响整体可用性,即异地多活。

单元化部署遵循以下原则:

  • 1)单元化的依赖也必须单元化(核心业务);
  • 2)单元化粒度为应用,非api;
  • 3)单元化技术栈对应用尽量避免产生侵入性。

 

如上图所示:非单元化的业务部署在主机房,单元化的业务则部署在主机房和单元机房。

4、稳定性保障

4.1 上行链路稳定

超大型直播方案最核心的诉求就是直播稳定性,下面我们将以该次在线演唱会为案例,重点阐述一下直播的全链路稳定性架构。

上图是我们直播的媒体流链路示意简图:整体方案可以承受任何单节点、单线路、单机房网络出口的故障。

如直播源站部分:采用了多线策略收流,包含机房专线和4G背包方案,一主一备两个线路。同时每个单元的源站集群都有4层负载均衡,一台机器宕机不会影响整体可用性。LMS、LSS、MPS都是跨机房部署,所有服务模块都可配置专有资源池供使用,保证不会受其他租户影响。

整个推流链路:采用双路热流、互为主备,且部署上是互相独立的两个单元,能做到支持Rack级别的故障灾备。双路热流实现了自动主备切换,端上无需专门添加应用层的线路切换逻辑。当任何一个链路出现问题的时候,观众的直播流不会受到影响,端上平均卡顿感知时间在1s以内。

除了推流链路的整体主备单元容灾,每个单元的服务本身也会有容灾手段。比如UPS接入,可以接受30min的供电故障,比如当实时互动流出现问题时,导播台会推垫片流以保证链路数据不中断。

4.2 下行链路稳定

在访次直播活动中,全局智能调度服务会承受较大的峰值压力,在单元化部署的基础上,我们经过多轮压测和性能调优,模型上可支撑千万级用户在半分钟内全部进入直播间。

除了上述关于推流链路的高可用,下行链路也有相关的容灾策略。当GSLB智能调度服务整体不可用,在客户端SDK预埋了融合CDN的local DNS灾备逻辑与比例配置,将云端的全局智能调度fail-over到客户端的本地兜底调度,并保持大数据统计层面的各CDN厂商的流量分配均衡。

同时:客户端也会有播放体验方面的容灾策略,诸如清晰度降级、线路调整等。

5、安全性保障

除了直播全链路的稳定之外,直播安全也很重要。

该次直播活动中,为TFBOYS活动链路多环节都提供了安全保障机制(如防盗链鉴权、IP黑白名单、HTTPS等能力),以及地区、运营商等下行调度的动态限制,实现全链路安全保障。

在此基础上:此次活动采用了端到端的视频流数据加密。

直播场景的加密有几点基本要求:压缩比不变、实时性和低计算复杂度。

除此之外:在融合多cdn的方案背景下,视频流的加密必须考虑到CDN厂商的兼容性。

比如须满足以下要求:

  • 1)不破坏流媒体协议格式、视频容器格式;
  • 2)metadata/video/audio tag的header部分不加密;
  • 3)对于avcSequenceHeader和aacSequenceHeader tag整体不加密。

具体加密算法,可以采用一些流式加密算法,这里我们不再赘述。

 

6、监控与报警

6.1 概述

一场大型直播将会有大量的计算节点参与,除了媒体数据处理与分发的各个服务器节点,还有分布在国内外的海量客户端。

我们对网络链路、服务节点、设备端的健康与质量感知,都离不开数据监控系统。

同时:我们在现有系统无法自动fail-over的故障场景下,需要人工预案介入,而后者的决策判断,也强依赖于完善的全链路数据质量监控与报警系统。

6.2 全链路监控

整个直播链路的监控包含了:

  • 1)上行推流链路的流质量;
  • 2)媒体流实时转码处理;
  • 3)端上播放质量;
  • 4)智能调度系统的可用性;
  • 5)业务量水位等相关监控数据。

上行链路常见的QoS指标有:帧率、码率、RTT等,其维度包含主备线路、出口运营商、CDN厂商节点等。

端上的QoS指标则包含了:拉流成功率、首帧时长、卡顿率、httpdns缓存命中率,维度则覆盖包含CDN厂商、国家、省份、运营商、直播流、清晰度档位、客户端等。

此次直播中:内容上支持了多种机位流以及多个清晰度的转码输出流,同时通过多个CDN厂商进行分发,我们把上行链路中节点的码率、帧率,直观地通过N个指标卡集中展示在单个大盘页面上,并且通过增加预警值进行异常显示和弹窗消息告警。活动作战室现场,我们采用了多个大屏展示,非常直观地展现当前主备双推流链路的实时帧率、码率等情况,为现场地指挥保障提供了强大的数据决策支撑。

以下图为例:蓝色表示上行帧率,绿色表示正常的上行码率,红色表示码率值过低,N/A表示当前没有上行推流数据。

而在下行播放链路中,比较常用的指标就是卡顿率。

下面是我们对卡顿相关的描述:

  • 1)一次卡顿:播放器持续2s发生缓冲区空,即播放器2s没有拉到流;
  • 2)一分钟用户卡顿:1分钟窗口内,用户只要卡顿一次,则该用户计作卡顿用户;
  • 3)一分钟用户卡顿率:1分钟窗口内,卡顿用户数/总的用户数;
  • 4)一分钟用户零卡顿率:1分钟窗口内,(总的用户数 - 卡顿用户数)/总的用户数。

为什么会选择用户卡顿率这个指标,而不是使用整体的卡顿采样点/总采样数呢?

是因为:我们更想看到有多少用户没有出现过卡顿现象,这更能直观体现优质网络的整体占比。通过对各省份用户零卡顿率、用户数排行,以及各省用户卡顿率的观察,我们可以非常直观地找到卡顿严重的地区,以便重点关注,进行资源调度优化。

7、应急预案

任何一个系统,无论你号称它被设计得多么健壮,它仍然会有故障时间的存在。

硬件故障、软件bug、人为操作失误等等,这些都无可避免地存在着。他们未必是一个必须多少时间内将其彻底解决的问题,他们是我们必须认清并接受共存的一个事实。

所以:预案管理是大型直播活动保障中不可缺少的一环。

我们遵循以下的预案原则:

  • 1)预案信息明确:大盘自动监控不具备二义性,确保预案信息来源正确,触发执行预案的条件明确且有数值化约束;
  • 2)预案操作简洁:所有的预案操作都有有简洁明确(开关型)的操作输入;
  • 3)预案操作安全:所有预案要经过充分预演,同时预演操作本身需要有明确的确认机制,以确保在正常情况下不会被误触发;
  • 4)预案影响验证:明确理清预案操作的影响,QA在预演阶段需要对相关影响进行充分验证。

此次活动的前期筹备中,我们总计进行了3次直播全链路的拟真演练,以及2次联合互动现场、导播台现场的活动全流程级别的彩排,另外进行了大大小小总计数十次的各类风险预案演练。所有演练过程中发现的问题,都会进行专项解决。

风险预案这块,包含了各类资源故障、上下行链路质量、地区性网络故障、CDN异常流量水位等在内的场景应对。其中资源故障包含了机器宕机、机架整体断电、堆叠交换机宕机、机房外网出口不可用,我们均进行了风险预案演练覆盖。

下面列举几点直播解决方案中的部分预案机制:

  • 1)如果因为误操作等导致非正常解密等,可在推流不中断的情况下,动态中止流加密,客户端无任何感知影响;
  • 2)某家cdn在某地区运营商出现大面积故障瘫痪,该地区相应运营商线路的QoS指标会大幅度下降并触发报警,将故障cdn在该地区运营商进行黑名单处理,动态停止对其的调度,将流量调度至正常提供服务的cdn厂商;
  • 3)在两路热流均正常的情况下,但是正在分发的一路出现质量问题,方案可支持手动触发主备切换,让监控数据质量更好的另一路流参与分发,客户端感知时间在1s以内;
  • 4)因为一些不可抗因素,某机房出现大面积故障整体不可用,触发链路报警,此时我们会紧急将流切至另一机房,故障感知与恢复的时间在一分钟内。

8、相关文章

[1] 移动端实时音视频直播技术详解(一):开篇

[2] 移动端实时音视频直播技术详解(二):采集

[3] 移动端实时音视频直播技术详解(三):处理

[4] 移动端实时音视频直播技术详解(四):编码和封装

[5] 移动端实时音视频直播技术详解(五):推流和传输

[6] 移动端实时音视频直播技术详解(六):延迟优化

[7] 淘宝直播技术干货:高清、低延时的实时视频直播技术解密

[8] 爱奇艺技术分享:轻松诙谐,讲解视频编解码技术的过去、现在和将来

[9] 零基础入门:实时音视频技术基础知识全面盘点

[10] 实时音视频面视必备:快速掌握11个视频技术相关的基础概念

[11] 网易云信实时视频直播在TCP数据传输层的一些优化思路

[12] 浅谈实时音视频直播中直接影响用户体验的几项关键技术指标

[13] 首次披露:快手是如何做到百万观众同场看直播仍能秒开且不卡顿的?

[14] 直播系统聊天技术(一):百万在线的美拍直播弹幕系统的实时推送技术实践之路

[15] 直播系统聊天技术(二)阿里电商IM消息平台,在群聊、直播场景下的技术实践

[16] 直播系统聊天技术(三):微信直播聊天室单房间1500万在线的消息架构演进之路

[17] 直播系统聊天技术(四):百度直播的海量用户实时消息系统架构演进实践

[18] 直播系统聊天技术(五):微信小游戏直播在Android端的跨进程渲染推流实践

[19] 直播系统聊天技术(六):百万人在线的直播间实时聊天消息分发技术实践

[20] 直播系统聊天技术(七):直播间海量聊天消息的架构设计难点实践

本文同步发布于:http://www.52im.net/thread-3875-1-1.html

posted @ 2022-04-13 10:58 Jack Jiang 阅读(203) | 评论 (0)编辑 收藏

本文由小枣君分享,文案:小枣君、漫画:杨洋,来自鲜枣课堂,有少许改动,原文链接见文末。

1、引言

网络编程能力对于即时通讯技术开发者来说是基本功,而计算机网络又是网络编程的理论根基,因而深刻准确地理解计算机网络知识显然能夯实你的即时通讯应用的实践品质。

本文风格延续了社区里的《网络编程懒人入门》、《脑残式网络编程入门》两个系列,没有更多的理论堆砌,通俗而不失内涵,非常适合希望轻松快乐地学习计算机网络知识的网络编程爱好者们阅读,希望能给你带来不一样的网络知识入门视角。

本篇文章将利用简洁生动的文字,配上轻松幽默的漫画,助你从零开始快速建立起对IPv6技术的直观理解,非常适合入门者阅读。

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

 (本文同步发布于:http://www.52im.net/thread-3868-1-1.html

2、系列文章

本文是该系列文章中的第3篇:

  1. 网络编程入门从未如此简单(一):假如你来设计网络,会怎么做?
  2. 网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?
  3. 网络编程入门从未如此简单(三):什么是IPv6?漫画式图文,一篇即懂!》(本文

本文是IPv6的轻松入门文章,希望你能喜欢。

* 推荐阅读:本文作者的另一篇也同样优秀:网络编程懒人入门(十一):一文读懂什么是IPv6,感兴趣的建议一并阅读 。

3、技术背景

随着移动网络的不断建设和普及,加速了我们迈入万物互联时代的步伐。

我们的整个互联网络,正在发生翻天覆地的变化。急剧增加的网络连接数和流量,对网络的承载和传送能力,提出了前所未有的挑战。

除了速率和带宽之外,5G在垂直行业的落地,也要求网络能够提供灵活的差异化定制服务能力。

也就是说,面对不同的行业应用场景,网络需要能够提供套餐式的服务,支持不同的QoS(Quality of Service,服务质量),支持端到端的切片。

4、IP协议

众所周知,我们现在形影不离的互联网,最早诞生于上世纪60年代。它的核心基础,就是大名鼎鼎的IP协议Internet Protocol,网际互连协议,见《技术往事:改变世界的TCP/IP协议(珍贵多图、手机慎点)。

如果没有IP协议,以及基于它的IP地址,我们就没办法刷剧、网购、吃鸡、聊微信。

说白了,互联网就是一套“快递系统”。IP地址是你的快递地址,而IP协议,则是快递公司的“工作流程和制度”。

所有我们需要传递的信息,包括文字、图片、音频、视频等,都需要被打包成一个个的“快递包裹”,然后经过快递系统的运输,送到最终目的地。

5、第一、第二代“快递系统”:IPv4

互联网诞生后,长期使用的是v4版本的IP协议,也就是大家熟知的IPv4。

我们可以把它理解为第一代快递系统,它为互联网的早期发展奠定了坚实基础。

后来,随着互联网的迅速发展扩张,原始的IPv4系统暴露出了很多的问题,进行了一些技术上的升级改进。尤其是MPLSMulti-Protocol Label Switching,多协议标签交换)技术的引入,将这个快递系统升级到了第二代。

到了最近这几年,因为前面我们提到的网络挑战,远远超过了第二代快递系统的能力范围。

6、第三代“快递系统”:IPv6

于是,IPv6以及IPv6+,作为第三代快递系统,正式闪亮登场。

IPv6,是v6版本的IP协议。而IPv6+,则是IPv6的升级加强版。

具体来说,IPv6+基于IPv6,实现了更多的创新。

这些创新,既包括以IPv6分段路由、网络切片、随流检测、新型组播和应用感知网络等协议为代表的协议创新,又包括以网络分析、自动调优、网络自愈等网络智能化为代表的技术创新。

凭借这些创新,IPv6+更适合行业用户,更能够有力支撑行业的数字化转型和发展。

接下来,我们仔细看看,IPv6+究竟带来了哪些变化和升级。

7、IPv6优势1:IP地址大幅增加

首先,IPv6最广为人知的优点就是IP地址的大幅增加。具体来说,IPv6的地址数量是IPv4的2的96次方倍(详见《一文读懂什么是IPv6》的第6节内容)。

这么说吧,如果采用IPv6,即便是给地球上的每粒沙子都赋予一个IP地址,都绰绰有余。

传统的IPv4快递系统,邮箱地址不够,快递员往往需要将快速送到门卫处或快递柜,然后再二次派送给用户(在IPv4时代,这就是NAT路由技术啦,详见《NAT详解——详细原理、P2P简介》、《什么是公网IP和内网IP?NAT转换又是什么鬼?)。

 

在IPv6快速系统下,每个用户都有属于自己的邮箱地址,快递员可以直接将快递送到用户手中。

很显然,这样不仅提升了快递的收发速度,也节省了门卫或快递柜的开支,简化了维护,减少了能耗,降低了成本。

其实,IP地址数量的压力,主要来自物联网场景。因为物的数量远远超过人的数量。而且,物联网的控制,更需要端到端的直达。这样才能有更低的时延,实现更精准的控制。

8、IPv6优势2:“快递包装”的升级

IPv6的第二个重大改进,在于“快递包装”的升级。IPv6的数据报文结构变得更加丰富,里面可以记录更多的内容和信息。

简单来说,就是运输快递的纸箱变得更高级了。

传统的快递系统,包装很简单,我们并不知道里面到底是什么物品。

IPv6的快递系统,纸箱上可以贴更多的标签,标识纸箱里的货物属性,例如重货、易碎品、紧急文件等。系统根据标签,可以快速判断这个快递包裹所需的服务,例如需要加急、需要小心轻放等。

这样一来,快递公司可以根据包裹显示的信息,为不同的客户提供更精细化的服务,采用差异化的收费标准。

快递公司还可以走精品路线,提供专属的快递通道,实现高端用户的资源独享。

IPv6+对数据包属性的精准识别,也可以帮助运营商更好地掌握整个网络中数据业务的流动趋势,更好地调动和分配资源。

例如,从A地到B地的视频大颗粒传输需求很多,那么,就可以建立视频大颗粒业务专线,更好地满足传输需求。

这就好像从A地到B地的海鲜运输需求很多,那快递公司就采购更多的冷链运输车,专门投入到这条线路上,赚取更多的利润。

9、IPv6优势3:升级了“导航能力”

传统快递系统的运输路径,是相对固定和死板的。运输车从起点到终点,经过每一个路口,都由路口指定下一步前进的方向。

 

而IPv6+的话,通过与SR(Segment Routing,分段路由)技术、SDN(Software Defined Network,软件定义网络)技术进行结合,具有更强的路径选择能力。

快递包裹在出发时,就已经从管理中心获得了从起点到终点的最佳路径。每一次选路,都按照规划进行,可以避开拥堵,也可以避免绕路。

换言之,IPv6+超强的路径编排能力,可以实现数据报文的一跳入云,大幅提升效率。

10、IPv6优势4:降低运维成本

因为网络的管理功能集中,可以更方便地将配置意图转换成脚本,自动部署给各个网络节点。

引入AI之后,更能够对故障现象进行自动分析,更快地找到原因。

甚至说,AI还可以根据对故障模型的学习,主动提前识别网络中潜在的故障风险,实现事故预防。

集中管理+AI管理,大幅降低了网络的维护难度,提升了运维效率,减少了维护成本。

11、IPv6优势5:更安全

IPv6+的安全防御能力相比IPv4有了很大的提升,真正实现了云、网、安一体化防御。

传统网络中,因为大量私网的存在,恶意行为很难溯源。也就是说,很多坏人躲在暗处,发出有问题的包裹,对快递系统造成破坏。

在IPv6+网络中,节点采用公网地址取代私网地址,这就意味着,在快递系统中运输的每一个包裹,都有真实可溯源的寄件人信息。失去了私网的伪装,破坏行为将无所遁形。

升级后的快递包装(数据报文结构),也大幅增加了破坏分子对包裹进行恶意伪造和窃听的难度,增强了包裹的安全性和私密性。

 

12、写在最后

总而言之,IPv6+是一个高速、高效、灵活、智能的先进“快递系统”。

它可以提供满足千行百业应用需求的差异化服务能力,适配不同行业的业务承载需求,支撑各个行业的数字化转型,助力消费互联网向产业互联网升级,推动整个社会数字经济的发展。

目前,IPv6在我国已经取得了显著的成果。截至今年8月,我国IPv6地址资源储备位居世界第一。IPv6活跃用户数达5.51亿,占我国全部网民数的54.52%。

IPv6+的黄金时代,已然到来!

 

13、参考资料

[1] TCP/IP详解 卷1 - 第3章 IP:网际协议

[2] 网络编程懒人入门(十一):一文读懂什么是IPv6

[3] IPv6技术详解:基本概念、应用现状、技术实践(上篇)

[4] IPv6技术详解:基本概念、应用现状、技术实践(下篇)

[5] Java对IPv6的支持详解:支持情况、相关API、演示代码等

[6] NAT详解——详细原理、P2P简介

[7] 什么是公网IP和内网IP?NAT转换又是什么鬼?

本文同步发布于:http://www.52im.net/thread-3868-1-1.html

posted @ 2022-03-30 12:56 Jack Jiang 阅读(307) | 评论 (0)编辑 收藏

本文由小米技术团队分享,原题“小爱接入层单机百万长连接演进”,有修订。

1、引言

小爱接入层是小爱云端负责设备接入的第一个服务,也是最重要的服务之一,本篇文章介绍了小米技术团队2020至2021年在这个服务上所做的一些优化和尝试,最终将单机可承载长连接数从30w提升至120w+,节省了机器30+台

提示:什么是“小爱”?

小爱(全名“小爱同学”)是小米旗下的人工智能语音交互引擎,搭载在小米手机、小米AI音箱、小米电视等设备中,在个人移动、智能家庭、智能穿戴、智能办公、儿童娱乐、智能出行、智慧酒店、智慧学习共八大类场景中使用。

(本文同步发布于:http://www.52im.net/thread-3860-1-1.html

2、专题目录

本文是专题系列文章的第7篇,总目录如下:

  1. 长连接网关技术专题(一):京东京麦的生产级TCP网关技术实践总结
  2. 长连接网关技术专题(二):知乎千万级并发的高性能长连接网关技术实践
  3. 长连接网关技术专题(三):手淘亿级移动端接入层网关的技术演进之路
  4. 长连接网关技术专题(四):爱奇艺WebSocket实时推送网关技术实践
  5. 长连接网关技术专题(五):喜马拉雅自研亿级API网关技术实践
  6. 长连接网关技术专题(六):石墨文档单机50万WebSocket长连接架构实践
  7. 长连接网关技术专题(七):小米小爱单机120万长连接接入层的架构演进》(* 本文

3、什么是小爱接入层

整个小爱的架构分层如下:

接入层主要的工作在鉴权授权层和传输层,它是所有小爱设备和小爱大脑交互的第一个服务。

由上图我们知道小爱接入层的重要功能有如下几个:

  • 1)安全传输和鉴权:维护设备和大脑的安全通道,保障身份认证有效和传输数据安全;
  • 2)维护长连接:维持设备和大脑的长连接(Websocket等),做好连接状态存储,心跳维护等工作;
  • 3)请求转发:针对每一次小爱设备的请求做好转发,保障每一次请求的稳定。

4、早期接入层的技术实现

小爱接入层最早的实现是基于AkkaPlay,我们使用它们搭建了第一个版本,该版本特点如下:

  • 1)基于Akka我们基本做到了初步的异步化,保障核心线程不被阻塞,性能尚可。
  • 2)Play框架天然支持Websocket,因此我们在有限的人力下能够快速搭建和实现,且能够保障协议实现的标准性。

5、早期接入层的技术问题

随着小爱长连接的数量突破千万大关,针对早期的接入层方案,我们发现了一些问题。

主要的问题如下:

1)长连接数量上来后,需要维护的内存数据越来越多,JVM的GC成为不可忽略的性能瓶颈,且一旦代码写的不好有GC风险。经过之前事故分析,Akka+Play版的接入层其单实例长连接数量的上限在28w左右。

2)老版本的接入层实现比较随意,其Akka Actor之间存在非常多的状态依赖而不是基于不可变的消息传递这样使得Actor之间的通信变成了函数调用,导致代码可读性差且维护很困难,没有发挥出Akka Actor在构建并发程序的优势。

3)作为接入层服务,老版本对协议的解析是有很强的依赖的,这导致它要随着版本变动而频繁上线,其上线会引起长连接重连,随时有雪崩的风险。

4)由于依赖Play框架,我们发现其长连接打点有不准确的问题(因为拿不到底层TCP连接的数据),这个会影响我们每日巡检对服务容量的评估,且依赖其他框架在长连接数量上来后我们没有办法做更细致的优化。

6、新版接入层的设计目标

基于早期接入层技术方案的种种问题,我们打算重构接入层。

对于新版接入层我们制定的目标是:

  • 1)足够稳定:上线尽可能不断连接且服务稳定;
  • 2)极致性能:目标单机至少100w长连接,最好不要受GC影响;
  • 3)最大限度可控:除了底层网络I/O的系统调用,其他所有代码都要是自己实现/或者内部实现的组件,这样我们有足够的自主权。

于是,我们开始了单机百万长连接的漫漫实践之路。。。

7、新版接入层的优化思路

7.1 接入层的依赖关系

接入层与外部服务的关系理清如下:

7.2 接入层的功能划分

接入层的主要功能划分如下:

  • 1)WebSocket解析:收到的客户端字节流,要按照WebSocket协议要求解析出数据;
  • 2)Socket状态保持:存储连接的基本状态信息;
  • 3)加密解密:与客户端通讯的所有数据都是加密过的,而与后端模块之间传输是json明文的;
  • 4)顺序化:同一个物理连接上,先后两个请求A、B到达服务器,后端服务中B可能先于A得到了应答,但是我们收到B不能立刻发送给客户端,必须等待A完成后,再按照A,B的顺序发给客户端;
  • 5)后端消息分发:接入层后面不止对接单个服务,可能根据不同的消息转发给不同的服务;
  • 6)鉴权:安全相关验证,身份验证等。

7.3 接入层的拆分思路

把之前的单一模块按照是否有状态,拆分为两个子模块。

具体如下:

  • 1)前端:有状态,功能最小化,尽量少上线;
  • 2)后端:无状态,功能最大化,上线可做到用户无感知。

所以,按照上面的原则,理论上我们会做出这样的功能划分,即前端很小、后端很大。示意图如下图所示。

8、新版接入层的技术实现

8.1 总览

模块拆分为前后端:

  • 1)前端有状态,后端无状态;
  • 2)前后端是独立进程,同机部署。

补充:前端负责建立与维护设备长连接的状态,为有状态服务;后端负责具体业务请求,为无状态服务。后端服务上线不会导致设备连接断开重连及鉴权调用,避免了长连接状态因版本升级或逻辑调整而引起的不必要抖动;

前端使用CPP实现:

  • 1)Websocket协议完全自己解析:可以从Socket层面获取所有信息,任何Bug都可以处理;
  • 2)更高的CPU利用率:没有任何额外JVM代价,无GC拖累性能;
  • 3)更高的内存利用率:连接数量变大后与连接相关的内存开销变大,自己管理可以极端优化。

后端暂时使用Scala实现:

  • 1)已实现的功能直接迁移,比重写代价要低得多;
  • 2)依赖的部分外部服务(比如鉴权)有可直接利用的Scala(Java)SDK库,而没有C++版本,若用C++重写代价非常大;
  • 3)全部功能无状态化改造,可以做到随时重启而用户无感知。

通讯使用ZeroMQ

进程间通讯最高效的方式是共享内存,ZeroMQ基于共享内存实现,速度没问题。

8.2 前端实现

整体架构:

 

如上图所示,由四个子模块组成:

  • 1)传输层:Websocket协议解析,XMD协议解析;
  • 2)分发层:屏蔽传输层的差异,不管传输层使用的什么接口,在分发层转化成统一的事件投递到状态机;
  • 3)状态机层:为了实现纯异步服务,使用自研的基于Actor模型的类Akka状态机框架XMFSM,这里面实现了单线程的Actor抽象;
  • 4)ZeroMQ通讯层:由于ZeroMQ接口是阻塞实现,这一层通过两个线程分别负责发送和接收。

8.2.1)传输层:

WebSocket 部分使用 C++ 和 ASIO 实现 websocket-lib。小爱长连接基于WebSocket协议,因此我们自己实现了一个WebSocket长连接库。

这个长连接库的特点是:

  • a. 无锁化设计,保障性能优异;
  • b. 基于BOOST ASIO 开发,保障底层网络性能。

压测显示该库的性能十分优异的:

这一层同时也承担了除原始WebSocket外,其他两种通道的的收发任务。

目前传输层一共支持以下3种不同的客户端接口:

  • a. websocket(tcp):简称ws;
  • b. 基于ssl的加密websocket(tcp):简称wss;
  • c. xmd(udp):简称xmd。

8.2.2)分发层:

把不同的传输层事件转化成统一事件投递到状态机,这一层起到适配器的作用,确保无论前面的传输层使用哪种类型,到达分发层变都变成一致的事件向状态机投递。

8.2.3)状态机处理层:

主要的处理逻辑都位于这一层中,这里非常重要的一个部分是对于发送通道的封装。

对于小爱应用层协议,不同的通道处理逻辑是完全一致的,但是在处理和安全相关逻辑上每个通道又有细节差异。

比如:

  • a. wss 收发不需要加解密,加解密由更前端的Nginx做了,而ws需要使用AES加密发送;
  • b. wss 在鉴权成功后不需要向客户端下发challenge文本,因为wss不需要做加解密;
  • c. xmd 发送的内容与其他两个不同,是基于protobuf封装的私有协议,且xmd需要处理发送失败后的逻辑,而ws/wss不用考虑发送失败的问题,由底层Tcp协议保证。

针对这种情况:我们使用C++的多态特性来处理,专门抽象了一个Channel接口,这个接口中提供的方法包含了一个请求处理的一些关键差异步骤,比如如何发送消息到客户端,如何stop连接,如何处理发送失败等等。对于3种(ws/wss/xmd)不同的发送通道,每个通道有自己的Channel实现。

客户端连接对象一创建,对应类型的具体Channel对象就立刻被实例化。这样状态机主逻辑中只实现业务层的公共逻辑即可,当在有差异逻辑调用时,直接调用Channel接口完成,这样一个简单的多态特性帮助我们分割了差异,确保代码整洁。

8.2.4)ZeroMQ 通讯层:

通过两个线程将ZeroMQ的读写操作异步化,同时负责若干私有指令的封装和解析。

8.3 后端实现

8.3.1)无状态化改造:

后端做的最重要改造之一就是将所有与连接状态相关的信息进行剔除。

整个服务以 Request(一次连接上可以传输N个Request)为核心进行各种转发和处理,每次请求与上一次请求没有任何关联。一个连接上的多次请求在后端模块被当做独立请求处理。

8.3.2)架构:

Scala 服务采用 Akka-Actor 架构实现了业务逻辑。

服务从 ZeroMQ 收到消息后,直接投递到 Dispatcher 中进行数据解析与请求处理,在 Dispatcher 中不同的请求会发送给对应的 RequestActor进行 Event 协议解析并分发给该 event 对应的业务 Actor 进行处理。最后将处理后的请求数据通过XmqActor 发送给后端 AIMS&XMQ 服务。

一个请求在后端多个 Actor 中的处理流程:

8.3.3)Dispatcher 请求分发:

前端与后端之间通过 Protobuf 进行交互,避免了Json 解析的性能消耗,同时使得协议更加规范化。

后端服务从 ZeroMQ 收到消息后,会在 DispatcherActor 中进行PB协议解析并根据不同的分类(简称CMD)进行数据处理,分类包括如下几种。

* BIND 命令:

鉴权功能,由于鉴权功能逻辑复杂,使用C++语言实现起来较为困难,目前依然放在 scala 业务层进行鉴权。该部分对设备端请求的 HTTP Headers 进行解析,提取其中的 token 进行鉴权,并将结果返回前端。

* LOGIN 命令:

设备登入,设备鉴权通过后当前连接已成功建立,此时会进行 Login 命令的执行,用于将该长连接信息发送至AIMS并记录于Varys服务中,方便后续的主动下推等功能。在 Login 过程中,服务首先将请求 Account 服务获取长连接的 uuid(用于连接过程中的路由寻址),然后将设备信息+uuid 发送至AIMS进行设备登入操作。

* LOGOUT 命令:

设备登出,设备在与服务端断开连接时需要进行 Logout 操作,用于从 Varys 服务中删除该长连接记录。

* UPDATE 与 PING 命令:

a. Update 命令,设备状态信息更新,用于更新该设备在数据库中保存的相关信息;

b. Ping 命令,连接保活,用于确认该设备处于在线连接状态。

* TEXT_MESSAGE 与 BINARY_MESSAGE:

文本消息与二进制消息,在收到文本消息或二进制消息时将根据 requestid 发送给该请求对应的RequestActor进行处理。

8.3.4)Request 请求解析:

针对收到的文本和二进制消息,DispatcherActor 会根据 requestId 将其发送给对应的RequestActor进行处理。

其中:文本消息将会被解析为Event请求,并根据其中的 namespace 和 name 将其分发给指定的业务Actor。二进制消息则会根据当前请求的业务场景被分发给对应的业务Actor。

8.4 其他优化

在完成新架构 1.0 调整过程中,我们也在不断压测长连接容量,总结几点对容量影响较大的点。

8.4.1)协议优化:

a. JSON替换为Protobuf: 早期的前后端通信使用的是 json 文本协议,后来发现 json 序列化、反序列化这部分对CPU的占用较大,改为了 protobuf 协议后,CPU占用率明显下降。

b. JSON支持部分解析:业务层的协议是基于json的,没有办法直接替换,我们通过"部分解析json"的方式,只解析很小的 header 部分拿到 namespace 和 name,然后将大部分直接转发的消息转发出去,只将少量 json 消息进行完整反序列化成对象。此种优化后CPU占用下降10%。

8.4.2)延长心跳时间:

在第一次测试20w连接时,我们发现在前后端收发的消息中,一种用来保持用户在线状态的心跳PING消息占了总消息量的75%,收发这个消息耗费了大量CPU。因此我们延长心跳时间也起到了降低CPU消耗的目的。

8.4.3)自研内网通讯库:

为了提高与后端服务通信的性能,我们使用自研的TCP通讯库,该库是基于Boost ASIO开发的一个纯异步的多线程TCP网络库,其卓越的性能帮助我们将连接数提升到120w+。

9、未来规划

经过新版架构1.0版的优化,验证了我们的拆分方向是正确的,因为预设的目标已经达到:

  • 1)单机承载的连接数 28w => 120w+(普通服务端机器 16G内存 40核 峰值请求QPS过万),接入层下线节省了50%+的机器成本;
  • 2)后端可以做到无损上线。

再重新审视下我们的理想目标,以这个为方向,我们就有了2.0版的雏形:

具体就是:

  • 1)后端模块使用C++重写,进一步提高性能和稳定性。同时将后端模块中无法使用C++重写的部分,作为独立服务模块运维,后端模块通过网络库调用;
  • 2)前端模块中非必要功能尝试迁移到后端,让前端功能更少,更稳定;
  • 3)如果改造后,前端与后端处理能力差异较大,考虑到ZeroMQ实际是性能过剩的,可以考虑使用网络库替换掉ZeroMQ,这样前后端可以从1:1单机部署变为1:N多机部署,更好的利用机器资源。

2.0版目标是:经过以上改造后,期望单前端模块可以达到200w+的连接处理能力。

10、参考资料

[1] 上一个10年,著名的C10K并发连接问题

[2] 下一个10年,是时候考虑C10M并发问题了

[3] 一文读懂高性能网络编程中的线程模型

[4] 深入操作系统,一文读懂进程、线程、协程

[5] Protobuf通信协议详解:代码演示、详细原理介绍等

[6] WebSocket从入门到精通,半小时就够!

[7] 如何让你的WebSocket断网重连更快速?

[8] 从100到1000万高并发的架构演进之路

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

(本文同步发布于:http://www.52im.net/thread-3860-1-1.html

posted @ 2022-03-22 17:00 Jack Jiang 阅读(613) | 评论 (0)编辑 收藏

仅列出标题
共43页: First 上一页 11 12 13 14 15 16 17 18 19 下一页 Last 
Jack Jiang的 Mail: jb2011@163.com, 联系QQ: 413980957, 微信: hellojackjiang