分布式多级缓存

本文介绍了分布式系统中采用多级缓存的策略,包括Nginx本地缓存、分布式缓存(如Redis)和Tomcat本地缓存,分别解决了缓存热点、减少回源率及缓存失效风暴等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基本概念

所谓分布式多级缓存,就是指在整个系统的不同层级进行数据的缓存,以提升系统的访问速度。通常情况下,分布式系统的访问流程如下所示:

这里写图片描述

  1. 接入层Nginx将请求负载均衡到应用层Nginx,常用的负载均衡算法是轮询/一致性哈希。轮询可以是请求更加的平均,一致性哈希可以提升应用层Nginx的缓存命中率。
  2. 应用层Nginx首先访问Local Cache(Lua Shared Dict、Nginx Proxy Cache等),如果Local Cache命中,则直接返回。Nginx本地缓存应对热点问题非常有效。
  3. 如果Local Cache未命中,则会读取分布式缓存(如Redis)。如果命中,则返回结果,并写入应用层Nginx本地缓存。
  4. 如果分布式缓存未命中,则会回源到Tomcat集群。
  5. 此时首先读取Tomcat本地缓存,若有则返回,并异步的写入Redis集群。若无则回源到DB中去查询,然后再写入到Redis中。这里面需要注意的一点是,Tomcat的Local Cache可以有效的缓解缓存失效风暴的问题。详情请见:《分布式缓存击穿

上述缓存主要分为了三大类:应用层Nginx本地缓存分布式缓存Tomcat应用服务器Local Cache。并且每一层都是用来解决不同的问题:应用层Nginx用来解决缓存热点问题;分布式缓存用来减少回源率;Tomcat本地缓存用于解决缓存失效风暴的问题。

缓存数据的方式

是否过期

不过期缓存

通常情况下我们使用缓存都会设置一个过期时间,但在某些场景下我们需要设置不过期的缓存。这个时候通常情况下是在事务结束后去写入缓存的,此时需要注意的是不要同步的去写入缓存,以免阻塞主流程。对于这种常驻缓存的数据,一定要合理的管理,一般情况下可以定期的全量更新缓存。

对于长尾缓存(缓存相对集中,但是有可能两会很大的),如以时间为维度的数据(订单/流水等),可以考虑使用LRU Cache,来使不常用的数据剔除缓存。

过期缓存

对于过期缓存,我们通常的用法是”懒加载”的方式。数据变更的时候去删除缓存,当读取数据时,缓存中没有,回源DB之后再写入缓存。这里面需要根据业务场景去设置一个合理的超时时间,对于比较热点的数据,可以根据使用场景让缓存有一定的延迟,在用户的忍受范围之内就行了(如商品库存/火车票库存等)。

细粒度缓存

对于一个电商系统,一个商品可能拆分成基础属性,图片列表、上下架、规格参数等。当商品信息变更时,此时就需要控制缓存的粒度了,尽量小成本的去更新缓存。如商品上下架,就只更新上下架维度的缓存即可。

大Value缓存

当使用Redis缓存时,应尽量避免使用大Value存储,这样会拖慢读取的速度。可以考虑的是:将其拆分为更小维度的数据,然后再组合返回前端。

热点缓存

对于热点缓存,通常情况下需要设置多级缓存,尽量避免数据通过网络去获取。当分布式缓存挂掉时,此时还需要考虑到”缓存击穿”的问题,此时可以使用白名单/布隆过滤器来作为缓存的最后一道防线。


参考:《亿级流量网站架构核心技术》
链接:http://moguhu.com/article/detail?articleId=99

### 分布式多级缓存概述 分布式多级缓存是指在一个分布式的环境中,在多个层次上设置缓存机制来加速数据读取并减轻后端压力。这种架构能够显著改善系统的整体性能和可扩展性[^1]。 ### 设计原则 为了有效实施分布式多级缓存,设计时应考虑以下几点: - **分层结构**:通常分为本地缓存、近缓存(如应用服务器上的内存缓存)、远缓存(如Redis集群)。每一层都有不同的作用范围和服务对象。 - **一致性维护**:当底层数据发生变化时,需确保各级缓存的一致性和及时更新。这可以通过事件驱动的方式完成,比如利用Canal监听MySQL变更日志来触发缓存刷新操作[^3]。 - **失效策略**:合理配置TTL (Time To Live),以及采用LRU(Least Recently Used)等算法管理空间有限的缓存资源。 - **容错处理**:考虑到单点故障的风险,应该部署冗余节点,并且具备自动切换的能力;对于集中式的缓存服务而言,还需要支持水平扩展以应对流量增长带来的挑战。 ### 技术选型与实现方式 #### Redis作为主要组件之一 Redis因其高性能、丰富的数据类型支持而成为构建分布式缓存的理想工具。特别是在面对高并发场景下表现尤为突出。它可以被放置于不同位置形成多层次布局: - 应用程序内部集成小型嵌入式KV存储; - 部署独立的服务实例供多个前端调用; - 构建跨数据中心甚至云端环境下的全局共享池。 ```bash # 安装Redis sudo apt-get install redis-server ``` #### Canal用于实时同步数据库变动至缓存 Canal模拟MySQL主从复制协议捕获增量变化记录,进而通知相关模块适时调整对应的缓存条目。这种方式有助于保持缓存内容的新鲜度而不必频繁查询原生DBMS。 ```java // Java代码片段展示如何使用Canal Client API连接到Canal Server获取binlog事件 public class SimpleCanalClient { public static void main(String[] args) throws Exception { CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress("example.com", 11111), "example", "", ""); int batchSize = 1000; try { connector.connect(); connector.subscribe(".*\\..*"); while (true) { EntryBatch batch = connector.getWithoutAck(batchSize); if (batch.getEntries().isEmpty()) continue; processBinLogEvents(batch.getEntries()); connector.ack(batchId); // 提交确认已成功消费的消息ID列表 } } finally { connector.disconnect(); } } private static void processBinLogEvents(List<Entry> entries){ // 对接收到的日志项进行解析和相应逻辑处理... } } ``` ### 实践中的注意事项 在具体项目里运用上述理论和技术手段时需要注意如下事项: - 平衡好缓存命中率与过期时间之间的关系,既不过早丢弃有用的数据也不让陈旧的信息长期占据宝贵的空间。 - 谨慎评估引入额外复杂性的成本效益比,特别是涉及到异步消息传递或者复杂的事务协调机制的时候。 - 测试阶段充分验证各种边界情况的表现,包括但不限于网络分区期间的行为模式、大规模写入风暴来临之际能否稳定工作等等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值