Redis线程模型
⼀、Redis是什么?
Redis 全称 REmote DIctionary Server,远程字典服务,是⼀个完全开源的,⾼性能的Key-Value数据库。官网地址: https://redis.io/。
核心总结:
-
数据结构复杂
Redis相⽐于传统的K-V型数据库,能够⽀撑更更复杂的数据类型。这意味着Redis 已经远远超出了缓存的范围,可以实现很多复杂的业务场景。并且还在不断发展更多的业务场景。 -
数据保存在内存,但是持久化到硬盘
数据全部保存在内存,意味着Redis进⾏数据读和写的性能⾮常⾼。是集中式缓存的不⼆之选数据持久化到硬盘,意味着Redis上保存的数据是⾮常安全的。⽬前Redis完全可以当做⼀个数据库来⽤。
所以,官⽅对Redis的作用,也已经定位成了三个方面:Cache(缓存),Database(数据库),Vector Search(向量搜索)。
⼆、Redis到底是单线程还是多线程?
整体来说,Redis的整体线程模型可以简单解释为客户端多线程,服务端单线程。
Redis为了能够与更多的客户端进行连接,还是使⽤的多线程来维护与客户端的Socket连接。但是,在服务端,Redis响应网络IO和键值对读写的请求,则是由⼀个单独的主线程完成的。Redis基于epoll实现了IO多路复⽤,这就可以⽤⼀个主线程同时响应多个客户端Socket连接的请求。
三、Redis如何保证指令原⼦性
1、复合指令
Redis内部提供了很多复合指令,他们是⼀个指令,可是明显干着多个指令的活。比如 MSET(HMSET)、GETSET、SETNX、SETEX。这些复合指令都能很好的保持原子性。
2、Redis事务
像MySQL⼀样,Redis也提供了事务机制。
127.0.0.1:6379> help @transactions
DISCARD (null) -- 放弃事务
summary: Discards a transaction.
since: 2.0.0
EXEC (null) -- 执⾏事务
summary: Executes all commands in a transaction.
since: 1.2.0
MULTI (null) -- 开启事务
summary: Starts a transaction.
since: 1.2.0
UNWATCH (null) --去掉监听
summary: Forgets about watched keys of a transaction.
since: 2.2.0
WATCH key [key ...] --监听某⼀个key的变化。key有变化后,就执⾏当前事务
summary: Monitors changes to keys to determine the execution of a
transaction.
since: 2.2.0
Redis的事务并不是像数据库的事务那样,保证事务中的指令⼀起成功或者⼀起失败。Redis的事务作用,仅仅只是保证事务中的原⼦操作是⼀起执行,而不会在执行过程中被其他指令加塞。
3、Pipeline(管道)
在Linux上编辑⼀个⽂件 command.txt。⽂件中可以包含⼀系列的指令。然后在客户端执行redis-cli指令时,就可以直接执行这个⽂件中的指令。
如果你有⼤批量的数据需要快速写⼊到Redis中,这种方式可以⼀定程度提⾼执行效率。核心作用:优化RTT(round-trip time)。
RTT:当客户端执行⼀个指令,数据包需要通过网络从Client传到Server,然后再从Server返回到Client。这个中间的时间消耗,就称为RTT(Rount Trip Time)。
Pipeline不具备原子性,它只是将多条命令发送到服务端,最终还是可能会被其他客户端的指令加塞的,虽然这种概率通常⽐较⼩。所以在Pipeline中通常不建议进行复杂的数据操作。Pipeline机制适合做⼀些在⾮热点时段进行的数据调整任务。
4、lua脚本
lua是⼀种小巧的脚本语言,他拥有很多高级语言的特性。lua语言最⼤的特点是他的线程模型是单线程的模式。这使得lua天生就非常适合⼀些单线程模型的中间件。比如Redis,Nginx等都非常适合接入lua语言进行功能定制。所以,在Redis中执行一段lua脚本,天然就是原子性的。
EVAL script numkeys [key [key ...]] [arg [arg ...]]
script参数是⼀段Lua脚本程序,它会被运⾏在Redis服务器上下⽂中,这段脚本不必(也不应该)定义为⼀ 个Lua函数。
numkeys参数⽤于指定键名参数的个数。键名参数 key [key ...] 从EVAL的第三个参数开始算 起,表示在脚本中所⽤到的那些Redis键(key),这些键名参数可以在 Lua中通过全局变量KEYS数组,⽤1 为基址的形式访问( KEYS[1] ,KEYS[2] ,以此类推)。
在命令的最后,那些不是键名参数的附加参数 arg [arg ...] ,可以在Lua中通过全局变量ARGV数组访问, 访问的形式和KEYS变量类似( ARGV[1] 、 ARGV[2],诸如此类)。
在lua脚本中,可以使⽤redis.call函数来调⽤Redis的命令。
-- 调整1号商品的库存。如果库存⼩于10,就设置为10
eval "local initcount = redis.call('get', KEYS[1])
local a = tonumber(initcount)
local b = tonumber(ARGV[1])
if a >= b then redis.call('set', KEYS[1], a)
return 1 end
redis.call('set', KEYS[1], b)
return 0 " 1 "stock_1" 10
使⽤lua注意点
-
不要在Lua脚本中出现死循环和耗时的运算,否则redis会阻塞,将不接受其他的命令。相⽐之下,管道pipeline不会阻塞redis。
-
尽量使⽤只读脚本
只读脚本是Redis7中新增的⼀种脚本执行⽅法,表示那些不修改Redis数据集的只读脚本。需要在脚本上加上⼀个只读的标志,并通过指令EVAL_RO触发。在只读脚本中不允许执行任何修改数据集的操作,并且可以随时使⽤SCRIPT_KILL指令停⽌。使⽤只读脚本的好处⼀⽅⾯在于可以限制某些⽤户的操作。另⼀⽅⾯,这些只读脚本通常都可以转移到备份节点执行,从⽽减轻Redis的压⼒。 -
热点脚本可以缓存到服务端
四、Redis高性能体现
Redis 的高性能可以概括为:基于内存的闪电级存储,结合单线程与多路复用的高效调度,辅以精雕细琢的数据结构实现,并通过子进程与渐进式算法避免了重量级操作对主线程的影响。
1.纯内存操作
-
数据存储位置:Redis 的所有数据都存储在内存中,而传统数据库(如 MySQL)的数据主要存储在磁盘上。
-
读写速度差异:内存的读写速度通常在纳秒级,而磁盘的读写速度在毫秒级。内存的访问速度比磁盘快几个数量级,避免了磁盘 I/O 带来的巨大延迟。
2.高效的数据结构
Redis 不仅仅是一个简单的 Key-Value 存储,它针对不同的业务场景设计了多种底层高效的数据结构。
-
多样化的数据结构:提供了 String(字符串)、Hash(哈希)、List(列表)、Set(集合)、Sorted Set(有序集合)等。
-
底层编码优化:Redis 会根据存储数据的大小和数量,动态选择最节省内存且访问速度最快的底层编码方式。例如,对于较小的 Hash 表,它会使用压缩列表
ziplist,而非哈希表,从而减少内存碎片和指针跳转。
3.单线程模型(核心处理逻辑)
虽然 Redis 6.0 之后引入了多线程处理网络 I/O,但其核心的数据处理逻辑(执行命令)仍然是单线程的。
-
避免上下文切换:没有多线程的竞争和锁竞争(如无死锁问题),也就没有线程上下文切换带来的 CPU 开销。
-
无锁数据结构:因为单线程,所以不需要复杂的锁机制来保护数据,这使得数据操作极其快速。
-
简化设计:基于单线程和 I/O 多路复用,Redis 内部实现简洁高效。
4.I/O 多路复用机制
Redis 在网络 I/O 处理上采用了 I/O 多路复用技术(如 epoll 在 Linux 上的实现)。
-
原理:允许单个线程同时监听多个网络连接的读写事件。
-
效果:这种机制让 Redis 能够高效处理成千上万个客户端连接,避免了传统的“一个连接一个线程”模式带来的高内存占用和高上下文切换成本,使得它在高并发场景下表现卓越。
5.优秀的持久化机制(兼顾性能与安全)
虽然持久化涉及磁盘操作,但 Redis 的设计尽量减少了对性能的影响。
-
RDB(快照):通过 fork 子进程来执行持久化,主进程继续处理命令,子进程负责将内存数据写入磁盘,实现了读写分离。
-
AOF(追加日志):通过 appendfsync 策略(如 everysec),可以将磁盘同步频率控制在每秒一次,既保证了数据安全,又最大限度减少了对主线程的阻塞。
6.渐进式 Rehash
当哈希表(Hash Table)中的键值对越来越多时,Redis 需要进行扩容(rehash)。
-
与很多传统数据库一次性完成全部 rehash 导致长时间卡顿不同,Redis 采用渐进式 rehash。
-
它将 rehash 的操作分散到对哈希表的每一次增、删、改、查操作中,每次只迁移一小部分数据,从而避免了服务阻塞,保证了性能的稳定性。
在标准硬件环境下,Redis 的单机 QPS(每秒查询率)通常可以达到 10万+,读写延迟通常控制在亚毫秒级别(0.5ms - 1ms),这使得它非常适合缓存、实时计数器、消息队列、分布式锁等高吞吐、低延迟的应用场景。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)