热点缓存key重建优化
    开发人员使用“缓存+过期时间”的策略既可以加速数据读写, 又保证数据的定期更新, 这种模式基本能够满足绝大部分需求。 但是有两个问题如果同时出现, 可能就会对应用造成致命的危害:

    • 当前key是一个热点key(例如一个热门的娱乐新闻),并发量非常大。
    • 重建缓存不能在短时间完成, 可能是一个复杂计算, 例如复杂的SQL、 多次IO、 多个依赖等。

    在缓存失效的瞬间, 有大量线程来重建缓存, 造成后端负载加大, 甚至可能会让应用崩溃。
    要解决这个问题主要就是要避免大量线程同时重建缓存。
    我们可以利用互斥锁来解决,此方法只允许一个线程重建缓存, 其他线程等待重建缓存的线程执行完, 重新从缓存获取数据即可。
    示例伪代码:

    1. String get(String key) {
    2. // 从Redis中获取数据
    3. String value = redis.get(key);
    4. // 如果value为空, 则开始重构缓存
    5. if (value == null) {
    6. // 只允许一个线程重建缓存, 使用nx, 并设置过期时间ex
    7. String mutexKey = "mutext:key:" + key;
    8. if (redis.set(mutexKey, "1", "ex 180", "nx")) {
    9. // 从数据源获取数据
    10. value = db.get(key);
    11. // 回写Redis, 并设置过期时间
    12. redis.setex(key, timeout, value);
    13. // 删除key_mutex
    14. redis.delete(mutexKey);
    15. }// 其他线程休息50毫秒后重试
    16. else {
    17. Thread.sleep(50);
    18. get(key);
    19. }
    20. }
    21. return value;
    22. }