直播中聊天室踩过的坑以及我的填坑历程

我所在的项目,最近正在打造直播功能,并且也已经上了两期直播了,总体来说坑还是比较多的,因为你要定制播放器、聊天室、点赞、弹幕等等的,这些种种功能,组成一个直播间,其中的性能优化是非常重要的。这篇文章主要聊聊我解决聊天室相关问题的填坑之路。

第一次直播(无限刷新)

我们的名厨APP,是在2.1.0版本第一次加入的直播,实际上整体的开发时间是比较充足的,也经过了几轮测试,但在进行了第一场线上直播后,确实发现了很多影响用户体验的bug。这其中非常严重的一个问题就是,在接收到大量聊天消息时,处理聊天列表刷新耗费了太多内存和性能,以至于iPhone6s都会因为内存不足而杀掉APP进程。
  为了方便快速的完成直播中的聊天功能,我的建议是在开发团队没那么强能力和时间的前提下,尽量选择一些三方服务商,我们APP中直播所用到的聊天室,选择了融云的服务。
  具体集成起来是很方便的:1、在AppDelegate中初始化融云SDK并配置自定义消息;2、当前APP使用用户获取融云Token,并用Token连接融云服务;3、加入聊天室;4、在指定Controller中设置融云代理,接收消息。
  接收消息的方法为:

// 监听消息接收的方法
- (void)onReceived:(RCMessage *)message left:(int)nLeft object:(id)object {
}

第一个参数message,为接收到的聊天消息;第二个参数nLeft,为剩余的历史消息数量;第三个参数object,是接收消息的监听key值。按融云文档的说法是,同一时间会收到大量消息,nLeft代表你接收到的消息的剩余数量,当并发接收消息数量巨大的情况下,可以在nLeft等于0的时候,再刷新聊天列表,似的,我是这么做的,if (nLeft == 0) { self.chatTableView reloadData }。
  在经过了几轮的测试后,APP安心的上线了,虽然会觉得肯定还有测试不到的地方,会有些突发的bug出现,但聊天这块肯定不会有问题。结果万万没想到,我们的直播太火爆了,不仅服务器负载过高,聊天这里也因为消息接收过多,导致聊天列表刷新过于频繁而引发APP占用内存暴增、卡顿,甚至闪退。

第一次改进(每秒刷新)

既然问题出现了,就赶紧修复吧,我们直播是每周一期的,所以要赶在下次直播前,快速找出新的解决方案。
  既然刷新过于频繁,那就改为定期的刷新吧,所以新的方案为,每次接收到消息,就存储到数据源中,但每1s只刷新一次,这种方案还是比较靠谱的,毕竟不管你接收到多少消息,都只会每1s刷新一次,从之前的狂刷到现在的定期刷,效果还是比较明显的。但伴随而来的问题还是比较突出的,采用UITableView reloadData的方式进行刷新,当数据源数据量巨大的情况下,就算每1s刷新一次,但这1s的这次刷新,也会有一定的线程堵塞。
  如图是我们名厨APP的直播页面,当数据源中的数据到达500条时(iPhone6s),在刷新列表的时候,就会有明显的卡顿,例如图中的红色标记的功能,在持续使用这些功能的时候,你会发现每隔1s都会卡顿一下。显然这样的体验是不好的。


名厨APP直播界面

第二次改进(每秒在适当的时候刷新)

因为数据源中数据过多的时候,只要刷新就会卡顿,所以尽量控制刷新的次数,既然固定了每秒刷新,这是不可改变的,因为加长这个时间,则消息的实时性就会大打折扣。所以要针对这1s的刷新做一定的条件限制。限制条件如下:
<li>当聊天列表在最底部的时候才刷新,因为聊天列表展示新消息的策略是,聊天列表在最底部的时候,接收到新消息并滚动到底部,不再最底部的时候,不用滚动到最底部。
<li>当当前直播页面展示在用户眼前的时候,才刷新,也就是说,在用户全屏的时候、点击右下角弹出提问列表的时候、当前页面需要登录权限弹出登录页面的时候不会刷新。

加入以上的限制,就能保证当前页面展示在眼前、并且聊天列表滚动到最底部的时候才进行刷新。

第三次改进(缓存数据源的引入)

但通过以上的改进后,还存在一种卡顿,就是只要你停留在聊天列表最底部的时候,每秒都会刷新一次,用户看直播、聊天的目的就在于消息的实时性,大部分用户,都会停留在聊天的最底部以接收最新的消息。但每秒的刷新,还是过于频繁,如何降低这个频率,是很重要的。所以,为什么要每秒都进行刷新呢?为什么不回归到最古老的方案,在接收到消息的时候再刷新呢?所以缓存数据源诞生了。
  现在直播页面,有两个数据源,一个咱们叫它正式数据源,用于存放当前聊天列表展示的数据,另一个数据源为缓存数据源,缓存数据源用于存放新接收到的聊天消息。
  则整个聊天的功能循环就变成了这样:
  1、接收到新的消息,并将新消息存储在缓存数据源中;
  2、每1s,都将缓存数据源中的数据放置到正式数据源中;
  3、刷新聊天列表并清空缓存数据源;
  4、重复上面的流程以反复接收新的消息;
  引入了缓存数据源,就可以针对第二次改进,多加入一个限制,就是缓存数据源中有数据的时候,才进行上面的循环。

第一次完善(insertRow的引入)

做了上面这些修改,就能彻底摆脱卡顿吗?答案是NO,因为所有的根源都在UITableView reloadData这个方法上。而且既然引入了缓存数据源,则数据的插入,就更好控制了,每次将缓存数据源加入到正式数据源的时候,直接实用UITableView的insertRowsAtIndexPaths方法,将这些新数据追加到聊天列表后面就好了。

第二次完善(聊天数量的限制,缓存机制的完善)

当然以上的所有方案综合在一起,当数据量巨大的时候,还是会有堵塞主线程的现象存在,主要表现在iPhone6s以下的机型上。所以,历史消息的数量,是需要进行限制的。
  在观察了斗鱼、映客这些成熟的直播软件的处理方案后发现,在历史消息达到一定数量后,就会将最老的消息删除掉,这也就说明了,历史消息数量不是无限的增大下去的。
  所以历史消息应该有一个最大上限,综合测试后,在5s上也能流畅运行的最大上限为500左右。但具体策略就是超过500就删除到500吗?显然不是,如果这样处理,当历史消息到达500后,则之后手机的处理量就一直维持为500这个数量上了,而且在做删除消息的操作时,你要向正式数据源结尾追加缓存数据源数据,并从最前面删除最老的历史消息,这个时候,再更新聊天列表,就要用到tableview的reloadData方法,所以如果历史消息始终维持在500这个级别,就会有很多次的reloadData方法被调用,卡顿还是不可避免的。
  所以针对历史消息的数量的限制,我引入了两个关键数字,一个是maxNum(假设为500),一个是minNum(假设为300),代表正式数据源和缓存数据源汇总后,消息数量的两个阶段,并针对不同阶段有不同的处理。
  1、当汇总后的正式数据源中的消息数量不超过300时,会将新加入的缓存数据源消息追加到聊天列表中,而不是刷新聊天列表。
  2、当汇总后的正式数据源中的消息数量超过500时,会从正式数据源的第一条消息开始删除,删除到只剩300条消息后,刷新聊天列表。
  3、当汇总后的正式数据源中的消息数量介于300到500之间时,按少于300处理,每次总数到达500后,循环这个处理,保证聊天消息数量控制在minNum和maxNum之间,也就保证了性能。
  以上处理方法,保证了始终有maxNum-minNum(也就是500-300=200)这么多的空间可供使用缓存数据源去追加消息(insertRow的方式)。
  maxNum的调整:针对手机的性能进行调整,尽量保证iPhone5s也能承受的数量。
  minNum的调整:minNum越小,则insertRow处理的聊天列表刷新越多,性能越好,minNum越大,则reloadData出现的频率更快,则会有更多的不定期卡顿出现。当然minNum也不是可以无限的小下去,比如定为0,这样的后果就是,一旦聊天消息总数到达500,则所有消息都被删除了,则用户看不到任何历史消息了。
  我们公司最后定下来的比例是200、500。
  最终综合上面的方案,上线了一个新的版本。

第二次直播

在进行了第二场直播后,我的心终于能放下了,因为聊天不会再卡顿了,并发收到大量消息的时候,也处理的游刃有余。

类似场景

一、以生活中的场景为例,就好比一个壮汉搬运货物,他的力气是很大的,比如搬运可乐,要搬到100m以外的柜台上,运用第一次直播的方案就是,可乐是源源不断出货的,但壮汉每次只能拿一瓶,并运到100m以外,虽然壮汉能力是有的,但他的能力都浪费在了运输的途中,有点大材小用了。手机也是,手机接收消息是很简单的,但很多性能和内存都浪费在了刷新聊天列表上。现在换到使用第二场直播的方案,壮汉一直在等,每收到一瓶可乐,就将可乐放到箱子中,等箱子装满了,或者到了壮汉可以承受的重量的时候,再将可乐运到100m以外,这样的壮汉只要平时歇着,偶尔出下力就可以了。手机也一样,大部分时间都在接收消息,但实际并没有刷新聊天列表,只在特定场景,刷新很多数据。跟饿么吗的外卖送餐员一样(为什么要做这个比喻!因为午餐时间到,正在订餐...),他都是取到很多份再统一配送的,而不是取到一份就送一份。
  二、另外,说到缓存,大家想到的肯定就是在线视频了,视频的处理也是缓存形式的,有缓存和没缓存绝对是两种体验。如果不进行缓存的处理,则播放器每时每刻都在请求视频流,这无疑很耗费性能,还很容易导致卡顿。加入了缓存,就可以一劳永逸,在视频播放到缓存快没有的时候,再请求一段视频流,缓存下来就好了。

总结

整个事件,还是比较提心吊胆的,因为毕竟直播是个大模块,而且并发量比较巨大,自己在参考融云的Demo的时候,没有验证并发量巨大的情况下是否适用,同时也没有考虑到直播的真实应用场景,而且第二版虽然顺利修复了聊天室中的问题,但赶上要圣诞节了,苹果马上就要放假了,能否顺利上线新版本也是比较担心的。所谓吃一堑长一智,知耻而后勇,以后再碰到类似问题,还是多长点心吧。
  总得来说,以上聊天的处理,我是没在网上找到类似的处理方案,有做直播聊天的,可以稍微参考下,有什么疑问或是更好的解决方案,可以给我留言。而解决问题,主要的目的还是找到问题出在哪,是哪些原因导致的,只有找对了原因,对症下药,才能更高效的解决问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,846评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • 和恶化
    58c7953d7b7b阅读 144评论 0 1
  • 2016年很快就要过去,现在用十张图追忆一下这一年。 今年去了西藏,一个神秘又让人向往的地方 天很干净,云很干净,...
    晚风过境阅读 364评论 0 2