1.Redis数据丢失场景
1.1 持久化丢失
采用RDB或者不持久化,就会有数据丢失,因为是手动或者配置以快照的形式来进行备份。
解决: 启用AOF,以命令追加的形式进行备份,但是默认也会有1s丢失,这是在性能与数据安全性中寻求的一个最适合的方案,如果为了保证数据一致性,可以将配置更改为always,但是性能很慢,一般不用。
1.2主从切换
因为Redis的数据是主异步同步给从的,提升了性能,但是由于是异步同步到从。所以存在数据丢失的可能。
1.3 sentinel脑裂
a.假如有个sentinel集群跟redis集群,如图
b. 当我的master机器(129)跟另外2台发生分区容错,网络断开
c. sentinel2跟sentinel3大于三分之二,满足故障转移条件(sentinel故障转移需要过半),这个时候会从2个slave中选出一个master
d. 客户端假如连接到sentinel1,我们数据会写入129,连接到sentinel2或sentinel3,数据就会写入128,同时有2个master写入数据。假如129写入了k1
e.当网络恢复后,129会变成128的从,129的数据全部从128同步
f. k1丢失
尽量减少主从切换跟sentinel数据丢失的解决办法:
2. Redis缓存跟DB一致性问题
在并发环境下,可能导致redis跟DB的数据产生不一致。
2.1 怎么产生?
查询缓存逻辑
a.在我们查询DB之前,先去查询Redis,如果Redis存在,直接返回;如果Redis不存在,从DB查询。
b.从DB查询后,回写到Redis
缓存依赖
当修改DB的数据,DB数据修改成功后,删除Redis数据,做好缓存依赖。
丢失场景
因此,最终我们发现,redis的数据为1,db数据为2,出现了数据一致性问题。
所以,数据一致性产生的根本问题,是查询DB跟操作Redis不是原子性的,所以并发会导致数据一致性问题。
2.2 怎么解决?
2.2.1 不可取的强一致性方案
延时双删
采用锁机制,不让有并发
综上,我们只能采用最终一致性,不应该去保证强一致性。
2.2.2 最终一致性方案
每个缓存设置过期时间
设置过期时间,就算不一致,也只是在有效时间内的不一致。
Mysql canal等数据同步工具
捕捉到DB的更改,同步到相关Redis,相对比较复杂,要知道每个数据对应的缓存。
3. edis缓存雪崩、穿透、击穿问题分析
3.1缓存雪崩
缓存雪崩就是redis大量的数据同时过期(失效) 并且并发很高,则会导致所有的key全部打到DB
3.2 缓存穿透
缓存穿透就是恶意攻击,指的是查询的key redis没有 db也没有,就会导致每次请求都会走DB
怎么解决? 最好的办法就是找运维 封IP
能不能把数据放到另外一个地方, 在访问redis和db之间就过滤一次。举个例子
上面例子到我们的redis中,就是腾出一部分内存空间,为value值打标记,这就是我们布隆过滤器的思想。
3.2.1 布隆过滤器
位图里面只有0和1 zsc jack tom代表的是 value值 布隆过滤器的key, 向上指向的1 为两次hash后得到的位置 标记为1.但是我们没有办法判断tom是不是真的存在,因为Tom所在的两个位置与zsc和jack的hash冲突,因为无法判断tom是不是存在,但是布隆过滤器一定能够判断数据不存在。
思考: 那么怎么减少hash冲突呢? 多次hash; 增大位图大小。
还有一个弊端: 必须首先初始化数据到布隆过滤器,并且不能删除(就拿tom来说,如果tom删除了,第3和第5的位置就会置为0,影响其他的元素会导致 zsc和jack即使db中有,也判断为了没有)
实现方式:
3.3 缓存击穿
缓存击穿是说单个key过期的时候有大量的并发访问。 解决办法: 使用互斥锁,回写redis,并且采用双重检查锁来提升性能,减少对DB的访问
以上,我们Mysql现在有集群等方案,所以也没那么脆弱,如果真的到了瓶颈我们也可以进行DB横向扩容
4. 慢查询分析
许多存储系统都会有慢日志查询,提供给开发跟运维来找到哪些指令是比较耗时的。比如Mysql,那么Redis中也会有慢日志查询。
但是Redis的慢查时间只会去统计执行指令的时间,不会统计网络消耗时间,所以没有慢查不代表没有超时。
多慢才是慢查询?可配
最多存储多少慢查?可配
如果发现慢查,怎么避免?