您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

分布式多级缓存系统设计与实战

时间:2023-05-05 12:07:28  来源:政采云技术  作者:

1. 缓存系统概述

 

图片

如上图,是一次最基本的网络请求。用户请求从界面(浏览器或 App 界面)到网络转发、应用服务再到存储(数据库或文件系统),然后返回到界面呈现内容。

 

随着互联网的普及,内容信息越来越复杂,用户数和访问量越来越大,我们的应用需要支撑更多的并发量,同时我们的应用服务器和数据库服务器所做的计算也越来越多。但是往往我们的应用服务器资源是有限的,数据库每秒能接受的请求次数也是有限的。如何能够有效利用有限的资源来提供尽可能大的吞吐量?是每个开发同学绕不开的课题。一个有效的办法就是引入缓存,打破标准流程,如下图1到4每个环节中请求可以从缓存中直接获取目标数据并返回,从而减少计算量,有效提升响应速度,让有限的资源服务更多的用户。

图片

image.png

缓存可以应用上图1到4个的各个环节中,且不同环节缓存策略略有不同。本文将主要从3和4点讲解缓存的使用。

2. 缓存架构演变

2.1. 无缓存架构

 

图片

如上图,是一次最基本的网络请求。请求从网络层直接请求到 DB。此时请求耗时最大卡点在数据库的磁盘 IO 上。

 

2.2. 引入分布式缓存数据库

 

针对2.1无缓存架构的数据库磁盘IO耗时,可添加了一道缓存数据库例如 redis。借助缓存中间件,可消除数据库的 IO 瓶颈。快速返回数据。如下图:

图片

通过缓存数据库1、可防止流量直接打到数据库层,减缓数据库压力。2、缓存快速返回,可提高请求查询速率。

 

2.2.1 为什么选择redis?

  • 内存操作,无磁盘 IO 耗时
  • key-value 数据库,时间复杂度 O(1),相比数据库的 O(Log n),访问速度更快
  • IO 多路复用线程模型,IO 阶段无阻塞

此时系统卡点在缓存数据库的网络通信上。即使缓存数据库读取数据很快,但是和应用服务间仍然隔着一层网络通信。

2.3. 引入 JVM 本地缓存

 

针对2.2缓存数据库架构,访问缓存数据库的网络通信问题,可在 JVM 应用层添加本地缓存,解决网络 IO 问题。如下图

图片

 

在应用内部新增本地缓存,使流量在应用层直接返回。避免进一步访问到 redis。

本架构虽然可大大提高数据读取速率,但其成本也是更高的。

  • 需要在多台 JVM 机器上冗余缓存,对内存要求高。
  • 缓存在多台 JVM 实例,数据一致性维护成本高。

建议根据自身业务场景,从以下3方面考量是否才有本地缓存。

  • 业务访问量 QPS
  • 硬件资源内存是否充足
  • 变更场景是否频繁

常用本地缓存

  • JDK MAP
  • guavaCache
  • Caffeine Cache

2.3.1 数据读取流程

图片

按优先级依次从本地、redis、DB 中读取数据。实现了本地(一级缓存)、缓存数据库(二级缓存)和 DB 的多级缓存架构。

3. 痛点和优化

3.1 数据一致性问题

 

存在多级缓存,虽然大大提高了数据的读取速率。但是数据散落在各个不同的区域,数据一致性就是一个绕不过去的问题。特别是针对本地缓存,同时散落在多个多台 JVM 实例中。数据变更时,必须同步修改redis、本地缓存和DB。以下是基于canal + 广播消息实现的一致性异步处理方案。

图片

 

  • DB 修改数据
  • 通过监听 canal 消息,触发缓存的更新
  • 针对 redis 缓存中,因为集群中只共享一份,直接同步缓存即可
  • 针对本地缓存,因为集群中存在多分,且分散在不同的 JVM 实例中。故再借助广播 MQ 机制,通知到各个业务实例。同步本地缓存

3.1.1 同步缓存机制

  • 直接删除缓存,查询时直接加载

优点:操作简单

缺点:未命中缓存时,取重新加载。此次查询请求慢。

  • 重新加载缓存
  • 优点:提前设置缓存,查询效率高

**注意:**此方案同步缓存,为先 DB 操作、后异步同步缓存。会存在短暂 DB 和缓存不一致场景。需根据自身业务场景考量,如有必要,可前置删除缓存,再 DB 操作。

3.2. 热点 key 监控

 

以上架构,系统缓存只能被动加载。只有 key 被访问后,系统才能触发加载。在高并发的情况下,如一直出现缓存穿透,大量流量请求到数据库,对数据库还是很大的考验。所以优秀的缓存系统,应该能自动识别出热点 key。前置将数据缓存下来。

图片

 

3.2.1 热点 key 探测

引入缓存中间调度服务:热点 key 探测中间服务器概念

  • 1、业务实例汇总 key 访问情况并将上报到“热点 key 探测中间服务器”。
  • 2、“热点 key 探测中间服务器”根据各业务实例上报的信息,识别该 key 是否为热点。
  • 3、“热点 key 探测中间服务器”将识别结果通知到各业务实例。
  • 如若为热点 key:业务实例自动预热缓存,等待流量访问。
  • 如若非热点 key:业务实例释放该热点 key,释放内存占用。

详情见:参考

4. 缓存注意事项

4.1 key 设计

  • 长度短:redis key 越短,占用内存越小
  • 高命中率:命中率不高,缓存意义不大

4.1.1 value 设计

  • 尽可能小,避免出现 big key

redis 是单线程机制,big key 会阻塞后续请求。

仅缓存必要的字段,不必要字段,及时瘦身

  • 2、改少读多
  • 变更频繁的数据不建议缓存,频繁的数据变更会导致缓存实现和一致性同步问题,反而会损耗系统性能

  • 3、计算逻辑复杂的结果

4.1.2 缓存穿透

访问一个不存在的 key。由于实际上并不存在,所以每次都会访 DB

  • 解决方案
  • 缓存空值或默认对象(依据业务场景)
  • 布隆过滤器

4.1.3 缓存击穿

某个 key 瞬间访问量过大,但突然过期,导致大部分流量打到了 DB

  • 解决方案
  • histrix 保护,对 DB 的访问限流
  • 只有获得锁的线程才能去 DB 读取数据,并填充到缓存中
  • 1.使用互斥锁
  • 2.永不过期
  • 3.资源保护

4.1.4 缓存雪崩

由于大部分 key 设置了相同的失效时间,某一时间大量缓存同时失效,导致大部分流量瞬间打到 DB,导致 DB 压力过大。

  • 解决方法
  • key 使用不同的过期时间,或者加一个随机时间

5. 实战经验

  • 评估预计占用的缓存大小,避免占满 redis 集群和 JVM 内存
  • 评估预计 QPS,如2.2架构。大量从 redis 中获取对象,会涉及平凡的对象反序列化操作,此处存在耗 CPU 操作。
  • 严格禁止 bigKey。redis的单线程模型,出现 bigKey 会严重降低 redis 服务吞吐量。
  • 必须设置过期时间

6. 踩坑记录

6.1. 本地缓存被污染

由于缓存在 JVM 内部,且保存在老年代。业务方拿去使用的时候,直接修改了缓存的数据,导致缓存数据不正确。

  • 解决

取对象时,直接 copy 一份。(复制对象耗 CPU,不推荐)

将缓存对象设置成不可编辑。(推荐)

6.2. 缓存计算结果,而不是响应结果

缓存的 value 是 Response 对象,首次请求失败,导致缓存的数据为response.success=false。后续所有命中均操作失败。

  • 解决
  • 将缓存结果由 Response,调整为实际的计算结果

6.3. 本地内存彪高,触发频繁 full GC

初次引入本地缓存(之前是 redis )。将大量数据缓存在本地,导致 JVM 内存彪高。

  • 解决

引入本地缓存前考虑预计内存,进而考虑是否值得接入本地缓存。

仅缓存热点 key,非热点 key 不缓存在本地

6.4. 降级到 redis 缓存,CPU 彪高

为优化 JVM 内存,将本地缓存降级到 redis。QPS 高场景,触发大量序列化和young GC,导致系统 CPU 彪高。

  • 解决

评估 QPS,考虑是否可降级

仅缓存热点 key,非热点 key 不缓存在本地

7. 总结

在计算机世界里,缓存无处不在。但不管缓存系统如何设计,其本质都是空间换时间。也就是提升数据的获取速率。

缓存系统的设计各有千秋、各有优劣。没有最优秀的架构,只有最适合的架构。应该根据自身实际业务情况考虑缓存架构的设计。并从缓存命中率、数据库压力、数据一致性、系统吞吐量等综合评估设计的合理性。



Tags:分布式   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
一篇文章带你了解Python的分布式进程接口
在Thread和Process中,应当优选Process,因为Process更稳定,而且,Process可以分布到多台机器上,而Thread最多只能分布到同一台机器的多个CPU上。一、前言在Thread和Process中,应当优...【详细内容】
2024-04-11  Search: 分布式  点击:(2)  评论:(0)  加入收藏
在Redis中如何实现分布式锁的防死锁机制?
在Redis中实现分布式锁是一个常见的需求,可以通过使用Redlock算法来防止死锁。Redlock算法是一种基于多个独立Redis实例的分布式锁实现方案,它通过协调多个Redis实例之间的锁...【详细内容】
2024-02-20  Search: 分布式  点击:(49)  评论:(0)  加入收藏
手动撸一个 Redis 分布式锁
大家好呀,我是楼仔。今天第一天开工,收拾心情,又要开始好好学习,好好工作了。对于使用 Java 的小伙伴,其实我们完全不用手动撸一个分布式锁,直接使用 Redisson 就行。但是因为这些...【详细内容】
2024-02-19  Search: 分布式  点击:(40)  评论:(0)  加入收藏
雪花算法详解与Java实现:分布式唯一ID生成原理
SnowFlake 算法,是 Twitter 开源的分布式 ID 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 ID。在分布式系统中的应用十分广泛,且 ID 引入了时间戳...【详细内容】
2024-02-03  Search: 分布式  点击:(50)  评论:(0)  加入收藏
Python分布式爬虫打造搜索引擎
简单分布式爬虫结构主从模式是指由一台主机作为控制节点负责所有运行网络爬虫的主机进行管理,爬虫只需要从控制节点那里接收任务,并把新生成任务提交给控制节点就可以了,在这个...【详细内容】
2024-01-25  Search: 分布式  点击:(59)  评论:(0)  加入收藏
分布式事务框架选择与实践
分布式事务是处理跨多个服务的原子操作的关键概念,而选择适合应用场景的框架对于确保事务一致性至关重要。以下是几个常见的分布式事务框架,并讨论它们的使用和实践。1. XA协...【详细内容】
2024-01-05  Search: 分布式  点击:(96)  评论:(0)  加入收藏
分布式场景下的事务机制
事务消息是RocketMQ的一个非常特色的高级特性,它的基础诉求是通过RocketMQ的事务机制,来保证上下游的数据⼀致性。我们在单机版本下面只需要在业务方法上加上对应的事务就可以...【详细内容】
2023-12-26  Search: 分布式  点击:(124)  评论:(0)  加入收藏
分布式存储系统在大数据处理中扮演着怎样的角色?
如果存储节点本身可以定制,则通常会让其支持部分计算能力,以利用数据的亲和性,将部分计算下推到相关的存储节点上。如果存储是云上的 S3 等对象存储,无法定制,则通常会将数据在计...【详细内容】
2023-12-19  Search: 分布式  点击:(48)  评论:(0)  加入收藏
MongoDB与大数据处理:构建高性能分布式数据库
MongoDB是一种非关系型数据库,具有高度灵活性和可扩展性。在处理大量数据时,索引的优化是提升查询性能的关键。下面将介绍一些MongoDB索引优化的指南,帮助用户更好地利用索引来...【详细内容】
2023-12-18  Search: 分布式  点击:(72)  评论:(0)  加入收藏
聊一聊雪花算法与分布式ID生成
生成全局唯一ID的雪花算法原理雪花算法是一种用于生成全局唯一ID的算法,最初由Twitter开发,用于解决分布式系统中生成ID的问题。其核心思想是将一个64位的长整型ID划分成多个...【详细内容】
2023-12-12  Search: 分布式  点击:(134)  评论:(0)  加入收藏
▌简易百科推荐
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(6)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(13)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(9)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(11)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(9)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
Kubernetes 究竟有没有 LTS?
从一个有趣的问题引出很多人都在关注的 Kubernetes LTS 的问题。有趣的问题2019 年,一个名为 apiserver LoopbackClient Server cert expired after 1 year[1] 的 issue 中提...【详细内容】
2024-03-15  云原生散修  微信公众号  Tags:Kubernetes   点击:(6)  评论:(0)  加入收藏
站内最新
站内热门
站内头条