• 记一次定位风控服务自成交错误的问题


    问题描述,生产环境上,分析风险控制服务(Risk Control Service,以下简称为RCS)日志,找到错误提示,内容为请求触发自成交规则。正常情况下,该次请求应该被RCS拦截,而RCS没有拦截,通过后由柜台返回相关错误。

    问题分析

    根据日志简要分析得知该笔请求为报价请求,时间前后有的请求被RCS拦截,有的没有,说明RCS伪通过的情况是偶发的。分析代码,梳理处理自成交规则的主要流程,以买方向为例子简要说明,卖方向同理:

    1. 取当前合约所有卖方向,正在排队的订单列表,按价格升序排列。
    2. 取当前合约所有卖方向,已发送待应答的订单列表, 按价格升序排列
    3. 比较当前买入价与卖方向最低价格卖方向最低价格 等于 min(步骤1列表的最低价,步骤2列表的最低价)
    • 买入价大于等于卖方向最低价格,拦截此请求。
    • 买入价小于卖方向最低价格,放行此请求。

    逻辑上看起来没什么问题,接着分析实现,提出疑问:

    • 步骤1和步骤2的订单列表的价格顺序实现与设计是一致的吗?
      • 通过单独测试订单列表更新函数,验证实现与设计是一致的。
    • 正在排队的订单列表以及已发送待应答的订单列表的维护有疑问?
      • 从实现上看,在维护上述订单列表时,排除了报价子单的相关订单。通过询问产品和开发人员,得知此处是有特殊需求,与具体柜台相关。
    • 对上述订单列表取最低价的方式有疑问?
      • 走查代码发现,对已发送待应答订单列表的实现与设计不符,取最低价订单的逻辑有问题。

    问题复现以及修改验证

    找到了怀疑点,接下来就朝着这个方向,构建复现环境。在具体构建中,有两个大的方向:

    • 黑盒法复现: 将生产环境上出现问题的程序,部署在测试环境中,通过构造测试指令集来复现问题 。
    • 白盒法复现:根据生产环境上出现问题的程序版本号,在本地获取提取对应版本的源码,修改代码增加调试日志,屏蔽掉某些处理分支,配合测试指令集来来复现问题

    在本次定位过程中,两种方法都有尝试,下面分别介绍。

    黑盒法复现

    整个请求链路可简化如下,

    风控服务流程图.jpg

    根据之前分析的怀疑点,构建请求与已发送待应答订单列表比较的场景,首先需要已发送待应答订单列表中有数据才行,而该列表的维护时机如下:

    • 增加时机:当指令通过RCS检查后
    • 移除时机:
      • 收到指令响应信息
      • 收到指令推送信息

    只有在上条指令已发送,并且尚未收到响应或者推送时,又来了新的指令,才会进入可疑比较路径。因此,此问题转化为

    • 扩大发送和接收指令之间的时间窗口,让更多的指令进来
    • 在收发时间窗口内,接收更多的指令

    第一种场景,最初想到的是控制交易代理端的响应速度,经过一番搜索和尝试,有如下几种方法:

    • 通过nicerenice来更改进程优先级,让它被系统调度不怎么待见。 <--- 搜索资料发现,这种限制方法只适用于CPU密集型服务,对于IO密集型服务不适用。
    • 通过cpulimit,限制进程的cpu使用率。这样即使它被系统调度,也用不了太多cpu。 <-- 即使限制为最低1%,也能立即返回,不适合IO密集型服务。
    • 通过cgroup命令来进程资源使用,这个较为复杂,没有尝试过。
    • 限制交易代理端的网络速度,较为复杂,没有尝试过。
    • 通过 SIGSTOP 以及 SIGCONT 信号,通过脚本来控制进程周期性,尝试了下,没起到什么作用。

    第二种场景的构建思路,增加指令堆积数量。通过人工操作是不可能达到如此之快的订单堆积的,只能通过程序实现。因此,努力方向转为改造已有指令测试工具,支持快速批量发送指令,以便复现。

    通过改造指令测试工具,实现了快速发送指令以及按消息收发时间记录整个请求响应日志数据,通过构造特定的指令序列,连续发送,还是未能稳定复现。

    白盒法复现

    黑盒测试法感觉已经走到尽头,接下来工作转向白盒法复现

    前面已经把相关业务分析清楚,在白盒复现过程中,在订单列表关键地方增加日志,同时,屏蔽掉接收后端的响应以及推送数据,这样,接收到的指令只会进入预期路径中。

    指令测试工具以及配套的指令集合还是需要的,在测试环境搭建起服务后,按照如下步骤:

    • 关闭RCS,发送指令集,触发柜台响应错误
    • 开启修改后的RCS服务,发送一样的指令集,发现接收到的订单与客户端的发送订单顺序不一致,咨询其他同事得知,现有收发框架,使用多线程来派发指令,会导致接收的指令顺序与发送不一致。把框架接收线程设置为1后,后端接收顺序就与前端发送顺序一致,调整为一致后,再测试,就可稳定复现问题。预期没被拦截,实际也没被拦截。
    • 对此问题进行修改后,再次部署RCS,发送一样的指令集,预期被RCS拦截,实际也被拦截。

    构建可稳定复现环境后,验证过程也很顺利,一切都顺理成章完成了,心情舒畅。

    经验小结

    • 对于后台服务偶发问题,一定要结合代码以及日志来综合分析,仅仅使用黑盒法来尝试构建以及验证,存在很大的盲目性,并且复现问题效率较低。
    • 对与历史输入有关联的业务流程验证,可通过修改代码以及添加关键数据变动日志来验证自己的想法。为了更有针对性检查,建议将调试日志输出到独立文件
    • 构建测试环境,保证测试环境干净。当一次业务逻辑关联多个数据以及更新时机时,可每次只验证一类数据和一种更新时机,通过关键数据的增删日志,验证设计想法与实现是否一致。
    • 一个好的指令测试工具,对复现后台问题是非常有必要的。要求能做到批量发指令,每一类业务一个测试指令集文件,并按时间顺序保存所有请求响应结果,便于改动的回归测试。
  • 相关阅读:
    Speech Recognize 实用类 (发现bug的朋友,请留言如何修正,供他人参考)
    由“类的成员函数”充当“回调函数”引发的问题的思考和解决方案
    装载与软件体系结构
    artoolkit video 数据转换到 IplImage*
    CvCamShift算法+原理(转)
    基于SAPI的中文语音识别的xml书写与编程
    自己根据示例代码改写的可以用于TexttoSpeech的类库
    Linux下安装erlang及rabbitmq
    jaf activation
    基于DotNetOpenAuth实现OpenID 服务提供者<shou>
  • 原文地址:https://www.cnblogs.com/cherishui/p/14044226.html
Copyright © 2020-2023  润新知