JuneYuan / 修改缓存逻辑引起的一个伪bug

Created Sun, 02 Dec 2018 23:21:44 +0800
594 Words

mainLogic

根据入参提供的地理位置点,计算并输出其所在 country, city, service providers

原始逻辑

i. 先读缓存(redis), 若命中则直接返回

ii. 若未命中,则需要根据两部分信息构造结果。两部分分别是:1. 调用接口 foo; 2. 去查配置中心 configCenter

iii. 将上述结果写入缓存(注意其中包含了两部分信息)

iv. 返回结果

存在的问题

缓存有效期为1天,所以修改 configCenter 之后无法立即生效,要等到1天后缓存过期,才会生效。

修改缓存逻辑

作了两点改动——

  1. 当缓存命中时,仍然去读 configCenter, 而不是直接使用缓存中的配置信息;
  2. 既然不再使用缓存中的配置信息,那么写缓存时也不必包含 configCenter 了,只保留调用 foo 的结果即可。

伪 bug

上线时,先部署了一台机器(deploy canary), 观察到许多日志的 X 字段都为空,究其原因应该是从 configCenter 读到的那部分信息,是空值。但是反复看代码逻辑,又无法解释何以如此。

排查了很久,最后才意识到,这应当是符合预期的——

i. 一台机器(canary)部署了新代码

ii. 该机器发生 mainLogic 调用

iii. 缓存未命中,于是调用接口 foo, 并将结果写入缓存(注意这时 mainLogic 再遇到相同入参的话,缓存将会命中)

iv. 去查 configCenter

v. 将 iii 和 iv 两部分结果组合后,返回

vi. 非 canary 机器发生 mainLogic 调用,入参与 ii 相同

vii. 缓存命中,但其中仅包含 borders 调用结果,configCenter 那部分为空值。但是旧代码会认为,只要命中缓存那么其中就包含了全部所需信息,于是就返回了 configCenter 为空的结果。

Summary

涉及缓存的修改,必须充分考虑造成的影响,尤其是上线部署多台机器,过程中会发生什么,都要做到心中有数。