`
m635674608
  • 浏览: 5042376 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

应用多级缓存模式支撑海量读服务

 
阅读更多

缓存技术是一个老生常谈的问题,但是它也是解决性能问题的利器,一把瑞士军刀;而且在各种面试过程中或多或少会被问及一些缓存相关的问题,如缓存算法、热点数据与更新缓存、更新缓存与原子性、缓存崩溃与快速恢复等各种与缓存相关的问题。而这些问题中有些问题又是与场景相关,因此如何合理应用缓存来解决问题也是一个选择题。本文所有内容是跟读服务缓存相关,不会涉及写服务数据的缓存。本文也不考虑内容型应用前置的CDN架构。本文也不会涉及缓存数据结构优化、缓存空间利用率跟业务数据相关的细节问题,主要从架构和提升命中率等层面来探讨缓存方案。本文将基于多级缓存模式来介绍下应用缓存时需要注意的问题和一些解决方案,其中一些方案已经实现,而有一些也是想使用来解决痛点问题。

 

1、多级缓存介绍

所谓多级缓存,即在整个系统架构的不同系统层级进行数据缓存,以提升访问效率,这也是应用最广的方案之一。我们应用的整体架构如下图所示:



整体流程如上图所示:

1、首先接入Nginx将请求负载均衡到应用Nginx,此处常用的负载均衡算法是轮询或者一致性哈希,轮询可以使服务器的请求更加均衡,而一致性哈希可以提升应用Nginx的缓存命中率;后续负载均衡和缓存算法部分我们再细聊;

2、接着应用Nginx读取本地缓存(本地缓存可以使用Lua Shared DictNginx Proxy Cache(磁盘/内存)、Local Redis实现),如果本地缓存命中则直接返回,使用应用Nginx本地缓存可以提升整体的吞吐量,降低后端的压力,尤其应对热点问题非常有效;为什么要使用应用Nginx本地缓存我们将在热点数据与缓存失效部分细聊;

3、如果Nginx本地缓存没命中,则会读取相应的分布式缓存(如Redis缓存,另外可以考虑使用主从架构来提升性能和吞吐量),如果分布式缓存命中则直接返回相应数据(并回写到Nginx本地缓存);

4、如果分布式缓存也没有命中,则会回源到Tomcat集群,在回源到Tomcat集群时也可以使用轮询和一致性哈希作为负载均衡算法;

5、在Tomcat应用中,首先读取本地堆缓存,如果有则直接返回(并会写到主Redis集群),为什么要加一层本地堆缓存将在缓存崩溃与快速修复部分细聊;

6、作为可选部分,如果步骤4没有命中可以再尝试一次读主Redis集群操作,目的是防止当从有问题时的流量冲击;

7、如果所有缓存都没有命中只能查询DB或相关服务获取相关数据并返回;

8、步骤7返回的数据异步写到主Redis集群,此处可能多个Tomcat实例同时写主Redis集群,可能造成数据错乱,如何解决该问题将在更新缓存与原子性部分细聊。

 

整体分了三部分缓存:应用Nginx本地缓存、分布式缓存、Tomcat堆缓存,每一层缓存都用来解决相关的问题,如应用Nginx本地缓存用来解决热点缓存问题,分布式缓存用来减少访问回源率、Tomcat堆缓存用于防止相关缓存失效/崩溃之后的冲击。

 

虽然就是加缓存,但是怎么加,怎么用细想下来还是有很多问题需要权衡和考量的,接下来部分我们就详细来讨论一些缓存相关的问题。

 

2、如何缓存数据

2.1、过期与不过期

对于缓存的数据我们可以考虑不过期缓存和带过期时间缓存;什么场景应该选择哪种模式需要根据业务和数据量等因素来决定。

 

不过期缓存场景一般思路如下图所示:



如上图所示,首先写数据库,如果成功则写缓存。这种机制存在一些问题:

1、事务在提交时失败则写缓存是不会回滚的造成DB和缓存数据不一致;

2、假设多个人并发写缓存可能出现脏数据的;

3、同步写对性能有一定的影响,异步写存在丢数据的风险。

 

如果对缓存数据一致性要求不是那么高,数据量也不是很大,可以考虑定期全量同步缓存。

 

为解决以上问题可以考虑使用消息机制,如下图所示:



1、把写缓存改成写消息,通过消息通知数据变更;

2、同步缓存系统会订阅消息,并根据消息进行更新缓存;

3、数据一致性可以采用:消息体只包括ID、然后查库获取最新版本数据;通过时间戳和内容摘要机制(MD5)进行缓存更新;

4、如上方法也不能保证消息不丢失,可以采用:应用在本地记录更新日志,当消息丢失了回放更新日志;或者采用数据库binlog,采用如canal订阅binlog进行缓存更新。

 

对于长尾访问的数据、大多数数据访问频率都很高的场景、缓存空间足够都可以考虑不过期缓存,比如用户、分类、商品、价格、订单等,当缓存满了可以考虑LRU机制驱逐老的缓存数据。

 

过期缓存机制,即采用懒加载,一般用于缓存别的系统的数据(无法订阅变更消息、或者成本很高)、缓存空间有限、低频热点缓存等场景;常见步骤是:首先读取缓存如果不命中则查询数据,然后异步写入缓存并设置过期时间,下次读取将命中缓存。热点数据经常使用过期缓存,即在应用系统上缓存比较短的时间。这种缓存可能存在一段时间的数据不一致情况,需要根据场景来决定如何设置过期时间。如库存数据可以在前端应用上缓存几秒钟,短时间的不一致时可以忍受的。

 

2.2、维度化缓存与增量缓存

对于电商系统,一个商品可能拆成如:基础属性、图片列表、上下架、规格参数、商品介绍等;如果商品变更了要把这些数据都更新一遍那么整个更新成本很高:接口调用量和带宽;因此最好将数据进行维度化并增量更新(只更新变的部分)。尤其如上下架这种只是一个状态变更,但是每天频繁调用的,维度化后能减少服务很大的压力。

 

3、分布式缓存与应用负载均衡

3.1、缓存分布式

此处说的分布式缓存一般采用分片实现,即将数据分散到多个实例或多台服务器。算法一般采用取模和一致性哈希。如之前说的做不过期缓存机制可以考虑取模机制,扩容时一般是新建一个集群;而对于可以丢失的缓存数据可以考虑一致性哈希,即使其中一个实例出问题只是丢一小部分,对于分片实现可以考虑客户端实现,或者使用如Twemproxy中间件进行代理(分片对客户端是透明的)。如果使用Redis可以考虑使用redis-cluster分布式集群方案。

 

3.2、应用负载均衡

应用负载均衡一般采用轮询和一致性哈希,一致性哈希可以根据应用请求的URL或者URL参数将相同的请求转发到同一个节点;而轮询即将请求均匀的转发到每个服务器;如下图所示:



整体流程:

1、首先请求进入接入层Nginx

2、根据负载均衡算法将请求转发给应用Nginx

3、如果应用Nginx本地缓存命中,则直接返回数据,否则读取分布式缓存或者回源到Tomcat

轮询的优点:到应用Nginx的请求更加均匀,使得每个服务器的负载基本均衡;轮询的缺点:随着应用Nginx服务器的增加,缓存的命中率会下降,比如原来10台服务器命中率为90%,再加10台服务器将可能降低到45%;而这种方式不会因为热点问题导致其中某一台服务器负载过重。

 

一致性哈希的优点:相同请求都会转发到同一台服务器,命中率不会因为增加服务器而降低;一致性哈希的缺点:因为相同的请求会转发到同一台服务器,因此可能造成某台服务器负载过重,甚至因为请求太多导致服务出现问题。

 

解决办法是根据实际情况动态选择使用哪种算法:

1、负载较低时使用一致性哈希;

2、热点请求降级一致性哈希为轮询;

3、将热点数据推送到接入层Nginx,直接响应给用户。

 

4、热点数据与更新缓存

热点数据会造成服务器压力过大,导致服务器性能、吞吐量、带宽达到极限,出现响应慢或者拒绝服务的情况,这肯定是不允许的。可以从如下几个方案去解决。

 

4.1、单机全量缓存+主从



如上图所示,所有缓存都存储在应用本机,回源之后会把数据更新到主Redis集群,然后通过主从复制到其他从Redis集群。缓存的更新可以采用懒加载或者订阅消息进行同步。

 

4.2、分布式缓存+应用本地热点     



 

对于分布式缓存,我们需要在Nginx+Lua应用中进行应用缓存来减少Redis集群的访问冲击;即首先查询应用本地缓存,如果命中则直接缓存,如果没有命中则接着查询Redis集群、回源到Tomcat;然后将数据缓存到应用本地。

此处到应用Nginx的负载机制采用:正常情况采用一致性哈希,如果某个请求类型访问量突破了一定的阀值,则自动降级为轮询机制。另外对于一些秒杀活动之类的热点我们是可以提前知道的,可以把相关数据预先推送到应用Nginx并将负载均衡机制降级为轮询。

 

 

另外可以考虑建立实时热点发现系统来发现热点:



 

1、接入Nginx将请求转发给应用Nginx

2、应用Nginx首先读取本地缓存;如果命中直接返回,不命中会读取分布式缓存、回源到Tomcat进行处理;

3、应用Nginx会将请求上报给实时热点发现系统,如使用UDP直接上报请求、或者将请求写到本地kafka、或者使用flume订阅本地nginx日志;上报给实时热点发现系统后,它将进行统计热点(可以考虑storm实时计算);

4、根据设置的阀值将热点数据推送到应用Nginx本地缓存。

 

因为做了本地缓存,因此对于数据一致性需要我们去考虑,即何时失效或更新缓存:

1、如果可以订阅数据变更消息,那么可以订阅变更消息进行缓存更新;

2、如果无法订阅消息或者订阅消息成本比较高,并且对短暂的数据一致性要求不严格(比如在商品详情页看到的库存,可以短暂的不一致,只要保证下单时一致即可),那么可以设置合理的过期时间,过期后再查询新的数据;

3、如果是秒杀之类的,可以订阅活动开启消息,将相关数据提前推送到前端应用,并将负载均衡机制降级为轮询;

4、建立实时热点发现系统来对热点进行统一推送和更新。

 

5、更新缓存与原子性

正如之前说的如果多个应用同时操作一份数据很可能造成缓存数据是脏数据,解决办法:

1.1、更新数据时使用更新时间戳或者版本对比,如果使用Redis可以利用其单线程机制进行原子化更新;

1.2、使用如canal订阅数据库binlog;

2.1、将更新请求按照相应的规则分散到多个队列,然后每个队列的进行单线程更新,更新时拉取最新的数据保存;

2.2、分布式锁,更新之前获取相关的锁。

 

6、缓存崩溃与快速修复

6.1、取模

对于取模机制如果其中一个实例坏了,如果摘除此实例将导致大量缓存不命中,瞬间大流量可能导致后端DB/服务出现问题。对于这种情况可以采用主从机制来避免实例坏了的问题,即其中一个实例坏了可以那从/主顶上来。但是取模机制下如果增加一个节点将导致大量缓存不命中,一般是建立另一个集群,然后把数据迁移到新集群,然后把流量迁移过去。

 

6.2、一致性哈希

对于一致性哈希机制如果其中一个实例坏了,如果摘除此实例将只影响一致性哈希环上的部分缓存不命中,不会导致瞬间大量回源到后端DB/服务,但是也会产生一些影响。

 

另外也可能因为一些误操作导致整个缓存集群出现了问题,如何快速恢复呢?

 

6.3、快速恢复

如果出现之前说到的一些问题,可以考虑如下方案:

1、主从机制,做好冗余,即其中一部分不可用,将对等的部分补上去;

2、如果因为缓存导致应用可用性已经下降可以考虑:1、部分用户降级,然后慢慢减少降级量;2、后台通过Worker预热缓存数据。

 

也就是如果整个缓存集群坏了,而且没有备份,那么只能去慢慢将缓存重建;为了让部分用户还是可用的,可以根据系统承受能力,通过降级方案让一部分用户先用起来,将这些用户相关的缓存重建;另外通过后台Worker进行缓存数据的预热。

 http://jinnianshilongnian.iteye.com/blog/2283670

分享到:
评论

相关推荐

    分布式多级缓存实践

    分布式多级缓存实践是一种优化高并发环境下数据访问性能的重要技术。在现代互联网应用中,随着用户数量的增长和数据量的膨胀,单纯依赖数据库进行实时读写操作往往会导致性能瓶颈。为了解决这个问题,分布式多级缓存...

    redis多级缓存搭建资料

    Redis作为一款高性能的键值数据库,常被用作应用程序的缓存系统,以提高数据读取速度。在大型系统中,构建多级缓存架构是常见的优化策略,它能够更有效地利用资源,减少对主数据库的压力。本资料将详细介绍如何使用...

    分布式多级缓存技术在选课系统中的应用.pdf

    分布式多级缓存技术是近年来随着互联网应用规模的不断扩大而发展起来的一种高效数据处理技术。在大规模分布式系统中,尤其是那些对实时性要求较高的场景如在线教育的选课系统中,缓存技术能够显著提升系统性能和用户...

    基于Velocity CTP3分布式多级缓存的研究与应用.pdf

    _velocity CTP3分布式多级缓存的研究与应用_一文介绍了微软公司提供的VelocityCTP3分布式多级缓存解决方案,并探讨了其在提高应用服务性能方面的应用与实例。 首先,文章对VelocityCTP3进行了简介,指出其为一个...

    高级Java人才培训专家-多级缓存

    高级Java人才培训专家-多级缓存

    day04-多级缓存.rar

    在本教程中,我们将深入探讨多级缓存的概念、原理以及其在实际应用中的重要性。 一、缓存的基本概念 缓存,简单来说,就是一个临时存储区域,用于存放经常访问的数据,以便下次请求时能快速响应。由于内存访问速度...

    多级缓存.pdf

    ### 多级缓存详解 #### 1. 什么是多级缓存? 多级缓存是一种高级缓存机制,旨在通过在系统中的不同层级实施缓存策略,来提高整体性能和响应时间。传统缓存策略通常较为单一,比如在收到请求后首先检查Redis缓存,...

    亿级流量系统多级缓存架构4.pdf

    在这样的流量背景下,为了保证系统性能与用户体验,多级缓存架构便成为了重要的技术手段。本文档聚焦于亿级流量系统的多级缓存架构设计,其中涉及的关键知识点包括异常控制、错误编码、异步处理、CAP定理、分布式...

    面向分布式数据库的自适应多级缓存机制分析.pdf

    自适应多级缓存机制的核心在于根据系统的实时状态和数据访问模式动态调整缓存策略。主要包括以下几个关键策略: (1)层次化设计:多级缓存机制通常包含不同级别的缓存,如本地缓存、节点间缓存和全局缓存等。数据...

    第六讲-缓存接入之多级缓存实现及分布式部署落地实践.pdf

    分布式部署采用服务集群模式,通过负载均衡服务器如openresty来分散请求,实现多台服务器协同工作,有效提升了系统的处理能力和容错性。压力测试在此过程中起到了关键作用,能够检验不同部署策略下的服务性能。 接...

    微服务 - 多级缓存相关资料及软件

    下面我们将深入探讨多级缓存及其在微服务中的应用。 1. **什么是多级缓存?** 多级缓存是指在一个系统中设置多个不同层次的高速缓存,通常由近似于内存访问速度的高速缓存(如CPU缓存)和较慢但容量较大的二级缓存...

    使用多级缓存加载Bitmap图片

    "使用多级缓存加载Bitmap图片"这个主题是Android开发中的一个经典问题,它涉及到内存管理、用户体验以及应用程序的响应速度。在这个场景中,我们将探讨如何通过构建多级缓存系统来高效地加载Bitmap图片。 首先,...

    Java编程代码-多级缓存-源代码+讲义+资料

    在IT行业中,尤其是在Java开发领域,多级缓存是一个关键的概念,它被广泛应用于提高应用程序的性能和响应速度。这个压缩包文件包含了关于Java编程中实现多级缓存的源代码、讲义以及相关资料,旨在帮助学习者深入理解...

    有赞多级缓存解决方案怎么做的,你知道吗.docx

    TMC 能够自动发现热点,并将热点缓存访问请求前置在应用层本地缓存中,从而减少对分布式缓存系统的冲击,避免影响应用服务的性能及稳定性。 TMC 的整体架构分为三层:存储层、代理层和应用层。存储层提供基础的 KV ...

    php缓存多级目录的类

    一个php缓存多级目录的类 参数详解如下: 第一个参数:缓存二级目录 第二个参数:缓存时间 默认1800 第三个参数:是否需要三级目录 0:不需要 1 需要 默认0 第四个参数:缓存后缀 默认 .html 调用方法: $...

    多级缓存-安装Canal方法

    多级缓存-安装Canal方法

    数据库多级缓存架构设计.docx

    数据库多级缓存架构设计可以应用于 SOA 甚至微服务的场景,内存相当于存储业务数据的持久化数据库,其吞吐量肯定是远远小于缓存的。关系型数据库操作方便、易于维护且访问数据灵活,但是随着数据量的增加,其检索、...

    案例实战-高并发业务的多级缓存架构一致性解决方案

    多级缓存是指在应用程序中使用多个层次的缓存,通常包括本地缓存、分布式缓存和数据库缓存等。这种架构设计的目的是提高系统性能,减少对底层存储系统的访问压力,从而提升整体的响应速度。 本地缓存,如Java的...

    springboot缓存一致性解决

    在Spring Boot应用中,缓存一致性是一个重要的议题,特别是在分布式系统中,多个节点可能同时访问并更新同一数据,导致缓存中的数据不一致。本文将深入探讨Spring Boot中如何处理和解决缓存一致性问题。 首先,我们...

Global site tag (gtag.js) - Google Analytics