【Java八股面试系列】中间件-Redis

news2024/11/15 7:11:30

目录

Redis

什么是Redis

Redis解决了什么问题

Redis的实现原理

数据结构

String

常用命令

应用场景

List(列表)

常用命令

应用场景

Hash(哈希)

常用命令

应用场景

set(集合)

常见命令​编辑

应用场景

Sorted Set(有序集合)

常见命令​编辑

应用场景

数据持久化

RDB

优缺点

AOF

工作流程

AOF持久化的策略

AOF重写

AOF校验

Redis内存管理

内存淘汰机制

Redis实现分布式锁

Redis缓存问题

缓存穿透

解决方法

缓存击穿

解决办法

缓存雪崩

解决办法

缓存预热

数据库和缓存一致性

CAP原理

解决方法

常见问题


Redis

什么是Redis

Remote Dictionary Server(远程字典服务),是一个开源的使用C语言编写,基于内存,并且支持持久化的一个NoSQL数据库。

Redis解决了什么问题

Redis实现了:

  1. 高性能高并发缓存:Redis的数据是存放在内存中,所以读写都是非常快速

  2. 数据结构存储:Redis支持多种数据结构,字符串,哈希,列表等

  3. 数据持久化:使用AOF持久化,RDB持久化方案

  4. 发布与订阅:Redis支持发布与订阅模式,可以实现消息的发布和订阅。

Redis的实现原理

1、高性能

将经常访问的数据都放在Redis中,保证用户下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,不用去磁盘中读取,所以速度相当快。

2、高并发

一般像 MySQL 这类的数据库的 QPS 大概都在 w 左右 ,但是使用 Redis 缓存之后很容易达到 10w级别(就单机 Redis 的情况,Redis 集群的话会更高)。

QPS(Query Per Second):服务器每秒可以执行的查询次数;

所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。进而,我们也就提高了系统整体的并发。

数据结构

5 种基础数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。

String
常用命令

应用场景
  • 存储键值对的场景

  • 需要计数的场景,使用INCR key进行数字的增减

  • 分布式锁

List(列表)

Redis 的 List 的实现为一个 双向链表,即可以支持反向查找和遍历

常用命令

应用场景

保存历史记录,按照日期进行保存

Hash(哈希)

Redis 中的 Hash 是一个 String 类型的 field-value(键值对) 的映射表,特别适合用于存储对象,后续操作的时候,你可以直接修改这个对象中的某些字段的值。

常用命令

应用场景

可以用来对象数据的存储,一个用户下面的各种信息

set(集合)

类似Java中的 HashSet,集合中的元素无序但是唯一,提供了查询元素是否存在的接口

常见命令
应用场景
  • 可以做两个集合的交集例如共同好友

  • 抽奖系统,能够随机出一个名额

Sorted Set(有序集合)

Sorted Set 类似于 Set,但和 Set 相比,Sorted Set 增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列,还可以通过 score 的范围来获取元素的列表。有点像是 Java 中 HashMapTreeSet 的结合体。

常见命令
应用场景

数据持久化

数据持久化指的是将数据保存到磁盘中,Redis在4.0以后支持了三种持久化方式:

  • 快照(snapshotting,RDB)

  • 只追加文件(append-only file, AOF)

  • RDB 和 AOF 的混合持久化(Redis 4.0 新增)

数据持久化解决了重启机器或者就是机器故障以后的数据恢复工作

RDB

通过创建快照来获得存储在内存里面的数据在某个时间的副本。Redis获得了快照以后,可以使用快照进行重启恢复,可以复制给从服务器进行同步(提高Redis性能和高可用)

开启

通过在 redis.conf配置文件中设置

save 900 1           #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发bgsave命令创建快照。
​
save 300 10          #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发bgsave命令创建快照。
​
save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发bgsave命令创建快照。
​

是否阻塞主线程

Redis 提供了两个命令来生成 RDB 快照文件:

  • save : 同步保存操作,会阻塞 Redis 主线程;

  • bgsave : fork 出一个子进程,子进程执行,不会阻塞 Redis 主线程,默认选项

这里说 Redis 主线程而不是主进程的主要是因为 Redis 启动之后主要是通过单线程的方式完成主要的工作。如果你想将其描述为 Redis 主进程,也没毛病

执行后,会在服务端目录下生成一个dump.rdb文件,而这个文件中就保存了内存中存放的数据,当服务器重启后,会自动加载里面的内容到对应数据库中。

优缺点

优点:恢复快速,保存简单

缺点:

  • 可能丢失最新更新的数据

  • 性能开销,如果我们数据比较大的时候,子线程进行保存的时候会消耗较多的cpu资源

AOF

与快照持久化相比,AOF 持久化的实时性更好。

开启 AOF 持久化后每执行一条会更改 Redis 中的数据的命令,Redis 就会将该命令写入到 AOF 缓冲区 server.aof_buf 中,然后再写入到 AOF 文件中(此时还在系统内核缓存区未同步到磁盘),最后再根据持久化方式( fsync策略)的配置来决定何时将系统内核缓存区的数据同步到硬盘中的。

只有同步到磁盘中才算持久化保存了,否则依然存在数据丢失的风险,比如说:系统内核缓存区的数据还未同步,磁盘机器就宕机了,那这部分数据就算丢失了。

AOF 文件的保存位置和 RDB 文件的位置相同,都是通过 dir 参数设置的,默认的文件名是 appendonly.aof

工作流程

AOF 持久化功能的实现可以简单分为 5 步:

  1. 命令追加(append):所有的写命令会追加到 AOF 缓冲区中。

  2. 文件写入(write):将 AOF 缓冲区的数据写入到 AOF 文件中。这一步需要调用write函数(系统调用),write将数据写入到了系统内核缓冲区之后直接返回了(延迟写)。注意!!!此时并没有同步到磁盘。

  3. 文件同步(fsync):AOF 缓冲区根据对应的持久化方式( fsync 策略)向硬盘做同步操作。这一步需要调用 fsync 函数(系统调用), fsync 针对单个文件操作,对其进行强制硬盘同步,fsync 将阻塞直到写入磁盘完成后返回,保证了数据持久化。

  4. 文件重写(rewrite):随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。

  5. 重启加载(load):当 Redis 重启时,可以加载 AOF 文件进行数据恢复

AOF持久化的策略

在 Redis 的配置文件中存在三种不同的 AOF 持久化方式( fsync策略),它们分别是:

  1. appendfsync always:主线程调用 write 执行写操作后,后台线程( aof_fsync 线程)立即会调用 fsync 函数同步 AOF 文件(刷盘),fsync 完成后线程返回,这样会严重降低 Redis 的性能(write + fsync)。

  2. appendfsync everysec:主线程调用 write 执行写操作后立即返回,由后台线程( aof_fsync 线程)每秒钟调用 fsync 函数(系统调用)同步一次 AOF 文件(write+fsyncfsync间隔为 1 秒)

  3. appendfsync no:主线程调用 write 执行写操作后立即返回,让操作系统决定何时进行同步,Linux 下一般为 30 秒一次(write但不fsyncfsync 的时机由操作系统决定)。

可以看出:这 3 种持久化方式的主要区别在于 fsync 同步 AOF 文件的时机(刷盘)

为了兼顾数据和写入性能,可以考虑 appendfsync everysec 选项 ,让 Redis 每秒同步一次 AOF 文件,Redis 性能受到的影响较小。而且这样即使出现系统崩溃,用户最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候,Redis 还会优雅的放慢自己的速度以便适应硬盘的最大写入速度。

AOF重写

当 AOF 变得太大时,Redis 能够在后台自动重写 AOF 产生一个新的 AOF 文件,这个新的 AOF 文件和原有的 AOF 文件所保存的数据库状态一样,但体积更小。

AOF 重写

AOF 重写(rewrite) 是一个有歧义的名字,该功能是通过读取数据库中的键值对来实现的,程序无须对现有 AOF 文件进行任何读入、分析或者写入操作。

由于 AOF 重写会进行大量的写入操作,为了避免对 Redis 正常处理命令请求造成影响,Redis 将 AOF 重写程序放到子进程里执行。

AOF 文件重写期间,Redis 还会维护一个 AOF 重写缓冲区,该缓冲区会在子进程创建新 AOF 文件期间,记录服务器执行的所有写命令。当子进程完成创建新 AOF 文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新 AOF 文件的末尾,使得新的 AOF 文件保存的数据库状态与现有的数据库状态一致。最后,服务器用新的 AOF 文件替换旧的 AOF 文件,以此来完成 AOF 文件重写操作。

AOF校验

AOF 校验机制是 Redis 在启动时对 AOF 文件进行检查,以判断文件是否完整,是否有损坏或者丢失的数据。这个机制的原理其实非常简单,就是通过使用一种叫做 校验和(checksum) 的数字来验证 AOF 文件。这个校验和是通过对整个 AOF 文件内容进行 CRC64 算法计算得出的数字。如果文件内容发生了变化,那么校验和也会随之改变。因此,Redis 在启动时会比较计算出的校验和与文件末尾保存的校验和(计算的时候会把最后一行保存校验和的内容给忽略点),从而判断 AOF 文件是否完整。如果发现文件有问题,Redis 就会拒绝启动并提供相应的错误信息。AOF 校验机制十分简单有效,可以提高 Redis 数据的可靠性。

Redis内存管理

一般我们都是需要给内存设置过期时间,首先考虑我们的内存是有限的,其次有些数据也是有时效性的。

如何判断数据过期

Redis 通过一个叫做过期字典(可以看作是 hash 表)来保存数据过期的时间。

过期数据的删除策略

  1. 惰性删除:只会在取出 key 的时候才对数据进行过期检查。这样对 CPU 最友好,但是可能会造成太多过期 key 没有被删除。

  2. 定期删除:每隔一段时间抽取一批 key 执行删除过期 key 操作。并且,Redis 底层会通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响。

定期删除对内存更加友好,惰性删除对 CPU 更加友好。两者各有千秋,所以 Redis 采用的是 定期删除+惰性/懒汉式删除

但是,仅仅通过给 key 设置过期时间还是有问题的。因为还是可能存在定期删除和惰性删除漏掉了很多过期 key 的情况。这样就导致大量过期 key 堆积在内存里,然后就 Out of memory 了。

怎么解决这个问题呢?答案就是:Redis 内存淘汰机制。

内存淘汰机制

因为过期时间的删除策略都是具有局限性,惰性删除有时无法及时删除,定期删除会占用cpu大量的时间

相关问题:MySQL 里有 2000w 数据,Redis 中只存 20w 的数据,如何保证 Redis 中的数据都是热点数据?

Redis 提供 6 种数据淘汰策略:

  1. volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰。

  2. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰。

  3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰。

  4. allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)。

  5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰。

  6. no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!

Redis实现分布式锁

Redis缓存问题

缓存穿透

指的是访问一个数据库和缓存中都不存在的数据,每一次都会去访问数据库,也不会存在缓存中

解决方法

布隆过滤

布隆过滤器是将我们数据库中存在的数据都放置在一个二进制向量中,使用N个哈希值,将数据进行hash然后存放在里面。每一次查询的时候都先将我们查询的目标都进行N次hash然后如果有一个位置为0,则表示数据不存在。

缺点:

  • 数据越来越多则会越来越不准确。

  • 存放在布隆过滤器中的值不容易删除

接口限流

按照我们的用户或者IP对接口进行限流,设置防刷机制。

缓存击穿

比如某条热点数据过期,然后大量的数据去访问数据库,带来巨大的压力

穿透和击穿的区别就是数据库中有或者没有

解决办法

设置热点数据永不过期或者过期时间比较长。

针对热点数据提前预热,将其存入缓存中并设置合理的过期时间比如秒杀场景下的数据在秒杀结束之前不过期。

请求数据库写数据到缓存之前,先获取互斥锁,保证只有一个请求会落到数据库上,减少数据库的压力。

缓存雪崩

当你的Redis服务器炸了或是大量的Key在同一时间过期,这时相当于缓存直接GG了,那么如果这时又有很多的请求来访问不同的数据,同一时间内缓存服务器就得向数据库大量发起请求来重新建立缓存,很容易把数据库也搞GG。

解决办法
  • 采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。

  • 限流,避免同时处理大量的请求。

  • 多级缓存,例如本地缓存+Redis 缓存的组合,当 Redis 缓存出现问题时,还可以从本地缓存中获取到部分数据。

缓存预热

常见的缓存预热方式有两种:

  1. 使用定时任务,比如 xxl-job,来定时触发缓存预热的逻辑,将数据库中的热点数据查询出来并存入缓存中。

  2. 使用消息队列,比如 RabbitMQ,来异步地进行缓存预热,将数据库中的热点数据的主键或者 ID 发送到消息队列中,然后由缓存服务消费消息队列中的数据,根据主键或者 ID 查询数据库并更新缓存。

数据库和缓存一致性

Redis可以将常访问的数据保存起来,新的请求先在Redis中进行查询,能够缓解数据库的压力。

在读的情况下,无论怎样都是不会出现问题的,所以关键就是读写出现不一致的问题。

CAP原理

根据CAP原理,CAP原则又称CAP定理,指的是在一个分布式系统中,存在Consistency(一致性)、Availability(可用性)、Partition tolerance(分区容错性),三者不可同时保证,最多只能保证其中的两者。

一致性(C):在分布式系统中的所有数据备份,在同一时刻都是同样的值(所有的节点无论何时访问都能拿到最新的值)

可用性(A):系统中非故障节点收到的每个请求都必须得到响应(比如我们之前使用的服务降级和熔断,其实就是一种维持可用性的措施,虽然服务返回的是没有什么意义的数据,但是不至于用户的请求会被服务器忽略)

分区容错性(P):一个分布式系统里面,节点之间组成的网络本来应该是连通的,然而可能因为一些故障(比如网络丢包等,这是很难避免的),使得有些节点之间不连通了,整个网络就分成了几块区域,数据就散布在了这些不连通的区域中(这样就可能出现某些被分区节点存放的数据访问失败,我们需要来容忍这些不可靠的情况)

总的来说,数据存放的节点数越多,分区容忍性就越高,但是要复制更新的次数就越多,一致性就越难保证。同时为了保证一致性,更新所有节点数据所需要的时间就越长,那么可用性就会降低。

所以这里我们只能保证最终一致性

解决方法

当我们修改数据库的数据的时候,先更新数据库还是Redis缓存?

  1. 先删除缓存,再更新数据库

当多线程进行访问的时候,当线程A需要写入X,然后更新数据库的时候,线程2来访问缓存X,缓存中没有消息,进入数据库进行读取,读取旧的值X到缓存中,这个时候线程1再修改好数据库则最终一致性都不能保证。

  1. 先更新数据库再删除缓存

虽然有可能还是会最终一致性无法满足,但是概率很小,因为读和写请求的并发,读请求会更快的读取并且更新到缓存中,而读更慢。

  1. 双重删除

  2. 消息队列

使用消息队列异步删除,因为消息队列采用了确认机制,所以能够确保缓存中的数据被删除,虽然也会读取到脏数据,但是这个可以看作MVcc,读的操作是在更新的操作之前,不能看到更新完成后的失误,最后也能实现数据的最终一致性

常见问题

String 还是 Hash存储对象更好呢?

具体看我们的使用情况,string存储的是已经序列化的数据,存放整个对象。Hash是对每个字段单独的进行存储,可以获取部分的信息,可以修改。所以如果需要经常修改则Hash合适

String 存储更加的节省内存,因为Hash 需要保存更多的结构信息

        

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

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

相关文章

GitHub加速访问最简单的方法

Github是全球最大的代码开源平台,对于编程的小伙伴来说,这是一个巨大的宝库,也是编程学习的圣地。很对小伙伴在使用GitHub时会经常出现无法访问Github的情况。 一、解决方法——>修改hosts文件 通过 IP查询工具来获取当前Github网站的真实…

计算机网络:现代通信的基石

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

AcWing 4609:火柴棍数字 ← 贪心算法

【题目来源】 https://www.acwing.com/problem/content/4612/【题目描述】 给定 n 个火柴棍,你可以用它们摆出数字 0∼9。 摆出每个数字所需要的具体火柴棍数量如下图所示: 请你用这些火柴棍摆成若干个数字,并把这些数字排成一排组成一个整数…

Redis中的事件

事件 概述 Redis服务器是一个事件驱动程序:服务器需要处理以下两类事件: 1.文件事件(file event):Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接,而文件事件就是服务器对套接字操作的抽象。服务器与客户端(或者其他服务器)的通信会产生相应的文件…

机器学习作业二之KNN算法

KNN(K- Nearest Neighbor)法即K最邻近法,最初由 Cover和Hart于1968年提出,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路非常简单直观:如果一个样本在特征空间中的K个最相似&…

Ubuntu deb文件 安装 MySQL

更新系统软件依赖 sudo apt update && sudo apt upgrade下载安装包 输入命令查看Ubuntu系统版本 lsb_release -a2. 网站下载对应版本的安装包 下载地址. 解压安装 mkdir /home/mysqlcd /home/mysqltar -xvf mysql-server_8.0.36-1ubuntu20.04_amd64.deb-bundle.tar# …

Pandas操作MultiIndex合并行列的Excel,写入读取以及写入多余行及Index列处理,插入行,修改某个单元格的值

Pandas操作MultiIndex合并行列的excel,写入读取以及写入多余行及Index列处理 1. 效果图及问题2. 源码参考 今天是谁写Pandas的 复合索引MultiIndex,写的糊糊涂涂,晕晕乎乎。 是我呀… 记录下,现在终于灵台清明了。 明天在记录下直…

02-K近邻算法

机器学习其实有一个很朴实的想法: 预测 x x x的值, 那就在训练集 X X X中找到与 x x x相似的样本, 再把与x相似的这些样本的值加权作为预测值 那么我们如何度量样本之间的相似性?又该如何加权呢? 在k近邻中, 我们一般采…

【CXL协议-事务层之CXL.cache (3)】

3.2 CXL.cache 3.2.1 概述 CXL.cache 协议将设备和主机之间的交互定义为许多请求,每个请求至少有一个关联的响应消息,有时还有数据传输。 该接口由每个方向的三个通道组成: 请求、响应和数据。 这些通道根据其方向命名,D2H&…

基于FPGA实现的自适应三速以太网

一、三速以太网 千兆以太网PHY芯片是适配百兆和十兆的&#xff0c;十兆就不管了&#xff0c;我们的设计只适应千兆和百兆。 根据上图&#xff0c;我们是可以获取当前主机网口的速率信息的。 always(posedge w_rxc_bufr) beginif(w_rec_valid d0) beginro_speed < w_rec_…

【r-tree算法】一篇文章讲透~

目录 一、引言 二、R-tree算法的基本原理 1 数据结构 2 插入操作 3 删除操作 4 查询操作 5 代码事例 三、R-tree算法的性能分析 1 时间复杂度 2 空间复杂度 3 影响因素 四、R-tree算法的变体和改进 1 R*-tree算法 2 X-tree算法 3 QR-tree算法 五、R-tree算法的…

【物联网】Qinghub Kafka 数据采集

基础信息 组件名称 &#xff1a; kafka-connector 组件版本&#xff1a; 1.0.0 组件类型&#xff1a; 系统默认 状 态&#xff1a; 正式发布 组件描述&#xff1a;通用kafka连接网关&#xff0c;消费来自kafka的数据&#xff0c;并转发给下一个节点做相关的数据解析。 配置文…

http模块 获取http请求报文中的路径 与 查询字符串

虽然request.url已包含属性和查询字符串&#xff0c;但使用不便&#xff0c;若只需其中一个不好提取&#xff0c;于是用到了如下路径和字符串的单独查询方法&#xff1a; 一、获取路径 例如&#xff1a;我在启动谷歌端口时输入http://127.0.0.1:9000 后接了 "/search?k…

Docker 搭建Redis集群

目录 1. 3主3从架构说明 2. 3主3从Redis集群配置 2.1关闭防火墙启动docker后台服务 2.2 新建6个docker容器实例 2.3 进去任意一台redis容器&#xff0c;为6台机器构建集群关系 2.4 进去6381&#xff0c;查看集群状态 3. 主从容错切换迁移 3.1 数据读写存储 3.1.1 查看…

27---eMMC电路设计

视频链接 eMMC电路设计01_哔哩哔哩_bilibili eMMC电路设计 1、eMMC简介 eMMC叫嵌入式多媒体卡&#xff0c;英文全称为Embedded Multi Media Card。是一种闪存卡&#xff08;Flash Memory Card&#xff09;标准&#xff0c;它定义了MMC的架构以及访问Flash Memory的接口和协…

Linux 搭建jenkins docker

jekin docker gitee docker 安装 jenkins docker run -d --restartalways \ --name jenkins -uroot -p 10340:8080 \ -p 10341:50000 \ -v /home/docker/jenkins:/var/jenkins_home \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /usr/bin/docker:/usr/bin/docker je…

【双指针】Leetcode 盛最多水的容器

题目解析 11. 盛水最多的容器 木桶效应&#xff0c;寻找一个区间使得这个区间的体积最大 算法讲解 1. 暴力枚举 遍历这个容器&#xff0c;将每一个区间的体积求出来&#xff0c;然后找出最大的 class Solution { public:int maxArea(vector<int>& height){int n…

SQLite数据库文件损坏的可能几种情况(一)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;十三&#xff09; 下一篇&#xff1a;SQLite使用的临时文件&#xff08;二&#xff09; 概述 SQLite数据库具有很强的抗损坏能力。如果应用程序崩溃&#xff0c…

如何在内网访问其他电脑?

网络的发展使得人与人之间的通信变得更加便捷&#xff0c;而在公司或者家庭中&#xff0c;也经常遇到需要内网访问其他电脑的需求。内网访问其他电脑可以实现在局域网内部进行数据共享、文件传输、远程控制等操作&#xff0c;提高工作效率和便利性。本文将介绍内网访问其他电脑…

labelImg | windows anaconda安装labelImg

labelImg 是图片标注软件&#xff0c;用于数据集的制作、标注等等。 下面介绍 labelImg 的安装过程。 用的是 anaconda&#xff0c;所以以 anaconda prompt 作为终端&#xff1a; 在 Anaconda Prompt 中依次运行以下命令&#xff08;注意大小写&#xff09;&#xff1a; pi…