记客户端请求超时分析过程
请求处理过程描述
服务端 使用 框架 加载 业务so,并未业务so创建协程处理,处理完成后给出 响应。so入口函数接收(const Type&in, Type &out,Type &extend),是否给出响应的前提是 out里面要有 业务so的处理结果,即 out 不能是空的。这样处理的 原因是 有些客户端 只关心 消息是否被服务端收到,不关心处理结果,这时 服务端在收到 请求后 直接发送响应告诉 客户端 收到消息了, 而服务端业务so处理 完消息后 置out为空,就不会再次向同一笔请求 发送响应.
框架调用业务so伪码:
try
{
loadso;
proc_func=get_symbol:入口函数
proc_func(in,out,extend);
}
catch(...)
{
printf "unkow exception"
}
问题点:
业务现网请求消息20%超时,服务端框架日志里有 "unkow exception",但因为框架要处理很多业务,框架日志是公用的,不能确认"unkow exception"是不是超时请求引起的。
调整框架日志和业务so级别 为debug,框架调用业务so会输出两条接口日志(req,ans);
分析
a.怀疑是坏的请求,框架解析请求失败。根据请求里关键字,查看接口日志,发现只有req,没有ans,可以确定 框架接收到了请求,说明网络没问题(在进行这步是可以进行抓包,和有80%成功率),并且请求没问题。
b.业务so 有该请求的运行日志,发现运行到某 特定行后 就不往下处理,没产生core文件;可以确认问题不在框架,结合框架产生的异常异常日志,说明 业务so 产生了异常。
c.从业务so输出的最后一条debug日志点 往下分析,异常一定是后续产生的;逐行代码分析,重点关注可能抛出异常的函数(老司机一眼看出来,牛),最终锁定在string str.substr(pos),该函数原型为
string substr(size_t pos=0,size_t len=npos)const;
If this is greater than the string length, it throws out_of_range.
总结
a.发现现网问题,先向直接领导汇报,说自己正在处理,领导可以帮助协调资源,评估影响。
b.打开日志级别到debug,所有日志都要打开。(刚开始没有打印接口日志,导致框架没输出req,不能确定是不是框架没收到消息.)
c.确定请求处理的最后几行代码。逐行分析.(有经验老司机,一眼就看出来问题代码行)
d.建议框架既然捕获了异常,就输出标准异常的详情.e.what(),catch(exception e){} catch(...){}
e.业务so 使用guard 类 局部对象 在析构函数中判断 out 是否为空,以判断是不是异常退出,保证业务so 因业务异常退出时 能输出日志,有据可查. 同时guard 内也可以进行 资源释放回收,防止资源泄露.