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 主动更新机制(胜ÿ…...

重磅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">选择方式:</view><u--form labelPosition"left" :mod…...

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

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

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

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

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

从项目中突显技能:在面试中讲述你的编程故事
🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…...

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

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

jmeter性能测试入门完整版
1. Jmeter简介 Apache JMeter是一款纯java编写负载功能测试和性能测试开源工具软件。相比Loadrunner而言,JMeter小巧轻便且免费,逐渐成为了主流的性能测试工具,是每个测试人员都必须要掌握的工具之一。 本文为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 地址的原理和防范措施
在数字化时代,网络安全是至关重要的话题。其中,伪造 IP 地址是一种可能导致网络攻击和欺诈的技术手段。这里将深入探讨伪造 IP 地址的原理以及如何采取措施来防范这种风险。 一.伪造 IP 地址的原理 伪造 IP 地址是一种操纵网络通信的方式,它…...

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智能通信与网络国际学术会议(ICN 2023) 2023 International Conference on Intelligent Communication and Networking (ICN2023) 2023智能通信与网络国际学术会议(ICN 2023)将于2023年11月10-12日在中国常州召开。ICN 2023…...

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

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

信看课堂笔记—LDO和DC-DC电路打PK
LDO(low dropout voltage regulator,低压差线性稳压器)和DC-DC(Direct current-Direct current converter,直流电压转直流电压转换器)电源是非常常见的电源电路,LDO 出来的比较早,像老戏骨一样,…...

C++ Day6
目录 一、菱形继承 1.1 概念 1.2 格式 二、虚继承 2.1 作用 2.2 格式 2.3注意 三、多态 3.1函数重写 3.2 虚函数 3.3 赋值兼容规则 3.4 多态中,函数重写的原理 3.5 虚析构函数 3.5.1 格式 3.6 纯虚函数 3.6.1格式 四、抽象类 五、模板 5.1模板的特…...

分布式系统与微服务的区别是什么?
分布式系统和微服务是两个相关但不同的概念,它们都是在构建复杂的软件应用时使用的架构思想。 分布式系统: 分布式系统是指由多个独立的计算机或服务器通过网络连接共同工作,协同完成一个任务或提供一个服务。在分布式系统中,各个…...

python:用python构建一个物联网平台
要使用Python构建物联网平台,您需要考虑以下步骤: 确定平台的基本要求和功能 首先,您需要明确您将要构建的平台的功能和特点。例如,您可能需要支持多种设备,并使用各种传感器来收集数据。您可能需要实现实时数据可视化…...

基于Qt5开发图形界面——WiringPi调用Linux单板电脑IO
Qt5——WiringPi Qt5WiringPi示例教程 Qt5 Qt是一种跨平台的应用程序开发框架。它被广泛应用于图形用户界面(GUI)开发,可以用于构建桌面应用程序、移动应用程序和嵌入式应用程序。Qt提供了丰富的功能和工具,使开发人员可以快速、高…...

【MySQL】组合查询
目录 一、组合查询 1.创建组合查询 2.union规则 3.包含或取消重复的行 4.对组合查询结果排序 一、组合查询 多数SQL查询都只包含从一个或多个表中返回数据的单条SELECT语句。MySQL也允许执行多个查询(多条SELECT语句),并将结果作为单个查…...

ChatGPT:引领人机交互的未来
前言 在信息技术飞速发展的时代,人机交互的方式也在不断演进。技术对人们生活和工作的影响。本文将带您深入探讨一款引领人机交互未来的人工智能模型——ChatGPT。 ChatGPT简介 ChatGPT 是一种由开放AI(OpenAI)开发的人工智能模型…...

【算法】经典的八大排序算法
点击链接 可视化排序 动态演示各个排序算法来加深理解,大致如下 一,冒泡排序(Bubble Sort) 原理 冒泡排序(Bubble Sort)是一种简单的排序算法,它通过多次比较和交换相邻元素的方式,将…...

防溺水预警识别系统算法
防溺水预警识别系统旨在通过opencvpython网络模型深度学习算法,防溺水预警识别系统算法实时监测河道环境,对学生等违规下水游泳等危险行为进行预警和提醒。Python是一种由Guido van Rossum开发的通用编程语言,它很快就变得非常流行࿰…...

Redis 的整合 Jedis 使用
大家好 , 我是苏麟 , 今天带来 Jedis 的使用 . Jedis的官网地址: GitHub - redis/jedis: Redis Java client 引入依赖 <!--jedis--> <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version…...

Mainline Linux 和 U-Boot编译
By Toradex胡珊逢 Toradex 自从 Linux BSP v6 开始在使用 32位处理器的 Arm 模块如 iMX6、iMX6ULL、iMX7 上提供 mainline/upstream kernel ,部分 64位处理器模块如 Verdin iMX8M Mini/Plus 也提供实验性支持。文章将以季度发布版本 Linux BSP V6.3.0 为例介绍如何下…...