2020/03/11 Cache

哪些地方可以使用缓存?

  1. 数据库缓存
    在数据库内部也是支持缓存的,比如 MySQL 。不过这种方式并不是太好,首先缓存涉及到更新,会消耗数据库的性能,另一方面,查询是按照 sql 语句作为 key ,缓存的命中率不高,也失去了缓存的意义,所以在 MySQL5.7.20 之后就弃用缓存了。
  2. 本地缓存
    本地缓存是速度非常快的,可以利用一些本地缓存技术实现,如 Caffeine,GuavaCache,EhCache 等,也可以结合一些 ORM 框架使用 。但是本地缓存只能单机使用,多台机器之间不能共享。在某些场景下会有缓存不一致的问题,比如 MyBitas 的二级缓存
  3. 分布式缓存
    分布式缓存是用的最多的一种方案,利用独立的中间件来缓存数据,和应用程序以及数据库都是独立的。常用的技术有 redis ,Memcached 。
  4. Nginx 缓存
    Nginx 可以缓存用户请求过的 url 对应的 response 响应,当用户再次请求,可以直接返回缓存内容。
  5. 页面缓存
    比如静态化,ajax 等。

缓存更新的方式

  1. Cache Aside ,同时更新缓存和数据库。
    应用程序先从 cache 取数据,没有得到,则从数据库中取数据,成功后放到缓存中。如果需要更新数据,先更新数据库,成功后再让缓存失效。简单,但是同时操作 cache 和数据库,可能会有数据不一致。推荐先操作数据库,再删除缓存。
  2. Read/Write Through ,先更新缓存,缓存负责同步更新数据库。
    只操作缓存,但是实现比较复杂。
  3. Write Behind Caching ,先更新缓存,缓存定时异步更新数据库。
    异步操作,可能会造成数据丢失。

缓存常见问题

  1. 缓存击穿
    热点 key 失效后,大量的请求查询热点 key,导致数据库压力增大。
  2. 缓存穿透
    查询一个不存在的 key ,导致总会查询数据库。
  3. 缓存雪崩
    大量缓存设置了相同的失效时间,同一时间失效。

解决缓存问题的方案有很多种,可以综合使用:

  1. 随机设置缓存失效时间。
  2. 热点 key 永久不失效。
  3. 使用锁,保证并发时只有获得锁的请求可以访问数据库并重建缓存。
  4. 使用分段锁,保证不会有大量的线程阻塞。
  5. 缓存没查询到时返回默认提示。
  6. 查询备份缓存。