100亿内存只需要100MB内存?这个难道离不开Redis?( 三 )


6、redis和数据库双写一致性问题 分析:一致性问题是分布式常见问题 , 还可以再分为最终一致性和强一致性 。 数据库和缓存双写 , 就必然会存在不一致的问题 。 答这个问题 , 先明白一个前提 。 就是如果对数据有强一致性要求 , 不能放缓存 。 我们所做的一切 , 只能保证最终一致性 。 另外 , 我们所做的方案其实从根本上来说 , 只能说降低不一致发生的概率 , 无法完全避免 。 因此 , 有强一致性要求的数据 , 不能放缓存 。
回答:首先 , 采取正确更新策略 , 先更新数据库 , 再删缓存 。 其次 , 因为可能存在删除缓存失败的问题 , 提供一个补偿措施即可 , 例如利用消息队列 。
7、如何应对缓存穿透和缓存雪崩问题 分析:这两个问题 , 说句实在话 , 一般中小型传统软件企业 , 很难碰到这个问题 。 如果有大并发的项目 , 流量有几百万左右 。 这两个问题一定要深刻考虑 。
回答:如下所示
缓存穿透 , 即黑客故意去请求缓存中不存在的数据 , 导致所有的请求都怼到数据库上 , 从而数据库连接异常 。
解决方案:(一)利用互斥锁 , 缓存失效的时候 , 先去获得锁 , 得到锁了 , 再去请求数据库 。 没得到锁 , 则休眠一段时间重试(二)采用异步更新策略 , 无论key是否取到值 , 都直接返回 。 value值中维护一个缓存失效时间 , 缓存如果过期 , 异步起一个线程去读数据库 , 更新缓存 。 需要做缓存预热(项目启动前 , 先加载缓存)操作 。 (三)提供一个能迅速判断请求是否有效的拦截机制 , 比如 , 利用布隆过滤器 , 内部维护一系列合法有效的key 。 迅速判断出 , 请求所携带的Key是否合法有效 。 如果不合法 , 则直接返回 。
缓存雪崩 , 即缓存同一时间大面积的失效 , 这个时候又来了一波请求 , 结果请求都怼到数据库上 , 从而导致数据库连接异常 。
解决方案:(一)给缓存的失效时间 , 加上一个随机值 , 避免集体失效 。 (二)使用互斥锁 , 但是该方案吞吐量明显下降了 。 (三)双缓存 。 我们有两个缓存 , 缓存A和缓存B 。 缓存A的失效时间为20分钟 , 缓存B不设失效时间 。 自己做缓存预热操作 。 然后细分以下几个小点

  • I 从缓存A读数据库 , 否则直接返回
  • II A没有数据 , 直接从B读数据 , 直接返回 , 并且异步启动一个更新线程 。
  • III 更新线程同时更新缓存A和缓存B 。
8、如何解决redis的并发竞争key问题 分析:这个问题大致就是 , 同时有多个子系统去set一个key 。 这个时候要注意什么呢?大家思考过么 。 需要说明一下 , 博主提前百度了一下 , 发现答案基本都是推荐用redis事务机制 。 博主不推荐使用redis的事务机制 。 因为我们的生产环境 , 基本都是redis集群环境 , 做了数据分片操作 。 你一个事务中有涉及到多个key操作的时候 , 这多个key不一定都存储在同一个redis-server上 。 因此 , redis的事务机制 , 十分鸡肋 。
回答:如下所示(1)如果对这个key操作 , 不要求顺序这种情况下 , 准备一个分布式锁 , 大家去抢锁 , 抢到锁就做set操作即可 , 比较简单 。 (2)如果对这个key操作 , 要求顺序假设有一个key1,系统A需要将key1设置为valueA,系统B需要将key1设置为valueB,系统C需要将key1设置为valueC.期望按照key1的value值按照 valueA-->valueB-->valueC的顺序变化 。 这种时候我们在数据写入数据库的时候 , 需要保存一个时间戳 。 假设时间戳如下
系统A key 1 {valueA 3:00}系统B key 1 {valueB 3:05}系统C key 1 {valueC 3:10}
那么 , 假设这会系统B先抢到锁 , 将key1设置为{valueB 3:05} 。 接下来系统A抢到锁 , 发现自己的valueA的时间戳早于缓存中的时间戳 , 那就不做set操作了 。 以此类推 。
其他方法 , 比如利用队列 , 将set方法变成串行访问也可以 。 总之 , 灵活变通 。
9 总结本文对redis的常见问题做了一个总结 。 大部分是博主自己在工作中遇到 , 以及以前面试别人的时候 , 爱问的一些问题 。 另外 , 不推荐大家临时抱佛脚 , 真正碰到一些有经验的工程师 , 其实几下就能把你问懵 。 最后 , 希望大家有所收获吧 。