微服务化之缓存设计
一、为什么需要缓存
缓存作为微服务化设计的一把利剑,解决了高并发、大数据场景下的数据预读能力,大大提高了服务的性能。可以说缓存无处不在,但是真正使用好缓存并不是一件容易的事情。
本人目睹过很多缓存设计欠佳的项目,很多都没有考虑一致性问题,甚至有的连最基本的防止雪崩的能力都没有。
本文就个人经历并结合自己的思考提炼了一些设计要点,目的就是让大家可以更好的使用缓存,希望大家能有所收获。
二、缓存技术选型
缓存的重要性不言而喻,接下来我们需要考虑缓存的技术选型。是选择本地缓存,还是考虑远程缓存?如果使用远程缓存,是选择Memcache还是Redis?本节主要解答这些疑问。
1、本地缓存
本地缓存的好处:1)成本低,包括硬件成本和维护成本;2)速度更快,相对远程缓存少了一次网络交互
本地缓存的弊端:1)一致性很难保证;2)多次预热,对底层存储有一定压力(可以忽略,但是也作为一个分析项)
通过上述对比分析,当业务场景对一致性要求比较低的情况下可以优先考虑本地缓存。
2、MC or Redis ?
Redis适用场景:需要持久化,数据内容比较大,需要复杂的数据结构,有高可用的需求。
MC适用场景:纯KV,数据量和并发量非常大,使用MC更合适。
三、缓存设计要点
1、缓存 淘汰or更新?
数据有变更时,到底是对缓存进行淘汰还是更新操作?
总结:
1)一般选择淘汰缓存,任何场景都适用
2)在部分情形下,更新缓存可以提高性能(减少一次cache miss)
2、先操作 数据库or缓存?
数据有变更时,是先操作数据库还是先操作缓存?
先操作数据库,后操作缓存:存在原子性问题
先set缓存,后操作数据库:存在原子性问题
总结:先淘汰缓存,后操作数据库
3、缓存过期策略
为什么需要为缓存设置过期时间,或者说什么场景下需要为缓存设置过期时间?
数据变更有两种情况:1)可以收到数据变更的通知;2)无法感知数据变更。针对第一种情况,我们可以收到通知后,淘汰或者更新缓存。而第二种情况,就需要定时操作缓存。
缓存过期策略有三种:1)定时过期;2)定时同步刷新;3)定时异步刷新。
定时过期:会造成一次cache miss
定时同步刷新:更新缓存线程被阻塞,其他线程返回旧的缓存值。
定时异步刷新:缓存值异步更新,所有请求线程返回旧的缓存值。
从左到右,一致性降低,性能提高。
4、主从数据不一致优化
为提高数据库的读性能,我们在很多场景下都采用了读写分离。由于主从同步需要时间,所以在同步时间差内如果有读请求,会导致不一致的情况。如果引入缓存,不一致的时间会更长。
有两个优化方向:
1) 从库同步完立即淘汰缓存,减小不一致的时间;
2) 从库同步完成前,读请求访问主库。
当然,该节主要是讨论如何解决同步导致的不一致问题。如果使用场景对一致性要求不高的话,完全可以忽略,或者不做读写分离。
四、相关案例分析
案例一:缓存第三方公司的天气数据,供公司内部各个业务线使用。
1)由于第三方公司的数据是要付费的,所以在满足需要的情况下,尽可能的减少调用次数。因此选择远程缓存。
2)天气数据结构非常简单,最普通的k-v存储,MC完全满足需要。
3)由于天气数据来源于第三方,数据变更无法感知,所以采用缓存过期策略。
4)对一致性要求不高,因此采用性能最好的定时异步更新策略。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。