进程内缓存方案与使用场景

2018-09-10 15:03:30   最后更新: 2018-09-10 15:03:30   访问数量:151




缓存是数据交换的缓冲区,通常由于数据在交互过程中存在较高的代价,如服务器访问压力或数据查询效率等

而通过适当的缓冲区存储数据,形成数据的暂存或中转,可以对上述较高的代价带来很大程度上的缓解

简而言之,就是增加一层缓存存储器,让系统性能得以提高

在分布式系统的实现上,缓存又分为进程内缓存与缓存服务器,本篇日志我们就来探讨一下进程内缓存涉及的一些问题

 

顾名思义,进程内缓存就是数据存储在应用服务的进程内的缓存

最简单的,通过带锁的 Map 或是第三方库都可以实现,例如 java 中有 ConcurrentHashMap、ThreadLocal、guava cache 等

关于应用的实例,可以参考:

订单抢购系统详细设计方案

java 中线程安全的容器类

ThreadLocal 源码深入解析

 

优势

与没有缓存相比,进程内缓存有着缓存的直观优势:

  1. 减轻数据存储服务器压力
  2. 减少与数据存储服务器的通讯,提高响应速度

 

与缓存服务器相比,进程内缓存节省了与缓存服务器的通信,对提高响应速度,降低时延有较大优势

 

缺点

进程内缓存的缺点也很明显

由于缓存分散在分布式系统内的各处,管理、同步的成本都比较高,很难维护其一致性

而当分布式系统规模较大时,也很难保证缓存的命中率

 

建议

分层架构设计中有一条准则:站点层、服务层要做到无数据无状态

这样才能任意的加节点水平扩展,因此尽量必要频繁使用进程内缓存

  • 如无必要通常不推荐使用

 

单点通知

 

第一种方案是所有写请求都发生在 server1,在 server1 修改完成自己缓存中的数据与服务器上的数据后,将数据通知到其他 server

这种方案最明显的问题是如何保证 server1 的有效通知,一旦通知失败,将会导致部分或全部服务器的进程内缓存的不一致问题

 

依靠 MQ 通信

 

解决方案一存在缺点的方案是通过依赖可靠的 MQ 进行通信

然而,引入 MQ 以后,系统复杂度有了明显上升,而同时,并没有从根本上解决一致性问题

 

主动拉取

 

由于方案一和方案二在水平扩展中都面临着系统复杂度大幅增加的问题,同时,系统一致性难以保证,于是诞生了上图所示的方案:各节点通过一定的触发条件,如定时器定时触发,或访问触发等,定期从后端拉取最新数据,更新到内存中的进程内缓存

这样的设计避免了耦合,降低了复杂度,但是触发条件很难选取,如果使用最为常用的定时器触发,那么在两次触发间隔内将会有可能读取到脏数据,无法保证数据的实时一致性

上面提到的博主在工作中设计的秒杀系统就是通过这样的架构实现的

 

只读数据

如果数据仅仅是进程启动时需要加载一次的启动数据,那么使用进程内缓存无疑是最为方便也是最为高效的

同时,这种场景下,无须考虑系统的数据一致性

然而,在这种场景下,系统维护人员常常会在工作中忽略进程内缓存的存在,如果只读数据并非永久不变,那么在数据发生变化后,系统中各处数据却并未发生改变,可能会暴露出令维护人员难以排查和解决的诡异问题,而通过将数据缓存到缓存服务器则不会存在这个问题

 

极度高并发

降低后端服务器压力是缓存的一个主要存在价值,通常,解决这个问题通过缓存服务器即可,但是如果系统面临着极度的高并发场景,甚至连缓存服务器都难以承受,此时,增加进程内数据缓存也是挡住流量的一层保障

但,面临高并发场景,仍然建议通过缓存服务器集群、优化架构来解决,参考:

web 服务搭建需考虑的六大因素

 

允许数据不一致

对于一些应用场景下,数据一致性要求较低,此时在进程内缓存数据,通过定时拉取来同步数据

例如,页面缓存等就是这一场景的应用

 






技术帖      database      技术分享      缓存      数据库      db      分布式      分布式系统      数据      data     


京ICP备15018585号