当前位置: 首页 > news >正文

Redis项目实战——商户查询缓存

目录

  • 为什么要用Redis实现商户查询缓存?
  • 用Redis实现商户查询缓存的基本思路?
  • 使用Redis缓存的问题及解决方法?
    • 一、如何保持数据库数据和Redis缓存数据的一致性?
      • 1 内存淘汰机制
      • 2 超时剔除机制
      • 3 主动更新机制(胜)
        • 如何实现主动更新机制?
        • 操作缓存和数据库时应该更新缓存还是删除缓存?
        • 如何保证缓存与数据库的操作的原子性?
        • 先删除缓存还是先操作数据库?
    • 二、缓存穿透?
      • 解决方案1 缓存空对象
      • 解决方案2 布隆过滤器
    • 三、缓存雪崩?
      • 解决方案1 随机TTL值
      • 解决方案2 redis集群
      • 解决方案3 服务熔断和降级
      • 解决方案4 多级缓存
    • 四、缓存击穿?热点key问题?
      • 解决方案1 互斥锁
      • 解决方案2 逻辑过期

为什么要用Redis实现商户查询缓存?

  • 缓存是数据交换的缓冲区,是存储频繁用的数据的临时区,要求读写性能高,redis基于内存读写的高性能特点恰恰满足这一要求
  • 用redis实现缓存可以降低后端负载,提高读写效率
  • 增加缓存功能会增加成本,如数据一致性成本,代码维护成本,运维成本等,因此要根据业务场景选择合适的redis功能和机制

用Redis实现商户查询缓存的基本思路?

实战视频

  • 如果没有缓存,客户端频繁发出请求查询一个数据时,每次请求都会直接到达数据库,数据库的压力会很大
  • Redis缓存相当于在客户端和数据库之间增加了一个拦截,当客户端发出请求查询数据时,先到达Redis查询,如果命中直接返回查询结果,因此该请求就不会到达数据库,降低了数据库的压力
  • 如果在Redis中请求没有命中,该请求才会继续去数据库,将数据库的查询结果返回客户端
  • 若该客户端多次重复请求这个在Redis中不存在的数据,还是会多次请求数据库,这并不是我们希望的结果,因此数据库应该将查询结果返回客户端的同时,将查询结果也写入redis缓存中
    在这里插入图片描述

使用Redis缓存的问题及解决方法?

一、如何保持数据库数据和Redis缓存数据的一致性?

  • 数据一致性要求较低:数据变化频率较低,用内存淘汰机制就行
  • 数据一致性要求较高:数据变化频率较高,用主动更新,并用超时剔除当兜底

1 内存淘汰机制

  • redis为了解决内存不足的问题,自带的一种功能,会在内存不足时自动淘汰部分数据,下次查询该数据时更新缓存,在一定程度上可以保持数据的一致性
  • 优点:维护成本几乎为0,全程有Redis自己管
  • 缺点:不知道会淘汰掉哪些数据,什么时候淘汰,所以数据一致性比较差

2 超时剔除机制

  • 给缓存数据添加TTL时间,到期后自动删除缓存,下次查询时更新缓存
  • 优点:维护成本较低,只需要在原来数据的基础上增加一个过期时间
  • 缺点:可以控制哪些数据什么时候淘汰,数据一致性比内存淘汰机制好一些,但也不强

3 主动更新机制(胜)

  • 在修改数据库中数据的同时,更新缓存
  • 优点:数据一致性比较好
  • 缺点:维护成本高,需要自己编写大量的业务逻辑,比较难

如何实现主动更新机制?

  • 实现的第一种方案:自己写代码,在更新数据库的同时更新缓存(实际业务中用的最多)。
  • 实现的第二种方案:将缓存与数据库整合成一个服务,只需调用该服务,数据一致性由服务内部自己实现。但维护该服务比较难,也较难找到现成的服务可用
  • 实现的第三种方案:调用者不管数据库,只在缓存中增删改查,缓存一直保持最新的数据。由一个专门的线程通过异步的方式将缓存的数据更新到数据库中,保证数据最终一致。异步机制可以大大提升效率,主要体现的场景为,假如缓存中的某个数据更新了n次,此时异步线程来检查缓存中的数据有没有变化,然后将最新的数据写入数据库,相当于数据库只更新了1次,而数据库的读写比缓存读写费劲多,所以节省了更新n-1次数据库浪费的时间。缺点是维护异步线程的成本、Redis宕机丢失数据、在异步线程更新数据库之前数据完全不一致。

操作缓存和数据库时应该更新缓存还是删除缓存?

  • 更新缓存:每次更新数据库时都需要更新缓存,对于缓存来说无效的写操作比较多
  • 删除缓存:更新数据库时删除缓存中的数据,更新n次也只删一次,只有客户端用到该数据时,访问redis缓存,redis中没有该数据,才会从数据库中取最新的数据写到缓存中。

如何保证缓存与数据库的操作的原子性?

  • 意思就是更新数据库的时候必须保证删除缓存也成功执行,二者要么都成功,要么都失败
  • 对于单体系统:将缓存与数据库操作放在一个事务中
  • 对于分布式系统:利用TCC等分布式事务方案

先删除缓存还是先操作数据库?

  • 在多线程情景下,二者的执行顺序不一样会造成不一样的后果
  • 先删除缓存:假设线程1先删缓存后更新数据库,线程2在线程1刚删完缓存还没更新数据库时突然请求,此时缓存中的数据已经被删,线程2会去数据库中查询,但线程1还没更新数据库,因此线程2查到的是旧数据,还会把旧数据按照流程写入缓存,此时线程1再更新数据库,就会造成数据不一致
  • 先更新数据库:假设线程1先更新数据库后删除缓存,线程2在线程1更新数据库之前请求,恰好缓存由于某些原因失效,线程2便查询数据库返回客户端一个旧数据,此时线程2正常更新数据库删除缓存,线程1再继续将刚才从数据库中读到的旧数据写入缓存,此时就会造成数据不一致
  • 先更新数据库造成的数据不一致的可能性更低,且可以为缓存增加TTL,在一定程度上避免该问题的发生,因此应该先更新数据库后删除缓存
    在这里插入图片描述

二、缓存穿透?

客户端请求的数据在缓存和数据库中都没有,无法建立缓存,如果多次请求这个不存在的数据,这些请求就会全部打到数据库,给数据库造成压力

解决方案1 缓存空对象

  • 简单暴力,返回一个空值null,下次请求再来时会在缓存命中null,不会继续请求数据库
  • 优点:实现简单,好维护
  • 缺点1:如果有很多不同的请求的数据不存在,就会在缓存中存很多null,造成额外的内存消耗。解决方法:可以给null也增加一个TTL,避免长期占用缓存空间。
  • 缺点2:在null过期之前的请求得到的数据都是null,如果此时数据库更新了数据,就会造成短期的不一致。解决方法:用主动更新机制,在更新数据库的同时替换掉null

解决方案2 布隆过滤器

  • 在客户端和Redis之间增加布隆过滤器,当客户端发出一个请求时,首先由布隆过滤器判断该数据是否存在,若存在则放行,请求会继续执行正常流程,若不存在则拒绝,禁止请求频繁访问缓存和数据库
  • 布隆过滤器是一个bit数组,每一位非0即1,可以快速判断一个元素是否存在
  • 存数据:根据k个不同的hash函数将数据映射到bit数组的k个位置上,将k个位置置1
  • 判断数据:根据k个不同的hash函数将数据映射到bit数组的k个位置上,若k个位置有0,则该数据肯定不存在,拦截,若k个位置全为1,则该数据可能存在(hash可能冲突,所以存在误判),允许通过
  • 优点:速度快,占用空间小
  • 缺点:实现复杂,存在误判

在这里插入图片描述

三、缓存雪崩?

大量redis缓存中的key同时失效或过期,或者redis服务器宕机,大量请求直接到达数据库,给数据库造成巨大压力

解决方案1 随机TTL值

如果给大量key设置一样的TTL,就会在同一时间大量key同时失效,因此可以给不同的key添加分布较均匀的随机TTL

解决方案2 redis集群

宕机一个redis还有其他redis

解决方案3 服务熔断和降级

  • redis宕机时暂停redis缓存服务(熔断),预防出现雪崩
  • 若redis直接爆炸,只能降级服务,不理睬请求,直接返回错误

解决方案4 多级缓存

在多个层面建立缓存(比如浏览器、数据库等),一级缓存和二级缓存失效时间不同,一级缓存失效用二级缓存

四、缓存击穿?热点key问题?

部分热点key(被高并发访问且缓存重建业务较复杂的key)在缓存中失效或过期,如果第一次请求未命中,会去数据库查询并写入缓存,但若在此期间有大量同样的请求涌入,就会有大量请求涌到数据库要求查询,给数据库造成巨大压力

解决方案1 互斥锁

  • 当线程1查询缓存未命中时,尝试获取锁,获取成功才能去数据库查询,写缓存后释放锁。在此期间,其他同样的请求查询缓存未命中时,同样尝试获取锁,但获取失败,就会等待一段时间重新尝试查询缓存并获取锁
  • 优点:没有额外的内存消耗,数据一致性更好,实现简单
  • 缺点:其他线程需要一直等待,直到获取到锁的线程写入缓存或释放锁,还有死锁风险
    在这里插入图片描述

解决方案2 逻辑过期

  • 不再设置TTL,而是设置一个逻辑过期时间,TTL相当于倒计时,逻辑过期时间相当于一个具体的时间
  • 当线程1查询缓存时,发现该缓存的逻辑时间已经过期,便尝试获取互斥锁,并开启一个新线程2来进行查询数据库重建缓存,无需等待线程2执行完,直接返回一个过期的数据
  • 线程3若紧跟线程1之后也来查询该缓存,发现逻辑时间已过期,也尝试获取互斥锁,但此时锁被线程2占用,获取失败,则直接放弃,返回过期数据
  • 只有在释放锁之后到来的线程4才能命中缓存中没有过期的数据
  • 优点:线程无需等待,性能较好
  • 缺点:数据一致性较差,有额外的内存消耗,实现复杂

在这里插入图片描述

相关文章:

Redis项目实战——商户查询缓存

目录 为什么要用Redis实现商户查询缓存?用Redis实现商户查询缓存的基本思路?使用Redis缓存的问题及解决方法?一、如何保持数据库数据和Redis缓存数据的一致性?1 内存淘汰机制2 超时剔除机制3 主动更新机制(胜&#xff…...

重磅OpenAI发布ChatGPT企业版本

8月29日凌晨,Open AI官网发布ChatGPT企业版本! 企业版简介: ChatGPT企业版提供企业级安全和隐私、无限的高速 GPT-4 访问、用于处理更长输入的更长上下文窗口、高级数据分析功能、自定义选项等等。人工智能可以协助和提升我们工作生活的各个…...

# Go学习-Day7

文章目录 断言文件打开/关闭文件读取文件写入文件 命令行参数解析Argsflag包 JSON 个人博客:CSDN博客 断言 type Node struct {x inty int }func main() {var a interface{}var n Node Node{1, 2}a nvar b Nodeb a.(Node)fmt.Println(b) }此处我们有一个结构体…...

uniapp-form表单

<template><view class"ptb-20 plr-30 bg min100"><view class"bg-white radius-20 pd-30"><view class"bold mt-30 mb-50 size-32">选择方式&#xff1a;</view><u--form labelPosition"left" :mod…...

漏洞挖掘-利用

一、文章简介 整合一些web漏洞&#xff0c;以及对漏洞的理解。 二、Web漏洞 1.SQL注入 &#xff08;1&#xff09;定义 开发者程序编写过程中&#xff0c;对传入用户数据过滤不严格&#xff0c;将可能存在的攻击载荷拼接到SQL查询语句当中&#xff0c;再将这些查询语句传递到…...

React钩子函数之useDeferredValue的基本使用

在React中&#xff0c;使用钩子函数可以方便地管理组件的状态和副作用。useDeferredValue是React 18中新引入的钩子函数之一&#xff0c;它可以帮助我们优化渲染性能&#xff0c;让组件更加流畅。 useDeferredValue的作用是将一个值延迟更新。这个值可以是状态、属性或其他变量…...

lodash常用方法

cloneDeep 克隆 import { cloneDeep&#xff0c;reduce } from lodash; const b {c:1} const a cloneDeep(b)debounce 防抖 import { debounce } from lodash; debounce(() > {}, 300, { trailing: true })()omit方法删除指定属性&#xff0c;返回一个新的对象 import …...

QByteArray与结构体之间相互转换

Qt项目会碰到自定义结构体和字符数组之间的转换问题&#xff0c;不妨假设结构体名字为custom_struct, 字符数组名字为array_data QByteArray转换为自定义结构体 custom_struct *struct_data reinterpret_cast<custom_struct *>(array_data.data());自定义结构体转换为…...

npm如何安装淘宝镜像

通过命令配置 这种方法是通过修改npm的全局配置文件&#xff0c;将默认的镜像源改为淘宝镜像。具体步骤如下&#xff1a; 打开终端&#xff0c;输入以下命令&#xff0c;设置淘宝镜像源&#xff1a;&#xff08;windowr&#xff09; npm config set registry https://registr…...

从项目中突显技能:在面试中讲述你的编程故事

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…...

python的观察者模式案例

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言二、具体代码写在结尾 前言 最近写安卓的代码比较多&#xff0c;了解了java代码的注册回调机制&#xff0c;也就是观察者模式&#xff0c;搜索了一下python也有…...

C语言——类型转换

数据有不同的类型&#xff0c;不同类型数据之间进行混合运算时涉及到类型的转换问题。 转换的方法有两种&#xff1a; 自动转换(隐式转换)&#xff1a;遵循一定的规则&#xff0c;由编译系统自动完成强制类型转换&#xff1a;把表达式的运算结果强制转换成所需的数据类型 语法格…...

jmeter性能测试入门完整版

1. Jmeter简介 Apache JMeter是一款纯java编写负载功能测试和性能测试开源工具软件。相比Loadrunner而言&#xff0c;JMeter小巧轻便且免费&#xff0c;逐渐成为了主流的性能测试工具&#xff0c;是每个测试人员都必须要掌握的工具之一。 本文为JMeter性能测试完整入门篇&…...

报错sql_mode=only_full_group_by

首发博客地址 https://blog.zysicyj.top/ 报错内容 ### The error may exist in file[D:\code\cppCode20221025\leader-system\target\classes\mapper\system\TJsonDataMapper.xml] ### The error may involve defaultParameterMap ### The error occurred while…...

伪造 IP 地址的原理和防范措施

在数字化时代&#xff0c;网络安全是至关重要的话题。其中&#xff0c;伪造 IP 地址是一种可能导致网络攻击和欺诈的技术手段。这里将深入探讨伪造 IP 地址的原理以及如何采取措施来防范这种风险。 一.伪造 IP 地址的原理 伪造 IP 地址是一种操纵网络通信的方式&#xff0c;它…...

Linux通过libudev获取挂载路径、监控U盘热拔插事件、U盘文件系统类型

文章目录 获取挂载路径监控U盘热拔插事件libusb 文件系统类型通过挂载点获取挂载路径添libudev加库 获取挂载路径 #include <stdio.h> #include <libudev.h> #include <string.h>int main() {struct udev *udev;struct udev_enumerate *enumerate;struct ud…...

【会议征稿】2023智能通信与网络国际学术会议(ICN 2023)

2023智能通信与网络国际学术会议&#xff08;ICN 2023&#xff09; 2023 International Conference on Intelligent Communication and Networking (ICN2023) 2023智能通信与网络国际学术会议&#xff08;ICN 2023&#xff09;将于2023年11月10-12日在中国常州召开。ICN 2023…...

Android投屏总结

#android手机投屏 ####导语 至于手机投屏的实现方法可谓五花八门&#xff0c;今天小袁就说下以开发人员的角度来说下当今手机的主流投屏方法。目前这种将终端信号经由WiFi传输到电视、电视盒的技术有三种&#xff1a;DLNA、AirPlay、Miracast、Google Cast。 ##手机投屏智能电…...

vue2 组件组成部分,组件通信,进阶语法

一、学习目标 1.组件的三大组成部分&#xff08;结构/样式/逻辑&#xff09; ​ scoped解决样式冲突/data是一个函数 2.组件通信 组件通信语法父传子子传父非父子通信&#xff08;扩展&#xff09; 4.进阶语法 v-model原理v-model应用于组件sync修饰符ref和$refs$nextTic…...

信看课堂笔记—LDO和DC-DC电路打PK

LDO&#xff08;low dropout voltage regulator&#xff0c;低压差线性稳压器&#xff09;和DC-DC(Direct current-Direct current converter&#xff0c;直流电压转直流电压转换器)电源是非常常见的电源电路&#xff0c;LDO 出来的比较早&#xff0c;像老戏骨一样&#xff0c;…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...

Leetcode33( 搜索旋转排序数组)

题目表述 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...