Redis原理详解

article/2025/11/2 6:33:23

目录

1、什么是redis

2、为什么会出现redis

3、应用场景 

 4、架构原理

5、IO多路复用机制

6、redis为什么快

7、redis 数据淘汰策略

8、数据类型以及使用场景

9、持久化流程

10、常见问题解决方案


1、什么是redis

  • Redis是一个开源key-value存储系统。
  • 和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。
  • 这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。
  • 在此基础上,Redis支持各种不同方式的排序
  • 与memcached一样,为了保证效率,数据都是缓存在内存中。
  • 区别的是Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。
  • 并且在此基础上实现了master-slave(主从)同步。

2、为什么会出现redis

Web1.0的时代,数据访问量很有限,用一夫当关的高性能的单点服务器可以解决大部分问题。

随着Web2.0的时代的到来,用户访问量大幅度提升,同时产生了大量的用户数据。加上后来的智能移动设备的普及,所有的互联网平台都面临了巨大的性能挑战。

解决cpu及内存压力

 解决IO压力

NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,泛指非关系型的数据库

NoSQL 不依赖业务逻辑方式存储,而以简单的key-value模式存储。因此大大的增加了数据库的扩展能力。

  1. 不遵循SQL标准。
  2. 不支持ACID。
  3. 远超于SQL的性能。
  4. 对数据高并发的读写
  5. 海量数据的读写
  6. 对数据高可扩展性的。

所以出现了内存数据库,如redis,memcache、mongoDB等。 

3、应用场景 

1、配合关系型数据库做高速缓存

  • 高频次,热门访问的数据,降低数据库IO
  • 分布式架构,做session共享

多样的数据结构存储持久化数据

 

 4、架构原理

Redis 组件的系统架构如图所示,主要包括事件处理、数据存储及管理、用于系统扩展的主从复制/集群管理,以及为插件化功能扩展的 Module System 模块。

事件处理机制

Redis 中的事件处理模块,采用的是作者自己开发的 ae 事件驱动模型,可以进行高效的网络 IO 读写、命令执行,以及时间事件处理。

其中,网络 IO 读写处理采用的是 IO 多路复用技术,通过对 evport、epoll、kqueue、select 等进行封装,同时监听多个 socket,并根据 socket 目前执行的任务,来为 socket 关联不同的事件处理器。

当监听端口对应的 socket 收到连接请求后,就会创建一个 client 结构,通过 client 结构来对连接状态进行管理。在请求进入时,将请求命令读取缓冲并进行解析,并存入到 client 的参数列表。

然后根据请求命令找到 对应的redisCommand ,最后根据命令协议,对请求参数进一步的解析、校验并执行。Redis 中时间事件比较简单,目前主要是执行 serverCron,来做一些统计更新、过期 key 清理、AOF 及 RDB 持久化等辅助操作。

数据管理

redis 的内存数据都存在 redisDB 中。Redis 支持多 DB,每个 DB 都对应一个 redisDB 结构。Redis 的 8 种数据类型,每种数据类型都采用一种或多种内部数据结构进行存储。同时这些内部数据结构及数据相关的辅助信息,都以 kye/value 的格式存在 redisDB 中的各个 dict 字典中。

数据在写入 redisDB 后,这些执行的写指令还会及时追加到 AOF 中,追加的方式是先实时写入AOF 缓冲,然后按策略刷缓冲数据到文件。由于 AOF 记录每个写操作,所以一个 key 的大量中间状态也会呈现在 AOF 中,导致 AOF 冗余信息过多,因此 Redis 还设计了一个 RDB 快照操作,可以通过定期将内存里所有的数据快照落地到 RDB 文件,来以最简洁的方式记录 Redis 的所有内存数据。

Redis 进行数据读写的核心处理线程是单线程模型,为了保持整个系统的高性能,必须避免任何线程导致阻塞的操作。为此,Redis fock子线程,来处理容易导致阻塞的文件 close、fsync 等操作,确保系统处理的性能和稳定性。

在 server 端,存储内存永远是昂贵且短缺的,Redis 中,过期的 key 需要及时清理,不活跃的 key 在内存不足时也可能需要进行淘汰。为此,Redis 设计了 8 种淘汰策略,借助新引入的 eviction pool,进行高效的 key 淘汰和内存回收。

5、IO多路复用机制

简单来说,就是。我们的redis-client在操作的时候,会产生具有不同事件类型的socket。在服务端,有一段I/0多路复用程序,将其置入队列之中。然后,IO事件分派器,依次去队列中取,转发到不同的事件处理器中。 

我自己理解就是:

1、不同用户操作的时候会建立不同的socket。

2、在服务端,主线程会folck出多个子线程,这多个线程会不断的将用户的请求添加到队列中。所以是多路复用。

3、主线程在从队列中顺序取出请求交给事件处理器进行处理。

4、在这其中,真正对用户进行操作的是主线程,子线程只是负责运输用户请求而已,所以在redis处理层面,确实是主线程完成的数据处理。子线程不算在内,所以是redis操作是单线程操作。

6、redis为什么快

  • Redis是基于内存的操作,CPU不是Redis的瓶颈

  • 省去了很多上下文切换线程的时间,不用去考虑各种锁的问题

  • 多路I/O复用:使用了单线程来轮询描述符,减少了线程切换时上下文的切换和竞争

  • 能带来更好的可维护性,方便开发和调试

7、redis 数据淘汰策略

  • volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰

  • volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰

  • volatile-random:从已设置过期时间的数据集中任意选择数据淘汰

  • allkeys-lru:从所有数据集中挑选最近最少使用的数据淘汰

  • allkeys-random:从所有数据集中任意选择数据进行淘汰

  • noeviction:禁止驱逐数据 需要先设置最大内存maxmemory,然后如果内存不足,会触发我们选择的过期淘汰策略

分析:这个问题其实相当重要,到底redis有没用到家,这个问题就可以看出来。比如你redis只能存5G数据,可是你写了10G,那会删5G的数据。怎么删的,这个问题思考过么?还有,你的数据已经设置了过期时间,但是时间到了,内存占用率还是比较高,有思考过原因么?

redis采用的是定期删除+惰性删除策略。

为什么不用定时删除策略?
定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略.

定期删除+惰性删除是如何工作的呢?
定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。
于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。

采用定期删除+惰性删除就没其他问题了么?
不是的,如果定期删除没删除key。然后你也没及时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制

在redis.conf中有一行配置

# maxmemory-policy allkeys-lru

该配置就是配内存淘汰策略的(什么,你没配过?好好反省一下自己)
1)noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。应该没人用吧。
2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。推荐使用。
3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。应该也没人用吧,你不删最少使用Key,去随机删。
4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。这种情况一般是把redis既当缓存,又做持久化存储的时候才用。不推荐
5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。依然不推荐
6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。不推荐
ps:如果没有设置 expire 的key, 不满足先决条件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行为, 和 noeviction(不删除) 基本上一致。 

8、数据类型以及使用场景

1、String
这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。

2、list
使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。

3、set
因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。
另外,就是利用交集、并集、差集等操作

4、sorted set

sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。另外,参照另一篇《分布式之延时任务方案解析》,该文指出了sorted set可以用来做延时任务。最后一个应用就是可以做范围查找

5、hash
这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。

9、持久化流程

1.RDB(默认开启) 

按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb;如果系统发生故障,将会丢失最后一次创建快照之后的数据。

save 900 1

save 300 10

save 60 10000

保存流程(BGSAVE)

需要注意的是:

  • RDB写入,每次都是全量,在数据量特别大时,服务器负载会比较高

  • RDB会在服务器宕机时,丢失几分钟的数据,主要是根据save策略来的。

2.AOF

配置文件

appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

重写流程

需要注意的是:

  • 重写是直接把当前内存的数据生成对应命令,不需要分析老的AOF文件;

  • 恢复数据时,会先判断有没有AOF,没有的话,在加载RDB,因为AOF文件相对完整;

10、常见问题解决方案

1、雪崩

现象:缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩(由于原有缓存失效,新缓存未到期间);

解决方案:
(一)给缓存的失效时间,加上一个随机值,避免集体失效。
(二)使用互斥锁,但是该方案吞吐量明显下降了。
(三)双缓存。我们有两个缓存,缓存A和缓存B。缓存A的失效时间为20分钟,缓存B不设失效时间。自己做缓存预热操作。然后细分以下几个小点

  • I 从缓存A读数据库,有则直接返回
  • II A没有数据,直接从B读数据,直接返回,并且异步启动一个更新线程。
  • III 更新线程同时更新缓存A和缓存B。

2、穿透

现象:查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义;

(一)利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试。
(二)采用异步更新策略,无论key是否取到值,都直接返回。value值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。也就是如果一个查询返回的数据为空,我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟;
(三)提供一个能迅速判断请求是否有效的拦截机制,比如,利用布隆过滤器,内部维护一系列合法有效的key。迅速判断出,请求所携带的Key是否合法有效。如果不合法,则直接返回。

3、击穿(热点Key)

现象:缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮;

解决方案:对缓存查询加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询;其实不现实。就是每次设置key的时候,就设置随机的过期时间。

4、如何解决redis的并发竞争key问题

分析:这个问题大致就是,同时有多个子系统去set一个key。这个时候要注意什么呢?大家思考过么。需要说明一下,博主提前百度了一下,发现答案基本都是推荐用redis事务机制。博主不推荐使用redis的事务机制。因为我们的生产环境,基本都是redis集群环境,做了数据分片操作。你一个事务中有涉及到多个key操作的时候,这多个key不一定都存储在同一个redis-server上。因此,redis的事务机制,十分鸡肋。

回答:如下所示
(1)如果对这个key操作,不要求顺序
这种情况下,准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可,比较简单。
(2)如果对这个key操作,要求顺序
假设有一个key1,系统A需要将key1设置为valueA,系统B需要将key1设置为valueB,系统C需要将key1设置为valueC.
期望按照key1的value值按照 valueA-->valueB-->valueC的顺序变化。这种时候我们在数据写入数据库的时候,需要保存一个时间戳。假设时间戳如下

系统A key 1 {valueA  3:00}
系统B key 1 {valueB  3:05}
系统C key 1 {valueC  3:10}

那么,假设这会系统B先抢到锁,将key1设置为{valueB 3:05}。接下来系统A抢到锁,发现自己的valueA的时间戳早于缓存中的时间戳,那就不做set操作了。以此类推。

其他方法,比如利用队列,将set方法变成串行访问也可以。总之,灵活变通。

5、双写一致性问题

读写过程

1、读:
(1)先读cache,如果数据命中则返回
(2)如果数据未命中则读db
(3)将db中读取出来的数据入缓存

在这里插入图片描述

 2、写:
(1)先淘汰cache
(2)再写db

6、数据不一致问题

先操作缓存,在写数据库成功之前,如果有读请求发生,可能导致旧数据入缓存,引发数据不一致。
  在分布式环境下,数据的读写都是并发的,上游有多个应用,通过一个服务的多个部署(为了保证可用性,一定是部署多份的),对同一个数据进行读写,在数据库层面并发的读写并不能保证完成顺序,也就是说后发出的读请求很可能先完成(读出脏数据)。
 

在这里插入图片描述

上图解析: 写操作先执行1,删除缓存,再执行2,更新db;而读操作先执行3,读取cache数据,未找到数据时执行4,查询db。
问题所在: 写操作2没执行完时,读操作4执行了,则读到了脏数据到cache中,造成了cache和db的数据不一致问题。

分析:一致性问题是分布式常见问题,还可以再分为最终一致性和强一致性。数据库和缓存双写,就必然会存在不一致的问题。答这个问题,先明白一个前提。就是如果对数据有强一致性要求,不能放缓存。我们所做的一切,只能保证最终一致性。另外,我们所做的方案其实从根本上来说,只能说降低不一致发生的概率,无法完全避免。因此,有强一致性要求的数据,不能放缓存。
回答:首先,采取正确更新策略,先更新数据库,再删缓存。其次,因为可能存在删除缓存失败的问题,提供一个补偿措施即可,例如利用消息队列。

解决方案
方案1:Redis设置key的过期时间。
方案2:采用延时双删策略。
(1)先淘汰缓存
(2)再写数据库(这两步和原来一样)
(3)休眠100毫秒,再次淘汰缓存
这么做,可以将100毫秒内所造成的缓存脏数据,再次删除。(为何是100毫秒?需要评估自己的项目的读数据业务逻辑的耗时。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。当然这种策略还要考虑redis和数据库主从同步的耗时。

方案3:

用阿里的Canal框架,监控数据库。

mysql会将操作记录在Binary log日志中,通过canal去监听数据库日志二进制文件,解析log日志,同步到redis中进行增删改操作。

canal的工作原理:canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议;MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal );canal 解析 binary log 对象(原始为 byte 流)。
 

111.png


http://chatgpt.dhexx.cn/article/juJT2ZUg.shtml

相关文章

Redis之父全力推荐,一份超完美深入浅出Redis实战书籍

Redis的由来 来自Reids之父的Salvatore Sanfilippo的自述。 Redis 是我在大约3年前为了解决一个实际问题而创造出来的:简单来说,当时我在尝试做一件使用硬盘存储关系数据库( on-disk SQL database )无法完成的事情——在一台我能够支付得起的小虚拟机上面…

Redis---初识redis

一.认识Redis Redis诞生于2009年,是一个基于内存的键值型NoSQL数据库 特征: 1.键值型,value支持多种不同数据结构,功能丰富 2.单线程,每个命令具有原子性 3.低延迟,速度快(基于内存,IO多路复用,良好的编码) 4.支持数据持久化 5.支持主从集群,分片集群 6.支持多语言客户端…

Redis学习笔记

感谢尚硅谷 视频地址:【尚硅谷】Redis 6 入门到精通 超详细 教程_哔哩哔哩_bilibili 一、Redis介绍 Redis 是一个开源的 key-value 存储系统。和 Memcached 类似,它支持存储的 value 类型相对更多,包括 string(字符串)、list(链表)、se…

学习Redis的一本好书: Redis Essentials

Redis key-value内存数据库的典型代表,为了了解Redis以及和其它内存数据库进行比较,决定找一本书系统的看一下。 在Amazon上考察了一下,决定就从Redis Essentials这本书入手。 接下来,我会逐章阅读,然后每章写一篇…

学了这篇redis从入门到精通,redis笔记全收录,必须收藏

大家好,给大家先做个自我介绍 我是码上代码,大家可以叫我码哥 我也是一个普通本科毕业的最普通学生,我相信大部分程序员或者想从事程序员行业的都是普通家庭的孩子,所以我也是靠自己的努力,从毕业入职到一家传统企业&a…

Redis详细教程

框架高级课程系列之Redis6 1 NoSQL数据库简介 1.1 技术发展 技术的分类1、解决功能性的问题:Java、Jsp、RDBMS、Tomcat、HTML、Linux、JDBC、SVN2、解决扩展性的问题:Struts、Spring、SpringMVC、Hibernate、Mybatis3、解决性能的问题:NoSQL…

Redis数据库系列(一)、Redis 入门

第一章、Redis 入门 1.1、Redis简介 问题现象 海量用户高并发(无法同时处理海量请求) 罪魁祸首——关系型数据库 性能瓶颈:磁盘IO性能低下扩展瓶颈:数据关系复杂,扩展性差,不便于大规模集群 解决思路…

如何学习Redis

掌握数据结构和缓存的基本使用方法 要想会用一种系统,我们首先要会一些基本操作。我们平时在开发业务系统时,或多或少地会把 Redis 当作数据库或缓存使用。Redis 也提供了非常丰富的数据结构,这也给我们的开发提供了极大的便利。 所以&…

Redis数据库✧入门篇

Redis数据库(入门篇) Redis数据库:非关系型数据库,即NoSql数据库,基于内存存储系统(内存磁盘),其中有常用的五个数据类型:String,Hash(键值对集合…

详细Redis入门教程

目录 1 Redis的前世今生 1.1 简介 1.2 应用场景 2 Redis下载及安装 2.1 下载及安装 3 Redis使用 3.1 数据类型 3.2 持久化 3.3 事务 3.4 脚本 语法 4 Redis集群 4.1 主从模式 4.2 Sentinel模式 1.哨兵模式集群架构 2.哨兵模式作用 3.哨兵模式工作过程 4.3 Cl…

Redis详解

转载:Redis 详解_罗志宏的博客-CSDN博客_redis详解 1. 什么是 Redis   Redis 是一个基于内存的高性能 key-value 数据库。是完全开源免费的,用C语言编写的,遵守BSD协议。 Redis 特点: Redis 是基于内存操作的,吞吐量…

Redis入门一:Redis实战读书笔记

Redis提供5种不同类型的数据结构,并存储键与5种不同类型的值之间的映射,各式各样的问题都可以自然地映射到这些数据结构上。通过复制、持久化和客户端分片等特性,可以将存储在内存的键值对数据持久化到硬盘,可以使用复制特性来扩展…

Redis数据库介绍

1 Redis简介 Redis,全称远程字典服务(REmote DIctionary Server),是一个开源、基于内存、高性能、可数据持久化的key-value存储系统,遵守BSD协议,可用作数据库、缓存和消息中间件。 在Redis中文官网上是这…

redis详解(全)

学前小故事 数据库和缓存保证一致性小故事 windows && linux 安装redis redis 持久化 redis API 学前小故事 [我是redis] 你好,我是Redis,一个叫Antirez的男人把我带到了这个世界上。 说起我的诞生,跟关系数据库MySQL还挺有渊…

Redis 详解

文章目录 Redisredis 简介1. Redis 中的事务1.1 什么是事务?1.2 Redis 中的事务是怎么实现的?1.3 Redis 事务为什么不支持回滚?1.3.1 语法错误情况下的事务回滚状态1.3.2 类型错误情况下的事务回滚状态1.3.3 Redis事务不回滚总结 2. Redis 中…

Redis该怎么学?其实很简单,这份学习路线+资料+书单我全部贡献出来了!

前言 这绝对不是一篇水文,进来的兄弟们千万不要白嫖,真香警告⚠️。(点赞!!!) 这篇文章很早前就打算写了,特地留到现在是因为我想把Redis系列的文章全部更完,能让需要的…

Redis入门官方文档

Redis资料 Redis官网:http://redis.io/ Redis官方文档:http://redis.io/documentation Redis教程:http://www.w3cschool.cn/redis/redis-intro.html Redis下载:http://redis.io/download redis英文文档 https://redis.io/topics/data-types redis中文文档 http://www.red…

Redis内存数据库必读的4本书

Redis从一个不为人熟知、只有少量应用的崭新数据库,逐渐变成了内存数据库领域的事实标准。时至今日,经过大量的实践应用,Redis简洁高效、安全稳定的特性已经深入人心。 无论是国内还是国外,从五百强公司到小型初创公司都在使用Re…

【好书推荐】Redis入门必备 | 《Redis实战》

一、Redis入门必备 你好,我是小雨青年,一名程序员。 今天为你推荐的书籍是《Redis实战》。 Redis作为一个内存数据库服务器,本书提供了大量讲解和用例。 本书的大部分用例是用Python编写的,希望你有一些Python语言基础。 本书…