查看原文
其他

架构 | 300万在线答疑业务系统的演进之路

2017-05-10 苗广艺 51CTO技术栈

作者:苗广艺

编辑:王雪燕  高阳


作者经历了学霸君在线答疑业务从设计、研发、上线、迭代、步步优化,直到稳定的整个过程。

从一个技术负责人的角度来对这项业务的技术发展做一个全面的回顾。


2013年左右,深度学习技术在国内开始热起来,我也参与其中,将深度技术应用于人脸识别算法当中。接触了学霸君之后我发现,在教育行业,深度学习技术大有可为,因此我决定加入他们,并很快将深度学习技术应用到拍照搜题这个领域。


学霸君是一家教育行业的创业公司,主要面向的用户是中学生和小学生。学霸君APP最初的主要功能就是拍照搜题,学生可以拿起手机对着题拍照,框选出题目范围,进行搜索。搜索结果不仅有ABCD答案,还包含丰富全面解析,如题干、题目简析、推导过程、点评、题目考点相关介绍等。这个功能上线后,受到学生们的欢迎,因为学霸群APP的搜题准确度较高,APP的用户量增长非常快。


学霸君在只有拍照搜题这一个业务的时候,后端技术主要是题库的建设、搜索、OCR识别(文字识别技术),产品注重体验及App的开发。实时在线答疑业务等功能的出现,促使学霸君的技术快速发展,特别是后端技术。


在线答疑业务的流程是怎样的?

老师和学生各有一个客户端软件,老师端需在PC端登录,学生手机端登录。

  • 学生对难题进行拍照

  • 点击呼叫老师的按钮

  • 之后这道题目就会生成一个订单

    发送给全国各地的老师

  • 系统会对老师进行筛选

    推荐合适的老师与学生建立在线通话

  • 由老师给学生讲解

如果老师说话不能解释明白,还可使用我们提供的数码笔。数码笔是通过蓝牙或者 USB 与 PC 建立一个连接,将老师在纸上写的内容实时传输到学生的手机屏幕上。


对学生的题目,系统还会给老师推荐题目的答案以及解题过程作为参考,这样做可以大大节省老师审题的时间。


在线答疑业务的重要特点

  • 特点一,实时对话。通过语音和笔记让老师和学生进行实时沟通。系统需要做到不卡不断不延迟,音质尽量好。

  • 特点二Uber模式。在线答疑系统的逻辑和 Uber 打车相似,老师由我们系统自动分配,老师和学生建立连接之后,我们需要让老师和学生的连接尽量稳定。

  • 特点三:分配策略。我们希望能够尽快给学生分配到最合适的老师,分配策略会涉及到用户画像等方面。

  • 特点四:识别算法。学生是通过对题目进行拍照进行提问的,系统需要识别出题目的内容、年级、学科等,如果没有这些识别结果,系统无法做到自动分配老师。


在线答疑业务系统的演变之路

在线答疑业务从备战→上线→稳定经历了三个阶段:

  • 最初我们开发了一个基于 Web 客户端的简单的 Demo 版本,来验证业务的可行性;

  • 然后正式立项,开始组建团队、攻关难点技术,完成了 Beta 版本产品正式上线。

  • 上线后,又对系统进行了大量的优化,使得产品达到了很好的效果和体验。

我是在第一个阶段的中后期加入到这个项目的,不久后被任命为技术负责人。



Demo 版

是最小可用的简单版系统,一方面用来评估产品是否能立项,一方面实验一些技术。


这个版本的老师端是浏览器,通过插件驱动数码笔,音频数据都没有压缩,音频传输服务器用 Node.js 做的,业务后台也非常简单。


因为做的简单,可用性比较差,如果学生网络条件不好,订单的成功率不到 70%。这样的情况完全无法直接上线使用。


Beta 版

是在线答疑业务系统正式上线的版本,包含几个核心业务模块。

  • 音频服务用来音频和笔迹的传输,客户端需要集成一个音频引擎的 SDK;

  • 答疑中控负责整个答疑流程的核心逻辑,包括维持长连接和各种状态切换;

  • 识别集群是做一些图像、学科识别的算法等。

当时的状况是,公司在音频实时传输方面完全没有任何技术基础,在图像识别方面有一些技术积累。


实时音频传输技术有较大的技术难度:两个用户进行在线语音对话,整个对话流程会经过很多很复杂的技术环节,包括采集、预处理、压缩、打包、发送、传输、接收、缓冲、解码、后处理和播放等,这些环节会互相影响。


因此整个流程也会有很多不确定的因素,在真实场景中,还会遇到各种困难,如各种网络环境和复杂的适配。



我们面临的第一个问题就是技术选型问题,这个决定了后面产品的效果以及开发的难度。

在协议选择上,如果直接选择 RTMP 和 HLS,相对开发简单一些 ,但这些协议是基于 UDP 协议的封装,在实际应用场景中往往会经过多次 CDN 转发,至少有两秒钟的延迟,如网络不好还会有更多的延迟或者累积延迟。在线答疑业务的场景是老师和学生实时的对话,对延迟问题需求较高。


PTP 协议虽然是专门为音视频传输而生,但比较老旧,不能完全满足我们的需求,如果使用的话需要在它的基础上再封装一些协议。


最后我们选择了自有协议,在 UDP 协议上进行封装。虽然在开发上有难度,但是其延迟可以做到特别低,灵活度比较高,可以自控。


除了音频传输,我们的业务场景还需要传输笔记,可以考虑直接用视频传输音频和笔记,这样做虽然很灵活,但对网络和设备要求比较高,所以最终没有考虑。


我们将笔记的原始数据压缩后直接传输到对方终端,然后实时画出来,这样笔记传输的数据就会非常小,可做到延迟特别低。


另外,我们也可以直接用第三方技术,有的公司有相对成熟的 SDK 可以直接集成到我们产品中,但这样做会增加很多沟通成本,产品升级的速度会变慢,不掌握核心技术,无法完全根据我们的业务场景定制。长远考虑,最终我们选择自己研发一套我们自己的音频传输技术。



自研技术有很大挑战,因为上线时间紧迫,我们当时制定原则就是先尽量简单,快速做起来,做成一个可用的系统,然后再不断升级优化。

  • 我们用 ZK 集群管理所有服务器,其中音频服务器用于传输数据,每一个师生连接都会生成一个 room,老师和学生进入同一个 room 内进行通话;

  • 调度服务器用于管理音频服务器资源以及 room 资源;

  • 老师和学生客户端都需要集成一个 SDK,SDK 上包含了采集数据、编解码、缓冲、网络传输等模块,把所有逻辑打包在一起,这样业务开发人员就不用关心这些技术细节了。


Beta 版的音频服务虽然没有做到尽量好,但及时赶上了业务上线的时间,为业务快速在市场推广争取了时间。以下是音频服务的一些技术选择:

  • 采样:音频 8k,笔记 59 帧

  • 预处理:WebRTC 中的 audio_process 模块

  • 编解码:FFmpeg 框架,G723.1,固定码率

  • 打包:均匀切分成 udp 包,自增 sn

  • 缓存:固定缓冲长度

  • 丢包处理:音频不管,笔记重传

  • 传输:服务端中转,以 room 为单位

  • 录音:服务端存储 udp 包,异步转码


再说一下识别集群

学生用手机拍照上传题目的图片后,图片在系统中会经历 OCR 识别、语法纠正、题目搜索和学科识别四个环节。

  • OCR 识别,就是把图像上的文字识别成具体的一段文字;

  • 语法纠正,就是通过语法分析纠正那些识别错的字,尽量提高识别的准确率;

  • 识别出的文本会通过搜索服务来找到这个题目的答案;

  • 学科识别 是通过文本分类识别出题目所对应的年级和学科,有了题目的年级学科等信息,系统可以自动地把题目分配给该年级该学科的老师。

整个识别集群里,最复杂的是 OCR 识别。印刷体文字识别看似简单,但在实际业务场景中却是非常难的,因为会面临大量的模糊、图片扭曲、照片低质量、复杂公式排版等问题,一般的 OCR 算法在这样的业务场景中基本不能用。


我们的 OCR 识别的算法的大体流程是这样:首先对图片进行预处理,如图片角度纠正,图片亮度均匀纠正等;然后进行版面分析;最终得到识别结果。


版面分析是最复杂的部分:

  • 我们通过自研的二值化算法来定位文字的像素,并将像素转化成小碎块;

  • 然后进行排版组合,找到文本行的段落结构,顺便进行文本行扭曲矫正。

这其中涉及到大量的图像处理算法,重点是选择合适的高效的算法进行组合。版面分析的同时,还会用到字符识别。

  • 对于中文来说,一般会用卷积神经网络,也就是 CNN 算法

  • 对于英文来说,一般会用递归神经网络,就是 RNN。

我们用的是 RNN 中的一种经典网络 LSTM(长短记忆模型)。因为我们识别的是学生的题目,学生提问数学题的情况特别多,数学题中包含着大量的公式,公式识别需要做一些特殊处理,这也是所有识别中最难的部分,需要结合单字识别和公式版面分析综合来识别。


在线答疑业务系统的深度优化

Beta 版系统上线以后,随着用户量增大,各种各样的真实场景对系统的可用性提出了更大的挑战,加上产品需求不断增加,我们对整个系统进行了全面的升级。主要的升级有四个方面:

  • 音频通信(音质优化、延时降低、连接稳定等)45 34141 45 15534 0 0 3241 0 0:00:10 0:00:04 0:00:06 3241an>

  • 老师调度策略(更好策略、用户画像、供需调整等)

  • 系统架构(架构优化,模块化,监控报警)

  • 识别算法(更多科学、知识点分类、讲题模块等)


首选音频服务遇到了不少问题,例如:有的学生会反馈说和分配的老师连接不上,系统不是高可用,有时音质差,系统对网络抖动敏感、卡顿、掉线、超时、安卓记性适配等。针对这些问题,我们主要做了三点:

  • 音频引擎升级

  • 网络传输升级

  • 云适配

我们抛弃了 FFmpeg 框架,重新采用了 WebRTC 的整体音频引擎,增加了多种采样率、动态码率、多种编码方式、FEC(Forward Error correction)、DTX(Discontinuous Transmission),并将这些配置全部做成了动态可变的,针对网络状况和主机本身状态的不同,这些配置会实时地自适应变化。

比如,当主机 CPU 使用率较高的时候,引擎会切换到 CPU 效率较低的音频编码算法。为了减少传输的数据包数量,我们将笔记数据包和音频数据包进行了合并,通过自研的算法协调数据包的重发策略。



网络传输方面,我们没有使用 WebRTC 的传输模块,而是重新写了一套传输模块。整体架构如图:

  • 音频服务器负责传输音频数据

  • 调度服务器负责协调资源

  • ZK 集群负责监控各服务的生死

选择 BGP 机房作为核心机房,ZK 集群必须全部部署在同一个核心机房,调度服务器可以部署在不同的核心机房,客户端通过调度服务器获取到可用的音频服务器,以及建议的传输路由。


音频服务器可以部署在任何机房,音频传输的时候,也会经过一个或多个机房。调度服务器会提供多条路由,客户端和音频服务器都会不断地探测各条路由线路的网络状况,如果当前的传输路由网络不好,客户端会自动切换到网络状况最好的那条路由线路。


值得一提的是,我们的传输架构是双向独立传输,也就是说,近端到远端的路由与远端到近端的路由可能是不一样的。为了进一步提高连接成功率,系统还支持 TCP 协议传输和 P2P 直连。



为了解决安卓机型的适配问题,我们采用了云适配的架构。根据线上的录音和日志数据,人工设置出最合适的配置参数和策略,将配置和策略写入数据库,供调度服务器选择。随着不断的动态调整,配置和策略达到了最优效果。我们最终完成了4000多种机型的适配。


分发服务拆分

随着产品的发展,加上调度逻辑都放在答疑中控服务里,导致中控服务里的逻辑特别多,代码越来越臃肿。针对上面问题,我们从答疑中控中把调度逻辑拆出来单独放在一个分发服务里,通过消息队列解耦。


拆完之后产品和运营的需求就很快得到释放,调度策略的升级速度大大加速。分发服务后接模型和策略库,模型和策略库决定分发服务的各种调度策略。


从调度算法架构上,我们可以看到分发服务可以做到的一些事情。

  • 最下面是知识图谱和知识分类,我们有一个教研团队,专门研究知识图谱和知识分类方法,我们希望把问题分配给对这个题目背后的知识点最擅长的老师;

  • 然后上面是用户画像,我们通过老师和学生的行为数据来分析老师和学生的特点,比如有的学生特别喜欢讲得快的老师;

  • 再上面是需求与供给模型及预测,学生提问的需求量在不同时间段不一样,比如平时晚上会有一个提问高峰,而老师的供给量也有一个规律,我们的系统可以预估供给与需求的情况并进行调节,比如老师不够用的时间段提前给某些老师发消息;

  • 最上面是分发算法,根据下面几层提供的各种能力,通过多种策略实现实时调度和最优化。


整个业务逻辑是由答疑中控来控制的,由于当时上线时间紧,我们正好有一个 C++ 的异步网络框架,就用 C++ 开发了业务中控。但 C++ 做这个业务中控并不是特别合适,如 C++ 语言开发起来相对慢、容易出 Bug、网络库复杂等。我们决定重构业务中控,并升级整体架构。


在架构调整之前,中控服务既要做基础服务(如TCP连接、消息重传等),又要做业务逻辑。我们把基础服务和业务逻辑拆开,拆出一个单独的消息网关服务,专门负责长连接,通过消息队列与业务服务通信。


这样一来,消息网关服务可以将长连接做得更加可靠以及高可用,而业务服务可以只关心业务逻辑,整体架构更加合理。在架构调整的时候,我们采用了 GO 语言来开发,因为 GO 语言对网络和并发支持得更好,并且支持内存回收,使得开发效率更高。


答疑中控业务流程比较复杂,答疑中控需要维持老师、学生、服务器三者的状态一致,有很多异常情况需要处理。我们在重构中控业务逻辑的时候,引入了状态机的概念。我们用状态图详细地描述出整个答疑过程中老师、学生、服务器三者的所有的状态情况、状态的转化条件、状态的转化动作。


除了核心业务升级,我们还做了其他一些补充,如日志与监控。监控分为物理监控(zabbix+grafana)、接口监控(自研后台)、业务监控(ELK,自研后台)。日志收集基本上是用 ELK,主要是服务端日志,客户端 debug 用的日志也可以上传服务端再同步到 ELK。



除了上述的重点优化模块,我们还对整体服务做了很多拆分,最终形成了一个整体有序的业务架构。最上面的是客户端,然后是接入层,包括长连接和接口服务等,然后是主要的业务服务层,下面是一些公司公共的基础服务,最下面是存储服务。同时贯穿整个架构的有 BI 体系、日志体系和监控体系。


技术思考

一个技术负责人很容易过分关注技术本身,比如:

  • 团队的技术如何选型?

  • 后端是不是要做服务化?

  • 各业务是不是要做统一的监控?

  • 是一步到位还是要小步快走?

  • 到底什么样的技术才是最牛逼的?

  • ......


我认为最重要的反而是在业务上,因为所有的技术都是基于业务而存在的。如果抛开业务只谈技术,不能创造任何的价值。特别是一个技术总监或 CTO,他的脑子里最先考虑的应该是业务。他需要明确公司的战略和业务方向,未来半年到一年业务会变成什么样子,然后再把业务发展分解为技术的打发和节奏,最后量化到各个技术团队或成员。



苗广艺

学霸君高级技术总监

在加入学霸君之前,先后担任央视网高级研发工程师、搜狐研究院副研究员、欢聚时代(YY多玩)资深算法工程师、奇虎360资深算法工程师。早期工作经验以图像识别算法为主,研发过分布式存储内核,后投入深度学习技术研发。在业内最早将深度学习技术引入到拍照搜题领域,帮助学霸君App以技术优势快速占领市场。从头组建了直播答疑技术团队以及北京君君辅导事业部技术团队。目前在学霸君担任技术总监,负责学霸君App技术开发以及整个公司的基础技术研发。

本文选自《CTO说》

30+导师的倾情分享

扫描二维码

进入购买页面


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存