IT评测·应用市场-qidao123.com
标题:
【redis】变乱
[打印本页]
作者:
悠扬随风
时间:
2025-3-14 21:51
标题:
【redis】变乱
简单地说,变乱表示一组动作,要么全部实行,要么全部不实行。Redis变乱是一组命令的聚集,通过MULTI、EXEC等命令实现批量操纵的原子性实行。
Redis变乱的特点
其核心特点包括:
序次性
:命令按入队序次实行
隔离性
:单线程模型保证变乱实行不被打断
弱原子性
:不支持回滚机制(运行时错误不会中断后续命令)
乐观锁支持
:通过WATCH命令监控键值变革
留意:Redis变乱差异于传统数据库变乱,它更雷同于命令批处理机制。
Redis变乱的本质
命令队列机制
通过三个阶段实现变乱:
开启变乱
:MULTI命令创建命令队列
命令入队
:将操纵指令存入内存队列(不实行语法检查)
实行变乱
:EXEC触发队列命令的FIFO序次实行
单线程保障
Redis主线程依次实行变乱队列中的命令,保证:
实行期间不会被其他客户端哀求打断
天然实现隔离性(串行化实行)
Redis变乱命令使用
有关变乱类型的命令可以通过help @transactions命令来检察。有关命令的使用可以通过help 命令来检察,比方help exec。
127.0.0.1:6379> help @transactions
DISCARD -
summary: Discard all commands issued after MULTI
since: 2.0.0
EXEC -
summary: Execute all commands issued after MULTI
since: 1.2.0
MULTI -
summary: Mark the start of a transaction block
since: 1.2.0
UNWATCH -
summary: Forget about all watched keys
since: 2.2.0
WATCH key [key ...]
summary: Watch the given keys to determine execution of the MULTI/EXEC block
since: 2.2.0
复制代码
基础命令演示
变乱提交成功的演示:
# 开启事务
127.0.0.1:6379> multi
OK
# 命令进入队列,并没有直接执行
127.0.0.1:6379(TX)> set xxoo ooxx
QUEUED
# 命令进入队列,并没有直接执行
127.0.0.1:6379(TX)> incr count
QUEUED
# 执行事务
127.0.0.1:6379(TX)> exec
1) OK
2) (integer) 1
复制代码
变乱取消的演示:
# 开启事务
127.0.0.1:6379> multi
OK
# 命令进入队列,并没有直接执行
127.0.0.1:6379(TX)> set ooxx xxoo
QUEUED
# 命令进入队列,并没有直接执行
127.0.0.1:6379(TX)> incr count
QUEUED
# 取消事务
127.0.0.1:6379(TX)> discard
OK
复制代码
高级用法:乐观锁
乐观锁获取锁成功的演示:
127.0.0.1:6379> set balance:Morris 1000
OK
# 监视账户余额,类似cas
127.0.0.1:6379> watch balance:Morris
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby balance:Morris 100
QUEUED
127.0.0.1:6379(TX)> incrby balance:Bob 100
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 900
2) (integer) 100
复制代码
乐观锁获取锁失败的演示:
127.0.0.1:6379> set balance:Morris 1000
OK
127.0.0.1:6379> watch balance:Morris
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby balance:Morris 100
QUEUED
127.0.0.1:6379(TX)> incrby balance:Bob 100
QUEUED
# 此时balance:Morris被其他客户端修改,事务失败返回(nil)
127.0.0.1:6379(TX)> exec
(nil)
复制代码
原子性缺陷演示
Redis在变乱实行时,如果在命令入队时就有语法错误,好比命令不存在或者参数错误,那么整个变乱会被拒绝实行,这时间是原子性的。但如果在实行过程中出现运行时错误,好比对字符串举行INCR操纵,这时间错误命令之后的命令还会继续实行,这样原子性就被粉碎了。
语法错误导致全体失败
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
# 命令不存在,语法错误
127.0.0.1:6379(TX)> xxx k1
(error) ERR unknown command `xxx`, with args beginning with: `k1`,
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
复制代码
原子性表现:若存在入队时即可检测的语法错误(如命令不存在、参数错误),整个变乱会被拒绝实行,此时具有原子性。
运行时错误部分成功
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
# 类型错误(对字符串执行SADD)
127.0.0.1:6379(TX)> sadd k1 oo xx
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
复制代码
原子性缺陷:变乱中运行时错误(如数据类型不匹配)不会影响后续命令实行,结果中前两条命令见效,第三条失败,导致部分成功
与传统数据库变乱对比
特性Redis变乱MySQL变乱
原子性
部分支持(无回滚机制)完全支持(UNDO日记回滚)
隔离性
天然隔离(单线程模型)通过锁机制实现多隔离级别
持久性
依赖AOF配置默认保证(redo日记)
同等性
需配合WATCH实现外键/约束自动保障
实行机遇
命令延迟实行及时实行
Pipeline和变乱的区别
服务端活动VS客户端活动
变乱
:是Redis服务端原生支持的原子操纵机制,通过MULTI开启变乱模式后,服务端会将后续命令存入队列缓存,直到实行EXEC时才一次性按序次实行全部命令。
Pipeline
:本质是客户端批量发送命令的优化计谋,服务端无法区分平凡命令与Pipeline命令,仅作为一连的命令哀求处理。
原子性保障
变乱
:提供
弱原子性
保证,变乱队列中的命令在EXEC实行时会作为团体串行实行,但运行时错误(如类型操纵错误)不会中断后续命令
Pipeline
:完全不具备原子性,命令可能被其他客户端的操纵打断,仅在命令量少(能被内核缓冲区容纳)时可能保持原子性
实行流程对比
特性变乱Pipeline
命令实行机遇
EXEC触发批量实行立刻发送到服务端
网络交互次数
MULTI+命令+EXEC共3次来回单次批量发送全部命令
错误处理
语法错误导致全体失败,运行时错误部分实行无特殊处理,按平凡命令逐条响应
壅闭风险
长变乱可能壅闭其他哀求无服务端壅闭风险
应用场景与优化计谋
适用场景
变乱
:需要简单原子性操纵的场景(如库存扣减、转账),配合WATCH实现乐观锁控制
Pipeline
:批量非原子性操纵(如日记写入、数据预热),减少高并发场景下的网络开销
组合优化方案
可将变乱与Pipeline结合,减少变乱命令的网络传输时间:
# 将MULTI/EXEC封装在Pipeline中
pipe = redis.pipeline(transaction=True)
pipe.multi()
pipe.set('a', 1)
pipe.incr('b')
pipe.execute() # 单次网络请求完成事务
复制代码
特殊留意事项
变乱的范围性:
不支持回滚机制,需通过WATCH+重试计谋实现数据同等性
变乱内不能实行壅闭命令(如BLPOP),否则会退化为平凡命令
Pipeline的风险点:
大流量Pipeline可能触发服务端缓冲区溢出(需配置client-output-buffer-limit)
Cluster模式下需确保全部命令指向同一节点
选型建议
指标选择变乱选择Pipeline需要原子性✔️❌高吞吐量需求❌(变乱壅闭风险)✔️涉及跨键操纵✔️(配合WATCH)❌命令间存在逻辑依赖✔️(Lua脚本更优)❌
扩展方案
:对于需要强原子性的复杂操纵,推荐使用Lua脚本替换变乱,可实现真正的原子性实行。
-- Lua脚本原子扣减库存
if redis.call('GET', KEYS[1]) >= ARGV[1] then
return redis.call('DECRBY', KEYS[1], ARGV[1])
else
return -1
end
复制代码
Java中使用Redis变乱
package com.morris.redis.demo.transaction;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
import java.util.List;
/**
* jedis中事务的使用
*/
public class JedisTransactionDemo {
public static void main(String[] args) {
try (Jedis jedis = new Jedis("localhost")) {
// 监控关键键
jedis.watch("balance:Morris");
Transaction tx = jedis.multi();
try {
tx.decrBy("balance:Morris", 100);
tx.incrBy("balance:Bob", 100);
List<Object> results = tx.exec(); // 提交事务
System.out.println("转账成功:" + results);
} catch (Exception e) {
tx.discard(); // 放弃事务
System.out.println("数据被修改,事务回滚");
} finally {
jedis.unwatch(); // 解除监控
}
}
}
}
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/)
Powered by Discuz! X3.4