为什么分布式一定要有Redis?( 四 )

  • 采用异步更新策略 , 无论 Key 是否取到值 , 都直接返回 。Value 值中维护一个缓存失效时间 , 缓存如果过期 , 异步起一个线程去读数据库 , 更新缓存 。需要做缓存预热(项目启动前 , 先加载缓存)操作 。
  • 提供一个能迅速判断请求是否有效的拦截机制 , 比如 , 利用布隆过滤器 , 内部维护一系列合法有效的 Key 。迅速判断出 , 请求所携带的 Key 是否合法有效 。如果不合法 , 则直接返回 。
  •  
    缓存雪崩 , 即缓存同一时间大面积的失效 , 这个时候又来了一波请求 , 结果请求都怼到数据库上 , 从而导致数据库连接异常 。
    缓存雪崩解决方案:
    • 给缓存的失效时间 , 加上一个随机值 , 避免集体失效 。
    • 使用互斥锁 , 但是该方案吞吐量明显下降了 。
    • 双缓存 。我们有两个缓存 , 缓存 A 和缓存 B 。缓存 A 的失效时间为 20 分钟 , 缓存 B 不设失效时间 。自己做缓存预热操作 。
    • 然后细分以下几个小点:从缓存 A 读数据库 , 有则直接返回;A 没有数据 , 直接从 B 读数据 , 直接返回 , 并且异步启动一个更新线程 , 更新线程同时更新缓存 A 和缓存 B 。
     
    如何解决 Redis 的并发竞争 Key 问题
     
    这个问题大致就是 , 同时有多个子系统去 Set 一个 Key 。这个时候大家思考过要注意什么呢?
    需要说明一下 , 我提前百度了一下 , 发现答案基本都是推荐用 Redis 事务机制 。
    我并不推荐使用 Redis 的事务机制 。因为我们的生产环境 , 基本都是 Redis 集群环境 , 做了数据分片操作 。
    你一个事务中有涉及到多个 Key 操作的时候 , 这多个 Key 不一定都存储在同一个 redis-server 上 。因此 , Redis 的事务机制 , 十分鸡肋 。
    如果对这个 Key 操作 , 不要求顺序
     
    这种情况下 , 准备一个分布式锁 , 大家去抢锁 , 抢到锁就做 set 操作即可 , 比较简单 。
    如果对这个 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 方法变成串行访问也可以 。总之 , 灵活变通 。
    总结
    本文对 Redis 的常见问题做了一个总结 。大部分是自己在工作中遇到 , 以及之前面试别人的时候 , 爱问的一些问题 。
    另外 , 不推荐大家临时抱佛脚 , 真正碰到一些有经验的工程师 , 其实几下就能把你问懵 。最后 , 希望大家有所收获吧 。
    小编在学习过程中整理了一些学习资料 , 可以分享给做JAVA的工程师朋友们 , 相互交流学习 , 需要的可以私信(资料)即可免费获取Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码 , MyBatis , Netty,Redis,Kafka,MySQL,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)
    其中覆盖了互联网的方方面面 , 期间碰到各种产品各种场景下的各种问题 , 很值得大家借鉴和学习 , 扩展自己的技术广度和知识面 。最后记得帮作者点个关注

    【为什么分布式一定要有Redis?】


    推荐阅读