缓存层持久化

news2024/12/29 1:39:37

** 读缓存**

  • 分布式缓存
    先将所有的缓存数据集中存储在同一个地方,而非重复保存到各个服务器节点中,然后所有的服务器节点都从这个地方读取数据
    在这里插入图片描述
    在这里插入图片描述
    使用MongoDB的公司最少,目前,Redis比Memcached更流行:
    (1)数据结构:在使用Memcached保存List缓存对象的过程中,如果往List中增加一条数据,则首先需要读取整个List,再反序列化塞入数据,接着再序列化存储回Memcached。而对于Redis而言,这仅仅是一个Redis请求,它会直接帮助塞入数据并存储,简单快捷
    (2)持久化:对于Memcached来说,一旦系统宕机数据就会丢失。因为Memcached的设计初衷就是一个纯内存缓存
    (3)集群:Memcached的集群设计非常简单,客户端根据Hash值直接判断存取的Memcached节点。而Redis的集群因在高可用、主从、冗余、Failover等方面都有所考虑,所以集群设计相对复杂些,属于较常规的分布式高可用架构

  • 缓存何时存储数据

  • 使用缓存的逻辑如下。

  • 1)先尝试从缓存中读取数据。

  • 2)若缓存中没有数据或者数据过期,再从数据库中读取数据保存到缓存中。

  • 3)最终把缓存数据返回给调用方

  • 4)注意,存在数据库崩溃的情况,当大量缓存不存在的时候导致。

  • 数据库的崩溃可以分为3种情况
    1)单一数据过期或者不存在,这种情况称为缓存击穿。
    解决方案:第一个线程如果发现Key不存在,就先给Key加锁,再从数据库读取数据保存到缓存中,最后释放锁。
    如果其他线程正在读取同一个Key值,那么必须等到锁释放后才行。
    2)数据大面积过期或者Redis宕机,这种情况称为缓存雪崩。
    解决方案:设置缓存的过期时间为随机分布或设置永不过期即可。
    3)一个恶意请求获取的Key不在数据库中,这种情况称为缓存穿透。
    比如正常的商品ID是从100000到1000000(10万到100万之间的数值),那么恶意请求就可能会故意请求2000000以上的数据。这种情况如果不做处理,恶意请求每次进来时,肯定会发现缓存中没有值,那么每次都会查询数据库,虽然最终也没在数据库中找到商品,但是无疑给数据库增加了负担。
    这里给出两种解决办法。
    ①在业务逻辑中直接校验,在数据库不被访问的前提下过滤掉不存在的Key。
    ②针对恶意请求的Key存放一个空值在缓存中,防止恶意请求骚扰数据库。
    4)缓存预热:用户请求过来之前把数据都缓存到Redis中

  • 如何更新缓存: 更新数据库和更新缓存
    先删除缓存,更新数据库,再删除缓存

  • 缓存的高可用设计
    1)负载均衡:是否可以通过加节点的方式来水平分担读请求压力。
    2)分片:是否可以通过划分到不同节点的方式来水平分担写压力。
    3)数据冗余:一个节点的数据如果失效,其他节点的数据是否可以直接承担失效节点的职责。
    4)Failover:任何节点失效后,集群的职责是否可以重新分配以保障集群正常工作。
    5)一致性保证:在数据冗余、Failover、分片机制的数据转移过程中,如果某个地方出了问题,
    能否保证所有的节点数据或节点与数据库之间数据的一致性(依靠Redis本身是不行的)
    6)如果对缓存高可用有需求,可以使用Redis的Cluster模式

  • 缓存的监控
    缓存上线以后,还需要定时查看其使用情况,再判断业务逻辑是否需要优化
    在查看缓存使用情况时,一般会监控缓存命中率、内存利用率、慢日志、延迟、客户端连接数等数据

写缓存
写缓存的思路是后台服务接收到用户请求时,如果请求校验没问题,数据并不会直接落库,而是先存储在缓存层中,缓存层中写请求达到一定数量时再进行批量落库。
这里所说的缓存层实际上指的就是写缓存。它的意义在于利用写缓存比数据库高几个量级的吞吐能力来承受洪峰流量,再匀速迁移数据到数据库
数据库如果用批量插入语句,TPS也是可以非常高的,可能达到上万,这样不仅能防止数据库崩溃,还能确保用户的请求得到满足
在这里插入图片描述
在具体实施过程中要考虑6个问题。
1)写请求与批量落库这两个操作同步还是异步?
根据业务实际考虑
2)如何触发批量落库?
批量落库触发逻辑:
1)写请求满足特定次数后就落库一次,比如10个请求落库一次。
优点:是访问数据库的次数变为1/N,从数据库压力上来说会小很多。
不足:如果访问数据库的次数未凑齐N次,用户的预约就一直无法落库。
2)每隔一个时间窗口落库一次,比如每隔一秒落库一次。
优点:能保证用户等待的时间不会太久,
缺点:如果某个瞬间流量太大,在那个时间窗口落库的数据就会很多,多到在一次数据库访问中无法完成所有数据的插入操作(比如一秒内堆积了5000条数据),它们只能通过分批次来实现插入
3)两种方式一起使用
1)每收集一次写请求,就插入预约数据到缓存中,再判断缓存中预约的总数是否达到一定数量,达到后直接触发批量落库。
2)开一个定时器,每隔一秒触发一次批量落库
在这里插入图片描述

3)缓冲数据存储在哪里?
存放在本地内存中,
存放在分布式缓存中(比如Redis),
其中最简单的方式是存放在本地内存中
4)缓存层并发操作需要注意什么?
缓存层并发操作逻辑与冷热分离迁移冷数据的逻辑很相似
批量落库的实现逻辑:
1)当前线程从缓存中获取所有数据。
2)当前线程批量保存数据到数据库。
3)当前线程从缓存中删除对应数据(注意:不能直接清空缓存的数据,因为新的预约数据可能插入到缓存中了)
5)批量落库失败了怎么办?
在这里插入图片描述

6)Redis的高可用配置
Redis的数据备份
Redis主从功能
在这里插入图片描述
统一管理的Redis集群方案:
1)先使用简单的主从模式。
2)然后在Slave Redis里使用快照(30秒一次)+AOF(一秒一次)的配置。
3)如果Master Redis宕机了,千万不要直接启动,先把Slave Redis升级为Master Redis。
4)这时代码里已经有预案了,写缓存如果失败直接落库。
不过这个方案有个缺点,即一旦系统宕机,手动恢复时大家就会手忙脚乱,但数据很有保障。

  • Kafka是LinkedIn推出的开源消息中间件,它天生是为收集日志而设计的,而且具备超高的吞吐量和数据量扩展性,被称作无限堆积

  • Kafka的存储结构中每个Topic分区相当于一个巨型文件,而每个巨型文件又是由多个Segment小文件组成的。
    其中,Producer负责对该巨型文件进行“顺序写”,Consumer负责对该文件进行“顺序读”。
    可以把Kafka的存储架构简单理解为,Kafka写数据时通过追加数据到文件末尾来实现顺序写,读取数据时直接从文件中读,这样做的好处是读操作不会阻塞写操作,这也是其吞吐量大的原因。
    理论上只要磁盘空间足够,Kafka就可以实现消息无限堆积,因此它特别适合处理日志收集这种场景
    在这里插入图片描述

  • 目前流行的实时处理工具主要为Storm、Spark Streaming、Apache Flink
    Apache Flink,不仅因为它性能强(阿里采用这项技术后,活动期间一秒内能够处理17亿条数据),
    还因为它的容错机制能保证每条数据仅仅处理一次,而且它有时间窗口处理功能。
    在实际业务场景中,如果需要按照时间窗口统计数据,往往是根据消息的事件时间来计算。
    Apache Flink的特性恰恰是使用了基于消息的事件时间,而不是基于计算框架的处理时间,这也是它的另一个撒手锏

  • 不同流处理框架中采取不同的容错机制,能够保证不一样的一致性。

  • 1)At-Most-Once:至多一次,表示一条消息不管后续处理成功与否只会被消费处理一次,存在数据丢失的可能。

  • 2)Exactly-Once:精确一次,表示一条消息从其消费到后续的处理成功只会发生一次。

  • 3)At-Least-Once:至少一次,表示一条消息从消费到后续的处理成功可能会发生多次,存在重复消费的可能。

  • 架构的流程:

  • 1)后台服务端会记录所有的请求数据,存放到本地的日志文件。

  • 2)使用数据收集框架Logstash,从日志文件抽取原始的日志数据,不加工直接存放到Kafka当中。

  • 3)通过Apache Flink从Kafka中拉取原始的日志数据,并且经过业务加工,分别存放到Elasticsearch、HBase和MySQL中。

  • 4)Elasticsearch用来处理用户针对请求日志的查询请求,它将查询关键字段的值和请求ID存放到索引中,跟进查询关键字获得结果ID的列表,再通过结果ID去HBase中获取详细的请求数据。

  • 5)MySQL存放一些组合加工后的数据,用来做结算,结算的数据查询和处理请求量不大。
    在这里插入图片描述
    秒杀架构

  • 秒杀架构的原则:
    遵循商品不能超卖
    下单成功的订单数据不能丢失
    服务器和数据库不能崩溃
    尽量别让机器人抢走商品

  • 秒杀架构的设计方案就是一个不断过滤请求的过程。目标是尽量在上层处理用户请求,不让其往下层游动。

  • 在这里插入图片描述

  • 静态资源与负载均衡
    CDN:不用花费自己的服务器资源和带宽,且响应速度快。静态资源的压力拦截在系统分层的外面
    动态的请求3种实现方式。
    1)通过JS(JavaScript)在后台动态调用。可以把动态的数据与页面进行整合,然后再放入CDN。也可以把它放在Redis缓存中,
    2)JS访问服务器获取,针对获取服务器时间的这个请求,把它放在静态资源或负载均衡那层即可,这样用户请求就不会进入系统下游。
    3)放在Cookie中。
    总体来说,对于浏览页面的用户行为,需要把用户请求尽量拦截在CDN、静态资源或负载均衡侧,如果确实做不到,也要拦截在缓存中。

  • 网关页面如何将请求拦截在上游
    那在网关层面如何实现请求过滤呢?可以做3种限制。
    1)限定每个用户的访问频率,比如每5秒下单一次。nginx上就能快速完成配
    2)限定每个IP的访问频率。nginx上就能快速完成配。这种方式是为了避免有人通过机器人自动下单,导致错杀真实用户。
    3)把一个时间段内的请求拦截掉一定比例,或者只允许特定数量的请求进入后台服务器。这里可以使用限流的漏桶或令牌桶算法

  • 后台服务器过滤请求:目标已经不是如何过滤请求了,而是如何保证商品不超卖
    1)商品数据放入缓存Redis中(在秒杀期间不做上架或修改库存之类的业务操作,即不通过技术,而是通过业务流程来保证)
    2)订单写入缓存中
    3)订单批量落库
    4)Redis停止工作(挂掉)怎么办。
    比如读Redis中的库存时,如果失败了,那就让它直接去数据库扣减库存,把那些incr和decr的逻辑放到数据库去;
    若是把订单写入缓存的时候失败了,那就直接将订单数据写入数据库中,然后就不需要处理后面批量落库的逻辑了

  • 付款页面如何将请求拦截在上游
    这个环节,除了保障数据的一致性外,还有一个要点:
    如果业务逻辑中出现了一个订单未及时付款而被取消的情况,记得把数据库及Redis的库存加回去

  • 整体:静态资源服务器、网关、后台服务器均需要配置负载均衡,而缓存Redis和数据库均需要配置集群模式
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1855202.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot2+Vue3开发博客管理系统

项目介绍 博客管理系统,可以帮助使用者管理自己的经验文章、学习心得、知识文章、技术文章,以及对文章进行分类,打标签等功能。便于日后的复习和回忆。 架构介绍 博客管理系统采用前后端分离模式进行开发。前端主要使用技术:Vu…

Comfyui-ChatTTS-OpenVoice 为ComfyUI添加语音合成、语音克隆功能

‍‍ 生成多人播客: Comfyui-ChatTTS是一个开源的GitHub项目,致力于为ComfyUI添加语音合成功能。该项目提供了一系列功能强大的节点和模型,支持用户创建和复用音色,支持多人对话模式的生成,并提供了导出音频字幕文件的…

sed的用法

grep 就是查找文本当中的内容,扩展正则表达式 sed是一种流编辑器,一次处理一行内容 如果只是展示,会放在缓冲区(模式空间),展示结束之后,会从模式空间把操作结果删除。 一行一行处理&#xf…

消息认证码解析

1. 什么是消息认证码 消息认证码(Message Authentication Code)是一种确认完整性并进行认证的技术,取三个单词的首字母,简称为MAC。 消息认证码的输入包括任意长度的消息和一个发送者与接收者之间共享的密钥,它可以输出固定长度的数据&#x…

深入分析 Android BroadcastReceiver (六)

文章目录 深入分析 Android BroadcastReceiver (六)1. 广播机制的高级优化策略1.1 使用 Sticky Broadcast(粘性广播)示例:粘性广播(过时,不推荐) 1.2 使用 LiveData 和 ViewModel 进行组件通信示例&#xf…

【题解】—— LeetCode一周小结25

🌟欢迎来到 我的博客 —— 探索技术的无限可能! 🌟博客的简介(文章目录) 【题解】—— 每日一道题目栏 上接:【题解】—— LeetCode一周小结24 17.最长特殊序列 II 题目链接:522. 最长特殊序列…

Elastaticsearch与SpringBoot集成的互联网的实战分享

以前有过类似的文章,今天升级版分享重磅内容,Elastaticsearch与SpringBoot集成的互联网的实战。 一、需求分析: 起因是这样的,产品有这样一个需求:数据中的标题、内容、关键词等实现结构化搜索和半结构化搜索、数据时…

[SAP ABAP] 内表

内表是在程序中定义,仅在程序运行时间内,存在于内存中的表格,用于暂时存储数据库表中的数据,实现复杂的数据操作 内表中存放的数据是临时的,当程序执行时才会占用内存,关闭程序时会释放内存 内表的种类 ①…

MyBatis-Plus常用注解详解与实战应用

MyBatis-Plus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。它提供了大量的常用注解,使得开发者能够更方便地进行数据库操作。 MyBatis-Plus 提供的注解可以帮我们解决一些数据库与实体之间相…

车辆数据的提取、定位和融合(其二.一 共十二篇)

第一篇: System Introduction 第二篇:State of the Art 第三篇:localization 第四篇:Submapping and temporal weighting 第五篇:Mapping of Point-shaped landmark data 第六篇:Clustering of landma…

论坛实现随机发帖的学习

1、badboy操作,录制发帖全过程,录制结果保存,生成为.jmx格式的文件 2、在Jmeter中打开该.jmx文件,重命名,便于了解步骤 3、生成结果树,查看所以步骤是否正确 4、实现随机发帖。。。。还没写完

Vue2配置前端代理

在8080向5000请求数据 clivue2 一、cli内配置前端代理 1、使用 发送请求时写8080 在配置文件中配置 vue.config.js 2、缺点 无法配置多个代理无法控制某个请求知否要代理 二、方式二 module.exports {devServer: {proxy: {/api1:{ //匹配所有以/api1开头的请求路径…

【Docker】Docker简介_运行原理

1、简介 1.1基本概念 容器:容器是Docker的基本部署单元。它是一个轻量级的、独立的运行时环境,包含应用程序及其相关依赖。容器利用Linux内核的命名空间和控制组技术,实现了隔离性和资源管理,使得应用程序在不同的容器中运行不会…

上海交大阿里巴巴推出虚拟试衣新里程碑式工作——AnyFit:任意场景、任意组合!

文章链接:https://arxiv.org/pdf/2405.18172 工程链接:https://colorful-liyu.github.io/anyfit-page/ 今天和大家一起学习的是一种名为AnyFit的新型虚拟试穿系统,旨在解决现有技术在处理不同场景和服饰组合时出现的衣物风格不匹配和质量下…

如何在React中使用CSS模块,并解释为什么使用它们比传统CSS更有益?

在React中使用CSS模块是一种将CSS类名局部化到单个组件的方法,从而避免了全局作用域中的类名冲突。CSS模块允许你为组件编写样式,并确保这些样式只应用于该组件,而不会影响到其他组件。 以下是在React中使用CSS模块的步骤: 安装C…

g++制作C++动态库的简洁例程

g制作C动态库的简洁例程 code review! 文章目录 g\制作C动态库的简洁例程1. 创建 C 动态库1.1 动态库源文件1.2 编译动态库 2. 使用动态库2.1 命令行编译链接然后运行2.2 使用 CMake 编译链接然后运行 3.附加笔记:关于运行时是否能找到libmylib.so的问题汇总3.1.g -…

Vite: 前端环境的基础搭建

Vite初始化前端项目 初始化 $ pnpm create viteLibrary/pnpm/store/v3/tmp/dlx-42133 | Progress: resolved 1, reused 0, downlLibrary/pnpm/store/v3/tmp/dlx-42133 | 1 Library/pnpm/store/v3/tmp/dlx-42133 | Progress: resolved 1, reused 0, downlLib…

C语言 | Leetcode C语言题解之第188题买卖股票的最佳时机IV

题目: 题解: int maxProfit(int k, int* prices, int pricesSize) {int n pricesSize;if (n 0) {return 0;}k fmin(k, n / 2);int buy[k 1], sell[k 1];memset(buy, 0, sizeof(buy));memset(sell, 0, sizeof(sell));buy[0] -prices[0];sell[0] 0…

193.回溯算法:组合总和(力扣)

代码解决 class Solution { public:vector<int> res; // 当前组合的临时存储vector<vector<int>> result; // 存储所有符合条件的组合// 回溯函数void backtrcing(vector<int>& nums, int target, int flag, int index) {// 如果当前组合的和超过了…

如何下载油管视频

文章目录 1、IDM下载1.1 安装IDM工具1.2 浏览器安装IDM插件 2、命令行工具下载2.1 youtube-dl工具2.1.1 安装使用2.1.2 更新工具 2.2 yt-dlp 工具2.2.1 安装使用2.2.2 保存路径查看当前工作目录指定下载目录示例 2.2.3 保存文件名2.2.4 避坑指南1、请求被拒绝2、其他问题 在全球…