【复习】Redis

数据结构

Redis常见的数据结构

  • String:缓存对象
  • Hash:缓存对象、购物车
  • List:消息队列
  • Set:点赞、共同关注
  • ZSet:排序

Zset底层?

Zset底层的数据结构是由压缩链表或跳表实现的

  • 如果有序集合的元素 < 128,并且每个元素 < 64字节时,会用压缩列表作为Zset类型的底层数据结构
  • 如果有序集合的元素不满足上面的条件,会用跳表作为Zset类型的底层数据结构

跳表是怎么实现的?

请添加图片描述

跳表在创建节点时,随机生成每个节点的层数。

跳表在创建节点时,先生成[0, 1]的随机数,如果随机数 < 0.25,层数就会增加一层;然后继续生成下一个随机数,直到随机数 > 0.25结束,最终确定该节点的层数

为什么Zset使用跳表而不是B+树?

  1. B+树的设计目标是优化磁盘,通过减少树的高度来降低磁盘寻道次数;跳表是基于链表,通过多级索引加速查询,内存访问模式更符合CPU缓存局部性。Redis是内存数据库,数据完全存储在内存中,不需要优化磁盘IO,B+树的磁盘特性对Redis意义不大,跳表的设计更优
  2. 跳表相比B+树实现起来更简单,B+树插入和删除可能需要触发节点的分裂和合并,跳表插入时只需要随机生成层高,删除时直接移除节点并调整指针即可。
  3. B+树每个节点需要存储多个键值和叶子节点,存在内存碎片;跳表每个节点只需要存储键值、层高、多个前向指针,内存占用更紧凑。

压缩列表是怎么实现的?

压缩列表是由连续内存块组成的顺序型数据结构,类似数组。

  • 查找第一个元素和最后一个元素时间复杂度:O(1)
  • 查找其他元素:只能逐个查找,复杂度O(n)

压缩列表的缺点:会发生连锁更新,导致压缩列表占用的内存空间要多次重新分配,这回直接影响到压缩列表的访问性能。

压缩列表只适合保存数据量不多的场景。

quicklist和listpack这两种数据结构就是为了尽可能地保持压缩列表节省内存的优势

哈希表怎么扩容的?

在正常服务请求阶段,插入的数据都会写到哈希表1中,此时哈希表2没有被分配空间,随着数据量的增多,触发了rehash操作:

  1. 给哈希表2分配空间,一般比哈希表1大2倍
  2. 将哈希表1的数据移动到哈希表2中
  3. 迁移完成后,把哈希表1的空间释放,并把哈希表2设置为哈希表1,在哈希表1新创建一个空白的哈希表,为下次rehash做准备。

存在问题:如果哈希表1非常大,那么每次迁移到哈希表2的时候,可能会对redis造成阻塞,无法响应其他请求。

解决:在rehash进行期间,每次进行新增、删除、查找操作,redis除了操作哈希表1,还会操作redis2,这样就把一次大量数据的迁移工作分摊到了多个请求中。

注:哈希表扩容时,如果来了一个读请求,会现在哈希表1里查找;如果没找到,才会到哈希表2里查找。

String是用什么存储的?为什么不用c语言的字符串?

redis中的string字符串使用SDS数据结构存储的,SDS结构如下:

  • len:记录了字符串的长度
  • alloc:分配给字节数组的空间长度
  • flags:用来表示不同类型的SDS(sdshdr5、sdshdr8、sdshdr16、sdshdr32、sdshdr64)
  • buf[]:字符数组,用来保存实际数据

SDS数据结构可以O(1)获取字符串长度,c语言的字符串需要O(n)

SDS不需要"\0"来表示字符串结尾,有个len来记录字符串的长度(但是她为了兼容部分c的库函数,还是加了"\0")

C语言的字符串在追加的时候是不安全的,程序内部不会判断缓冲区大小是否够用,当缓冲区发生溢出后会导致程序异常;SDS结构里加入alloc和len,这样可以通过alloc - len来判断剩余缓冲区的大小,当缓冲区大小不够用时,redis会自动扩大SDS的空间大小。

线程模型

Redis为什么快?

单线程的redis吞吐量可以达到10w/s

  1. Redis大部分的操作都在内存中完成的,redis的瓶颈可能是机器的内存或网络带宽而非CPU
  2. Redis采用单线程模型可以避免多线程之间的竞争,省去了多线程切换带来的开销
  3. Redis采用IO多路复用机制处理大量客户端的Socket请求,在只运行单线程的情况下,该机制允许内核同时存在多个监听Socket和已连接Socket。

Redis的单线程指的是”接收客户端请求 -> 解析请求 -> 进行读写数据操作 -> 发送数据给客户端“这个过程是一个线程完成的,但是Redis程序不是单线程的,Redis在启动时,会启动后台线程

关闭文件、AOF刷盘、释放内存这些任务会创建单独的线程来处理,如果放在主线程来处理,Redis主线程就会发生阻塞。

Redis6也采用多个IO线程来处理网络请求,因为随着硬件的升级,Redis的性能瓶颈出现在网络IO的处理上

Redis怎么实现IO多路复用

因为Redis是单线程的,所有的操作都是按顺序进行,由于读写操作等待用户的输入和输出都是阻塞的,IO多路复用就是为了单线程的服务同时处理多个客户端的请求。

多路:指多个网络连接客户端

复用:指复用同一个进程

IO多路复用是使用一个线程来检查多个Socket的就绪状态,在单个线程中通过记录跟踪每个Socket的状态来管理处理多个IO流

日志

Redis的持久化方式?

Redis的读写操作都是发生在内存的,但是redis重启后,内存中的数据就会丢失,为了保证内存中的数据不丢失,就需要持久化机制,把数据存储到磁盘,这样Redis重启后就能从磁盘中恢复数据,Redis主要有两种持久化方式,分别是:

  1. AOF日志:每执行一条写操作,就会把该命令以追加的方式写入文件中,redis重启时,会逐一执行这个文件里的命令将数据恢复。redis由三种写回磁盘的策略:

    • Always:每次写操作命令执行完后,同步将AOF日志数据写回磁盘
    • Everysec:每次写操作命令执行完后,先将命令写到缓冲区中,再每隔一秒将数据写回磁盘
    • No:Redis不控制写回磁盘的时机,交给操作系统控制,每次写操作后先将命令写到缓冲区,由操作系统决定何时将命令写回磁盘。
  2. RDB快照:RDB快照只记录一瞬间的内存数据,记录的是实际的数据。Redis有两个命令来生成RDB快照:

    • save命令:在主线程中生成RDB文件(会阻塞主线程)
    • bgsave命令:创建一个子线程来生成RDB文件(避免阻塞主线程)

AOF日志记录的是操作命令,用AOF做故障恢复时,需要全量把日志全部执行一遍,一旦AOF日志非常多,会造成Redis恢复操作慢。所以引入了RDB快照(记录一瞬间的内存数据,记录的是实际数据,AOF文件记录的是命令操作的日志,而不是实际数据)

内存淘汰和过期删除

内存淘汰和过期删除的区别?

内存淘汰是在内存满时会触发内存淘汰策略来淘汰一些不必要的资源

过期删除是将已过期的键值对进行删除

内存淘汰策略有哪些?

内存淘汰:当Redis内存达到设置的阈值时,Redis就会主动挑选部分key删除以释放更多的内存。

Redis在每次处理客户端命令时,都会对内存使用情况判断,如果必要,则执行内存淘汰。内存淘汰的策略有:

  1. 前缀:
    • allkeys:对所有的key进行淘汰,从dict的哈希表中挑选
    • volatile:只对设置了TTL的key进行淘汰,从expires的哈希表中挑选
  2. 后缀:
    • ttl:淘汰ttl小的
    • random:随机挑选
    • lru:基于LRU算法
    • lfu:基于LFU算法

过期删除策略?

redis的失效缓存不会立即删除,而是使用惰性删除 + 定期删除这两种策略配合

  1. 惰性删除:在访问或修改key时,判断key是否过期,如果过期就删除key;如果没有过期,就不做处理,返回正常的键值对
  2. 定期删除:每隔一段时间随机从数据库中取出一部分key进行检查,删除过期的key,如果过期的key≥选举的key的四分之一,则再次选取,直到<四分之一,这个过程可能会很长时间,所以需要设置循环的上限。

集群

Redis主从同步

  1. 全量同步:以下情况会发生全量同步

    • 主从集群首次建立连接
    • 从服务器断开连接时间过长

    步骤:

    1. 从服务器发送SYNC命令,开始请求同步
    2. 主服务器收到SYNC命令后,生成RDB快照,并将生成的RDB文件发送到从服务器中
    3. 从服务器收到RDB文件后,先清空当前的数据集,并载入RDB文件中的数据
    4. 在RDB文件传输的过程中,如果又有新的指令,主服务器会将新的指令先放在缓冲区中,一旦RDB文件传输完成,主服务器又会将缓冲区里的命令发给从服务器,保证数据的一致性。
  2. 增量同步:允许从服务器从断点处继续同步

    步骤:

    1. 从服务器在网络恢复后,发送psync命令
    2. 主服务器收到psync命令后,告诉从服务器接下来要用增量同步的方式同步数据
    3. 主服务器将从服务器断开这段时间内执行的命令,发送给从服务器。

    (断开这段时间内执行的命令会存在主服务器的环形缓冲区中,主要存放的是最近传播的写命令,如果缓冲区里的一部分数据还没同步给从服务器,就已经被覆盖了,主服务器就会再次采取全量同步)

哨兵机制的原理?

redis的主从集群中,主从模式是读写分离的,如果主节点挂了,需要选择一个主节点变成从节点,如果没有哨兵机制,那么只能人工选择一个主节点变成从节点,还要通知其他从节点现在主节点的变更。

哨兵机制主要是实现了主从节点的故障转移,他会检测主节点是否存活,如果主节点挂了,就会选取一个从节点当成主节点,并且把新的主节点信息通知给其他的从节点。

哨兵机制选择主节点的算法?

  1. 故障节点主观下线:哨兵节点会定时对redis集群里的所有节点发送心跳包检测节点是否正常,如果一个节点没有恢复哨兵节点的心跳包,则认为该节点主观下线

  2. 故障节点客观下线:当一个节点被标记成故障,不代表这个节点下线了,但是如果哨兵集群中有超过quorum数量的哨兵节点认为该redis节点主观下线,则该redis客观下线

    如果下线的redis节点是从节点或哨兵节点,则没有后续操作了;如果是主节点,则开始故障转移,从剩下的从节点中选出一个节点升级为主节点

  3. 哨兵集群中选择Leader:要从redis集群中选择一个节点变成主节点,必须先从哨兵节点中选取leader,一个哨兵节点至少要拿到quorunm个赞成票,才能成为Leader

  4. 哨兵Leader选择新主节点:哨兵Leader从redis从节点中选择一个redis节点作为主节点

    • 首先判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点。
    • 然后判断slave节点的slave-priority值,值越小优先级越高。(如果是0则用不参与选举,默认是0)
    • 如果slave-priority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高。
    • 最后是判断slave节点的运行id大小,越小优先级越高。

Redis集群的模式?

Redis缓存数据量大到一台服务器无法缓存时,就需要使用Redis切片集群,将数据分布在不同的服务器上,降低对单主节点的依赖。

一个切片有16384个哈希插槽,这些哈希插槽类似数据分区,根据他的key被映射到一个哈希槽中。

场景

为什么使用Redis

  1. Redis具备高性能:如果用户第一次访问Mysql中的某些数据,这个过程比较慢,因为是从磁盘上读取的;如果将该用户的数据缓存在Redis中,下次在访问这些数据的时候就可以直接从Redis中读取了,操作Redis缓存就是直接操作内存,速度快。【需要考虑Mysql和Redis中的数据一致性】
  2. Redis具备高并发:单台Redis的QPS是Mysql的10倍,所以访问Redis能承受的请求远远大于Mysql,因此可以考虑将数据库中一部分数据缓存到Redis中,这样就不需要每次请求都到数据库中查了。

为什么Redis比Mysql快?

  1. Redis是基于内存存储、Mysql是基于磁盘存储
  2. Redis是基于键值对结构,支持简单的数据结构;Mysql需要定义表结构、索引等复杂的数据结构
  3. Redis采用单线程可以避免多线程之间的竞争,省去了多线程切换带来的开销。

本地缓存和分布式缓存的区别

本地缓存:将数据存储在本地应用程序或服务器上,用于加速数据访问,本地缓存通常是使用内存作为存储介质,利用内存的高速读写来提高访问速度。

本地缓存:由于本地缓存是存储在本地内存中,访问速度快,而且能够降低对远程服务器的访问次数;但是本地缓存的可扩展性收到硬件资源的限制,无法支持大规模的数据存储。

分布式缓存:将数据存储在多个分布式节点上,通过协同工作来提供高性能的数据访问服务,利用多台服务器来分担数据存储和访问的压力。

分布式缓存:节点可以动态扩展,能够支持大规模数据存储和访问的需求;但是相对本地缓存,分布式存储的访问速度相对慢,因为数据需要从多个节点进行访问,且需要通过网络进行数据传输。

Redis分布式锁的实现原理?

分布式锁是分布式环境下并发控制的一种机制,用来控制某个资源在同一时刻只能被一个应用使用。

Redis本身可以被多个客户端共享,可以用来保存分布式锁,而且Redis的读写性能高,可以应对高并发锁的场景。

redis的set命令有个nx参数可以实现”key不存在时插入“,所以可以使用它实现分布式锁:

  • 如果key不存在,则表示插入成功(加锁成功)
  • 如果key存在,则表示插入失败(加锁失败)

加锁的操作要注意:

  1. 加锁包括了:读取锁变量、检查锁变量值、设置锁变量三个操作,需要以原子操作的方式完成,所以使用set命令要带上nx选项来实现加锁。
  2. 锁变量需要设置过期时间,以免客户端拿到锁后发生异常,导致锁一直无法释放
  3. 锁变量的值需要能够区分来自不同客户端的加锁操作。

大Key问题?

字符串类型的Key对应的Value值占用空间很大就是大Key问题

大Key问题会导致:内存占用过高,从而触发内存淘汰策略;大Key会占用大量内存,导致性能下降;会造成网络拥堵;会导致主从同步延迟

解决:

  1. 对大Key进行拆分,将一个含有数万成员的hashkey拆分成多个hashkey;
  2. 将不适用Redis的数据移到别的地方存储,并在Redis中异步删除这个数据

什么是热key?

一般是以key的请求频率来判断的,例如:

  1. QPS集中在特定的key
  2. 带宽使用率集中在特定的Key
  3. CPU使用时间占比集中在特定的Key

解决:

  1. 将对应的热ky进行复制并迁移到其他的数据分片,来解决单个数据分片的热key压力
  2. 如果热key的产生来自读请求,可以使用读写分离架构来降低每个数据分片的读请求,也可以不断增加从节点。

怎么保证redis和mysql数据缓存的一致性?

  1. 对于读数据,如果redis不命中,会先去数据库中查询后加载到redis中
  2. 对于写数据,会更新数据库后去删除缓存

缓存系统就是CAP中的AP,通过牺牲强一致性来提高性能,如果需要数据库和缓存保持强一致性,就不适合用缓存。

缓存的过期时间设置是太短、太长都不好:

  • 太短的话,请求可能会比较多的落在数据库上,就失去了缓存的意义
  • 太长的话,缓存中的脏数据会让系统长时间处于一个延迟的状态,会浪费内存。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

我与Linux的爱恋:了解信号量+共享内存+消息队列的应用

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;Linux的学习 文章目录 信号量共享内存应用---Server&Client通信client.ccserver.ccnamepipe.hppShm.hpp 消息队列——实现Client&ServerCom.hppClient.ccServer.cc 信号量 信号量…

跟着李沐老师学习深度学习(十六)

继续学习深度学习&#xff08;十六&#xff09; 继续理解transformer 对于transformer的理解感觉还是云里雾里的&#xff0c;今天又找了一些视频进行一个梳理。 一个浅解 在B站学习发现评论区真的很不错&#xff0c;在沐神讲transformer论文的评论下&#xff0c;有一个评论…

DeepSeek-R1本地部署保姆级教程

一、DeepSeek-R1本地部署配置要求 &#xff08;一&#xff09;轻量级模型 ▌DeepSeek-R1-1.5B 内存容量&#xff1a;≥8GB 显卡需求&#xff1a;支持CPU推理&#xff08;无需独立GPU&#xff09; 适用场景&#xff1a;本地环境验证测试/Ollama集成调试 &#xff08;二&a…

hbase集群部署

1.hbase集群的搭建&#xff08;以及内部逻辑&#xff09; 虽然Hmaster有多个&#xff0c;但是属于热备&#xff0c;起作用的就active上的这个。 部署流程&#xff1a; 因为我配置的hadoop是一个非HA的&#xff0c;所以修改为以下 如果是HA的hadoop一定要做以下这一步。 在启动…

2.1 链路层发现协议(LLDP)

LLDP&#xff08;Link Layer Discovery Protocol&#xff0c;链路层发现协议&#xff09;是一种用于网络设备的链路层协议&#xff0c;用于在局域网&#xff08;LAN&#xff09;中自动发现和通告设备的信息。LLDP是一个开放标准协议&#xff0c;定义在IEEE 802.1AB中&#xff0…

3dtiles平移旋转工具制作

3dtiles平移旋转缩放原理及可视化工具实现 背景 平时工作中&#xff0c;通过cesium平台来搭建一个演示场景是很常见的事情。一般来说&#xff0c;演示场景不需要多完善的功能&#xff0c;但是需要一批三维模型搭建&#xff0c;如厂房、电力设备、园区等。在实际搭建过程中&…

LeetCode 2506 统计相似字符串对的数目

一、问题描述 我们面对的问题是处理一个下标从 0 开始的字符串数组 words。题目中定义了一种字符串相似的规则&#xff1a;如果两个字符串由相同的字符组成&#xff0c;那么就认为这两个字符串是相似的。例如&#xff0c;"abca" 和 "cba" 是相似的&#xf…

【Deepseek高级使用教程】Deepseek-R1的5种高级进阶玩法,5分钟教会你Deepseek+行业的形式进行工作重构的保姆级教程

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频https://aitools.jurilu.com/ 最近&#xff0c;有各行各业的小伙伴问我&#xff0c;到底应该怎么将deepseek融入进他们自身的工作流呢&#xff1f;其实这个问题很简单。我就以…

【LeetCode刷题之路】leetcode155.最小栈

LeetCode刷题记录 &#x1f310; 我的博客主页&#xff1a;iiiiiankor&#x1f3af; 如果你觉得我的内容对你有帮助&#xff0c;不妨点个赞&#x1f44d;、留个评论✍&#xff0c;或者收藏⭐&#xff0c;让我们一起进步&#xff01;&#x1f4dd; 专栏系列&#xff1a;LeetCode…

Linux版本控制器Git【Ubuntu系统】

文章目录 **前言**一、版本控制器二、Git 简史三、安装 Git四、 在 Gitee/Github 创建项目五、三板斧1、git add 命令2、git commit 命令3、git push 命令 六、其他1、git pull 命令2、git log 命令3、git reflog 命令4、git stash 命令 七、.ignore 文件1、为什么使用 .gitign…

2025年信息科学与工程学院科协机器学习介绍——机器学习基本模型介绍

机器学习 目录 机器学习一.安装基本环境conda/miniconda环境 二.数据操作数据预处理一维数组二维数组以及多维数组的认识访问元素的方法torch中tenson的应用张量的运算张量的广播 三.线性代数相关知识四.线性回归SoftMax回归问题&#xff08;分类问题&#xff09;什么是分类问题…

pyecharts介绍

文章目录 介绍安装pyecharts基本使用全局配置选项 折线图相关配置地图模块使用柱状图使用 介绍 echarts虑是个由百度开源的数据可视化&#xff0c;凭借着良好的交互性&#xff0c;精巧的图表设计&#xff0c;得到了众多开发者的认可&#xff0c;而Pyhon是门富有表达力的语言&a…

蓝桥杯——lcd显示

一&#xff1a;复制文件 从官方参考文件中复制相关文件&#xff0c;Src中的lcd.c&#xff0c;Inc中的lcd.h&#xff0c;fonts.h复制到自己创建的文件中 二&#xff1a;lcd初始化 在lcd.h中找到四个初始化函数&#xff0c;将其写到main文件中 三&#xff1a;写lcd显示函数 在…

ligerUI在前端层面对于数据的验证拦截

当你的系统框架采用ligerUI的时候&#xff0c;对于常见的数据验证&#xff0c;我们可以采取ligerUI本身的一些API调用来进行前端的数据验证&#xff0c;例如当你想遍历验证每行数据的时候&#xff1a; var rows liger.get("edit_Mtl").getData(); for (var i 0; i…

ubuntu-24.04.1-desktop 中的 QT6.7 QtCreator 调试程序

ubuntu-24.04.1-desktop 中的 QT6.7 QtCreator 中调试程序 &#xff11; 启动调试时提示&#xff1a;The kit does not have a debugger set.&#xff12; CDB配置问题&#xff12;.1 选择 工具 -> 外部 -> 配置&#xff12;.2 配置 CDB 路径 &#xff11; 启动调试时提示…

VSCode ssh远程连接内网服务器(不能上网的内网环境的Linux服务器)的终极解决方案

VSCode ssh远程连接内网服务器&#xff08;不能上网的内网环境的Linux服务器&#xff09; 离线下载vscode-server并安装: 如果远程端不能联网可以下载包离线安装,下载 vscode-server 的 url 需要和 vscode 客户端版本的 commit-id 对应.通过 vscode 面板的帮助->关于可以获…

【C语言基础】基本数据类型和常量介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 博客内容主要围绕&#xff1a; 5G/6G协议讲解 高级C语言讲解 Rust语言讲解 文章目录 基本数据类型和常量介绍一、整数类型 int二、浮点数值类型 f…

【Deepseek】AnythingLLM + Ollama

1. 下载安装 anythingllm 下载地址&#xff1a;https://anythingllm.com/desktop 2. 启动anything 点击 Get started 3.创建工作空间 4.选择Ollama大语言模型 聊天设置 当前只有一个1.5b的模型 下载完成7b模型后 选择后记得点击更新到工作空间&#xff01;&…

vscode settings(一):全局| 用户设置常用的设置项

参考资料 Visual Studio Code权威指南 by 韩骏 一. 全局设置与用户设置 1.1 Vscode支持两种不同范围的设置 用户设置(User Settings)&#xff1a;这是一个全局范围的设置&#xff0c;会应用到所有的Visual Studio Code实例中。工作区设置(Workspace Settings)&#xff1a;设…

Deepseek和Grok 3对比:写一段冒泡排序

1、这是访问Grok 3得到的结果 2、grok3输出的完整代码&#xff1a; def bubble_sort(arr):n len(arr) # 获取数组长度# 外层循环控制排序轮数for i in range(n):# 内层循环比较相邻元素&#xff0c;j的范围逐渐减少for j in range(0, n - i - 1):# 如果当前元素大于下一个元…