You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
本地锁的好处在于简单易实现,分布式锁的好处在于锁是全局锁。但是分布式锁会引入额外的 IO 开销,而且投入可能会和收益不匹配,即使一个应用部署了一百个实例,针对一条缓存数据同时有一百个请求访问 DB 进行查询,这压力也不会很大。除非有非常多的缓存数据需要访问 DB 进行查询,这种情况就需要用到分布式锁了。
The text was updated successfully, but these errors were encountered:
1 Cache 定义
缓存通常是介于应用层和存储层之间的一种数据冗余,具有存取速度快,吞吐量高的特征。
相比于存储层的 DB,缓存通常将数据存储在内存中以满足高并发需求,也有部分 Cache 提供持久化能力,但是一般来说,更多的是利用缓存的高速存取能力。
2 Cache 作用
使用 Cache 可以给我们的系统带来以下 好处 :
但是使用 Cache 不只是会给我们带来好处,也可能会引入一些 成本 :
所以在引入 Cache 到系统中时,需要考虑当前系统是否真的需要 Cache,如果没有必要的话,或许可以不引入。
目前来看,适合使用 Cache 的场景有以下这些:
不适合使用 Cache 的场景 :
3 Cache 类型
Cache 可以分为本地缓存和分布式缓存,本地缓存基于应用容器内的 mem 进行缓存,读取速率比使用分布式缓存要高很多(没有网络开销);但是分布式缓存耦合性更低,多个应用实例可以共享缓存;应用容器出现问题下线之后不受影响,可以通过新增一个容器解决问题(做到无状态化服务)。
4 Cache 策略
Cache 策略指的是我们读写 Cache 和 DB 的方式,不同的读写方式和顺序构成了多种多样的 Cache 策略,这一节会记述 5 种常用的 Cache 策略。
Cache 策略的使用取决于不同的应用场景,在学习和了解了这几种常用的 Cache 策略之后还要能够做到根据实际的应用场景采用合适的 Cache 策略,不同的场景采用不同的策略会有截然不同的效果。
4.1 Cache Aside
Cache Aside 策略是使用最广的缓存策略,它需要应用来操作 Cache 和 DB。
Cache Aside 策略指的是在读取数据时:
Cache Aside 策略在 Cache 不可用时,服务仍然可以基于 DB 正常工作,当然如果请求量太大把 DB 冲垮了,那服务仍然是不可用的。
Cache Aside 策略的缺点在于每一个缓存数据在第一次访问时都需要进入 DB 进行查找,所以在 Cache 上线之初可能会导致系统体验不佳的问题。
Cache Aside 策略适用于读多写少的场景,比如用户资料。
4.2 Read/Write Through
Read/Write Through 策略基于缓存进行数据的存取,数据库的操作由缓存层实现,所以用户无需关心 Cache 和 DB 的数据一致性。
这里的 Read Through 策略和 Cache Aside 策略的读操作十分类似,区别在于这里的读写操作都通过 Cache 中间层实现,用户不关心 DB。
缺点跟 Cache Aside 相同,Cache 上线之初缓存命中率非常低,如果需要获得较好的用户体验,需要开发者人为进行预热,将数据加载到缓存中。
4.3 Write Around
Write Around 策略,是指在写入数据时不直接写入 Cache,而是将数据写入到 DB 之后删除 Cache 中的已缓存数据。
在写入数据时:
这么做的好处是没有并发写入 Cache 导致的数据不一致问题,缓存数据的删除操作是幂等的。
Write Around 策略经常和 Cache Aside 策略搭配使用,它们都适合于读多写少的场景,数据更新后再次访问数据时总是需要访问 DB,这会带来额外的开销,尤其是当写入次数很多的时候。
4.4 Write Back
Write Back 策略在更新数据时会先更新 Cache,然后在之后的一段时间内更新 DB,这会导致某些时间段内 DB 和 Cache 的数据不一致,但是可以很好的减轻 DB 的写入负载。
Write Back 策略有两种实现方式,一种是通过定时任务定时同步 Cache 中的数据到 DB 中;另一种是通过 MQ + Event Handler 异步地将数据写入 DB 中。
这种策略可以很好的削减高峰期的访问峰值,减轻 DB 压力(甚至允许 DB 短时间内不可用),但是也存在数据不一致性以及数据丢失(Cache 不可用)的风险。
这种策略非常适合写入次数很多的场景。
在实际应用中,要根据不同的场景选择合适的 Cache 策略。
5 Cache 过期
Cache 的存储空间是有限的,当存储空间不够的时候,Cache 可能会针对数据进行清理。清理的策略大致有以下三种:
6 Cache 问题
6.1 缓存雪崩
缓存雪崩指的是大量 key 同时过期(或者就是 Cache 不可用)导致短时间内大量请求透过 Cache 直接访问 DB,从而导致 DB 不可用。
解决的办法是:
6.2 缓存击穿
缓存击穿指的是热点 key 过期导致的短时间内大量请求涌入 DB 导致 DB 不可用。
解决办法是:
6.3 缓存穿透
缓存穿透指的是访问一些不存在的数据时,请求每次都会透过 Cache 访问 DB,从而给 DB 造成较大的压力。
解决办法是:
针对三种场景,在大量缓存数据失效导致增加 DB 压力的情况下,都有一种解决方案叫做针对 DB 查询进行加锁。
这里加锁的方式也分为两种,一种是进程内的线程(或者协程)级别锁,另一种是分布式锁。
前者锁的实现比较简单,但是只在进程维度生效。如果部署了多个服务实例,那个每个实例都可能有一个协程访问到 DB。
后者是整个应用维度的加锁,整个应用不管维护了多少个实例,最终只会有一个请求去访问 DB,效果较好。
本地锁的好处在于简单易实现,分布式锁的好处在于锁是全局锁。但是分布式锁会引入额外的 IO 开销,而且投入可能会和收益不匹配,即使一个应用部署了一百个实例,针对一条缓存数据同时有一百个请求访问 DB 进行查询,这压力也不会很大。除非有非常多的缓存数据需要访问 DB 进行查询,这种情况就需要用到分布式锁了。
The text was updated successfully, but these errors were encountered: