转载

通过数据分析进行问题排查的case

前几天帮忙排查一个问题,简单记录一下。

1. 背景

答题服务,近期用户答题率(答题人数/发题时的在线人数)有明显下降,需要分析这部分用户没有答题的原因。

2. 初步排查

  1. 从服务端监控来看,客户端尝试连接、断连、超时比例都没有明显异常,整体也没有容量上的问题。
  2. 从没有答题的用户分析,没有明显的特征。
  3. 从没有答题的设备分析,大部分集中在IOS客户端。
  4. 从没有答题的设备网络分析,没有明显的地域或ISP分布。

3. 进一步排查

在初步排查基本排除了服务端整体性能问题之后,接下来的问题是:这一部分IOS用户为什么在房间里但是没有答题?

可能的解释有几种:

  1. 发题的时候用户在线,但是没有弹出题目
  2. 发题的时候用户在线,弹出题目了,但是没有选择答案
  3. 发题的时候用户在线,弹出题目、选择答案了,但是没有提交成功
  4. 发题的时候用户其实不在线,统计有问题

想要继续统计有一个比较麻烦的地方,如何根据已有日志判断某个用户在发布题目的时候是否在线,进而得知这个用户在这段时间内究竟发生了什么?

记录的日志大概是这个画风:

time:12:30:00, uid:aaa, event:join room
time:12:30:00, uid:bbb, event:join room
time:12:30:30, uid:bbb, event:show question
time:12:30:35, uid:bbb, event:submit answer
time:12:31:00, uid:aaa, event:exit room
time:12:30:00, uid:bbb, event:exit room

也就是说,需要通过事件日志获得“对于没有答题的用户来说,在发题的时间段内,哪些用户是在线状态”,进而分析“没有答题的用户的时间轴与正常用户的时间轴有什么区别”,如果是一个用户可以人肉观察的方式,针对具体case定性,但是对于几十上百万个用户来说,需要进行定量分析,从而判断出“影响答题率的关键因素究竟是哪个问题”。

在这里利用了红黑树进行辅助分析,针对每一个用户创建一颗基于事件的红黑树,key为时间戳,value则是具体事件类型。在对所有用户创建树后,则可以使用某一个具体的时间戳,获取某个指定用户“在这个时间点发生的事件“、”在这个时间之前(之后)发生的的事件”和“用户的完整时间轴”。

在此之上,如果某个用户在某个时间点之前的最后一个事件是断开连接,则是离线状态,否则为在线状态。

伪代码如下:

// 建森林
foreach(所有事件) {
    TreeMap userTree = allTree[uid];
    userTree.put(event.time,event.event);
}
 
// 获取某个时间点在线用户列表
public List<TreeMap> getOnlineUsers(long timestamp) {
    foreach(allTree) {
        if(!userTree.floorEntry(timeStamp).event == "断开连接") {
            result.add(userTree);
        }
    }
}

筛出异常用户后,进一步对异常用户的时间轴作分析,获取每个时间点上的事件数量。

for(time=start;time<end;time++) {
    foreach(allTree) {
        event = userTree.get(time);
        if (event != null) {
            eventStastics[timestamp][event]++;
        }
    }
}

将异常用户与正常用户的加入房间请求做对比,可以发现答题开始前有很多异常的加房间请求。

通过数据分析进行问题排查的case

由于红黑树可以顺序遍历,因此用程序对所有异常用户的时间轴进行分析,可以发现异常用户都是有两次加入房间请求,连接关闭后直接发起请求,但第二次加入房间后没有任何操作。

因此怀疑有误加房间逻辑,重新review客户端断线重连代码,发现bug,解决。

原文  http://blog.2baxb.me/archives/1665
正文到此结束
Loading...