演讲嘉宾:周锦民 | 2011年毕业进入腾讯, 现任在线教育部在线教育后台中心高级工程师,多年linux后台开发工作经验,目前主要负责腾讯课堂和企鹅辅导两款产品的后台系统架构设计与研发管理。
今天分享的主题分三个部分。第一部分,跟大家介绍一下腾讯课堂和企鹅辅导这两款产品。第二,讲一下课堂直播系统,和腾讯云这边的具体实践案例。第三,谈一下在线教育的房间系统设计方案和这几年过程中的优化效果。
腾讯课堂是什么?(ke.qq.com)
腾讯课堂是什么?腾讯课堂是腾讯推出的在线教育平台,它会聚了大量的优质机构和讲师,涵盖了大量的精品课程。包括考验考证、IT教学、英语培训等等。这里给老师一站式的线上教学和学生的互动学习体验,这是我们的课堂特点。我们有海量的资源和流量,目前的入驻机构超过了4万多家,其中在线教育课程超过了20多万了。各种各样的科目类型可以选择,目前累计的上课数3000万,每周有超百万级,目前单门课程同时在线6万人。腾讯课堂里面有丰富的教学教务工具,助力机构和老师有一个更加丰富的教学管理。
企鹅辅导是什么?(fudao.qq.com)
企鹅辅导是面向小学、初中、高中的学生在线学习平台,目前已经有教师团队200多人,学科覆盖10个年级,有200万的学生用户。这是企鹅辅导的教师团队,他们都是我们辅导的全职教师团队,这些老师都是来自于清华、北大各个名校,我们曾经是各科的高考状元。企鹅辅导有完整细致的教学任务,从学前到学后,助力学生完整地提升。企鹅辅导支持直播1V1的答疑辅导,还有专业的课后老师给学生进行作业的批改。企鹅辅导有各种各样的辅助学习工具,例如在线互动抢答,利用图像识别技术,在线拍照批改,还有抢红包互动,提升学生的学习兴趣。腾讯课堂和企鹅辅导支持多终端学习,在电脑或手机上可以轻松学。
腾讯课堂总体技术架构
下面是腾讯课堂整个后台的技术架构,终端包括PCQQ、H5端、APP端、PC独立版、Mac端。通道层,这是对应的通道。接入层是统一的接入层,主要作用是把各端各自的协议,转成内部的通信协议。逻辑层。我们整个教育课堂后台主要分三大块,第一块,是机构平台,包括资料、订单支付、活动运营。第二块,是直播系统。第三,房间系统。下面是我们的核心模块,就是基础功能,像数据中心、订单系统、基础资料、个人中心。存储层有多种,Mysql、Ckv、Es、Redis。
下面介绍一下腾讯在线教育结合腾讯云互动直播技术的案例,我们具体是这么做的。老师直播的时候,接入了腾讯云的互动直播系统,走的是腾讯云私有协议UDP协议。学生端可以实时跟老师进行互动。
腾讯云的互动直播系统,会通过旁路推流,转发音视频流给腾讯云直播系统。直播系统接入模块收到推过来的流,会做两件事情。
第一件事,把互动直播系统推过来的流,转交给全局转码模块。全局转码模块支持定制很多参数,例如可以制定多种分辨率的转码方式;可以加上腾讯课堂的LOGO水印,并支持视频加密,保证视频的资料、知识产权的安全,还有支持多种协议的封装等。
第二件事情,全局转码模块会提供音视频流给云端混流功能,云端混流功能也是直播系统的能力。这个功能怎么用呢?它支持预设多种混流模块。我们教育这边有几款产品,比如我们有PPT、画中画、学生端的举手上麦。我们会预设几种混流模板,当老师把PPT切画中画,或者画中画切PPT,或者有学生举手上麦的时候,客户端会发起一个变更信令到教育服务,教育服务这边会调云端混流服务的接口,来改变混流的方式。云端混流模块会根据混流模板的要求,到直播接入模块拉取指定的多路音视频流,然后把多路流合成一路,再交给全局转码进行重新转码。转码完成之后,交给分发模式,分发模块把音视频文件缓存到cdn模块。
腾讯云的cdn模块,在国内有1000多个加速节点,全球有200多个加速节点。因为腾讯课堂这边的老师、学生遍布国内外。通过这些CDN节点的加速,能够给课堂的直播提供一个稳定良好的播放质量。
直播的时候,我们H5和PcWeb端采用的是经过混流后的一路流的方式,这种方式它的好处就是能够减少手机带宽流量,兼容性和稳定性更好。
直播的同时,腾讯云的点播系统还会实时进行录制。录制的时候,会产生多个录制文件分片。结束之后,会把分片拉回到本地,重新对这些分片进行视频对齐,会重新进行布局、调整,包括分辨率调整,然后插帧补流,当有视频断流时,会插入带有课堂logo的静态画面,保证音视频的连贯性。最后重新生成定制的回放文件。这样学生看录制回放的时候,能有一个连贯性的观看体验。
最后是录制的方式。录制这边学生端也支持录播一路的方式或者录播多路的方式。PC端由于家庭带宽足够稳定,我们采用的是录播多路的方式。路过多路的方式在客户端可以做很多定制化的需求。比如回放过程中,PC客户端可以动态调整画中画和ppt的切换,分辨率或布局的调整。
以上就是在线教育课堂结合腾讯云音视频产品的实践。我们运用了腾讯云提供的的互动直播、直播、点播、CDN加速、视频加密的一整套解决方案。应用了腾讯云一整套解决方案,我们还需要做的事情就很少了。现在腾讯内部CTO和公司总办们也在大力推广技术整体上云的发展战略。我们也积极响应领导的号召,积极上云,这样可以大大减少音视频这块的运营和维护成本,可以把更多的精力聚焦于产品打磨,给老师和学生有一个更好的产品体验。
房间系统架构
房间系统的架构请观看下面的流程,它分几个模块。首先是接入层,进出代理服务接入客户端请求,并把请求转发给心跳服务和成员列表进行状态存储。接着是逻辑层,它包括很多课堂交互的功能,比如学生举手、聊天区、红包互动等等,每个交互行为会产生一个消息,通过push代理服务把消息转播给其他老师和学生。
房间系统在开发过程中我们遇到三大挑战。心跳服务,成员列表,因为并发量非常大,那怎么做到平滑扩容?怎么保证服务的可靠性和可用性,还有容灾怎么做?另外消息push服务,怎么保证通用性和易用性,怎么保证消息的可靠性?在消息并发量高的时候,怎么解决消息风暴导致服务过载的问题?下面分别讲一下这三个模块我们的一些优化实践。
心跳服务优化
心跳服务优化之前,它采用msgq接入(msgq是腾讯自研的内存消息队列),采用双机单进程模型。这个方案实践简单,在项目初期的时候能够满足业务快速上线,但随着用户量越来越大,现在已经无法支撑现在业务的实现。它现在有几个问题,高峰时期容易丢消息,当系统消息量突然间增大的时候,msgq缓冲队列到达上限或者msgq服务异常就有丢消息的风险。第二,逻辑复杂、不通用,比如超时检查、多终端登录需要定制开发。第三,因为心跳服务要保存目前的心跳状态,现在双机相互同步的方案无法扩容。基于这三个问题我们做了新的优化。
下面是新版的优化方案。 我们把心跳服务的架构分了两层,心跳代理heart_proxy和心跳存储服务heart_svr, 然后通过L5服务进行路由。L5是什么呢?L5是腾讯内部的路由决策服务。
新版的心跳服务要解决4个问题。1、服务扩展性。2、保证服务的可靠性。3、通用性设计。4、踢人检测,避免误踢。
- 扩展性方面,扩展性我们怎么做呢?我们解决方案是引入了一致性哈希算法。根据业务bid 房间roomid 用户qq进行hash,把请求路由到指定的heart_svr进行存储。
- 可靠性方面,当某一个心跳存储节点挂掉的话,L5服务会在1分钟之内发现,并把此台机ip剔除。Proxy就会把它路由到其他正常节点上面去。通过这个方式,来保持心跳状态的继续维持。
- 通用性设计方面,我们现在有课堂和辅导两款产品,后面可能还有其他新产品出现。每一款产品都涉及到心跳的功能,所以我们预先把心跳服务作成一个通用的服务,引入业务号Bid的方式,这样多个产品可以套用同一套心跳服务,以此解决多个产品的共用问题。
- 踢人检测方面,很重要的一个点怎么避免误踢?比如学生正在上课,突然间被踢出课堂,就会引起学生的反馈,对学生造成不友好的体验。所以一个心跳存储节点发现某一个用户超时的时候,会给heart_proxy发起反查,heart_proxy会把查询请求广播给所有heart_svr存储节点,通过这种方式来保障踢人安全。
成员列表服务优化
成员列表的初期版本,采用了代理加CKV存储的方式。CKV是腾讯内部的自研的key-value数据库。每个房间的成员列表用pb序列化后存入ckv,需要读取时是整体读出来再进行反序列化使用,这种方式存储几个问题。
- 第一,当房间用户量过多,频繁进出房间产生大量的网络IO。一个用户信息现在有40Bytes,如果有1万人的话,成员列表就有400多K。如果是使用高峰期的时候,大量的网络IO,网卡就成为了瓶颈。
- 第二,CAS冲突严重。因为对ckv服务进行频繁的更新、删除、修改操作,会造成大量cas冲突,这样会影响到服务性能。
- 第三,读写性能低。ckv get的方式,长列表反序列化耗时。总体上性能还打不到200qps,超时比较严重。目前我们的用户量已经高了很多,目前的架构已经无法满足现在的需求,新版我们做了改造。
新版的改造我们怎么做了? 我们调研了几种存储选型。
- 首先是redis,它是支持成员列表和排行榜存储。但我们的业务成员列表需要有定制化的查询需求,例如按照版本号查询,按照平台类型查询等,还需要支持分页。在这一块,redis的数据结构支持不够。
- 第二个是grocery,是腾讯内部自研的存储方案,采用的是多阶hash的方式,它完美支持现在成员列表的存储选型。问题是它的长度有限,最多支持5000人,现在QQ列表在用。但我们单房间现在人数已经超过w级别,所以这种方案现在也不适合。
- 第三个是分级ilst,用于微博的场景,它支持超长列表。主要用于离线paas,延时较高。
- 第四个是phxkv,phxkv是微信出的一个解决方案,基于phxkv协议,强一致性、性能好。这个方案我目前在调研中。
目前我们最终采用的是内存存储,多主同步的设计方案。它由如下几个特点:
- 全内存结构,使用二级hash_map结构,c stl的标准数据结构,多主模式。最终一致性模型,写完就返回,性能好,靠心跳来修复。单set性能可到3w qps。
- 扩展性,按照业务bid来分档存储,按照proxy来中转,保证可扩展性。
- 内存列表数据每3分钟dump到虚拟磁盘,保证重启快速恢复。
- 一致性:
- 1)心跳修复, 保证最终一致性
- 2)同时提供强一致性的api能力, 通过多读方式实现。
消息push优化
消息push优化前,每个逻辑服务独自拉成员列表,还要制定对应的每个通道的push代理。此方案的缺点是代码非常冗余,没有统一的接口,模块间的强耦合。现在这个方案是无法满足我们的需求快速迭代开发,所以我们对这个方案进行了改造。
新版消息push改造方案,新版push主要分三块:push_proxy统一接入层,引入腾讯云的ckafka做消息缓冲, 引入redis做异步消息存储。
push_proxy支持多种业务定制push方式: 单播、广播、指定人、指定角色、指定端。
我们对push服务做了性能优化:
- pushProxy采用的是进程级cache,缓存大房间(>2000人)成员列表,2s超时。 小房间实时啦成员列表,保证push实时性。 怎么使用cache的。全局还是进程级的?
- 消息分级:重要和非重要消息。如果消息比较少,那么就直接推送,过多就走消息合并机制。 这是msg_center能力,能够实时累计消息数,超过阀值采用合并推送
- 另外, 老师客户端也是提供直接禁言能力,防止恶意用户刷屏。
- 房间大班拆小班,分小班推送,避免聊天消息滚屏,增强用户体验。
容灾降级我们怎么做呢?
- 在正常情况下,老师端可以主动禁言。
- 另外支持全局流控,以时间戳(s)为单位,限制向下游push的消息总量。每当pushProxy的qps超过了3k/s,就反馈到edu_msg_center降低聊天消息频率, 以此保证重要消息正常push。
最后是消息可靠性的实践:
- 消息实时推送, 异步保存redis, 采用kafka消息队列能力缓解扩散写压力。
- 客户端如果丢消息怎么办? 处理方案:每个用户收到的push消息都带有严格自增的msgid,客户端维护已收到的最大msgid和缺失的msgid列表; 定时2s上报丢失的msgid列表和收到的最大msgid, 后台返回丢失的消息列表。通过这样的方式来解决丢消息问题。
以上的分享就结束了,谢谢大家!