我怎么能只懂得使用Redis呢?(一)

2023-05-16

前言

最近在回顾&学习Redis相关的知识,也是本着分享的态度和知识点的记录在这里写下相关的文章。希望能帮助各位读者学习或者回顾到Redis相关的知识,当然,本人才疏学浅,在学习和写作的过程中难以会出现说文章的内容有出入或错误,也希望读者们能及时指出,我会及时加以修正。谢谢,加油!
  那么接下来,就让我们一起来学习Redis相关的知识点吧!

哦?缓存

什么是缓存

什么是缓存呢?缓存就是数据交换的缓冲区(称作:Cache),这里我们可以简单的理解为存储在内存中的一个区域或数据。

缓存的作用

那么缓存究竟有什么作用呢?缓存的作用,主要有两个作用:高性能、高并发。

  • 高性能
      在不使用缓存的情况下,通常查询所需数据需要从数据库(如:MySQL)中读取,读取结果后我们还可能对结果进行一系列的复杂且耗时的计算,进而得出的我们真正想要的结果。在操作结果不会频繁发生变化的情况下,使用缓存后,查询请求一过来,直接从内存查询获取到最终的结果,免除了重新进行复杂且耗时的计算,性能极大的提高。
  • 高并发
      缓存走内存,天然支持高并发(单机甚至可支持到上万QPS),而相对,数据库来说,一般并发请求量在2000QPS左右(单机)。
      缓存单机承载并发量是MySQL单机的几十倍。(归根到底,还是因为缓存走内存,执行效率高,可以快速查询到我们想要的结果,立马返回结束请求)

使用缓存后常见的缓存问题

  • 缓存与数据库双写一致性
  • 缓存雪崩
  • 缓存穿透
  • 缓存击穿
  • 缓存并发竞争
    (后续会针对这些问题进行分析)

常见的缓存问题分析

缓存雪崩

随机保存key的过期时间、缓存预热、缓存高可用架构、缓存持久化方案的实施

缓存穿透

布隆过滤器、保存空值

缓存击穿

热点Key问题,能不设置过期时间就不设置、key过期的情况下加锁控制并发从数据库中读取,避免高并发情况下由于缓存过期直接将请求打到数据库使得数据库宕机。

缓存与数据库的双写一致性

说起使用缓存,不得不提及这样一个重要的问题,即缓存和数据库的数据一致性问题(保证缓存和数据库保存的数据一致)。

Cache Aside Pattern

介绍

Cache Aside Pattern是一个由国外友人提出的经典的缓存+数据库的读写模式,该模式分为:

  • 读实践:
    1. 先读缓存,如果缓存中读取到值,则返回;
    2. 若缓存中没有则查询数据库,计算值;
    3. 将计算结果放入缓存中,返回结果。
  • 写实践:
    1. 先更新数据库;
    2. 再删除缓存。

进一步分析

针对Cache Aside Pattern的写实践我们来进行讨论如下几个问题:

  • 问:为什么不更新缓存而是删除缓存?
  • “先更新数据库,再删除缓存”是否会出现数据不一致问题呢?
    • 删除缓存失败,缓存内存储旧数据而数据库存储的是新数据,出现数据不一致问题,不满足业务要求。
  • 为什么不“先删除缓存,再更新数据库”呢?这种情况是否能保证数据一致呢?
    • 更新数据库失败,但缓存内存储的数据同数据库一致,满足业务要求。
    • 但是如果出现并发情况,请求A先删除缓存,此时有另外个请求B进行读取,发生缓存未命中,从数据库读取旧数据又保存到缓存中,接着请求A继续更新数据库。那么此时同样会出现缓存同数据库数据不一致问题。

  •   这里的数据一致性问题,归根到底,还是操作的原子性问题(要么一起成功,要么一起失败)。

TODO

总结

针对这个问题,是实际场景中,如果业务上允许缓存与数据库存在短暂或一段时间的数据不一致,那么我们尽可能地不去采用“缓存读写请求串行化的”等方案去解决数据不一致的问题。

缓存读写请求串行化:

  • QPS、吞吐量降低
  • 读请求长阻塞
  • 多服务实例服务部署的请求路由(将请求打到同一台机)
  • 热点数据路由,请求倾斜问题

Redis的线程模型

(支持多线程的 Redis 6.0 版本于 2020-05-02 终于发布,所以在这讲的是Redis单线程版的!!!需要注意)

  • 参考:支持多线程的Redis 6.0终于发布了!

客户端与Redis的通信流程

客户端与Redis的通信流程
  这里先不说一些比较概念性的内容,而是先对《客户端与Redis的通信流程》结合上图做一个整体的描述说明,阅读期间可能会因为一些专有名词而产生疑惑甚至出现阅读障碍,但是不要方,hold住,先看完有个整体大概的印象,知道大概大概后再结合后续具体的说明会进一步了解。(当然这里阅读之前,你需要对网络Socket编程有些理解,不懂?没事,先去了解下再回来继续看吧。可以了解下Java的Socket编程会很有意思哦,写个Demo,写个简单的“聊天室”,对你来说不会是个难事啦~~)
  
  来吧,让我们来看看这个通信流程是个怎样的肥事。

  1. 在Redis启动初始化,会将Server Socket的AE_READABLE事件与连接应答处理器关联。(我***~~~AE_READABLE事件、连接应答处理器 咩玩意哦。听我的,先结合图尽可能理解先)
  2. 客户端发起同Redis服务端建立连接时,Server Socket会产生一个AE_READABLE事件,IO多路复用程序监听到该事件后,会将该Socket产生的AE_READABLE事件压入队列中。
  3. 文件事件分派器会从队列中取出服务端产生的这个AE_READABLE事件会交由连接应答处理器处理。(为什么是交给连接应答处理器处理呢?因为在一开始Server Socket的AE_READABLE事件与连接应答处理器关联了哈!)
  4. 连接应答处理器会创建一个同客户端连接通信的Socket,这里我们假定该Socket为 socket01,并将 socket01的AE_READABLE事件与命令请求处理器关联。
  5. 客户端发送请求,如:set key value,此时与客户端连接的socket01会产生AE_READABLE事件,同样地,IO多路复用程序监听到socket01的事件后,会将socket01产生的AE_READABLE事件压入队列中。
  6. 文件事件分派器从队列中取出socket01产生的AE_READABLE事件会交由命令请求处理器进行处理。(因为在第 4 步中已经将 socket01的AE_READABLE事件与命令请求处理器关联 了哈)
  7. 命令请求处理器执行客户端的请求命令,如:在内存中实现对key的set操作,设置为新的值,接着将socket01的AE_WRITABLE事件与命令回复处理器关联。
  8. 客户端准备好接收请求结果后,Redis中的socket01会产生一个AE_WRITABLE事件,同样会经由IO多路复用程序压入队列中。
  9. 文件事件分派器从队列中取出socket01产生的AE_WRITABLE事件会交由命令回复处理器进行处理。(因为在第 7 步中已经将 socket01的AE_WRITABLE事件与命令回复处理器关联 了哈)
  10. 命令回复处理器会向socket01输入本次操作的结果,并最后将 socket01的AE_WRITABLE事件与命令回复处理器的关联解除,最终完成一次与客户端的通信。

Redis线程模型说明

Redis基于Reactor模型开发了网络事件处理模型,称为文件事件处理器。采用IO多路复用机制,同时监听多个socket,当socket产生对应事件时,会根据socket的事件来(文件事件分派器)选择相应的事件处理器来处理事件。
  文件事件处理器,包括:多个socket、IO多路复用程序、文件事件分派器、事件处理器。其中事件处理器,包括:连接应答处理器、命令请求处理器、命令回复处理器。因为文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型。
  为什么Redis使用的是单线程模型但效率还是很高呢?

  • 单线程操作,反倒避免了多线程上下文切换的问题&多线程共享资源的竞争问题。
  • 基于IO多路复用机制,非阻塞。

Redis的过期策略&淘汰机制

这一节,让我们来了解下Redis的过期策略和内存淘汰机制。了解这些知识点的原因,在于可以帮助我们清楚地知道Redis针对过期的key是如何进行处理的,解答类似“为什么这个key过期了,但还占用着内存”等问题,也可以让我们了解到在Redis可使用的内存满了情况下,它又是如何处理的,解答类似“为什么我一些没有设置过期时间的key也被删除了呢”等问题。

Redis的过期策略

针对过期的key,Redis是如何处理的呢?已过期的key不会立马被删除。在默认情况下,Redis每隔100ms会随机抽取一些设置了过期时间的key,检查其是否过期,如已过期则进行删除。为什么是随机抽取一些呢?因为在定期删除的情况下,如果设置了过期时间的key真的很多的话,Redis需要全部检查这些key是否真的过期,那将是一个CPU负载很高的操作。
  从上面我们了解到Redis的定期删除可能会遗漏掉一些真的已经过期了的key,那么这些key又是怎么被删除的呢?
  Redis的惰性删除,即在访问某个key的时候,会先校验该key是否已过期,如果已过期则进行删除,并返回空结果。在定期删除的过程中,如果已经过期的key没有被抽取到,则在访问该key的时候将会被删除。
  总结,Redis的过期策略:定期删除+惰性删除。

Redis的内存淘汰机制

采用Redis这样的过期策略,仍会出现很多过期的key没有被删除的情况(被定期删除遗漏,又没有及时访问走惰性删除),堆积在内存中,后续又有新的key存到内存中,直到Redis可使用的内存耗尽,那此时Redis又是如何处理的呢?
  答案是:走Redis的内存淘汰机制。
  Redis会依据某种策略会一些key进行淘汰,腾出内存空间。其中最常用的策略为:allkeys-lru,即当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用(LRU)的 key。(其他几种Redis的内存淘汰机制,我就不在这里做过多说明啦,可参考其他文献)
  Redis使用的是一种近似LRU的算法实现的 allkeys-lru 内存淘汰。LRU算法,参考:缓存淘汰算法–LRU算法。


额外分享:值得了解的是,LRU算法在Java中可以使用 LinkedHashMap 快速实现。

class LRUCache<K, V> extends LinkedHashMap<K, V> {
    private final int CACHE_SIZE;

    /**
     * 传递进来最多能缓存多少数据
     *
     * @param cacheSize 缓存大小
     */
    public LRUCache(int cacheSize) {
        // true 表示让 linkedHashMap 按照访问顺序来进行排序,最近访问的放在头部,最老访问的放在尾部。
        super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
        CACHE_SIZE = cacheSize;
    }

    /**
     * 钩子方法,通过put新增键值对的时候,若该方法返回true
     * 便移除该map中最老的键和值
     */
    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        // 当 map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据。
        return size() > CACHE_SIZE;
    }
}

Redis持久化

TODO
持久化方式:
RDB
AOF
持久化方式的对比

Redis主从架构

TODO
Redis集群工作原理等

参考资料

  • Java面试——缓存
  • 帮你解读什么是Redis缓存穿透和缓存雪崩(包含解决方案)
  • 缓存穿透、缓存击穿、缓存雪崩区别和解决方案
  • 究竟先操作缓存,还是数据库?
  • 缓存,究竟是淘汰,还是修改?
  • 彻底搞懂Redis的线程模型
  • 彻底弄懂Redis的内存淘汰策略
  • 缓存淘汰算法–LRU算法

总结

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我怎么能只懂得使用Redis呢?(一) 的相关文章

  • Node Js:Redis 作业在完成其任务后未完成

    希望你们做得很好 我在我的 Nodejs 项目中实现了 BullMQ Bull 的下一个主要版本 来安排发送电子邮件的作业 例如 发送忘记密码请求的电子邮件 所以 我编写了如下所示的代码 用户服务 await resetPasswordJo
  • Lua中按字符分割字符串

    我有像这样的字符串 ABC DEF 我需要将它们分开 字符并将两个部分分别分配给一个变量 在 Ruby 中 我会这样做 a b ABC DEF split 显然Lua没有这么简单的方法 经过一番挖掘后 我找不到一种简短的方法来实现我所追求的
  • 2 个具有共享 Redis 依赖的 Helm Chart

    目前 我有 2 个 Helm Charts Chart A 和 Chart B Chart A 和 Chart B 对 Redis 实例具有相同的依赖关系 如Chart yaml file dependencies name redis v
  • StackExchange.Redis Get 函数抛出 TimeoutException

    我在用着StackExchange Redis与 C 和StackExchangeRedisCacheClient Get函数抛出以下异常 myCacheClient Database StringGet txtKey Text myCac
  • 如何将“.csv”数据文件导入Redis数据库

    如何将 csv 数据文件导入 Redis 数据库 csv 文件中包含 id 时间 纬度 经度 列 您能否向我建议导入 CSV 文件并能够执行空间查询的最佳方法 这是一个非常广泛的问题 因为我们不知道您想要什么数据结构 您期望什么查询等等 为
  • Spring Redis删除不删除key

    我正在尝试删除一个 Redis 键 但由于某种原因它没有删除 但也没有抛出异常 这是我要删除的代码 import com example service CustomerService import com example model Cu
  • Laravel 异常队列最大尝试次数超出

    我创建了一个应用程序来向多个用户发送电子邮件 但在处理大量收件人时遇到问题 该错误出现在failed jobs table Illuminate Queue MaxAttemptsExceededException App Jobs ESe
  • 在 Spring 4 中干掉通用的 RedisTemplate

    我读到你可以拥有 Autowired从 Spring 4 开始泛型 这太棒了 我有一个摘要RedisService我想参加的课程 Autowired一个通用的 RestTemplate 如下所示 public abstract class
  • 当 Jedis 与 Spring Data 一起使用时,为什么数据会以奇怪的键存储在 Redis 中?

    我将 Spring Data Redis 与 Jedis 一起使用 我正在尝试存储带有密钥的哈希值vc list id 我能够成功插入到redis 但是 当我使用 redis cli 检查密钥时 我没有看到密钥vc 501381 相反我看到
  • Spring Data Redis 覆盖默认序列化器

    我正在尝试创建一个RedisTemplatebean 将具有更新的值序列化器来序列化对象JSONredis 中的格式 Configuration class RedisConfig Bean name redisTemplate Prima
  • 为什么单个 Redis 实例不是线程安全的?

    https github com xetorthio jedis wiki Getting started https github com xetorthio jedis wiki Getting started 在多线程环境中使用Jed
  • Web API 缓存 - 如何使用分布式缓存实现失效

    我有一个 API 目前不使用任何缓存 我确实有一个正在使用的中间件 它可以生成缓存标头 Cache Control Expires ETag Last Modified 使用https github com KevinDockx HttpC
  • 使用 Redis 中的键

    我是 Redis 和键值数据库的新手 你能告诉我如何在redis中正确实现这种关系方法吗 我有一个关系表 其中两个键对应一个值 master id slave id 价值 Example 主站 ID 从属ID 价值 1 1 值1 2 1 值
  • 检查 Redis 列表中是否已存在某个值

    我想知道是否有办法检查 redis 列表中是否已存在某个键 我无法使用集合 因为我不想强制唯一性 但我确实希望能够检查字符串是否确实存在 Thanks 您的选择如下 Using LREM如果发现则更换它 维护一个单独的SET与您的LIST
  • Redis AOF fsync(始终)与 LSM 树

    我对日志结构化合并树 LSM 树 的理解是 它利用了附加到磁盘非常快 因为它不需要查找 这一事实 只需将更新附加到预写日志并返回到客户端即可 我的理解是 这仍然提供了立即的持久性 同时仍然非常快 我不认为 Redis 使用 LSM 树 它似
  • 具有匹配模式的 ioredis 密钥

    我想用键匹配模式 LOGIN 搜索 Redis 数据库 我在我的应用程序中使用 ioredis 昨天我搜索了整个网络 我得到了一些执行这项工作的选项 如下所示 KEYS 扫描流 Issue import Redis from ioredis
  • Microsoft.Extensions.Caching.Redis 选择与 db0 不同的数据库

    一个关于了解使用哪个redis数据库以及如何配置它的问题 我有一个默认值ASP NET Core Web 应用程序和默认配置的本地redis服务器 含15个数据库 通过包管理控制台我已经安装了 Install Package Microso
  • 如何暂停或恢复 celery 任务?

    我的项目中有一项要求 客户可以暂停或恢复正在挂起的流程 而不是流程流程 我在用网络套接字显示芹菜任务结果 但在暂停 恢复时我不明白如何设计代码 我想到的唯一方法就是revoke暂停请求中的任务 同时保留数据撤销的过程在缓存中 并稍后在res
  • Redis 会话序列化器 3.2 和 4.2 之间不匹配

    我有一个基于 Spring Cloud 的应用程序在多个 spring boot 服务器上运行 所有服务器使用 EnableRedisHttpSession共享相同的Spring Session 我现在想将第三方小部件集成到我的应用程序中
  • 有没有好的方法支持 Redis 排序集中的 pop 成员?

    有没有好的方法可以像 List 的 api LPOP 一样支持 Redis 排序集中的 pop 成员 我发现从 Redis 排序集中弹出消息是使用 ZRANGE ZREM 但是它不是线程安全性 并且当多个线程从不同主机同时访问它们时需要分布

随机推荐

  • 安卓Service生命周期

    官方说明图 startService xff1a 开启一个Service且Service生命周期只与自身有关 xff0c 当调用stopService或者stopSelf时停止 如果多次调用startService xff0c 只有第一次会
  • 阿里2014年校园题目最后一题答案及证明

    该题目来自cdsn的一位网友 xff08 可见http blog csdn net thebestdavid article details 11975809 xff09 xff0c 具体内容如下 xff1a 在黑板上写下50个数字 xff
  • 编程——两种list的翻转方法

    对于题目相信大家都比较熟悉了 xff0c 下面就直接上代码了 xff0c 其中没有给出list的creat函数 xff0c 有兴趣的同学可以自己实现 1 模板node的定义 template lt class T gt class TNod
  • 数组旋转新方法

    题目 xff1a 对一个int数组进行左右任意长度的旋转 xff0c 如 xff1a 原始数组为 1 2 3 4 5 xff0c 左旋两位 xff08 可用 2表示 xff09 得 3 4 5 1 2 xff0c 右旋两位 xff08 可用
  • 常见Linux shell脚本中的“-e -d -f -eq -ne -gt -ge”操作符的含义

    常见shell脚本中的 e d f eq ne gt ge 操作符的含义 xff1a 文件表达式 e filename xff1a 如果filename存在 xff0c 则为真 d filename xff1a 如果filename为目录
  • 基于注解的spring源码解析之总体流程

    基于注解的spring源码解析1 总体流程 总体流程图 Demo代码 span class token keyword public span span class token keyword class span span class t
  • Android ViewBinding 替换 findViewById 的神器

    ViewBinding中文官网 ViewBinding 的出现就是为了替代 findViewById 的 以前我们写完布局后就要在代码中使用 findViewById 方法找到 xml 文件中对应的 view xff0c 这样耗时费力 xf
  • 套接字选项(SO_RCVBUF和SO_SNDBUF)

    有时候我们需要控制套接字的行为 如修改缓冲区的大小 这个时候我们就要学习套接字选项 int getsockopt int sockfd int level int optname void optval socklen t optlen i
  • 欢迎使用CSDN-markdown编辑器

    欢迎使用Markdown编辑器写博客 本Markdown编辑器使用StackEdit修改而来 xff0c 用它写博客 xff0c 将会带来全新的体验哦 xff1a Markdown和扩展Markdown简洁的语法代码块高亮图片链接和图片上传
  • 工作一年,辞职复习半年,考杭电计算机的经验分享

    工作一年 xff0c 辞职复习半年 xff0c 考杭电计算机的经验分享 如果 xff0c 毕业了工作顺利的人大概率是不会去考研的 xff0c 去考研的人 xff0c 大概率是想改变的 题记 2019 4 6 关于我 纠结的人生 为什么考研
  • ICPR-2018-OCR笔记

    2018年第24届国际模式识别大会International Conference on Pattern Recognition ICPR 在北京国家会议中心召开 xff0c 会议从8月20日到24日持续1周时间 有阿里的读光平台的介绍 x
  • centos7 firewalld导致docker网络异常

    centos7 自带防火墙是firewalld 在某下情况下可能导致docker 的某些网络问题 docker 有4种网络模式 xff1a 1 bridge模式 xff08 默认 xff09 xff1a 网桥模式 xff0c 通过虚拟网桥使
  • Linux(centOS)安装yum

    查看是否有安装yum rpm qa grep yum 红框内代表已安装的 xff0c 如果为空代表未安装yum 删除yum下的所有组件 rpm qa grep yum xargs rpm e nodeps 查看原有的yum配置 xff0c
  • Java实现-删除数字

    给出一个字符串 A 表示一个 n 位正整数 删除其中 k 位数字 使得剩余的数字仍然按照原来的顺序排列产生一个新的正整数 找到删除 k 个数字之后的最小正整数 N lt 61 240 k lt 61 N 您在真实的面试中是否遇到过这个题 x
  • CentOS7, CentOS8 firewalld docker 端口映射问题,firewall开放端口后,还是不能访问,解决方案

    启动sqlserver容器 docker run d restart 61 always e 34 ACCEPT EULA 61 Y 34 e 34 SA PASSWORD 61 Abc12345 34 p 1433 1433 name s
  • firewalld 命令大全

    1 firewalld的基本使用 启动 xff1a systemctl start firewalld 查看状态 xff1a systemctl status firewalld 停止 xff1a systemctl disable fir
  • vscode通过文件名查找文件的方法

    vscode通过文件名查找文件的方法 这篇文章给大家分享的是有关vscode通过文件名查找文件的方法的内容 小编觉得挺实用的 xff0c 因此分享给大家做个参考 一起跟随小编过来看看吧 按快捷键ctrl 43 p可以弹出一个小窗 xff0c
  • HTML几种设置水平居中和垂直居中的方式

    水平居中 1 平居中设置 定宽块状元素 当被设置元素为 块状元素 时用 text align xff1a center 就不起作用了 xff0c 这时也分两种情况 xff1a 定宽块状元素和不定宽块状元素 这一小节我们先来讲一讲定宽块状元素
  • 【Django网络安全】如何正确设置跨域

    原文作者 xff1a 我辈李想 版权声明 xff1a 文章原创 xff0c 转载时请务必加上原文超链接 作者信息和本声明 Django网络安全 Django网络安全 如何正确设置跨域 Django网络安全 如何正确防护CSRF跨站点请求伪造
  • 我怎么能只懂得使用Redis呢?(一)

    前言 最近在回顾 amp 学习Redis相关的知识 xff0c 也是本着分享的态度和知识点的记录在这里写下相关的文章 希望能帮助各位读者学习或者回顾到Redis相关的知识 xff0c 当然 xff0c 本人才疏学浅 xff0c 在学习和写作