当前位置:首页 > 问答 > 正文

Redis那些技术难题怎么破,答案其实没那么复杂,说白了就是一步步来解决问题

基于对多位资深技术专家实践经验的归纳与总结)

Redis虽然快,但用起来总会遇到各种让人头疼的问题,别怕,这些问题听起来高大上,其实解决思路说白了就是一步步来,跟咱们平时解决生活问题一个道理。

第一个大难题:缓存和数据库数据不一致怎么办?

这大概是所有人最先碰到的坎儿,你在Redis里改了数据,但数据库里还是老的,用户一看,哎,刚才我明明改成功了,怎么又变回去了?一下子就火了。

答案没那么复杂,说白了就是:别追求绝对一致,那代价太高,咱们追求最终一致,并且想办法让这个“来得快一点。 具体怎么一步步做呢?

最傻但最有效的起步方法就是:先更新数据库,再删缓存,为啥是删缓存而不是更新缓存?因为有时候更新缓存的计算很复杂,或者你可能连续改好几次数据库,但只需要最后一次的结果,你直接删掉,下次有人来读的时候,发现缓存是空的,自然就会从数据库把新数据查出来再塞回缓存,这叫“懒加载”。

那要是删除缓存失败了呢?好问题,那就引入第二步:重试机制,但重试不能放在业务代码里同步做,那会拖慢用户的请求,简单点的办法是,把这次删除操作丢到一个消息队列里,让一个独立的程序慢慢去重试删除,直到成功,这样主流程就快了,如果公司有现成的数据库变更监听工具(比如Canal),可以监听数据库的更新日志,然后由这个工具去删缓存,这样更可靠,你看,这就是一步步从“先更后删”到“加消息队列保证删除”再到“用binlog监听”,问题就越来越稳妥了。

第二个难题:缓存雪崩、击穿、穿透,这三个词听着就晕。

Redis那些技术难题怎么破,答案其实没那么复杂,说白了就是一步步来解决问题

其实你把它们想象成房子漏水就行,雪崩是redis里大量数据同时到期,像房顶塌了,所有请求都砸向数据库,数据库扛不住就挂了,击穿是某个特别热的key(比如顶流明星新闻)突然过期,像在房顶打了个洞,所有请求都从这个洞涌进来,把数据库压垮,穿透更可气,是有人故意请求根本不存在的数据(比如查不存在的用户ID),这个请求在缓存和数据库都找不到,相当于请求直接穿过去了,每次都会查库,要是恶意攻击,数据库也危险。

答案其实很简单,核心就一句话:保护数据库别被高并发请求打死。 一步步来对付它们:

对付雪崩:别让大量key同时过期,给key的过期时间加个随机数,比如原本都设1小时,现在改成1小时加上0到5分钟的随机值,这样key就不会在同一时间点集体失效,压力就分散开了。

对付击穿:给热点key加把“锁”,当发现缓存失效时,不是所有请求都放过去查数据库,只让第一个请求去查,然后重建缓存,后面的请求等着,缓存建好了大家直接用,在Redis里可以用SETNX命令(set if not exists)简单实现这种锁的效果。

对付穿透:把“门”堵上,办法更直接,第一种,对不合理的请求参数直接拦在业务层,比如id是负数,直接返回错误,第二种,就算数据库查不到,也往缓存里塞一个空值(比如null),并设置一个短的过期时间(比如2分钟),这样下次同样的请求来,缓存里有个空值顶着,就不会再去查数据库了。

Redis那些技术难题怎么破,答案其实没那么复杂,说白了就是一步步来解决问题

第三个难题:内存不够用了,或者数据要怎么持久化不丢?

Redis是内存数据库,内存满了可就真写不进去了,数据持久化也是为了重启后数据不丢。

说白了,解决办法就是“分清主次,有舍有得”。

内存满了怎么办?一步步来,你得设置过期时间,这是最基本的,配置内存淘汰策略,别用默认的,根据业务选,比如你是做缓存的,那就选allkeys-lru,淘汰最近最少使用的key,保证新数据能写进来,如果你的数据有重要和不重要之分,可以给key设不同的优先级,让Redis优先淘汰低优先级的。

持久化怎么选?RDB是拍快照,AOF是记流水账,RDB恢复快,但可能丢几分钟数据,AOF数据更安全,但文件大,恢复慢,简单起步的话,可以两者都用,用AOF保证数据不丢,用RDB方便快速备份和恢复,现在通常的作法是把两者结合,既开启AOF,又定时执行RDB做冷备。

你看,这些听起来吓人的技术难题,拆开来看,每一步都不是什么高深莫测的魔法,关键就是别想着一口吃成胖子,先用一个最简单可行的方案让系统跑起来,然后盯着监控,发现问题了,再针对这个问题点,用下一个更细致的方案去补上,一步一步来,系统就越来稳健了。