需求描述

  最近在做一个项目,使用redis作数据缓存,主要业务为:每当进入系统时自动生成系统工单,记录用户接触行为,同时将工单主键返回到前台作为缓存主键(redis的key值),后续进行业务主流程时将业务数据存到对应的key,最后提交业务工单时,将缓存里的数据取出来,存入对应的系统工单。

现象描述

  在开发过程中引入其它模块(已经上线使用,且此模块使用相同的方式实现,下文称为模块1),由于引用模块1,需要将其缓存的key值替换成自己模块的key,便于后业务的使用。替换后后台处理数据时报错---找不到对应的缓存值。

解决思路

  对于后台的报错,显示就是resdis没有缓存数据或者缓存数据失败,但这个项目使用redis缓存数据有一段时间且其它厂家也在使用,不可能无法缓存数据。最大的可能就是自己使用的方式不当。运行项目报错的时候查看缓存,确实没有缓存对应的数据,但有其它的数据,那就是个别数据存不进去。后来问了一下技术群,他们提供了一种思路:给每个请求加个时间戳,以验证是请求所有的数据都没有缓存,还是请求中某个数据没有缓存。加时间戳后查缓存,可以明显地看到里面只存在一个时间戳,缓存的也是当前请求的数据。那么基本上可以确定其它请求的数据都被覆盖为某个请求的数据,后来经过多次取样,其它请求的数据都被替换为某个特定请求的数据。在放缓存的位置打印放放入缓存前,放入缓存后缓存内情况的日志,可以发现存在缓存内数据对应的请求在将放入缓存前没有获取到其它请求缓存的数据。将数据放入缓存的步骤为:获取缓存内原来的数据,将需要缓存的数据合并到原来的数据里,最后一起放入缓存。因此问题就清楚了。 原因大致如下:请求B在A将数据放入缓存之前拿取数据,因此B拿不到A缓存的数据,同时B在A将数据放入缓存后更新缓存数据,因此A缓存的数据被B覆盖,查不到数据。在引入的模块1中有自动获取缓存主键key值的请求,同时初始化一下数据。获取时判断是否存在缓存主键key值,没有才生成,但无论是否存在缓存主键key值都会初始化数据。因此这个请求在操作key的时候就会出现以上情况。

后记

  后来在网上查了一下资料,这种情况类似在分布式环境下并发请求对redis同一个key访问修改。解决方式也多种多样。如使用redis的setnx实现分布式事务锁,watch(监控)+mutil(事务),消息队列。大致思路为将并发请求的并行操作转换为串行操作。

  是全角缩进