一、redis pipeline
redis pipeline 是一个客户端提供的机制,而不是服务端提供的;
二、redis事务
事务:用户定义一系列数据库操作,这些操作视为一个完整的逻辑处理工作单元,要么全部执行,
MULTI开启事务begin / start transactionEXEC提交事务commitDISCARD取消事务rollbackWATCH检测 key 的变动,若在事务执行中, key 变动则取消事务;在事务开启前调用,乐观锁实现( cas ) ;若被取消则事务返回 nil ;
lua 脚本
lua脚本实现原子性;
redis 中加载了一个 lua 虚拟机;用来执行 redis lua 脚本;redis lua 脚本的执行是原子性的;当某 个脚本正在执行的时候,不会有其他命令或者脚本被执行;
一、从文件加载 Lua 脚本(高效批量加载)
命令
cat script.lua | redis-cli script load --pipe
作用
将本地 Lua 脚本文件通过标准输入(
cat
)传递给redis-cli
,利用--pipe
选项批量加载脚本到 Redis 缓存,避免逐行传输的网络开销。实例
假设脚本文件
test.lua
内容为:-- 功能:获取键对应的值并返回 local value = redis.call('GET', KEYS[1]) return value
执行加载:
cat test.lua | redis-cli -h 127.0.0.1 -p 6379 script load --pipe
输出
SHA1哈希值(如): "a1b2c3d4e5f67890abcdef1234567890abcdef12"
注意
--pipe
用于批量执行命令,此处仅加载单个脚本,实际生产中可批量加载多个脚本。- 加载后脚本存储在 Redis 服务器的脚本缓存中,后续可通过
EVALSHA
命令调用,减少网络传输量。二、加载 Lua 脚本字符串(手动生成 SHA1)
命令
redis-cli script load "脚本内容"
作用
直接传入 Lua 脚本字符串,Redis 会执行语法检查并生成 SHA1 哈希值,用于后续通过
EVALSHA
调用,避免重复传输完整脚本。实例
# 加载一个简单脚本(返回第一个传入的键名) > script load 'local val = KEYS[1]; return val'
输出
"b8059ba43af6ffe8bed3db65bac35d452f8115d8" # SHA1 哈希值
三、检查脚本是否存在于缓存(避免重复加载)
命令
redis-cli script exists SHA1哈希值 [SHA1哈希值 ...]
作用
检查指定的 SHA1 哈希值对应的脚本是否已加载到 Redis 缓存中,返回 1(存在)或 0(不存在)。
实例
# 检查之前生成的 SHA1 是否存在 > script exists "b8059ba43af6ffe8bed3db65bac35d452f8115d8"
输出
1) (integer) 1 # 表示存在
应用场景
- 在调用
EVALSHA
前先执行script exists
,若脚本不存在则先用script load
加载,避免EVALSHA
报错(NOSCRIPT
错误)。四、清除所有脚本缓存(释放内存)
命令
redis-cli script flush
作用
删除 Redis 服务器中缓存的所有 Lua 脚本,释放相关内存。
实例
> script flush
输出
OK # 表示清除成功
注意
- 清除后,所有通过
script load
或EVAL
加载的脚本都会被删除,后续调用EVALSHA
会报错,需重新加载。- 生产环境中慎用,避免影响正在运行的依赖脚本的业务。
五、终止长时间运行的脚本(处理阻塞)
命令
redis-cli script kill
作用
杀死当前正在执行的、运行时间过长的 Lua 脚本(仅能终止 非阻塞写操作 的脚本,即未执行过
WRITE
命令的脚本)。实例
# 假设存在一个死循环脚本,尝试终止 > script kill
输出
(error) NOTBUSY No scripts in execution right now. # 无正在执行的脚本时提示
注意
- 若脚本已执行过写操作(如
SET
、DEL
),script kill
无法终止,只能通过重启 Redis 实例强制停止(可能导致数据不一致,需谨慎)。- Redis 的单线程模型决定了脚本会阻塞其他命令,应避免编写耗时过长的脚本(建议控制在毫秒级)。
六、核心命令对比表
命令 功能描述 典型场景 输出示例 script load
加载脚本,生成 SHA1,存入缓存 预加载脚本,后续通过 EVALSHA
调用以减少网络传输SHA1 哈希值 script exists
检查脚本是否在缓存中 调用 EVALSHA
前判断是否需要重新加载脚本1
(存在)或0
(不存在)script flush
清除所有脚本缓存 重置环境、释放内存或脚本更新后强制重新加载 OK
script kill
终止正在执行的脚本(仅非阻塞写脚本) 处理脚本死循环或长时间阻塞 OK
(成功终止)或错误提示七、最佳实践
预加载脚本:
在服务启动时通过script load
加载所有需要的脚本,后续用EVALSHA
调用(比EVAL
更高效,无需传输完整脚本)。# 调用示例:EVALSHA SHA1 键数量 键1 键2 ... 参数1 参数2 ... redis-cli evalsha b8059ba43af6ffe8bed3db65bac35d452f8115d8 1 mykey "arg1"
处理
NOSCRIPT
错误:
若EVALSHA
因脚本未加载报错,捕获错误后重新调用script load
加载脚本,再重试EVALSHA
。避免长耗时脚本:
确保脚本逻辑简洁,必要时拆分复杂操作,防止阻塞 Redis 事件循环。脚本调试:
先用redis-cli eval
直接执行脚本调试(如eval "脚本内容" 0
),确认无误后再加载到缓存。
三、ACID特性分析
A :原子性;事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败; redis不支持回滚;即使事务队列中的某个命令在执行期间出现了错误,整个事务也会继续执行下去,直到将事务队列中的所有命令都执行完毕为止。C :一致性;事务的前后,所有的数据都保持一个一致的状态,不能违反数据的一致性检测;这里的一致性是指预期的一致性而不是异常后的一致性;所以 redis 也不满足;这个争议很大: redis 能确保事务执行前后的数据的完整约束;但是并不满足业务功能上的一致性;比如转账功能,一个扣钱一个加钱;可能出现扣钱执行错误,加钱执行正确,那么最终还是会加钱成功;系统凭空多了钱;I :隔离性;各个事务之间互相影响的程度; redis 是单线程执行,天然具备隔离性;D :持久性; redis 只有在 aof 持久化策略的时候,并且需要在 redis.conf 中appendfsync=always 才具备持久性;实际项目中几乎不会使用 aof 持久化策略;面试时候回答: lua 脚本满足原子性和隔离性;一致性和持久性不满足;
四、redis发布订阅
为了支持消息的多播机制,redis 引入了发布订阅模块;
# 订阅频道
subscribe 频道
# 订阅模式频道
psubscribe 频道
# 取消订阅频道
unsubscribe 频道
# 取消订阅模式频道
punsubscribe 频道
# 发布具体频道或模式频道的内容
publish 频道 内容
# 客户端收到具体频道内容
message 具体频道 内容
# 客户端收到模式频道内容
pmessage 模式频道 具体频道 内容
五、redis异步连接
redis协议图

异步连接
同步连接方案采用阻塞 io 来实现;优点是代码书写是同步的,业务逻辑没有割裂;缺点是阻塞当 前线程,直至 redis 返回结果;通常用多个线程来实现线程池来解决效率问题;
实现方案
详情代码见:https://github.com/jerry123456123456/redis.git 中的redis-master
0voice · GitHub