草庐IT

对redis的实战理解

pzistart 2023-04-19 原文

把黑马的redis实战看了将近一半,自己也做了挺多思考,现在对于Redis的使用,以及业务方面的思考,有了更深刻的理解。

  • 使用缓存能够加快数据的查询速度,提高用户的使用感受,对于经常需要访问的数据,都可以放到缓存中,这样也能给数据库减少压力。

但是,使用缓存之后,就有许多问题需要解决,包括业务场景的考虑。

1. 缓存和数据库一致性的问题
  • 这个问题是确保用户能够从缓存中访问到最新的数据。
    -- 一般需要考虑的场景就是:更新了数据库,那么我们的缓存也要更新。否则用户去查数据走缓存,那么拿到的数据就可能是假的。
  • 如何去更新也是有技巧,能够确保不做过多的无效操作,也要确保用户能拿到最新数据。
  • 根据学习,我理解的就是采用:先更新数据库,再删除缓存这么一个策略
    -- 相较于每次更新完数据库都去更新缓存。这个策略就能避免很多无效的写操作。也能确保缓存是最新的(这其中就涉及到一些并发的业务逻辑)。
2. 缓存击穿问题
  • 这个问题就是热点key失效了,而重构这个key又需要比较久的时间。
    -- 而在这个重构的时间段里面,如果并发访问数据,那么就又会给数据库造成很大压力。
  • 如何去解决这个问题。我理解的就是加锁。
    -- 如果用户进来查询数据,后台发现未命中缓存,那么就去尝试获取锁,而这个锁,是redis中的一个分布式锁,setnx这个命令。拿到了锁,那么就去执行缓存重建逻辑。
    -- 而如果这时候,其他用户也进来查数据,此时肯定拿不到锁,那么就会休眠一会,然后尝试重新去查询数据。
  • 这就是1一个解决方案,这个方案能避免给数据库造成很大压力,但是也可能会影响用户体验,因为需要进行等待。
  • 还有一个解决方案就是逻辑超时,也就是不给key设置过期时间,但是给他设置一个逻辑超时时间,这个方案的话就是给k-v的v中存储一个key的有效期。这个方式的话,在缓存重建之前,用户会拿到脏数据。
  • 还得根据具体业务去选择
3. 缓存穿透问题
  • 这个问题就是客户端发来了很多请求,但是这些请求需要的数据在缓存、数据库都没有,给数据库造成了很大的压力。
  • 解决方案:1.缓存空数据 2.布隆过滤器(对这个不是很了解,没用过)
4. 缓存雪崩问题
  • 这个问题是redis宕机,或者说大量的key失效
  • 解决方案:搭建redis集群

分析一个具体的业务场景
用户抢优惠券,要满足条件:一人一单
要考虑并发时出现的问题。
1.首先要查该用户是否有券,如果没有就能让它去抢,否则就不允许
2.如果该用户没券,就去执行抢券逻辑

在查券的时候,如果同一个用户发来了很多请求,这是一个并发问题。
如果说线程1判断无券,那么就去执行抢券逻辑。如果这时候线程2进来了,也会判断无券,又会执行它的抢券逻辑。
所以需要加一个锁,即使同一个用户发来多次请求,此时也是串行的,只有等他执行完抢券逻辑,才会释放锁。那么如果该用户的其他的抢券请求进来,也不会去执行抢券。
同时,抢券逻辑也在这个锁的锁定范围内,也避免了超卖的问题。

这里的锁需要使用分布式锁,比如redis的setnx()。

分析:我们采用的锁对象是,user.getId()。在单体项目之下,对于一个用户的多个请求进来,该锁对象确实是唯一的。

但是如果将该项目做成集群的形式,由于每个Tomcat都有自己的JVM,那么此时的锁就不是同一吧了,而是这台服务器认为他的这把锁是唯一的,那台服务器认为他的这把锁是唯一的。这样子就做不到唯一锁。所以我们这里需要使用分布式锁。

但是分布式锁也会遇到一些问题,比如说误删锁问题,以及删锁时的原子性问题。

有关对redis的实战理解的更多相关文章

  1. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  2. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  3. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  4. ruby - 易于初学者理解的 Ruby 库 - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭3年前。Improvethisquestion我正处于学习Ruby的阶段,我想查看一些小型库的源代码以了解它们是如何构建的。我不知道什么是小型图书馆,但希望SO能推荐一些易于理解的图书馆来学习。因此,如果有人知道一两个非常小的库,这是新手Rubyists学习的好例子,请推荐!我想使用Manveru'sInnatelib,因为它试图保持在2000LOC以下,但我还不熟悉其中经常使用的Ruby速记。也许大约100-5

  5. ruby - 无法理解 `puts{}.class` 和 `puts({}.class)` 之间的区别 - 2

    由于匿名block和散列block看起来大致相同。我正在玩它。我做了一些严肃的观察,如下所示:{}.class#=>Hash好的,这很酷。空block被视为Hash。print{}.class#=>NilClassputs{}.class#=>NilClass为什么上面的代码和NilClass一样,下面的代码又显示了Hash?puts({}.class)#Hash#=>nilprint({}.class)#Hash=>nil谁能帮我理解上面发生了什么?我完全不同意@Lindydancer的观点你如何解释下面几行:print{}.class#NilClassprint[].class#A

  6. ruby - 如何理解 Ruby 中的发送者和接收者? - 2

    我很难理解Ruby中sender和receiver的实际含义。它们一般是什么意思?到目前为止,我只是将它们理解为方法调用和获取其返回值的调用。但是,我知道我的理解还远远不够。谁能给我一个Ruby中发送者和接收者的具体解释? 最佳答案 面向对象中的一个核心概念是消息传递和早期概念化,这在很大程度上借鉴了计算的Actor模型。艾伦·凯(AlanKay)创造了面向对象一词并发明了最早的OO语言之一SmallTalk,他拥有voicedregretatusingatermwhichputthefocusonobjectsinsteadofo

  7. ruby-on-rails - Rails - 理解 application.js 和 application.css - 2

    rails新手。只是想了解\assests目录中的这两个文件。例如,application.js文件有如下行://=requirejquery//=requirejquery_ujs//=require_tree.我理解require_tree。只是将所有JS文件添加到当前目录中。根据上下文,我可以看出requirejquery添加了jQuery库。但是它从哪里得到这些jQuery库呢?我没有在我的Assets文件夹中看到任何jquery.js文件——或者直接在我的整个应用程序中没有看到任何jquery.js文件?同样,我正在按照一些说明安装TwitterBootstrap(http:

  8. ruby - 你如何理解 Ruby 中的这个三元条件? - 2

    我在某些代码中遇到了三元组,但我无法理解条件:str.split(/',\s*'/).mapdo|match|match[0]==?,?match:"somestring"end.join我确实理解我是在某些点上拆分字符串并将总结果转换为数组,然后依次处理数组的每个元素。除此之外,我不知道发生了什么。 最佳答案 一种(稍微)不那么令人困惑的写法是:str.split(/',\s*'/).mapdo|match|ifmatch[0]==?,matchelse"somestring"endend.join我认为多行三元语句很糟糕,尤其是

  9. ruby - 您如何将 S3 理解为 Ruby 中的分层目录结构? - 2

    有没有人成功地将S3存储桶读取为子文件夹?文件夹1--子文件夹2----文件3----文件4--文件1--文件2文件夹2--子文件夹3--文件5--文件6我的任务是读取文件夹1。我希望看到子文件夹2、文件1和文件2,但看不到文件3或文件4。现在,因为我将存储桶键限制为prefix=>'folder1/',你仍然会得到file3和4,因为它们在技术上具有folder1前缀。似乎真正做到这一点的唯一方法是吸收folder1下的所有键,然后使用字符串搜索从结果数组中实际排除file3和file4。有没有人有过这方面的经验?我知道像Transmit和Cyber​​duck这样的FTP风格的S3

  10. 你真正了解什么是接口测试么?接口实战一“篇”入魂 - 2

    最近在工作中,看到一些新手测试同学,对接口测试存在很多疑问,甚至包括一些从事软件测试3,5年的同学,在聊到接口时,也是一知半解;今天借着这个机会,对接口测试做个实战教学,顺便总结一下经验,分享给大家。计划拆分成4个模块跟大家做一个分享,(接口测试、接口基础知识、接口自动化、接口进阶)感兴趣的小伙伴记得关注,希望对你的日常工作和求职面试,带来一些帮助。注:文章较长有5000多字,希望小伙伴们认真看完,当然有些内容对小白同学不是太友好,如果你需要详细了解其中的一些概念或者名词,请在文章之后留言,后续我将针对大家的疑问,整理输出一些大家感兴趣的文章。随着开发模式的迭代更新,前后端分离已不是新的概念,

随机推荐