2

微服务化之缓存设计

一、为什么需要缓存

缓存作为微服务化设计的一把利剑,解决了高并发、大数据场景下的数据预读能力,大大提高了服务的性能。可以说缓存无处不在,但是真正使用好缓存并不是一件容易的事情。
本人目睹过很多缓存设计欠佳的项目,很多都没有考虑一致性问题,甚至有的连最基本的防止雪崩的能力都没有。
本文就个人经历并结合自己的思考提炼了一些设计要点,目的就是让大家可以更好的使用缓存,希望大家能有所收获。

二、缓存技术选型

缓存的重要性不言而喻,接下来我们需要考虑缓存的技术选型。是选择本地缓存,还是考虑远程缓存?如果使用远程缓存,是选择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)对一致性要求不高,因此采用性能最好的定时异步更新策略

图片描述


架构进阶之路
9 声望0 粉丝

下一篇 »
JVM之垃圾回收