美文网首页
spring cache 背黑锅一记

spring cache 背黑锅一记

作者: 菜的无法无天 | 来源:发表于2019-10-09 17:00 被阅读0次

活着真好

愁死了,经验不足
前段时间,我对系统的一部分用户的登录状态做了更改,原先是单独操作redis对app端的用户的登录状态进行长时间存储(用户登录,生成一个独一无二长字符串,然后以这个字符串为key,将当前登录用户的相关信息封装成对象存进redis中,下一次用户请求服务器,将这个长字符串放在请求头中,我们系统就可以定位到这个用户的信息进行其余操作,系统内将这个长字符串称之为token)。但是由于前期系统设计不全面,再加上我们公司业务比较飘,直接召唤我等猿人对数据库进行写操作,所以redis中缓存的信息始终不是最新的,为了图省事,每次修改都要修理厂端进行重新登录。这样感觉不太好,所以得想个办法来解决问题。

死亡之始

开想,因为当时系统已经集成了spring cache,所以就打算在Spring cache上做手脚。

我单独写了个服务用来操作修理厂端用户的缓存信息,在这个服务中,加上了缓存注解,设计好相关逻辑,比如创建token函数使用@CachePut 将信息存入缓存中,删除token使用 @CacheEvict ,刷新token还是使用@CachePut,获取token信息使用@Cacheable。设计是不是很完美,我也觉得。
后来又开始第二步作死之旅,为了想人为控制token信息的刷新,就是单独的刷新某个人的token信息,我又想到了对redis中的key做手脚,现有的redis的key是随机生成的,无法单独辨别,当然也可以遍历所有的key,依次获取redis中的数据来进行对比,但是这样太傻逼了,不符合我气质。所以想到用userid(用户主键id)作为key但是这样的话太容易造假了,对咱们系统的安全性不好。得对这个法子让这个userid对用户来说每次是不同的,但是对系统而言却是透明的。于是想到了jasypt,这个工具包刚好可以达成我的目的。是的,我使用了他,结束了作死的第三步。

思路已基本完善,开始实现,实现过程简单,不进行描述了。测试、上线一切显得完美。

过一段时间后,查询系统日志,老是报一个相同的错误,jasypt解码错误,郁闷,查找了很久没发现问题,加上没有运营反应相关错误,就想先放一放。

前几天运营反应:ios端出现频繁登录状态,ios和android基本我都参与了编码,对代码熟的很,android没有事情,只有ios出现问题,而且是反应在app首页返回服务器错误,分析代码找出原因,然后发现原先设计存在一些漏洞,修复漏洞。在此期间我添加了一下Spring cache关于用户登录状态的一个注解,本地测试没问题,就在晚上10点左右部署了服务器,测试所有的流程都是正常的,包括我修改的其他的地方都是好的,然后我安心的😪了,美美的睡了一觉!

死亡终结

第二天一早 洗漱的时候 拿手机试了一下 app ,发现出现服务器错误,卧槽! 懵逼了..
查询日志,说是用户未登录。卧槽 打开rdm一看,嗝屁了,所有的用户的登录状态都没了。。。
完了 卧槽 这咋整 找我老大 ,他也没法子 只能让用户重新登录了 有点绝望呀

错误猜测

因为我重新在原有的逻辑上新增了一个注解,导致Spring自行清空了用户的登录状态。日,以前我以为spring的cache并不会自行刷新,只会按照系统设置的逻辑对数据进行增、删、查,没想到他自己也会按照自己的逻辑进行相关操作。

再此基础上,我对原先的逻辑代码进行改造,删除用户token操作接口上的所有缓存注解,自设定相关逻辑代码redis进行缓存 本次测试 不影响 原先的缓存信息

今晚部署服务器之前,现将redis的持久化文件备份一份,假如嗝屁了,还能还原。如果明天没事,再来继续修改此文档。如果嗝屁了,那就代表我就嗝屁了,这就是我的遗作.......

还原真相

晚间重新部署了服务器,当然部署之前将redis的存储文件进行了备份,但目前负责的系统晚间几乎无人访问,所以不用担心晚间的redis信息丢失情况。测试一切业务正常,然后就睡觉去了。
md,第二天早上一打开app,发现又挂了,草。立马利用redis的备份文件恢复了redis中的数据量。这个现象又发生,我明白了这个不是属于Spring cache的锅,也就是说有逻辑代码在删除用户的token,利用idea全系统查找,最后我终于找到了原因,我的一个定时任务是罪魁祸首,原先设计是晚间将当天登录的所有的token在redis中进行刷新并延长时间,逻辑是在for循环中执行的。

在逻辑如下:

  if(null != token){  
        //从数据库重新查询token信息
        //并延长redis中对象存储时间
  }else{
      //删除redis中的token信息
  }

误写成了:

  if(null == token){  
        //从数据库重新查询token信息
        //并延长redis中对象存储时间
  }else{
      //删除redis中的token信息
  }

悲伤的故事.....
原先没有出现所有登录状态都被定时任务删除,是因为上面逻辑在解析部分token时会存在异常,会直接截断for循环,影响范围较小,再加上日常是针对性分析错误日志也没察觉到代码异常。但是这次更改代码,我对上面的逻辑进行了异常捕捉,所以循环完美的执行了下去,删除了所有的用户的登录状态,还让cache背了一个大锅。

结局

或许是因为想换跳槽了,对公司业务就没有那么关注了,写代码就下意识的写的随意了,就造成了这个结果。让我自己忙着好几天挨个用户来辅助他们进行账户登录(不要问原因,按我们boss讲,客户都是大傻子)。下次一定要注意,避免这种低级并且致命的错误。要对自己写的代码负责!

相关文章

网友评论

      本文标题:spring cache 背黑锅一记

      本文链接:https://www.haomeiwen.com/subject/wjrgpctx.html