哪些地方可以使用缓存?
- 数据库缓存
在数据库内部也是支持缓存的,比如 MySQL 。不过这种方式并不是太好,首先缓存涉及到更新,会消耗数据库的性能,另一方面,查询是按照 sql 语句作为 key ,缓存的命中率不高,也失去了缓存的意义,所以在 MySQL5.7.20 之后就弃用缓存了。 - 本地缓存
本地缓存是速度非常快的,可以利用一些本地缓存技术实现,如 Caffeine,GuavaCache,EhCache 等,也可以结合一些 ORM 框架使用 。但是本地缓存只能单机使用,多台机器之间不能共享。在某些场景下会有缓存不一致的问题,比如 MyBitas 的二级缓存。 - 分布式缓存
分布式缓存是用的最多的一种方案,利用独立的中间件来缓存数据,和应用程序以及数据库都是独立的。常用的技术有 redis ,Memcached 。 - Nginx 缓存
Nginx 可以缓存用户请求过的 url 对应的 response 响应,当用户再次请求,可以直接返回缓存内容。 - 页面缓存
比如静态化,ajax 等。
缓存更新的方式
- Cache Aside ,同时更新缓存和数据库。
应用程序先从 cache 取数据,没有得到,则从数据库中取数据,成功后放到缓存中。如果需要更新数据,先更新数据库,成功后再让缓存失效。简单,但是同时操作 cache 和数据库,可能会有数据不一致。推荐先操作数据库,再删除缓存。 - Read/Write Through ,先更新缓存,缓存负责同步更新数据库。
只操作缓存,但是实现比较复杂。 - Write Behind Caching ,先更新缓存,缓存定时异步更新数据库。
异步操作,可能会造成数据丢失。
缓存常见问题
- 缓存击穿
热点 key 失效后,大量的请求查询热点 key,导致数据库压力增大。 - 缓存穿透
查询一个不存在的 key ,导致总会查询数据库。 - 缓存雪崩
大量缓存设置了相同的失效时间,同一时间失效。
解决缓存问题的方案有很多种,可以综合使用:
- 随机设置缓存失效时间。
- 热点 key 永久不失效。
- 使用锁,保证并发时只有获得锁的请求可以访问数据库并重建缓存。
- 使用分段锁,保证不会有大量的线程阻塞。
- 缓存没查询到时返回默认提示。
- 查询备份缓存。