1.数据一致性
策略一
- 方案:对于写操作先插入数据库,在进行同步redis;对于更新、删除操作先,先删除缓存在操作数据库。
- 弊端:写入的操作需要手动同步到redis;更新的时候在高并发的情况下会出现脏数据,有可能缓存删除了之后,数据库还没更新的时候,有请求进来会查到老数据。
策略二
- 方案:延时双删,先删除redis中的缓存,然后在更新数据库,让线程等待1s,然后在删除redis中的缓存
redis.del(key)
mysql.update(data)
Thread.sleep(1000)
redis.del(key)
- 弊端:不是适用于高并发,而且在没有第二次删除缓存之前仍然会有可能出现脏数据,线程等也会导致请求耗时过长
策略三
- 方案:修改redis的缓存时间,等到数据写入数据库之后在删除redis中的缓存
redis.expire(key, 2)
mysql.update(data)
redis.del(key)
- 这种方案优化了请求耗时过长,即使没删除缓存,key的有效期也会到了也会重新获取数据
策略四
- 方案:使用MySQL中binlog的同步机制,当数据库中出现写、改、删的时候将数据异步写入redis。阿里提供了开源项目Canal,模仿了MySql的主从复制
- 弊端:会导致MySql的binlog文件占用磁盘过大
2.缓存
1. 缓存穿透
- 原因:请求访问的数据redis中没有,数据库中也没有,所以没有访问数据库的结果加入到缓存中,就会一直请求数据库,数据库压力增加
- 案例:黑客攻击
- 解决方案:
- 空值缓存:如果数据库中查不到结果就将null存入到redis缓存中
- 布隆过滤器:它会在缓存前面加了一层过滤,过滤的规则是只允许数据库存在的数据进行下一步操作
2. 缓存击穿
- 原因: 请求访问的数据redis中没有,数据库中有,高并发情况下会有多个请求同时访问数据库,数据库压力增加
- 案例:热点数据过期
- 解决方案:
- 加锁:同时只能有一个请求访问数据库,单线程可以使用普通锁,多线程可以使用redis分布式锁
- 将数据设为永久有效
3. 缓存雪崩
- 原因:缓存的数据同时过期,或者redis宕机,导致大量请求直接访问数据库,数据库压力增加
- 解决方案:
- 将缓存时间增加区间随机值
- 使用多级缓存
- 配置高可用缓存(redis集群),宕机之后尽快重启redis,通过持久化恢复数据