云上视频业务基于边缘容器的技术实践

2020-12-31 10:10:49 浏览数 (1)

作者刘腾飞,后台开发,目前从事腾讯云微瓴平台、边缘网关、大数据融合等相关研发工作。

‍视频网关是视频云系统下的一个边缘容器设备,它起着将视频数据承上启下的功能。

视频云

说到边缘视频网关就不得不提到云计算中的视频云,它是各领域的视频系统比如安防监控等向着智能化、物联网、上云发展的产物。

在云平台上通过云服务器和边缘视频设备将采集的视频输出编码后经过网络实时传输给终端,终端进行实时解码后显示输出。终端同时可以进行操作,经过网络将操作控制信息实时传送给云端应用后台对边缘视频设备进行控制。

视频云一般框架

一个物联网场景下云边协同的智能视频云系统,具有实时流、历史录像功能,并支持对视频数据算法分析与结果联动控制,可以兼容市面上大多数厂商的视频设备比如摄像头和NVR。不仅可以在公有云/私有云部署,甚至提供支持有损服务的本地局域网视频最小系统。

云/边端服务框架

视频网关

视频网关是云计算在视频垂直领域中的边缘容器设备,可以将其理解连接视频数据在视频传感器与云上服务之间的桥梁,是视频云系统中的关键一环,实现视频设备广泛的兼容性以及云边协同都离不开它的身影。设计一个功能完备,可扩展,高可用的视频网关是非常值得投入的。

如何实现

视频网关需要实现的基本功能包括视频流采集与推送、视频设备接入与管理等,作为一个与底层硬件打交道的设备,又涉及到云计算中的接入、安全以及云边协同等方面,可谓麻雀虽小五脏俱全。

视频数据采集

视频云系统中视频数据的采集由位于边缘侧的视频网关完成,视频网关连接视频采集设备比如IPC/NVR, 通过厂家SDK或者ONVIF协议对视频采集设备进行管理,网关拉取视频采集设备的数据流并推送云端或者边缘侧的视频服务,由视频服务对视频数据进行转码、数据流协议转换等操作以适配不同的播放客户端。

视频云架构

视频设备管理

摄像头、NVR等视频设备位于用户局域网内,通过边缘视频网关接入到视频云系统中。边缘视频网关和视频设备需要在管理平台上通过导入的方式做登记以便明确视频网关与视频设备以及视频网关与业务的绑定关系。视频网关管理视频设备并将设备状态实时同步到云视频系统中,管理平台实现"设备影子"并提供对视频网关以及视频设备状态信息的增删改查接口。

设备影子管理

数据安全

视频上云需要安全认证,视频云系统中边缘容器设备接入云端服务、边缘容器设备之间以及边缘容器设备与云端服务之间的数据流采用标准国密算法保证其运行的安全性,其中边缘容器设备接入云视频流程中采用国密sm2非对称秘钥技术保证接入安全,边缘容器设备与云视频之间的数据通道采用国密sm4对称秘钥技术保证信令与视频数据的安全。

设备接入

视频云系统中视频网关等边缘容器设备通常位于用户局域网内,视频网关在局域网内连接视频设备比如IPC或者NVR,并作为一个边缘容器设备接入到云视频。视频网关通过注册、登录方式接入云视频保证安全性,整个设备接入流程中视频网关与云视频之间通信采用国密sm2非对称加密技术进行消息加密与签名校验,接入云视频后视频网关与云视频之间的信令通道采用国密sm4对称秘钥方式进行数据加解密。

1)在视频云开放平台为视频网关设备申请sn序列号后即可以得到视频网关的私钥以及接入云视频所需的公钥;

2)视频网关接入云视频的注册阶段,首先网关使用网关私钥对自身信息进行签名,然后使用云视频公钥将签名信息以及设备sn等信息进行加密并发送云视频,这一过程可以保证网关的注册请求只能被云视频解析,并且云视频可以通过签名验签识别消息是由视频网关发出。

3)注册云视频成功后,云视频会将其与视频网关之间的信令通道等相关信息经过云视频私钥加密后返回给视频网关,视频网关通过云视频公钥可以解析。

4)视频网关接入云视频的登录阶段会与云视频协商信令通道对称秘钥,首先网关使用网关私钥对自身信息进行签名,然后使用云视频公钥将签名信息以及设备唯一标识、对称秘钥向量等信息进行加密后发送云视频,这一过程可以保证网关的登录请求只能被云视频解析,并且云视频可以通过签名验签识别消息是由视频网关发出。

5)登录云视频成功后,云视频会将其与视频网关之间信令通道中使用的对称秘钥key、token以及有效时间等信息经过云视频私钥加密后返回给视频网关,视频网关通过云视频公钥可以解析。

数据通道

边缘容器设备与云视频之间的业务数据,比如视频网关与云视频之间的视频流推送、摄像头列表维护等消息通过数据通道传达,采用国密sm2对称秘钥技术加密,如果数据通道的token、对称秘钥过期需要视频网关重新登录云视频获取。

以边缘视频网关向云视频推送视频流这一过程为例说明,视频网关采集到摄像头设备的视频流后对视频帧加密后传输到云端视频后台服务,其中视频网关与云端视频后台服务之间推视频流建立握手的token以及推流数据加密使用的国密sm4 key等安全信息是通过视频网关与云视频之间的数据通道下发的,视频链路保证该加密信息的单次使用时效性,也就是说单次推流的信令中所包含的加密信息如果在一个时间阈值内不使用或者握手成功后就不可再次复用了。

视频云系统中边缘容器设备接入与数据通道的安全认证机制如下图所示。

云边协同

灵活的云边协同和边缘计算能力,集中管理能力云端收拢,部分逻辑下沉边缘,保证快速响应,即便在云环境网络异常下也能提供基础的本地视频服务实现高可用。

在传统的视频监控领域,摄像头、算法和监控软件会部署在同一个局域网内,对于用户而言,往往有在公网短时播放的需求。如果将视频放到公网上进行播放,又会带来带宽成本以及安全问题。视频云系统为解决以上问题,提供云边协同和边缘计算能力,在云端控制边缘节点,可以将已训练好的算法或者事件联动能力下沉到边缘容器设备进行运行,大大降低云端压力。同时拥有灵活边缘路由能力,根据云端拉流需求,将部分视频推到云端进行播放,极大降低带宽成本,提高系统的稳定性

云边系统高可用

技术方案

跨平台编程

视频网关作为一种嵌入式媒体网关设备,主要有两种设备形态:一种是以通用服务器搭载网关服务的形式,这样的系统比较重,成本比较高但是性能强劲;另一种是嵌入式盒子设备比如树莓派,成本低同时性能较低,按照项目应用场景合理搭配解决方案。

视频网关作为一个可以跨平台、跨系统并深度融合云计算视频云领域的服务,软件我们采用了golang语言,借助于其天然的跨平台特性,可以支持网关服务运行在各种芯片平台以及操作系统之上。go tool dist list 可以看到go语言支持的平台和系统如下。

操作系统

主控芯片平台

linux

386/amd64/arm/arm64/mips/mips64/mips64le/mipsle/ppc64/ppc64le/riscv64/s390x

android

386/amd64/arm/arm64

darwin

386/amd64/arm/arm64

freebsd

386/amd64/arm/arm64

solaris

amd64

plan9

386/amd64/arm

openbsd

386/amd64/arm/arm64

netbsd

386/amd64/arm/arm64

aix

ppc64

windows

386/amd64/arm

从上述列表可以看出,从linux/arm64的嵌入式系统到linux/s390x的大型机系统,再到Windows、linux和darwin(mac)这样的主流操作系统、amd64、386这样的主流处理器体系,go对各种平台和操作系统的支持不可谓不广泛。

go语言被称作互联网时代的c语言其优点很多,语法简单、原生支持并发、平台可移植性好、运行速度快、有功能丰富并且统一的标准库等等,其中关于跨平台有一种说法go是为了解决c/c 那些复杂的依赖而来的,这一定程度上得益于go独立实现了runtime,作为技术栈上的选型这里关于runtime多说一些。

runtime是支撑程序运行的基础。libc(C运行时)是目前主流操作系统上应用最普遍的运行时,通常以动态链接库的形式(比如:/lib/x86_64-linux-gnu/libc.so.6)随着系统一并发布,它的功能大致有如下几个:

  1. 提供基础库函数调用,比如:strncpy;
  2. 封装syscall(操作系统提供的API口,当用户层进行系统调用时,代码会trap(陷入)到内核层面执行),并提供同语言的库函数调用,比如:malloc、fread等;
  3. 提供程序启动入口函数,比如:linux下的__libc_start_main。

早期的系统的磁盘/内存资源十分紧张,采用动态链接库的方式可以使得编译的程序/进程磁盘/内存占用小。不过时代变了,现在的服务器配置已经足够,由于libc等c runtime lib是基于线程模型的并且历史版本复杂,对于开发人员来说这里的负担很重,一些从事c/c 开发多年的同学可能有过这样的经历,链接runtime库时需要选择链接支持多线程的库还是只支持单线程的库。

go独立实现runtime层,封装了syscall将Go user-level code与OS syscall解耦,把go移植到一个新平台时,将runtime与新平台的syscall对接即可,基本摆脱对libc的依赖,这样静态编译的go程序具有很好的平台适应性。而且交叉编译很简单,只涉及两个重要的环境变量:GOOS和GOARCH,分别代表Target Host OS和Target Host ARCH,这里需要注意CGO_ENABLED=0的情况下,即不涉及cgo的前提下go采用纯静态编译。

业务功能

视频网关位于视频系统的边缘侧,主要业务功能是负责拉取视频流并推送到视频后台服务。在系统管理层面,视频网关需要连接设备侧的IPC/NVR等,并接入到视频系统的控制内核,作为边缘容器设备接收云视频系统内核的信令对视频设备进行管理,执行相应的操作,并将视频设备的反馈结果以及状态上报到云视频系统内核。

功能框架

网络接入

视频网关不仅可通过固网接入视频云系统,也可通过蜂窝网,wifi等无线方式接入。视频网关通过驱动搭载WIFI/4G/5G等通信模块实现无线接入能力,其中局域网内可以使用WIFI等协议,连接互联网可以使用4G/5G通信。视频网关可根据视频系统组网的实际情况以及现场视频设备的实际能力,将整个视频系统的有线/无线网络结合。

无线接入框架

设备初始化

视频网关在接入层采用插件化的框架,向下可以兼容ONVIF协议、SDK等多种方式接入视频设备,向上可以兼容mqtt/http等物联网传输协议接入云计算视频平台。

初始化能力集

视频网关通过视频设备的设备影子中厂商、流来源等属性判断使用ONVIF协议还是厂商SDK对视频设备进行初始化,获取视频设备的能力列表比如RTSP连接等。

视频设备初始化流程

初始化消息通道

视频网关和云视频系统内核之间的消息通道支持http/mqtt等物联网通信协议,视频网关具体使用某种通信协议由用户选择相应的配置在系统启动阶段完成初始化。

消息通道的初始化流程

安全策略

视频网关在接入云视频系统内核过程支持双向鉴权,信令通道以及视频流传输支持数据加密等多种安全策略。

视频网关接入云视频系统内核分为注册、挑战、登录三步,网关与内核之间采用tcp私有协议方式通信,接入过程中使用sm2/4国密进行数据加密和签名。其中视频网关的设备私钥、设备公钥以及云视频系统内核的公钥由视频网关在申请云视频系统内核放号的过程中获取。

视频网关安全策略

视频流加密

内核下发推流消息命令字通知视频网关推视频数据流,网关根据消息中的流来源字段区分收流设备是IPC还是NVR,网关推送视频流的目的端信息以及视频流加密秘钥由内核下发消息指定。

推流加密

信令加密

网关接入云视频系统内核成功后即可通过消息通道实现网关与内核间的云边协同,为了增强消息安全性在视频网关与内核之间的消息通道设置了token过期时间,当token过期,网关在接收与上报消息将出现异常,此时需要网关主动重新登录内核换取新token,网关在定时心跳过程中维护检测token过期机制。

Token 过期策略

云边协同
事件处理

视频网关具有边缘节点监控、数据统计与告警、事件处理能力。

视频网关接入云视频系统内核后,由云视频系统内核下发消息控制视频网关执行相关功能,定义视频网关与内核之间消息命令字。视频网关与内核之间的消息通道可以采用mqtt/http等协议。消息通道中使用管道实现队列的能力,内核下发消息通过管道分发到不同的接收消息任务中并发处理,网关上报消息通过管道由发送任务上报内核。

事件处理流程

状态上报

网关与云视频系统内核之间通信的加密key通过网关的心跳上报定时检测更新。

消息上报流程

视频网关位于设备侧局域网内,可以通过其与云视频系统内核之间的消息通道上报统计与告警消息。实现对设备状态全程监控、有效实时获取状态变更通知。

视频网关通过消息通道上报统计和告警消息到云视频系统内核,结合云计算视频云的后台服务以及绑定接入的应用实现告警上报。

消息通道上报统计与告警

双机热备

为避免视频网关单点异常宕机对视频服务造成影响,视频网关采用主备方式提高服务可用性,结构简单容易维护。

主备模式下设备侧局域网内多个视频网关涉及调度和配置管理,这里使用了项目中zookeeper组件提供分布式抢占锁和配置中心的能力,zookeeper使用znode目录节点作为锁和共享存储。

网关接入

视频网关作为接入视频云系统的边缘容器设备具有唯一性,主备模式下局域网内同一时间只有一个视频网关作为主网关提供服务,其余网关作为主网关的从网关监视主网关状态,当主网关出现异常从网关尝试切换成为主网关。其中多个视频网关对视频云系统等效为一个接入设备。具体部署可以是一主一从或者一主多从。

使用zookeeper的临时目录编号节点(EPHEMERAL_SEQUENTIAL)实现分布式抢占锁可以为多个网关的运行提供调度,保证同一时刻只有一个网关接入到视频云内核(IOT)。

网关切换

主网关由于宕机与zk断开连接或者业务异常主动释放与zk之间的锁时,zk将对应的编号节点删除,并通知其他监听临时节点的网关可以抢占,新抢占到锁的网关成为主网关。

边缘部署

随着Docker为代表的容器技术和Kubernates为代表的容器编排工具逐渐成熟,越来越多的应用通过容器封装、分发和运行,这种部署方式非常合适边缘计算场景。

按照端设备—边缘—云”三层模型, 视频网关作为一种边缘设备与摄像头、nvr等视频终端设备直接相连,然而边缘节点的硬件资源往往比较紧张, 视频云系统需要十分灵活的对边缘节点的计算能力与资源调度策略进行调整。

使用容器技术对边缘节点进行资源隔离,不仅CPU、内存和存储的开销非常小,而且容器可以实现在毫秒级开启和关闭,生命周期管理非常快捷。

视频云系统中边缘视频网关往往分散在建筑、园区等各个局部区域中,远离云中心。随着用户对视频播放需求的变化,边缘视频网关的资源分配与部署也需要随时调整,并且需要支持监控、日志等等运维手段。因此采用了tke edge边缘容器架构支撑视频云系统的边缘计算场景,tke edge支持边缘计算、多云管理和混合云,具有完备的k8s功能与标准api,可以方便地从中心云运维边缘容器,具有边缘自治能力,支持边缘节点健康检查,服务可以下沉到边缘机房,而且和tke拥有一致的控制台页面,运维管理可视化十分便捷。

性能调优

视频网关的业务场景决定了其主要功能模块是设备接入与消息通道、任务调度、采集与推送视频流,性能优化的关键点往往就在这里。

go tool可以很方便的使用pprof对进程详细的性能分析,使用 -memprofile 和 -cpuprofile 选项生成cpu和内存采样文件,再用工具go tool pprof查看文件内容。

在开发过程中遇到的性能优化问题挑了两个比较典型的案例进行分析。

Mqtt 订阅

视频网关与云视频系统内核(IOT)之间的mqtt消息通道使用了开源的paho.mqtt.golang,视频网关作为客户端需要订阅IOT分配的topic,开发调试过程中发现网关进程在启动后既没有接收来自于IOT的消息也没有推流的情况下,cpu占用都有2~3个点,于是通过火焰图对调用接口进行性能分析,发现mqtt客户端的Subscribe接口cpu时间占用异常。

检查代码原来是由于接口误使用,订阅接口本来在mqtt客户端初始化的时候订阅一次就可以了,但是写代码时把它当成了异步阻塞接收接口,在一个轮询的循环中不停的调用,结果就是不停的在订阅同一个topic。

代码语言:javascript复制
token := client.Subscribe(m.subOption.topic, m.subOption.qos, msgSubscribeHandler)
token.Wait()
if token.Error() != nil {
   log.Errorf("Subscribe msg to mqtt broker error:%s", token.Error().Error())
}

使用开源库中接口不熟悉误用造成的问题比较低级也很典型,如果没有pprof这样的工具,排查起来还是挺麻烦了,采用了正确的姿势,再分析可以看到已经没有订阅接口的时间占用了。

优化推流 buffer

既然视频网关的主要功能是推流那么网络传输接口这块一定是cpu和内存性能的消耗大户,通过火焰图发现封装的推流接口cpu占用时间几乎都集中在底层的Write和recv,这一块优化空间不大,但是发现runtime.gcBgMarkWorker(垃圾回收器)这块消耗比较高,排查代码原来是推流任务中的buffer申请时机不合理导致。

代码语言:javascript复制
func (v *videoPush) PushToWeLink(pushData *pb.PushReq) error {
   //申请内存空间
   packet := make([]byte, mvsTCPHeadLen)
   //组装数据
   ......
   //发送数据
   middleware.SendTCPMsg(v.Conn, v.packet)
   return err
}

在每次收到视频帧并推流的时候都新申请一块buffer,造成go的gc压力过大,其实对于视频网关每次从视频采集设备收到的数据帧大小是可以预估的,在每次建立推流任务初始化的时候可以针对任务将固定空间的buffer预留好。

代码语言:javascript复制
//videoPush
type videoPush struct {
   //摄像头推流属性等
//token与秘钥等
   //与视频服务器连接等
//状态等
   ……
   PushCtx       context.Context
   PushCancel    context.CancelFunc
   frameHead     []byte                            //加密帧头
   packet        []byte                            //sharp包体
   head          *com_tencent_weling_proto.MvsHead //sharp包头
}

func (v *videoPush) PushToWeLink(pushData *pb.PushReq) error {
   //取内存空间
   v.packet = v.packet[0:mvsTCPHeadLen]
   //组装数据
   ......
   //发送数据
   if err = middleware.SendTCPMsg(v.Conn, v.packet); err == nil {
      //更新推流状态, 在线、推流时间戳
      v.camerasInfo.setPushingByIntDinSubDin(v.SDin, int(v.StreamID), v.StreamType, v.getVideo.StreamHandler)
   } else {
      log.Errorf("push send msg error:%s, packet len:%d", err.Error(), len(v.packet))
   }
   return err
}

经过简单适配,可以看到gc的性能消耗已经有了明显改善。

项目总结

基于go的技术栈实现了一个跨芯片平台的视频网关,用户可以选择边缘服务器或者边缘嵌入式硬件等环境部署视频网关,融合云计算敏捷灵活、可靠稳定的特点,将网络连接、管理运维及调度的能力应用于视频场景,提供实时、可靠的视频端到端服务。

通过插件化的网络接入层,视频网关可以选择多种物联网协议接入云计算服务,并且兼容多种厂商的视频设备;

通过云边协同,实现云端下发边缘处理,提供有损服务能力,系统可用性强;

通过边缘侧状态监控、统计与告警,掌握视频设备实时状态上报,构建全链条的打点数据采集,设备级的精细化状态追踪,支持设备行为轨迹等数据分析;

通过从端到云全方位的安全策略,视频网关设备接入云端过程中双向身份认证,保证设备唯一性不受篡改,全面杜绝伪造设备/云服务器发送请求。视频流数据加密传输防止敏感信息泄露。

使用效果

以公司普通计算型服务器的配置(8核16G内存千兆网卡)为例,设置动态码率2m以内的摄像头实时流推流实测可以支持到400路。树莓派3B 搭载视频网关在同样场景下可以支持不低于100路摄像头实时流推流。

目前go重构的视频网关已经在多个项目环境中使用,整体表现良好,并计划在后续的新项目以及老项目的视频网关升级改造中逐步替换成go重构版本。

设计感悟

现在的设备正逐渐朝着物联网,智能化方面发展,探索发现一条适合未来智能设备发展要求的技术栈是云相关产品开发工程师必须面对的;

不要重复造轮子,优秀的官方库,活跃的开源社区可以让开发工作稳定可控并且丰富多彩;

追求产品质量和开发效率是每位开发同学都需要要考虑的问题,有了它们才能保证产品在市场竞争中立于不败之地,用合适的工具做合适的事。

0 人点赞