redis经典问题
1.缓存雪崩
指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案:
1)Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃;
2)本地 ehcache 缓存 + hystrix 限流&降级,避免 MySQL 被打死;
3)缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生;
4)逻辑上永不过期给每一个缓存数据增加相应的缓存标记,缓存标记失效则更新数据缓存;
5)多级缓存,失效时通过二级更新一级,由第三方插件更新二级缓存;
2.缓存穿透
缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案:
1)接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
2)从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒。这样可以防止攻击用户反复用同一个id暴力攻击;
3)采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力。(宁可错杀一千不可放过一人)
3.缓存击穿
这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:
1)设置热点数据永远不过期,异步线程处理。
2)加写回操作加互斥锁,查询失败默认值快速返回。
3)缓存预热系统上线后,将相关可预期(例如排行榜)热点数据直接加载到缓存。写一个缓存刷新页面,手动操作热点数据(例如广告推广)上下线。
4、数据不一致
在缓存机器的带宽被打满,或者机房网络出现波动时,缓存更新失败,新数据没有写入缓存,就会导致缓存和 DB 的数据不一致。缓存 rehash 时,某个缓存机器反复异常,多次上下线,更新请求多次 rehash。这样,一份数据存在多个节点,且每次 rehash 只更新某个节点,导致一些缓存节点产生脏数据。
1)Cache 更新失败后,可以进行重试,则将重试失败的 key 写入mq,待缓存访问恢复后,将这些 key 从缓存删除。这些 key 在再次被查询时,重新从 DB 加载,从而保证数据的一致性。
2)缓存时间适当调短,让缓存数据及早过期后,然后从 DB 重新加载,确保数据的最终一致性。不采用 rehash 漂移策略,而采用缓存分层策略,尽量避免脏数据产生。
5.数据并发竞争
数据并发竞争在大流量系统也比较常见,比如车票系统,如果某个火车车次缓存信息过期,但仍然有大量用户在查询该车次信息。又比如微博系统中,如果某条微博正好被缓存淘汰,但这条微博仍然有大量的转发、评论、赞。上述情况都会造成并发竞争读取的问题。
1)加写回操作加互斥锁,查询失败默认值快速返回。
2)对缓存数据保持多个备份,减少并发竞争的概率。
6.热点key问题
明星结婚、离婚、出轨这种特殊突发事件,比如奥运、春节这些重大活动或节日,还比如秒杀、双12、618 等线上促销活动,都很容易出现 Hot key 的情况。
如何提前发现HotKey?
1)对于重要节假日、线上促销活动这些提前已知的事情,可以提前评估出可能的热 key 来。而对于突发事件,无法提前评估,可以通过 Spark,对应流任务进行实时分析,及时发现新发布的热点 key。
2)而对于之前已发出的事情,逐步发酵成为热 key 的,则可以通过 Hadoop 对批处理任务离线计算,找出最近历史数据中的高频热 key。
解决方案:
1)这 n 个 key 分散存在多个缓存节点,然后 client 端请求时,随机访问其中某个后缀的 hotkey,这样就可以把热 key 的请求打散,避免一个缓存节点过载;
2)缓存集群可以单节点进行主从复制和垂直扩容;
3)利用应用内的前置缓存,但是需注意需要设置上限;
4)延迟不敏感,定时刷新,实时感知用主动刷新;
5)和缓存穿透一样,限制逃逸流量,单请求进行数据回源并刷新前置;
6)无论如何设计,最后都要写一个兜底逻辑,千万级流量说来就来;
7.BigKey问题
比如互联网系统中需要保存用户最新 1万 个粉丝的业务,比如一个用户个人信息缓存,包括基本资料、关系图谱计数、发 feed 统计等。微博的 feed 内容缓存也很容易出现,一般用户微博在 140 字以内,但很多用户也会发表 1千 字甚至更长的微博内容,这些长微博也就成了大 key。
1)首先Redis底层数据结构里,根据Value的不同,会进行数据结构的重新选择;
2)可以扩展新的数据结构,进行序列化构建,然后通过 restore 一次性写入;
3)将大 key 分拆为多个 key,设置较长的过期时间;
8.redis数据分区
Hash:(不稳定)
客户端分片: 哈希+取余
节点伸缩: 数据节点关系变化,导致数据
迁移迁移数量和添加节点数量有关: 建议翻倍扩容
一个简单直观的想法是直接用Hash来计算,以Key做哈希后对节点数取模。可以看出,在key足够分散的情况下,均匀性可以获得,但一旦有节点加入或退出,所有的原有节点都会受到影响,稳定性无从谈起。
一致性Hash:(不均衡)
客户端分片: 哈希+顺时针(优化取余)
节点伸缩: 只影响邻近节点,但是还是有数据迁移
翻倍伸缩: 保证最小迁移数据和负载均衡一致性Hash可以很好的解决稳定问题,可以将所有的存储节点排列在收尾相接的Hash环上,每个key在计算Hash后会顺时针找到先遇到的一组存储节点存放。而当有节点加入或退出时,仅影响该节点在Hash环上顺时针相邻的后续节点,将数据从该节点接收或者给予。但这又带来均匀性的问题,即使可以将存储节点等距排列,也会在存储节点个数变化时带来数据的不均匀。
Codis的Hash槽
Codis 将所有的 key 默认划分为 1024 个槽位(slot),它首先对客户端传过来的 key 进行 crc32 运算计算 哈希值,再将 hash 后的整数值对 1024 这个整数进行取模得到一个余数,这个余数就是对应 key 的槽位。
RedisCluster
Redis-cluster把所有的物理节点映射到[0-16383]个slot上,对key采用crc16算法得到hash值后对16384取模,基本上采用平均分配和连续分配的方式。
9.三大高可用模式
1.主从模式=简单
主从模式最大的优点是部署简单,最少两个节点便可以构成主从模式,并且可以通过读写分离避免读和写同时不可用。不过,一旦 Master 节点出现故障,主从节点就无法自动切换,直接导致 SLA 下降。所以,主从模式一般适合业务发展初期,并发量低,运维成本低的情况
原理:
①通过从服务器发送到PSYNC命令给主服务器;
②如果是首次连接,触发一次全量复制。此时主节点会启动一个后台线程,生成 RDB 快照文件;
③主节点会将这个 RDB 发送给从节点,slave 会先写入本地磁盘,再从本地磁盘加载到内存中;
④master会将此过程中的写命令写入缓存,从节点实时同步这些数据;
⑤如果网络断开了连接,自动重连后主节点通过命令传播增量复制给从节点部分缺少的数据;