成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Redis篇:事務和Lua 腳本的使用

存儲 存儲軟件 Redis
現在多數秒殺,抽獎,搶紅包等大并發高流量的功能一般都是基于 redis 實現,然而在選擇 redis 的時候,我們也要了解 redis 如何保證服務正確運行的原理.

[[436743]]

本文轉載自微信公眾號「潛行前行」,作者cscw 。轉載本文請聯系潛行前行公眾號。

 現在多數秒殺,抽獎,搶紅包等大并發高流量的功能一般都是基于 redis 實現,然而在選擇 redis 的時候,我們也要了解 redis 如何保證服務正確運行的原理

前言

  • redis 如何實現高性能和高并發
  • reids 事務的 ACID 原理
  • WATCH、EXEC 命令實現 redis 事務
  • lua 實現 redis事務
  • 搶紅包方案

redis 如何實現高性能和高并發

  • redis 是一個內存數據庫,讀寫非常高效。除了開啟 AOF,RDB 異步線程去持久化數據,基本沒有磁盤I/O消耗,性能方面是比 mysql,oracle 快很多
  • redis 自己實現一套簡單高效的基礎數據結構:動態字符串(SDS),鏈表,字典,跳躍鏈表,整數集合和壓縮列表。然后在這個基礎上去實現用戶能操作的對象:字符串,列表,哈希,集合,有序集合等對象
  • reactor 模式的網絡事件處理器。它使用了 I/O 多路復用去同時監控多個套接字,這是一種高效的I/O模型。reactor 相關知識可以看下這篇文章框架篇:見識一下linux高性能網絡IO+Reactor模型
  • 事件處理器是單線執行的,這大大減少CPU的上下文切換,和對資源鎖的競爭問題,極大提高redis服務處理速度(至于為啥使用單線程,因為CPU夠用了,它的性能瓶頸在內存而不是CPU)
  • Redis直接自己構建了VM 機制 ,因為一般的系統調用系統函數的話,會浪費一定的時間去移動和請求

reids 事務的 ACID 原理

redis 的事務需要先劃分出三個階段

  • 事務開啟,使用 MULTI 可以標志著執行該命令的客戶端從非事務狀態切換至事務狀態redis> MULTI
  • 命令入隊,MULTI開啟事務之后,非 WATCH、EXEC、DISCARD、MULTI 等特殊命令;客戶端的命令不會被立即執行,而是放入一個事務隊列
  • 執行事務或者丟棄。如果收到 EXEC 的命令,事務隊列里的命令將會被執行。如果是 DISCARD 則事務被丟棄

命令入隊過程如果出錯(如使用了不存在的命令),則事務隊列會被拒接執行

執行事務期間出現了異常(如命令和操作的數據類型不匹配),事務隊列的里的命令還是繼續執行下去,直到全部命令執行完。不會回滾

WATCH 可用于監控 redis 變量值,在命令 EXEC 之前;redis 里的數據是有機會被其他客戶端的命令修改的。使用 WATCH,監控的變量被修改后,執行 EXEC 時則會返回執行失敗的 nil 回復

  1. redis> WATCH "name" 
  2. OK 
  3. redis> MULTI   ### 此時name已被其他客戶端的命令修改 
  4. OK 
  5. redis> SET "name" "lwl" 
  6. QUEUED 
  7. redis> EXEC 
  8. (nil) 

從嚴格意義上來說,redis 是沒有事務的。因為事務必須具備四個特點:原子性(Atomicity),一致性(Consistency),隔離性(Isolation),持久性(Durability)。然后 redis 是做不到這四點,只是具備其中一些特征,redis的事務是個偽事務,而且不支持回滾。下面將為各位同學一一道來

原子性

從上面可以,事務的異常會發生在EXEC命令執行前、后

EXEC命令執行前:在命令入隊時就報錯,(如內存不足,命令名稱錯誤),redis 就會報錯并且記錄下這個錯誤。此時,客戶還能繼續提交命令操作;等到執行EXEC時,redis 就會拒絕執行所有提交的命令操作,返回事務失敗的結果 nil

EXEC命令執行后:命令和操作的數據類型不匹配,但 redis 實例沒有檢查出錯誤。在執行完 EXEC 命令以后,redis 實際執行這些指令,就會報錯。此時事務是不會回滾的,但事務隊列的命令還是繼續被執行。事務的原子性無法保證

EXEC執行時,發生故障:如果 redis 開啟了 AOF 日志,那么,只會有部分的事務操作被記錄到 AOF 日志中。需要使用 redis-check-aof 工具檢查 AOF 日志文件,這個工具可以把未完成的事務操作從 AOF 文件中去除。事務的原子性得到保證

一致性

EXEC命令執行前:入隊報錯事務會被放棄執行,具有一致性

EXEC命令執行后:實際執行時報錯,錯誤的執行不會執行,正確的指令可以正常執行,一致性可以保證

EXEC執行時,發生故障:RDB 模式,RDB 快照不會在事務執行時執行,事務結果不會保存在RDB;AOF 模式,可以使用 redis-check-aof 工具檢查 AOF 日志文件,把未完成的事務操作從 AOF 文件中去除。可以保證一致性

隔離性

EXEC 命令前執行,隔離性需要通過 WATCH 機制保證。因為 EXEC 命令執行前,其他客戶端命令可以被執行,相關變量會被修改;但可以使用 WATCH 機制監控相關變量。一旦相關變量被修改,則 EXEC 后則事務失敗返回;具有隔離性

EXEC 命令之后,隔離性可以保證。因為 redis 是單線程執行,事務隊列里的命令和其他客戶端的命令只能二選一被順序執行,因此具有隔離性

持久性

如果 redis 沒有使用 RDB 或 AOF,事務的持久化是不存在的

使用 RDB 模式,那么在一個事務執行后,而下一次的 RDB 快照還未執行前,如果發生了實例宕機,數據丟失,這種情況下,事務修改的數據也是不能保證持久化

AOF 模式,因為 AOF 模式的三種配置選項 no、everysec 和 always 都會存在數據丟失的情況。所以,事務的持久性屬性也還是得不到保證

總結

redis 的事務機制可以保證一致性和隔離性;但是無法保證持久性;具備了一定的原子性,但不支持回滾

WATCH、EXEC 命令實現 redis 事務

  1. redis> WATCH "map" 
  2. OK 
  3. redis> MULTI  
  4. OK 
  5. redis> HSET map "csc" "lwl"   
  6. QUEUED 
  7. redis> HGET map "csc" 
  8. QUEUED 
  9. redis> EXEC 
  10. 1) OK 
  11. 2) "lwl"   

lua 實現 redis 事務

除了 MULTI、WATCH、EXEC 命令,還有其他的方式可做到 redis 原子性和隔離性嗎?有的,lua 腳本;redis 內置了lua的執行環境,并自帶了一些 lua 函數庫。redis 執行 lua 時,會啟動一個偽客戶端去執行腳本里的 redis 命令

一致性,原子性,持久性 和 MULTI,EXEC 過程相似:如果 lua 存在錯誤的命令名稱,事務會執行失敗。如果在執行 redis 命令過程出現異常,之前正常執行的命令也不會回滾

lua 腳本被當做一命令集合一起被執行,且 redis 是單線處理機制,因此不需要 WATCH 保證隔離性,天然具備隔離性

Lua調用Redis指令: redis.call("命令名稱",參數1,參數2)

優點

減少網絡開銷:可以將多個請求通過腳本的形式一次發送,減少網絡時延

原子操作:Redis會將整個腳本作為一個整體執行,中間不會被其他請求插入。在腳本運行過程中無需擔心會出現競態條件

可重復使用:客戶端發送的腳本會永久存在 redis 中,這樣其他客戶端可以復用這一腳本,而不需要使用代碼完成相同的邏輯

搶紅包方案

問題關鍵點

  • 一:用戶是否參與過活動,不可重復參與
  • 二:紅包數量有限;而且一個可搶的紅包,保證不能讓多個人同時搶到
  • 三:持久化存儲紅包與用戶的關系
  • 四:如何保證 步驟一到步驟三的原子性和隔離性

關鍵點一

redis 的集合對象 set 是無序且唯一的。set 集合由整數集合或字典實現的,添加,刪除,查找的復雜度基本視為 O(1),存放的最大對象個數是2^32 - 1 (4294967295)

使用 set 集合保存參加過的用戶,每次用戶參與活動時先判斷是否在 set 里。不在則可以搶紅包

如果是用戶可以重復參與多次的場景,則使用哈希對象,key存用戶對象,value 存放參與次數。使用 INCR 原子操作增加 value,如果返回數值 > 上限,說明搶的次數用完

關鍵點二

使用 list 或者 set 存放事先創建好的有限個紅包;因為 redis 是單線程操作,同一時間,多人搶紅包,只會有一個人成功。而紅包是事先生成的,消費用完即止,不存在超發的可能

使用 list 列表存放紅包

  • 因為紅包金額大小不一,為增加搶到紅包大小的隨機性,需要先shuffle一次,再 LPUSH 入隊列
  • RPOP 出隊列一個紅包,如果返回不為nil,則代表獲取成功,繼續下一步,反之則說明已搶完,返回

set 集合中有兩個指令非常適合在搶紅包、抽獎的場景使用

  • SPOP key [count] 移除并返回集合中的一個隨機元素
  • SRANDMEMBER key [count] 返回集合中一個或多個隨機數;需要再調 SREM 移除一遍
  • 將所有的紅包通過 SADD 添加到 set 中,然后通過隨機命令獲取對應的紅包即可

如果有謝謝惠顧之類的落空選項,生成對應的無效紅包、獎品放入 set 或 list 即可

搶紅包一般是有時效性,正好可以配合 redis 的 key 的失效時間使用。使得搶紅包功能很完美的解決

關鍵點三

使用額外的 list 列表保存用戶與紅包的關系,用戶搶到紅包后,將對應的關系 LPUSH 入隊列,然后服務去消費拉取數據批量保存到數據庫即可

關鍵點四

使用 lua 腳本實現即可

  1. -- 參數:KEYS[1]-紅包list,KEYS[2]-用戶和紅包的消費list,KEYS[3]-去重的哈希對象,KEYS[4]-用戶ID 
  2. -- 函數:嘗試獲得紅包,如果成功,則返回json字符串,如果不成功,則返回nil 
  3. -- 返回值:nil 或者 json字符串,{"userId":"用戶ID","id":"紅包ID"} 
  4. -- 如果用戶已搶過紅包,則返回nil 
  5.  
  6. -- 步驟一,攔截重復參與 
  7. if redis.call('hexists', KEYS[3], KEYS[4]) == 1 then 
  8.   return nil 
  9. else 
  10.   -- 步驟二,先取出一個紅包 
  11.   local lunkMoney = redis.call('rpop', KEYS[1]); 
  12.   if luckMoney then 
  13.     local data = cjson.decode(luckMoney); 
  14.     data['userId'] = KEYS[4]; -- 加入用戶ID信息 
  15.     local re = cjson.encode(data); 
  16.     -- 把用戶ID放到去重的哈希,value設置為 1 
  17.     redis.call('hset', KEYS[3], KEYS[4], 1); 
  18.     -- 步驟三: 用戶和紅包放到已消費隊列里 
  19.     redis.call('lpush', KEYS[2], re); 
  20.     return re; 
  21.   end 
  22. end 
  23. return nil 

參考文章

redis事務一致性問題?

Redis的ACID屬性

搶紅包設計

騰訊二面:Redis 事務支持 ACID 么?

 

責任編輯:武曉燕 來源: 潛行前行
相關推薦

2023-04-04 07:52:26

RedisLua腳本

2024-01-09 07:25:31

2025-02-28 08:21:36

C語言C++Java

2019-08-06 14:06:19

數據庫工具技術

2022-08-03 08:17:00

Redis事務內存

2023-05-05 08:08:06

JavaRedis事務

2011-08-23 09:56:52

UnicodeLua

2011-08-25 13:22:40

CEGUILua腳本

2011-08-23 09:44:28

LUA腳本

2011-08-25 09:55:27

2024-12-30 07:20:00

Redis數據庫MySQL

2024-08-13 17:35:27

2022-03-08 07:22:48

Redis腳本分布式鎖

2024-01-18 11:54:44

Redis事務命令

2024-03-29 08:56:47

2022-04-26 21:49:55

Spring事務數據庫

2011-08-30 10:28:11

MySQL ProxyLUA

2011-08-24 14:26:08

Lua游戲腳本

2021-08-01 07:19:16

語言OpenrestyNginx

2023-10-12 07:54:02

.NETXamarin框架
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美精品一区二区在线观看 | 男人视频网站 | 中文字幕日韩欧美 | 成人黄色在线 | 欧美黑人一级爽快片淫片高清 | 日本天堂一区 | 欧美一区二区三区视频 | 精品久| www成人啪啪18 | 久久国产精品视频观看 | 国产精品视频一区二区三区不卡 | 中文字幕一区二区三区日韩精品 | 蜜桃av一区二区三区 | 国产精品久久久久国产a级 欧美日韩国产免费 | 国产精品久久毛片av大全日韩 | 国产免费黄网 | 日韩一二区 | 免费午夜电影 | 国产乡下妇女做爰 | 久久久久国产 | 91九色porny首页最多播放 | 国产永久免费 | 激情欧美一区二区三区中文字幕 | 亚洲综合中文字幕在线观看 | 国产精品视频500部 a久久 | 久久精品视频在线观看 | 伦理片97| 日韩av在线播 | 男女又爽又黄视频 | 99爱免费| 色一级| 精品日韩在线 | 成人欧美一区二区三区白人 | 欧美一级黄视频 | 亚洲高清免费 | 久久日本| 中文字幕精品一区二区三区在线 | 少妇精品亚洲一区二区成人 | 久久99精品国产自在现线小黄鸭 | 国产最新精品视频 | 久久久久久久久久影视 |