Redis进阶一之深入理解Redis线程模型--重点笔记

一 redis优势

数据结构复杂
Redis相⽐于传统的K-V型数据库,能够⽀撑更更复杂的数据类型。这意味着Redis已经远远超出了缓存的范围,可以实现很多复杂的业务场景。并且还在不断发展更
多的业务场景。
 
数据保存在内存,但是持久化到硬盘
1,数据全部保存在内存,意味着Redis进⾏数据读和写的性能⾮常⾼。是集中式缓存的不⼆之选。
2,数据持久化到硬盘,意味着Redis上保存的数据是⾮常安全的。⽬前Redis完全可以当做⼀个数据库来⽤。
 

⼆、Redis到底是单线程还是多线程?

⾸先:整体来说,Redis的整体线程模型可以简单解释为 客户端多线程,服务端单线程
Redis为了能够与更多的客户端进⾏连接,还是使⽤的多线程来维护与客户端的Socket连接。在redis.conf中就有⼀个参数maxclients维护了最⼤的客户端连接数
其次,在服务端,Redis响应⽹络IO和键值对读写的请求,则是由⼀个单独的主线程完成的。Redis基于epoll实现了IO多路复⽤,这就可以⽤⼀个主线程同时响应多个
客户端Socket连接的请求。

image

 在这种线程模型下,Redis将客户端多个并发的请求转成了串⾏的执⾏⽅式。因此,在Redis中,完全不⽤考虑诸如MySQL的脏读、幻读、不可重复读之类的并发问

题。并且,这种串⾏化的线程模型,加上Redis基于内存⼯作的极⾼性能,也让Redis成为很多并发问题的解决⼯具。
重要的是,尤其在现在的Redis7.x版本中,Redis后端的很多⽐较费时的操作,⽐如持久化RDB,AOF⽂件、unlink异步删除、集群数据同步等,都是由额
外的线程执⾏的。例如,对于 FLUSHALL操作,就已经提供了异步的⽅式。
总结:Redis⼀直保持核⼼线程的单线程模型,其实是因为对于现代的Redis来说,CPU通常不会成为Redis的性能瓶颈。影响Redis的性能瓶颈⼤部分是内存和⽹
络。因此,核⼼线程改为多线程的要求并不急切。另外,Redis的这种单线程为主的⼯作机制还可以减少线程上下⽂切换的性能消耗。⽽且,如果Redis将核⼼
线程改为多线程并发执⾏,那么就必然带来资源竞争,反⽽会极⼤增加Redis的业务复杂性,影响Redis的业务执⾏效率。
 

三、Redis如何保证指令原⼦性

1、复合指令

Redis内部提供了很多复合指令,他们是⼀个指令,可是明显⼲着多个指令的活。⽐如 MSET(HMSET)、GETSET、SETNX、SETEX。这些复合指令都能很好的保持
原⼦性。

2、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

注:事务回滚机制,见源文档。

3、Pipeline

cat command.txt | redis-cli -a 123qweasd --pipe
当客户端执⾏⼀个指令,数据包需要通过⽹络从Client传到Server,然后再从Server返回到Client。这个中间的时间消耗,就称为RTT(Rount Trip Time)。
就是将客户端的多个指令打包,⼀起往服务端推送,这种⽅式可以⼀定程度提⾼执⾏效率,优化RTT。

4、lua脚本

127.0.0.1:6379> help eval
EVAL script numkeys [key [key ...]] [arg [arg ...]]
summary: Executes a server-side Lua script.
since: 2.6.0
group: scripting
(1)script参数是⼀段Lua脚本程序,它会被运⾏在Redis服务器上下⽂中,这段脚本不必(也不应该)定义为⼀ 个Lua函数。
(2)numkeys参数⽤于指定键名参数的个数。键名参数 key [key ...] 从EVAL的第三个参数开始算 起,表示在脚本中所⽤到的那些Redis键(key),这些键名参数可
以在 Lua中通过全局变量KEYS数组,⽤1 为基址的形式访问( KEYS[1] ,KEYS[2] ,以此类推)。
(3)在命令的最后,那些不是键名参数的附加参数 arg [arg ...] ,可以在Lua中通过全局变量ARGV数组访问, 访问的形式和KEYS变量类似( ARGV[1] 、 ARGV[2],诸如此类)

5、Redis Function

Redis Function允许将⼀些功能声明成⼀个统⼀的函数,提前加载到Redis服务端(可以由熟悉Redis的管理员加载)。客户端可以直接调⽤这些函数,⽽不需要再去开
发函数的具体实现。
Redis Function更⼤的好处在于在Function中可以嵌套调⽤其他Function,从⽽更有利于代码复⽤。相⽐之下,lua脚本就⽆法进⾏复⽤。

 

 
posted @ 2026-03-26 10:02  OMGq  阅读(15)  评论(0)    收藏  举报