V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
fcfangcc
V2EX  ›  程序员

分享下最近查一个 BUG 的过程和心路历程

  •  
  •   fcfangcc · 2023-07-21 15:32:56 +08:00 · 1473 次点击
    这是一个创建于 520 天前的主题,其中的信息可能已经有所发展或是发生改变。

    应用调用链路为

    X -> H (一个消息推送的聚合应用) -> E(提供用户信息的各种接口) 
    
    H -> 其他接口发送各种消息
    

    X 应用反馈发出的钉钉通知部分新入职的员工无法收到

    排查 H 应用日志:

    1.发现 H 应用接受到了 X 的请求,但是发送的目标 id 在 H 的逻辑中被过滤掉了导致最终没有发送出去.
    2.开始在逻辑中+日志复现请求排查.
    3.发现 H 应用缓存了用户信息,而不是每次从 E 应用拿员工信息. H 请求 E.get_by_ids/E.get_by_names 接口的内容进行了缓存.
    4.从 Redis 中读取对应用户的缓存信息证实由于 data 中缺少 user_id 字段,所以被 H 应用过滤掉了发送目标,导致没有发送出去.
    5.在测试环境无法复现相同的问题,任何情况下 E.get_by_ids/E.get_by_names 接口都会返回全量的用户的信息字段.但是在线上偶现
    

    开始排查 E 应用:

    1.仔细翻看代码后发现 E.get_by_ids/E.get_by_names 两个接口逻辑不一致
    	ps: 后来发现此处有 2 个名单来控制权限 W1 和 W2 ,H 在 W2 中,但是不在 W1 中
    2.get_by_ids 接口会根据来源方应用判断是否返回 user_id 这个字段.(后面证实逻辑为只判断了 H 应用是否在 W1 名单)
    3.get_by_names 接口会直接判断来源方,如果不允许的来源方直接拒绝。但是一旦返回就是完整数据.
    4.此处没有日志,但是根据逻辑基本判断出来是由于 get_by_ids 逻辑判断有问题,加了日志打印后证实。
    

    开始梳理整个 bug 出现的原因:

    1.H 应用对外也提供了 H.send_by_ids/H.send_by_names 两个接口,对应调取 E.get_by_ids/E.get_by_names
    2.又因为对 E.get_by_ids/E.get_by_names 调用结果进行了缓存,并且 redis 的 key 没有设置过期时间!!!
    3.新用户一旦先调用 H.send_by_ids 接口,获取到不带 user_id 的 data 后,后续再也无法正确推送过去。
    4.此处又有疑惑,按这个逻辑不应该只会发生在新用户身上啊,老用户按理也会遇到这个问题???
    5.继续查看 H 应用的逻辑,发现启动时会全量覆盖一遍当前的缓存,此处调用 H.list_all 接口,此接口没做任何限制,所以能拿到 user_id ,所以这个逻辑问题已经存在 2 年了,一直没有其他人反馈过
    

    开始修复:

    1.修复了 E 应用里面 get_by_ids 逻辑与 get_by_names 保持一致(由于不敢大改逻辑,又添了一堆屎上去)
    2.修改 H 应用缓存 key 增加了过期时间,然后清理了历史的所有的 redis key (此处有大坑)
    3.自信发布后 X 应用负责人表示问题解决了,又开始摸鱼
    

    没多久 A 应用开始反馈调用 H.send_by_ids([张三,李四]) 接口开始报错,提示用户张三不存在。。。

    开始排查新问题

    经排查后用户张三是因为已经离职所以接口提示不存在!

    但是 A 应用反馈之前一直这样发的也没有报错过, 并且李四也能正确接受到消息。。。

    又去仔细翻看 H 应用相关的代码 发现了里面有一段逻辑是判断调用方输入的列表和从 E/缓存 拿到的数据是否一致(判断是否有不存在的人员),此处现在两个列表不一致导致抛出的 not_found error

    思考和梳理原因:

    1.之前由于 redis key 没有设置过期时间,所以离职的张三信息一直在缓存中,一直能拿到对应的信息!!!
    2.刚才清理了所有的 key 之后现在拿不到了,所以提示张三不存在!!!
    

    解决办法 1:

    想让 A 应用调用之前判断一下是否存在这个用户,不要把不存在的发过来,A 应用表示段时间内做不到,需要改的地方太多了……
    

    解决办法 2:

    1.新增 send_by_ids_v2 接口,支持 ignore_miss 参数
    2.A 应用修改源码调用 send_by_ids_v2 接口
    	
    

    最坑的是,这个问题只有在线上能复现,又缺少日志,所以排查问题及其困难!!!然后 H ,E 应用的开发全部已经跑路了.

    后来发现其他环境无法复现是因为 E 应用只在生产进行了权限判断,在某个配置里面把其他环境的都关了……

    修改和查看代码过程中很多奇怪的逻辑不敢改,怕改坏了又影响其他应用……

    至此结束了此次 bug 的问题,在一堆屎山里面找逻辑,还不敢随便改看起来很奇怪的逻辑

    又因为上述原因又堆了几坨屎上去

    7 条回复    2023-07-24 10:49:57 +08:00
    hiveex
        1
    hiveex  
       2023-07-21 15:48:21 +08:00
    鄙夷屎山 拥抱屎山 一起拉屎
    4771314
        2
    4771314  
       2023-07-21 16:44:02 +08:00
    不然你以为💩是怎么产生的?
    拉的人多了,也就成了💩
    garibellee
        3
    garibellee  
       2023-07-21 16:54:10 +08:00
    佩服 好有耐心的说
    AltairT
        4
    AltairT  
       2023-07-21 17:20:00 +08:00
    接这种项目先把日志加多一点或日志系统改造下,宁愿打多点日志,也不要排查时没法排查。
    flyqie
        5
    flyqie  
       2023-07-21 22:51:49 +08:00
    还是那句话:

    代码和人有一个能跑就行
    L0L
        6
    L0L  
       2023-07-22 09:11:34 +08:00
    强,有耐心
    xubeiyou
        7
    xubeiyou  
       2023-07-24 10:49:57 +08:00
    以前有段时间很嫌弃无用的日志,但是后面如果改 BUG 就会发现 有日志总比没有好,人和程序有一个能跑!!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1096 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 23:32 · PVG 07:32 · LAX 15:32 · JFK 18:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.