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

296 天前
 fcfangcc

应用调用链路为

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 的问题,在一堆屎山里面找逻辑,还不敢随便改看起来很奇怪的逻辑

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

1372 次点击
所在节点    程序员
7 条回复
hiveex
296 天前
鄙夷屎山 拥抱屎山 一起拉屎
4771314
296 天前
不然你以为💩是怎么产生的?
拉的人多了,也就成了💩
garibellee
296 天前
佩服 好有耐心的说
AltairT
296 天前
接这种项目先把日志加多一点或日志系统改造下,宁愿打多点日志,也不要排查时没法排查。
flyqie
296 天前
还是那句话:

代码和人有一个能跑就行
L0L
296 天前
强,有耐心
xubeiyou
293 天前
以前有段时间很嫌弃无用的日志,但是后面如果改 BUG 就会发现 有日志总比没有好,人和程序有一个能跑!!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/958621

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX