按照现在流行的互联网分层架构模型,最简单的架构当属Web响应层+DB存储层的架构。从最开始的单机混合部署Web和DB,到后来将二者拆分到不同物理机以避免共享机器硬件带来的性能瓶颈,再随着流量的增长,Web应用变为集群部署模式,而DB则衍生出主从机来保证高可用,同时便于实现读写分离。这一连串系统架构的升级,本质上是为了追求更高的性能,达到更低的延时。
高德作为一款国民级别的导航软件,导航路线的数据质量是由数据中心统一管理的。为了保证数据的鲜度,数据中心需要对不断变化的现实道路数据进行收集,将这些变化的信息保存到数据库中,从而保证导航数据的鲜度;另一方面数据中心内部多部门协调生产数据的时候,会产生海量请求查询最新生产的数据,这就要求数据的管理者要控制数据库连接数,降低请求的响应耗时,同时也需要保证返回数据的实时性。
在平衡数据鲜度和性能之间,高德数据中心针对不同的业务场景使用了不同的策略,达到了数据变更和缓存同步低延迟的目标,同时保障了系统的稳定性。
本文将提及的缓存技术则是提升性能的另一把利刃。然而任何技术都是有可为有可不为,没有最好的技术只有最适合的技术,因此在使用缓存之前,我们也需要了解下引入缓存模块所带来的好处和坏处。
缘起:为何使用缓存在应用对外提供服务时,其稳定性受到诸多因素影响,其中比较重要的有CPU、内存、IO(磁盘IO、网络IO)等,这些硬件资源十分宝贵,因此对于那些需要经过复杂计算才能得到结果的,或者需要频繁读取磁盘数据的,最好将结果缓存起来,避免资源的重复消耗。
CPU瓶颈
如果项目中有很多正则表达式计算,或者某个计算结果是多次中间结果合并后才得出的,且CPU的使用率一直居高不下,那么就可以考虑是否应该将这些结果缓存起来,根据特定Key直接获取Value结果,减少中间链路的传递过程,减少CPU的使用率。
IO瓶颈
众所周知,从磁盘获取数据受到磁盘转速、寻道速度、磁盘缓冲区大小等诸多因素影响,这些因素决定了磁盘的IOPS,同时我们也知道对于数据的读写来说,CPU的缓存读写速度> 内存的读写速度>磁盘的读写速度。虽然磁盘内部也配备了缓存以匹配内存的读写速度,但其容量毕竟是有限的,那么当磁盘的IOPS无法进一步提升的时候,便会想到将数据缓存到内存中,从而降低磁盘的访问压力。这一策略常被应用于缓解DB数据库的数据访问压力。
选择本地缓存和分布式缓存的考量点既然可以使用缓存来提升系统吞吐能力,那么紧接着遇到的问题就是选择本地缓存,还是分布式缓存?什么时候需要使用多级缓存呢?接下来,让我们聊一聊在使用缓存优化项目的过程中,本地缓存和分布式缓存的应用场景和优缺点。
本地缓存的优缺点和应用场景
统一进程带来了以下优势:
由于本地缓存和应用在同一个进程中,因而其稳定性很高,达到了和应用同生共死的境界;
由于在同一进程中,避免了网络数据传输带来的消耗,所有缓存数据直接从进程所在的内存区域获取即可。
强耦合性也会导致以下这些劣势:
本地缓存和应用共享一片JVM内存,争抢内存资源,无法水平扩展,且可能造成频繁的GC,影响线上应用的稳定性。
由于没有持久化机制,在项目重启后缓存内数据就会丢失,对于高频访问数据,需要对数据进行预热操作。
多份进程内缓存存储着同样的数据内容,造成内存使用浪费。
同样的数据存储在不同的本地机器,数据变化后,很难保证数据的一致性。
结合以上优缺点,我们就会想到,如果有一种数据需要频繁访问,但一旦创建后就轻易不会改变,而且初始创建时就能预估占用的内存空间,那么这种类型的数据无疑是最适合用本地缓存存储了。
既然有了上述的应用场景,我们反观技术开发中的诉求,发现其实很多优秀的框架已经在这样使用了,比如缓存类class的反射信息,包括field、method等。因为class的数量是有限的,且内容不会轻易改变,在使用时无需再使用反射机制,而只需要从本地缓存读取数据即可。
分布式缓存的优缺点和应用场景
优势:
数据集中存储,消除冗余数据,解决整体内存的占用率,易于维护集群建缓存数据的一致性。
缓存中间件可以对缓存进行统一管理,便于水平扩容。
劣势:
依赖分布式缓存中间件稳定性,一旦挂了,容易造成缓存雪崩;
由于是跨机器获取缓存数据,因此会造成数据传输的网络消耗,以及一些序列化/反序列化的时间开销。