优化之前的性能表现
短时间内收到消息数过多比如1秒钟20条消息,网页卡顿/浏览器Crash掉,Chrome 的CPU使用率飙到100%以上。
消息接收的处理过程
- 通过更新
IM.vue
中的ims
来渲染消息内容 - 通过更新
Vuex
中的IMList
来刷新会话列表- 查询
IMList
,找到当前消息所属会话 - 如果,当前消息不在会话中,重新拉取会话
- 如果,当前消息在会话中,更新会话信息,更新未读消息总数,并根据更新时间进行排序
- 会话信息包含:未读数、最近一条消息内容、最新的更新时间
- 查询
最终排查的问题
最初的设想,每秒钟n条消息,上述的处理过程需要走n遍,因此计划通过setInterval来进行批次处理,比如200毫秒处理一次。实现后,问题变成浏览器Crash,到当前网页的Crash,Chrome CPU的使用率仍旧非常高。最终排查得到的性能问题在于结论是
- 频繁更新IMList非常耗费性能,包括修改数值、插入会话、排序
- 不必要的接口调用,比如重新调用会话列表,将所有会话涉及的账号数据一次请求回来
优化策略为
- 替换直接查询会话为更新会话(增、删、更新)
- 会话中涉及的动态消息,即
IMList
中每个会话的updatedAt、count、msgBody
转移到Vuex
外面 - 重写整套排序逻辑,即根据实际的业务场景来决定如何调整排序,例如,新会话进来直接插入到会话的顶部
- 后台接口调用延后,单聊群聊中涉及的账号信息,改为全部请求为只请求单聊中涉及的信息,群聊中改为选中群聊再请求
转移后台的计算策略到前台
最初的逻辑是:
- 每一条消息有一个唯一的requetId标识,前台负责告诉服务器,自己是否读了这条消息
- 在会话中,来一条消息,直接告诉服务端,已经读过这条消息了
- 在新进入的会话中,在调用消息列表的接口中,服务器将所有消息都设置为,该用户已读
- 服务器端,收到拉取会话的请求时
- 获取到会话消息并且标记该用户对单条消息的已读未读
- 统计群聊内所有用户对消息的已读未读,并推送给前端
优化后的逻辑是:
后台只返还每个群聊成员,阅读到的消息的seqNo,seqNo是根据消息前后顺序,数值逐渐递增的,前台根据返回数据对每一条未读消息进行计算,举例如下
群聊中有 A B C D三人,A 发送了4条消息,分别为 a1 a2 a3 a4
其中B读到了a2,C读到了a3,D读到了a4,那么计算逻辑为
a1=0 0人读到的最远位置
a2=1 1人读到的最远位置
a3=1 1人读到的最远位置
a4 =1 1人读到的最远位置
sa4 = a4 = 0
sa3 = a3 + sa4 = 1 + 0 = 1
sa2 = a2 + sa3 = 1 + 1 = 2
sa1 = a1 + sa2 = 1 + 2 = 3
其他待优化的点
- 会话消息数量过多时如何展示?动态渲染(Recycle List)。
网友评论