因为项目业务需要,我们要把数据库中的大量数据缓存到redis中,并且会随时更新缓存,刚开始更新频率是1Hz,没有什么问题,后来更新频率达到了5Hz,lettuce开始疯狂报错:redis command timeout。既然出了问题,就得解决呀,好好分析一下发现,更新缓存的任务跟其他任务搅在一起了,而且最重要的是,缓存更新任务的执行是单线程的。既然找到了问题的可能原因,那就动手改造吧,把缓存更新改成多线程的,但咱们知道,redis是单线程的,而且redis的操作是原子性的,原生操作并不支持事务(更新缓存要先查询,再更新,这样的话就会可能导致“脏读”),不过lettuce作为一个优秀的java redis客户端,已经帮咱们考虑到这些问题了,在更新方法上加@Transactional注解就完事儿了。
好,多线程改造完毕,再次运行试试,结果还是出现了上面的问题,只是问题出现的晚了一点,而且伴随着还有线程池抛出的异常,而且redis的执行时间高达600+ms,这不是要了亲命嘛!!!接着排查问题,查看redis的查询慢的日志,发现慢的记录都是get方法,目标数据都是字符串形式的list,这个时候恍然大悟,我把list存成字符串,每次存取的时候要各种序列化,反序列化,当数据量大的时候肯定特别慢啊。对了,redis不是支持String,list,hash,set ,zset等数据格式呢。为什么我不把list数据存为redis的list格式呢??谋定后动,赶紧改造,完成发现,哈哈,果然现在操作时间只有20ms左右了,用户体验一下子就好起来了呢,nice~
总结:此次问题的出现是经验不足,对redis了解不够导致的,平时习惯了使用string格式存取数据到redis中,而把另外四种数据格式完完全全地忘掉_!!!
网友评论