您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
   
 
     
   
 订阅
  捐助
Redis事务及CAS(Check-And-Set)机制
 
作者:小武
95 次浏览     评价:  
2020-11-17
 
编辑推荐:
本文是主要介绍了Redis事务概念及CAS(Check-And-Set)机制示例等,希望对您的学习有所帮助。
本文来自雷迪斯,由火龙果软件Linda编辑、推荐。

Redis事务

在网络/活动中见过事务机制保证发证券对对券码存量校正,这是典型的并发,理解操作的实例。

Redis的事务机制交易通过四个命令来完成:MULTI, EXEC, DISCARD and WATCH,建议精读链接文章对Redis事务机制有详细介绍。

Redis事务机制特性

事务(transaction)的定义从multi开始,到exec结束。

同一个事务内的多个命令,具有原子性,不会被打断

在Redis事务的执行过程中,永远不会发生另一个客户端发出的请求。这样可以确保将命令作为单个隔离操作执行。

实例一:multi和exec之间的命令不会被其他并发处理打断,事务原子性

1 客户端A:
2 127.0.0.1:6379>多
3 OK
4 127.0.0.1:6379>设置招呼一个
5 QUEUED

6

7 // clientB同时将hello设置为b

8

9 127.0.0.1:6379>获取问候
10 排队
11 127.0.0.1:6379> exec
12 1)OK
12 2)“ a”

14

15 clientB:
16 127.0.0.1 :6379 >设置问候b
17 确定



实例二:注意理解incr和set操作的区别

1 clientA:
2 127.0.0.1 :6379 >设置问候1
3 好

4

5 127.0.0.1:6379>多
6 行
7 127.0.0.1:6379>增量你好//
8 QUEUED
9 // clientB顺流组喂至22
10 127.0.0.1:6379>得到你好
11 QUEUED
12 127.0.0.1:6379> EXEC
13 1)(整数)23
14 2 )“ 23”

15

16 // clientB:
17 127.0.0.1 :6379 > set hello 22
18 OK

事务内部的命令或全部执行(仅指入带执行的命令编码成功),或者都不执行

所有命令都将被处理,或者不处理任何命令,因此Redis事务也是原子的。

multi执行之前分段连接,则全部命令不会执行;exec执行之后,所有命令操作都会被执行。

注意:这里仅指指命令的执行,但同时事务内部命令执行与否,并不意味着执行成功(存在命令执行后,返回异常的情况)。

事务期间的错误情况

命令入待执行命令队列失败,在此时exec前就会有错误:命令语法错误,内存不足等极端情况,此时一般会中断事务,自动discard事务。

1 127.0.0.1:6379>多
2 行
3 127.0.0.1:6379>组喂1
4 QUEUED
5 127.0.0.1:6379> LGET你好//非法的命令导致错误
6 (误差)ERR未知命令'LGET'
7 127.0.0.1:6379> EXEC
8 (错误)EXECABORT事务由于先前的错误而被丢弃。

在执行exec后部分命令可能失败:甚至部分命令失败,其他命令仍将正常执行完成

实例三:在执行exec后部分命令可能失败

1 127.0.0.1:6379> multi
2 OK
3 127.0.0.1:6379> set hello 1
4 QUEUED
5 127.0.0.1:6379> lset hello 0 1 //该命令可被执行,但执行失败
6 QUEUED
7 127.0.0.1:6379> exec
8 1)OK
9 2)(错误)WRONGTYPE对持有错误类型值的键进行操作
10 127.0.0.1:6379> get hello //事务中的第一步执行成功
11 “ 1”

CAS(Check-And-Set)支持

watch已监视的密钥,只允许在当前终端的multi和exec见被修改,其他情况的修改都将导致watch和此事务的失败。

实例:CAS的主要通过watch命令完成,依次在watch一个键后,其他终端修改此键的值时,都将触发当前事务的失败。

1 // clientA
2 127.0.0.1:6379>观看Hello
3 OK
4 127.0.0.1:6379> multi
5 OK
6 // clientB当前将hello设置为33
7 127.0.0.1:6379> set hello 2
8 QUEUED
9 127.0.0.1:6379> exec //观看hello更改,执行失败
10 (无)

11

12 // clientB:
13 127.0.0.1 :6379 > set hello 33
14 OK

15

16 // redis monitor
17 1496247607.225085 [0 127.0.0.1:43168]“ watch”“ hello”
18 1496247611.476334 [0 127.0.0.1:43168]“ multi”
19 1496247626.275239 [0 127.0.0.1:43216]“ set”“ hello”“ 33”
20 1496247632.092549 [0 127.0.0.1:43168]“执行程序”

注意:当前终端的watch和multi之间对密钥的修改,也会触发事务的失败详细。

predis的CAS使用

Laravel项目中有phpredis和predis两个扩展支持redis的,phpredis是?实现扩展,需要编译安装,性能卓越;predis是PHP实现扩展,安装方便(composer install),线上部署无需变更

这里对predis下使用Redis的事务机制展开说明

Check-And-Set:

示例代码:https : //github.com/nrk/predis/blob/v1.1/examples/transaction_using_cas.php

1 功能 zpop ($ client,$ key)
2 {
3 $ element = null ;
4 $ options = array('cas' => true, //通过支持CAS操作进行初始化'watch' => $ key, //需要监视以检测更改的键'retry' => 3, //重试中止的事务,//在此之后,客户端会异常退出。 ); $客户端- >交易($选项,功能($ TX)使用($键,&$元件) { @列表($元素)= $ TX-> zrange($键,0,0

5
6
7
8
9

10
11 ); if(isset($ element)){ $ tx-> multi(); //使用CAS,必须显式调用MULTI *。 $ tx-> zrem($ key,$ element); } }); 返回$ element; } $ client = new Predis \ Client($ single_server); $ zpopped = zpop($ client,'zset'); echo isset($ zpopped)?“ ZPOPed $ zpopped”:“ ZPOP没什么!” ,PHP_EOL;
12

13
14

15
16

17

18

19

20

21

在cas模式下,predis使用的注意事项:

必须显式的调用$tx->multi()

在调用multi之前必须显式的调用任何命令$tx->validRedisCmd(),否则直接调用multi并不会执行multi指令

cas的目的是监视某个键在此期间不会变化,所以应用场景应该是:取某个键的值,做一些操作,再进行键执行其他命令

此处适当的引用下php.net对memcached :: cas()的解释来辅助理解

Memcached :: cas()执行“检查并设置”操作,以便仅在自从此客户端上次获取该项目以来没有其他客户端对其进行更新的情况下,该项目才会被存储。

cas =检查并设置,某项将在没有其他终端修改的替代下保存,即当前终端是最新一次获取该值

实例:Lravel下通过predis的事务的CAS(check-and-set)机制保证竞争条件下的数据一致性

1 使用 Illuminate \ Support \ Facades \ Redis ;

2

3 $ keyTotal = '密钥总数' ;
4 $ keyOneUser = '密钥一用户' ;
5 $ total = 10 ;
6 $ oneUserLimit = 2 ;
7 $ options = [ “ cas” => true,“ watch” => [$ keyTotal,$ keyOneUser],//监视多键“ retry” => 3 ]; 试试{ $ redis = Redis :: connection('redis_conn'); $ transFunc =函数($ tx)使用($ keyTotal,$ keyOneUser,$ total,$ oneUserLimit) { $ curTotal = $ tx-> get($ keyTotal);
8

9

10

11

12

13

14

15

16 $ curLimit = $ tx-> get($ keyOneUser); 如果($ curTotal> = $ total || $ curLimit> = $ oneUserLimit){ \ Log :: info('[Rule ruleUpdateCasTransaction]超出限制,'。“ $ keyTotal:$ curTotal> = $ total,$ keyOneUser:$ curLimit> = $ oneUserLimit“); 返回false ; } $ tx-> multi(); // cas模式下必须调用multi,调用multi前必须执行其他redis命令 初始化配置$ tx-> incr($ keyTotal); $ tx-> incr($ keyOneUser); }; $ redis-> transaction($ options,$ transFunc); 返回true ; } catch(\例外$ e){ \ Log :: error(
17

18

19

20

21

22

23

24

25

26

27

28 “ [Rule ruleCntDec]总计和限制e $均失败,”。$ e); 返回false ; }

29

30

Redismonitor命令下的cas事务执行过程:

1 1496242439.690785 [0 127.0.0.1:43126]“ AUTH”“ e3b8d1e0xxxxxxxxxxxxxxVpEi”
2 1496242439.691136 [0 127.0.0.1:43126]“ SELECT”“ 4”
3 1496242439.691356 [4 127.0.0.1:43126]“ WATCH”“键合计”“键一个用户“
4 1496242439.691493 [4 127.0.0.1:43126]” GET“”密钥总计“
5 1496242439.691643 [4 127.0.0.1:43126]” GET“”密钥一用户“
6 1496242439.691834 [4 127.0.0.1:43126]” MULTI“
7 1496242439.692136 [4 127.0.0.1:43126]” INCR“”密钥总数“
8 1496242439.692146 [4 127.0.0.1:43126]” INCR“”密钥一用户“
9 1496242439.692152 [4 127.0.0.1:43126]” EXEC“

 

   
95 次浏览     评价: 订阅 捐助
相关文章

我们该如何设计数据库
数据库设计经验谈
数据库设计过程
数据库编程总结
 
相关文档

数据库性能调优技巧
数据库性能调整
数据库性能优化讲座
数据库系统性能调优系列
相关课程

高性能数据库设计与优化
高级数据库架构师
数据仓库和数据挖掘技术
Hadoop原理、部署与性能调优
最新课程计划
 
最新文章
InfluxDB概念和基本操作
InfluxDB TSM存储引擎之数据写入
深度漫谈数据系统架构——Lambda architecture
Lambda架构实践
InfluxDB TSM存储引擎之数据读取
最新课程
Oracle数据库性能优化、架构设计和运行维护
并发、大容量、高性能数据库设计与优化
NoSQL数据库(原理、应用、最佳实践)
企业级Hadoop大数据处理最佳实践
Oracle数据库性能优化最佳实践
更多...   
成功案例
某金融公司 Mysql集群与性能优化
北京 并发、大容量、高性能数据库设计与优化
知名某信息通信公司 NoSQL缓存数据库技术
北京 oracle数据库SQL优化
中国移动 IaaS云平台-主流数据库及存储技术
更多...