Redis
Redis主要面向缓存、分布式锁、消息队列等问题。
而在缓存中常存在穿透、击穿、雪崩、双写一致、持久化、数据过期、数据淘汰等问题。
1.缓存穿透
通过get请求查询redis,redis响应查数据库,正常情况下,若查询到数据,则正常返回数据值,get请求结束。
而缓存击穿,则是当数据库中,并不存在get请求所需要查询的值,使得redis反复查询数据库。若存在恶意攻击,反复请求数据库,数据库并发量有限,则会击垮数据库使其宕机。
一般解决方法,查询结果为空时,把空结果(null)进行缓存。但是消耗内存,不是最优解。
其他解决办法为布隆过滤器(站在布隆后面…),在redis之前设置一个布隆过滤器,存储预热数据。利用位图检索数据是否存储在一个集合中。但存在数组太大时,存在误判问题,需设置误判率。(5%以内)。
2.缓存击穿
通俗点来讲,就是当地有一家卖的很好的早餐店,吗喽们每天都会来买早餐,然后有一天这家店铺租约到期了,搬走了,但恰好这个时间点大家都来买早餐,就造成买不到早餐都站在店铺面前,给店铺挤爆了。
也就是说,正常通过redis查数据,但是key过期了,从redis中查不到数据,最后大量请求输送给数据库,导致数据库吃不下,爆了。
解决方法就是互斥锁、逻辑过期。
互斥锁无非就是等待其他线程完成数据提取任务以后,再继续进行。(就像早餐铺子,你排队买早餐,你得等你前面的人买完了,你才能买)。(强一致、性能不好)
而逻辑过期,就像是你去买早餐,发现了早餐到期了、不见了,然后你另辟蹊径,去另一家早餐店买相同的早餐。(过期时间的设置)可用性较好。
3.缓存雪崩
雪崩,顾名思义,大范围的崩了。那就是大量的key过期了,或者redis直接G了,导致大量的请求直接面向数据库,给数据库压垮了。
解决方法,使得过期时间随机,避免大量的key同时过期。或是启动集群,利用哨兵模式,使得主从结点自动替换。
4.双写一致
数据库与redis的数据进行同步。也就是数据库的数据变了,缓存里面的也要跟着变,保证数据的一致性。
数据的删除修改时,会导致脏数据。
读写时添加互斥锁,能解决一些不一致的问题。(或是共享锁(锁住,只准你读)、排它锁(当前执行,阻塞其他线程的读写操作))。
5.持久化
一般情况下使用数据备份文件or数据快照 RDB (Redis Database Backup file),将缓存的数据记录到磁盘中,若Redis出现故障、重启等问题是,可以从磁盘读取文件恢复数据,避免数据丢失。
AOF(Append Only File)追加文件。也就是redis每写入一个命令都会记录下来,像日志文件。文件很大。
6.数据过期
惰性删除:key自动过期以后,不会立即删除,只会在再次利用这个key时,判断过期以后删除掉。(内存占用问题)
定期删除:定期对一定数量的key进行检查,发现过期就干掉。分为(slow不超过25ms、fast不低于2ms 模式)
7.数据淘汰
内存满了怎么办?缓存不是无穷大的
那么就需要合理的对redis内的数据进行合理的淘汰。
一般的方法,要么就是写死,满了就不让写进去了(noeviction),没用幸存者,全部干掉。
要么对全体key随机淘汰一部分(allkeys-random)
要么就是,通过判断key的过期时间,快要过期的就先干掉(volatile-ttl),或是对设置了过期时间的key随机淘汰(volatile-random)
或是对全体key or 使用了过期使用的key 根据使用次数,使用少的淘汰(LRU)
或是基于使用频率,使用越少的优先淘汰。