记一次使用Redis Cache引起的Bug排查及修复总结

本文记录了一次因Redis Cache设置Key失效时间错误导致的工单流程状态异常的问题。在用户反馈异常后,作者通过日志排查发现代码中将天数转换为秒时出错,从而导致工单提前失效。修复方法是将Key的失效时间扩大24倍,并通过DBA协助更新Redis中的Key。事件提醒我们,代码审查和测试的全面性至关重要。

一次产品需求愉快的上线后,翌日下午有用户反馈,工单流程状态不对,为何不对呢?经过跟用户微信电话沟通,工单提交后,流程子状态应该展示转存量。是的,没有错,业务流程 没有问题,应该是我的程序出现bug了。恰巧上线后翌日,北京气象局多次短信通知,有大暴雨,注意防涝。尽管如此,当日我依然来到公司,排查一些其他反馈问题。室外开始大雨来临, 我收拾电脑准备回家,到家后准备吃饭,微信群又反馈出现几单状态不正确,我回复"刚到家,吃饭后立即排查"。吃饭后,经过电脑前一系列排查最终找到问题,当时已经晚上22点多了。

1.业务概述

数据流示意图

 

如上图业务逻辑是这么处理的:

  • 1.提交工单时,用户可以选择转存,输入一个天数,然后提交成功。这时候单子需要变成转存量
  • 2.技术方案中是这么处理,对于转存的订单,通过redis设置key的失效时间(这里的时间就是转存天数换算成的秒)。
  • 3.客户端通过订阅Key失效事件,判断是转存订单,然后会通过redis zset对象入队;同时,把转存队列的该工单出队,实现工单队列从转存队列转移到正式队列。
  • 4.正式队列的工单系统会定时轮询去派单。
  • 工单队列示例

![工单队列示例](img-blog.csdnimg.cn/20200813215…

2.排查过程

服务是基于容器构建部署,线上初步上线经过评估,仅发布了两个实例节点。我依次打开两个webshell窗口,根据我编写的代码业务逻辑排查输出的日志。

  • 应用实例服务器1关键日志截图:

应用实例服务器1关键日志截图

 

从上图截图,可以看到一次完成的工单提交操作,包括表单提交的数据,delayDays=3。但是,在正式队列入队前构建上下文对象时,expireSeconds=10800

日志的输出的时间是:2020-08-12 15:16:03.591

  • 应用实例服务器2关键日志截图:

应用实例服务器2关键日志截图

 

另一台服务器收到该工单(通过Redis存储并设置key失效时间)的失效事件,发生的时间2020-08-12 18:16:05.373。相当于当天该工单就失效了,转存才6个小时就失效了。

  • RedisKeyExpirationListener

监听Key失效事件

@Component
@Slf4j
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

    final static String STORED_CACHE_KEY_PREFIX = WorkOrderCacheManager.CacheType.stored_cache.getKey();

    final static String SUSPENDED_CACHE_KEY_PREFIX = WorkOrderCacheMan
<think>嗯,用户想了解一些令人印象深刻的bug案例,这些案例来自实际开发经验,通常涉及逻辑漏洞、边界条件或系统协作问题。从用户提供的引用材料看,ta特别关注bug的成因分析和解决思路,而不仅仅是现象描述。 用户可能是一位Java开发者或测试工程师,正在积累调试经验。ta提到"他人印象最深的bug",说明需要典型案例来拓展问题排查视野。深层需求可能是学习如何系统性分析复杂bug,毕竟引用[2]详细展示了定时任务覆盖bug的分析链条。 引用材料已经提供了四个典型bug: 1. 引用[1]概括了Java常见异常类bug 2. 引用[2]的定时任务文件覆盖bug最完整,包含复现路径和修复方案 3. 引用[3]的客户端参数传递错误展示了端到端校验的重要性 4. 引用[4]的缓存字段异常说明数据流验证的必要性 需要重点突出每个bug的独特价值:引用[2]适合展示分布式系统的时间耦合问题,引用[4]则演示了数据一致性的隐蔽漏洞。回复时要强调分析过程而非结果,比如引用[2]的"定时任务手动测试盲区"这点就值得展开。 安全方面需注意:案例中不能包含敏感信息,所有业务场景要做泛化处理。技术细节可以保留,比如引用[3]的Result=2这种具体参数可帮助理解。 准备用三个维度组织回复:问题现象简明扼要(如"按钮消失"),原因分析聚焦关键失误(如时间戳覆盖),解决方案体现工程思维(如命名规则升级)。最后补充思考题时,要延续用户对"深刻原因"的关注点,比如问"如何设计覆盖策略"就比问"如何修复"更有深度。 </think>以下是多个技术领域中令人印象深刻的Bug案例及其深层分析,结合系统协作、边界条件和隐蔽逻辑漏洞等典型场景: --- ### 一、定时任务覆盖导致数据丢失(分布式系统) #### 问题现象 系统A创建任务时上传含客户ID的文件,推送至系统C时部分客户数据丢失[^2]。 #### 根本原因 1. **文件覆盖机制**: - 推送流程依赖两个定时任务: - 任务1:推送文件到中间平台B(文件名按`年月日`命名) - 任务2:系统C从B获取文件 - 若任务1在任务2执行前再次运行,新文件覆盖旧文件(同名冲突) 2. **测试盲区**: - 测试时手动触发任务,未模拟连续执行场景 - 未监控中间平台B的文件状态 #### 解决方案 ```java // 修改文件命名规则(增加时间戳) String fileName = "customer_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) + ".csv"; ``` #### 反思 - **分布式协同陷阱**:跨系统任务需严格错峰执行或加锁 - **命名规范**:关键资源需全局唯一标识符(如UUID)[^2] --- ### 二、客户端参数错误传递(移动端) #### 问题现象 学生端习题详情页显示题目错误,但实际答案正确[^3]。 #### 根本原因 1. **数据流断裂**: - 客户端提交答案时误传错误参数值(如`Result=2`表示错误) - 服务端直接使用错误参数返回结果 2. **校验缺失**: - 客户端未验证参数与服务端计算结果一致性 #### 解决方案 ```java // 服务端增加业务校验层 if (request.getResult() != calculateCorrectResult()) { throw new IllegalParamException("客户端结果与服务器计算不一致"); } ``` #### 反思 - **端到端校验**:客户端不可信,关键逻辑必须在服务端复核[^3] --- ### 三、缓存字段引发界面异常(微服务架构) #### 问题现象 APP按钮意外消失,排查发现缓存接口返回字段值异常[^4]。 #### 根本原因 1. **缓存污染**: - 缓存服务`cache-services`返回字段值错误(如该返回`A`却返回`B`) - 客户端依赖该字段决定按钮显示逻辑 2. **更新机制缺陷**: - 上游数据变更后,缓存未及时失效或刷新 #### 解决方案 ```java // 增加缓存版本控制 public void updateCache(String id, String newValue) { redis.del("cache_key_" + id); // 先删除旧缓存 redis.set("cache_key_" + id, newValue); } ``` #### 反思 - **缓存一致性**:关键字段需设置过期时间或监听数据库变更[^4] --- ### 四、并发场景下的集合操作异常(Java基础) #### 问题现象 `ArrayList`迭代中删除元素抛出`ConcurrentModificationException`[^1]。 #### 根本原因 1. **快速失败机制**: - `ArrayList`的迭代器检查`modCount`(修改次数) - 直接调用`list.remove()`导致`modCount`变化,与迭代器预期值冲突 #### 解决方案 ```java // 使用迭代器的remove()方法 Iterator<String> it = list.iterator(); while (it.hasNext()) { if ("target".equals(it.next())) { it.remove(); // 安全删除 } } ``` #### 反思 - **线程安全**:多线程场景需改用`CopyOnWriteArrayList`或同步块[^1] --- ### 深度复盘启示 1. **时间耦合风险**:定时任务需考虑执行间隔、时钟漂移和并发覆盖 2. **数据链路验证**:跨系统传输需增加校验位/哈希值比对 3. **防御式编程**:客户端传入参数必须经过服务端业务规则校验 4. **缓存治理**:区分静态数据与动态数据,制定分级失效策略 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值