1. 程式人生 > >Redis的事務功能詳解

Redis的事務功能詳解

MULTI、EXEC、DISCARD和WATCH命令是Redis事務功能的基礎。Redis事務允許在一次單獨的步驟中執行一組命令,並且可以保證如下兩個重要事項:

Redis會將一個事務中的所有命令序列化,然後按順序執行。Redis不可能在一個Redis事務的執行過程中插入執行另一個客戶端發出的請求。這樣便能保證Redis將這些命令作為一個單獨的隔離操作執行。 > 在一個Redis事務中,Redis要麼執行其中的所有命令,要麼什麼都不執行。因此,Redis事務能夠保證原子性。EXEC命令會觸發執行事務中的所有命令。因此,當某個客戶端正在執行一次事務時,如果它在呼叫MULTI命令之前就從Redis服務端斷開連線,那麼就不會執行事務中的任何操作;相反,如果它在呼叫EXEC命令之後才從Redis服務端斷開連線,那麼就會執行事務中的所有操作。當Redis使用只增檔案(AOF:Append-only File)時,Redis能夠確保使用一個單獨的write(2)系統呼叫,這樣便能將事務寫入磁碟。然而,如果Redis伺服器宕機,或者系統管理員以某種方式停止Redis服務程序的執行,那麼Redis很有可能只執行了事務中的一部分操作。Redis將會在重新啟動時檢查上述狀態,然後退出執行,並且輸出報錯資訊。使用redis-check-aof工具可以修復上述的只增檔案,這個工具將會從上述檔案中刪除執行不完全的事務,這樣Redis伺服器才能再次啟動。

從2.2版本開始,除了上述兩項保證之外,Redis還能夠以樂觀鎖的形式提供更多的保證,這種形式非常類似於“檢查再設定”(CAS:Check And Set)操作。本文稍後會對Redis的樂觀鎖進行描述。

一、相關命令

1. MULTI

用於標記事務塊的開始。Redis會將後續的命令逐個放入佇列中,然後才能使用EXEC命令原子化地執行這個命令序列。

這個命令的執行格式如下所示:

MULTI

這個命令的返回值是一個簡單的字串,總是OK。

2. EXEC

在一個事務中執行所有先前放入佇列的命令,然後恢復正常的連線狀態。

當使用WATCH命令時,只有當受監控的鍵沒有被修改時,EXEC命令才會執行事務中的命令,這種方式利用了檢查再設定(CAS)的機制。

這個命令的執行格式如下所示:

EXEC

這個命令的返回值是一個數組,其中的每個元素分別是原子化事務中的每個命令的返回值。 當使用WATCH命令時,如果事務執行中止,那麼EXEC命令就會返回一個Null值。

3. DISCARD

清除所有先前在一個事務中放入佇列的命令,然後恢復正常的連線狀態。

如果使用了WATCH命令,那麼DISCARD命令就會將當前連線監控的所有鍵取消監控。

這個命令的執行格式如下所示:

DISCARD

這個命令的返回值是一個簡單的字串,總是OK。

4. WATCH

當某個事務需要按條件執行時,就要使用這個命令將給定的鍵設定為受監控的。

這個命令的執行格式如下所示:

WATCH key [key ...]

這個命令的返回值是一個簡單的字串,總是OK。

對於每個鍵來說,時間複雜度總是O(1)。

5. UNWATCH

清除所有先前為一個事務監控的鍵。

如果你呼叫了EXEC或DISCARD命令,那麼就不需要手動呼叫UNWATCH命令。

這個命令的執行格式如下所示:

UNWATCH

這個命令的返回值是一個簡單的字串,總是OK。

時間複雜度總是O(1)。

二、使用方法

使用MULTI命令便可以進入一個Redis事務。這個命令的返回值總是OK。此時,使用者可以發出多個Redis命令。Redis會將這些命令放入佇列,而不是執行這些命令。一旦呼叫EXEC命令,那麼Redis就會執行事務中的所有命令。

相反,呼叫DISCARD命令將會清除事務佇列,然後退出事務。

以下示例會原子化地遞增foo鍵和bar鍵的值:

<img>

正如從上面的會話所看到的一樣,EXEC命令的返回值是一個數組,其中的每個元素都分別是事務中的每個命令的返回值,返回值的順序和命令的發出順序是相同的。

當一個Redis連線正處於MULTI請求的上下文中時,通過這個連線發出的所有命令的返回值都是QUEUE字串(從Redis協議的角度來看,返回值是作為狀態回覆(Status Reply)來發送的)。當呼叫EXEC命令時,Redis會簡單地排程執行事務佇列中的命令。

三、事務內部的錯誤

在一個事務的執行期間,可能會遇到兩種型別的命令錯誤:

一個命令可能會在被放入佇列時失敗。因此,事務有可能在呼叫EXEC命令之前就發生錯誤。例如,這個命令可能會有語法錯誤(引數的數量錯誤、命令名稱錯誤,等等),或者可能會有某些臨界條件(例如:如果使用maxmemory指令,為Redis伺服器配置記憶體限制,那麼就可能會有記憶體溢位條件)。
在呼叫EXEC命令之後,事務中的某個命令可能會執行失敗。例如,我們對某個鍵執行了錯誤型別的操作(例如,對一個字串(String)型別的鍵執行列表(List)型別的操作)。

可以使用Redis客戶端檢測第一種型別的錯誤,在呼叫EXEC命令之前,這些客戶端可以檢查被放入佇列的命令的返回值:如果命令的返回值是QUEUE字串,那麼就表示已經正確地將這個命令放入佇列;否則,Redis將返回一個錯誤。如果將某個命令放入佇列時發生錯誤,那麼大多數客戶端將會中止事務,並且丟棄這個事務。

然而,從Redis 2.6.5版本開始,伺服器會記住事務積累命令期間發生的錯誤。然後,Redis會拒絕執行這個事務,在執行EXEC命令之後,便會返回一個錯誤訊息。最後,Redis會自動丟棄這個事務。

在Redis 2.6.5版本之前,如果發生了上述的錯誤,那麼在客戶端呼叫了EXEC命令之後,Redis還是會執行這個出錯的事務,執行已經成功放入事務佇列的命令,而不會關心先前發生的錯誤。從2.6.5版本開始,Redis在遭遇上述錯誤時,會採用先前描述的新行為,這樣便能輕鬆地混合使用事務和管道。在這種情況下,客戶端可以一次性地將整個事務傳送至Redis伺服器,稍後再一次性地讀取所有的返回值。

相反,在呼叫EXEC命令之後發生的事務錯誤,Redis不會進行任何特殊處理:在事務執行期間,即使某個命令執行失敗,所有其他的命令也將會繼續執行。

這種行為在協議層面上更加清晰。在以下示例中,當事務正在執行時,有一條命令將會執行失敗,即使這條命令的語法是正確的:

<img>

上述示例的EXEC命令的返回值是批量的字串,包含兩個元素,一個是OK程式碼,另一個是-ERR錯誤訊息。客戶端會根據自身的程式庫,選擇一種合適的方式,將錯誤資訊提供給使用者

需要注意的是,即使某個命令執行失敗,事務佇列中的所有其他命令仍然會執行 —— Redis不會停止執行事務中的命令。

再看另一個示例,再次使用telnet通訊協議,觀察命令的語法錯誤是如何儘快報告給使用者的:

<img>

這一次,由於INCR命令的語法錯誤,Redis根本就沒有將這個命令放入事務佇列。

四、為什麼Redis不支援回滾?

如果你具備關係型資料庫的知識背景,你就會發現一個事實:在事務執行期間,雖然Redis命令可能會執行失敗,但是Redis仍然會執行事務中餘下的其他命令,而不會執行回滾操作,你可能會覺得這種行為很奇怪。

然而,這種行為也有其合理之處:

只有當被呼叫的Redis命令有語法錯誤時,這條命令才會執行失敗(在將這個命令放入事務佇列期間,Redis能夠發現此類問題),或者對某個鍵執行不符合其資料型別的操作:實際上,這就意味著只有程式錯誤才會導致Redis命令執行失敗,這種錯誤很有可能在程式開發期間發現,一般很少在生產環境發現。
Redis已經在系統內部進行功能簡化,這樣可以確保更快的執行速度,因為Redis不需要事務回滾的能力。

對於Redis事務的這種行為,有一個普遍的反對觀點,那就是程式有可能會有缺陷(bug)。但是,你應當注意到:事務回滾並不能解決任何程式錯誤。例如,如果某個查詢會將一個鍵的值遞增2,而不是1,或者遞增錯誤的鍵,那麼事務回滾機制是沒有辦法解決這些程式問題的。請注意,沒有人能解決程式設計師自己的錯誤,這種錯誤可能會導致Redis命令執行失敗。正因為這些程式錯誤不大可能會進入生產環境,所以我們在開發Redis時選用更加簡單和快速的方法,沒有實現錯誤回滾的功能。

五、丟棄命令佇列

DISCARD命令可以用來中止事務執行。在這種情況下,不會執行事務中的任何命令,並且會將Redis連線恢復為正常狀態。示例如下所示:

<img>

六、通過CAS操作實現樂觀鎖

Redis使用WATCH命令實現事務的“檢查再設定”(CAS)行為。

作為WATCH命令的引數的鍵會受到Redis的監控,Redis能夠檢測到它們的變化。在執行EXEC命令之前,如果Redis檢測到至少有一個鍵被修改了,那麼整個事務便會中止執行,然後EXEC命令會返回一個Null值,提醒使用者事務執行失敗。

例如,設想我們需要將某個鍵的值自動遞增1(假設Redis沒有INCR命令)。

首次嘗試的偽碼可能如下所示:

val = GET mykey
val = val + 1
SET mykey $val

如果我們只有一個Redis客戶端在一段指定的時間之內執行上述偽碼的操作,那麼這段偽碼將能夠可靠的工作。如果有多個客戶端大約在同一時間嘗試遞增這個鍵的值,那麼將會產生競爭狀態。例如,客戶端-A和客戶端-B都會讀取這個鍵的舊值(例如:10)。這兩個客戶端都會將這個鍵的值遞增至11,最後使用SET命令將這個鍵的新值設定為11。因此,這個鍵的最終值是11,而不是12。

現在,我們可以使用WATCH命令完美地解決上述的問題,偽碼如下所示:

WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

由上述偽碼可知,如果存在競爭狀態,並且有另一個客戶端在我們呼叫WATCH命令和EXEC命令之間的時間內修改了val變數的結果,那麼事務將會執行失敗。

我們只需要重複執行上述偽碼的操作,希望此次執行不會再出現競爭狀態。這種形式的鎖就被稱為樂觀鎖,它是一種非常強大的鎖。在許多用例中,多個客戶端可能會訪問不同的鍵,因此不太可能發生衝突 —— 也就是說,通常沒有必要重複執行上述偽碼的操作。

七、WATCH命令詳解

那麼WATCH命令實際做了些什麼呢?這個命令會使得EXEC命令在滿足某些條件時才會執行事務:我們要求Redis只有在所有受監控的鍵都沒有被修改時,才會執行事務。(但是,相同的客戶端可能會在事務內部修改這些鍵,此時這個事務不會中止執行。)否則,Redis根本就不會進入事務。(注意,如果你使用WATCH命令監控一個易失性的鍵,然後在你監控這個鍵之後,Redis再使這個鍵過期,那麼EXEC命令仍然可以正常工作。)

WATCH命令可以被呼叫多次。簡單說來,所有的WATCH命令都會在被呼叫之時立刻對相應的鍵進行監控,直到EXEC命令被呼叫之時為止。你可以在單條的WATCH命令之中,使用任意數量的鍵作為命令引數。

當呼叫EXEC命令時,所有的鍵都會變為未受監控的狀態,Redis不會管事務是否被中止。當一個客戶單連線被關閉時,所有的鍵也都會變為未受監控的狀態。

你還可以使用UNWATCH命令(不需要任何引數),這樣便能清除所有的受監控鍵。當我們對某些鍵施加樂觀鎖之後,這個命令有時會非常有用。因為,我們可能需要執行一個用來修改這些鍵的事務,但是在讀取這些鍵的當前內容之後,我們可能不打算繼續進行操作,此時便可以使用UNWATCH命令,清除所有受監控的鍵。在執行UNWATCH命令之後,Redis連線便可以再次自由地用於執行新事務。

如何使用WATCH命令實現ZPOP操作呢?

本文將通過一個示例,說明如何使用WATCH命令建立一個新的原子化操作(Redis並不原生支援這個原子化操作),此處會以實現ZPOP操作為例。這個命令會以一種原子化的方式,從一個有序集合中彈出分數最低的元素。以下原始碼是最簡單的實現方式:

WATCH zset
element = ZRANGE zset 0 0
MULTI
ZREM zset element
EXEC

如果偽碼中的EXEC命令執行失敗(例如,返回Null值),那麼我們只需要重複執行這個操作即可。

八、Redis指令碼和事務

根據定義,Redis指令碼也是事務型的。因此,你可以通過Redis事務實現的功能,同樣也可以通過Redis指令碼來實現,而且通常指令碼更簡單、更快速。

由於Redis從2.6版本才開始引入指令碼特性,而事務特性是很久以前就已經存在的,所以目前的版本才有兩個看起來重複的特性。但是,我們不太可能在短時間內移除對事務特性的支援。因為,即使不用求助於Redis指令碼,使用者仍然能夠規避競爭狀態,這從語義上來看是適宜的。還有另一個更重要的原因,Redis事務特性的實現複雜度是最小的。

但是,在相當長的一段時間之內,我們不大可能看到整個使用者群體都只使用Redis指令碼。如果發生這種情況,那麼我們可能會廢棄,甚至最終移除Redis事務。

相關推薦

Redis事務功能

MULTI、EXEC、DISCARD和WATCH命令是Redis事務功能的基礎。Redis事務允許在一次單獨的步驟中執行一組命令,並且可以保證如下兩個重要事項: Redis會將一個事務中的所有命令序列化,然後按順序執行。Redis不可能在一個Redis事務的執行過程中插入執

_028_Redis_Redis的事務功能

轉自https://www.cnblogs.com/kyrin/p/5967620.html,感謝作者的無私分享。 MULTI、EXEC、DISCARD和WATCH命令是Redis事務功能的基礎。Redis事務允許在一次單獨的步驟中執行一組命令,並且可以保證如下兩個重要事項: >Red

Redis 復制功能

端口 重連 dia dong sort 擴展性 這一 ack 方法 Redis 復制功能的幾個重要方面:1. 一個Master可以有多個Slave;2. Redis使用異步復制。從2.8開始,Slave會周期性(每秒一次)發起一個Ack確認復制流(replication s

Spring基本功能

tex factor oid out 負責 sch bsp 初始化 pub 一、SpringIOC   Spring的控制反轉:把對象的創建,初始化,銷毀的過程交給SpringIOC容器來做,由Spring容器控制對象的生命周期。   1.1 啟動Spring容器的方式:

redis命令monitor

monitor 窗口 inf 做了 命令 linux blog linux中 技術分享 通過monitor這個命令可以查看數據庫在當前做了什麽操作,對於管理redis數據庫有這很大的幫助 如圖示,在redis客戶端進行操作顯示info,另一個窗口打

ServletContext作用功能

tle 記錄 人員 target 列表 頁面 catalog 程序 iyu 本文轉自http://blog.csdn.net/lvzhiyuan/article/details/4664624 感謝作者 ServletContext,是一個全局的儲存信息的空間,服務器開始

mysql慢查詢功能

mysql 慢查詢 優化有人的地方就有江湖,數據庫也是,sql優化這個問題,任重道遠,我們總是禁不住有爛sql。怎麽辦呢,還好各大數據庫都有相關爛sql的收集功能,而mysql的慢查詢收集也是異曲同工,配合分析sql的執行計劃,這個優化就有了搞頭了。開啟mysql慢查詢日誌1.查看當前慢查詢設置情況#查看慢查

Mysql數據庫分布式事務XA

oar 存儲引擎 成了 from get 分布式事務 value ive 進展 XA事務簡介 XA 事務的基礎是兩階段提交協議。需要有一個事務協調者來保證所有的事務參與者都完成了準備工作(第一階段)。如果協調者收到所有參與者都準備好的消息,就會通知所有的事務都可以提交了(第

ThinkSNS積分商城系統功能

信息 查看 修改 公開 送禮物 介紹 體驗 邏輯與 詳細 積分商城含PC端、Android APP、iOS APP;在ThinkSNS PC端首頁導航欄點擊“拓展功能”,然後選擇“積分商城”進行體驗;APP端則是在“發現”內,點擊“積分商城”進入應用,體驗。 PC積分商城功

UI Recorder 功能

斷言 完成 需要 加載完成 eight nal doc 字符 一段 前言: UI Recorder安裝教程見:UI Recorder 安裝教程(一)、UI Recorder 安裝教程(二) 本次著重介紹UI Recorder錄制過程中的功能按鈕:添加懸停,添加斷言,使用變量

Net Core中數據庫事務隔離——以Dapper和Mysql為例

事務 ring 增刪改 tostring 測試 stc efault 多個 log Net Core中數據庫事務隔離詳解——以Dapper和Mysql為例 事務隔離級別 準備工作 Read uncommitted 讀未提交 Read committed 讀取提交內

MySQL Flashback 閃回功能

轉換 下載 libstdc -s bin 二進制日誌 pos 發生 插入 閱讀目錄 1. 簡介 2. 閃回原理 3. flashback安裝 4. 使用簡介 5. Flashback工具使用註意點 回到頂部 1. 簡介 mysqlbinlog flashback(閃

PHP error_reporting() 錯誤控制函數功能

互操作 log 成了 bug art 恢復 tin 有意 cover 定義和用法: error_reporting() 設置 PHP 的報錯級別並返回當前級別。 函數語法: error_reporting(report_level) 如果參數 level 未指定,當前報

Yii2 教程 - yii2-redis 擴展

鍵值 lob hostname var 包括 blog 很多 框架 username 該教程已被合並到《Yii2 權威指南中文版》中!Yiichina 教程地址為《yii2-redis 擴展詳解》! 一、簡介 yii2-redis 擴展為 Yii2 框架提供了 redi

應用層協議及其功能

應用層應用層協議及其功能詳解 DNS: 域名服務,用於將名稱解析為IP地址,反之亦然 DNS是一個倒置的樹形結構。最頂部是根域,用英文句點(.)表示。全球有13個根域服務器,一臺主服務器在美國,9臺輔助服務器在美國,2臺在歐州,一臺在日本。 根域服務器以下是一級域(頂級域)、二級域、三級域……最多127級

NAT功能及案例分析—華為NAT server的實現

NATNAT #network address translation - 網絡地址轉換。 NAT的分類 #靜態NAT、動態NAT,動態NAT包含了我們常用的PNAT(PAT)。 端口nat (端口地址轉換 華為&思科NAT對比 靜態NAT #靜態轉換是指將內部網絡的私有IP地址轉換為公有IP地址

Bayboy功能

情況 style prope bubuko 文本 info ren enter 詳解 Bayboy功能詳解 一、Badboy中的檢查點 1.1以sogou.com搜索為例,搜索測試 步驟:打開Badboy工具,在地址欄中輸入搜狗網址;輸入 測試 進行搜索;點擊紅色按鈕停止錄

opensns功能

技術分享 正在 其他 style tdi 圖書 空間 標簽 css opensns功能詳解 #wmd-preview h1 { color: #0077bb } opensns功能詳解 軟件工程 輪播功能 此項可以用來發布廣告、新聞等。對於實驗室網站而言,可

Laravel 5使用Laravel Excel實現Excel/CSV文件導入導出的功能

使用 pat 不存在 data utf-8 標題 sts lda http https://mp.weixin.qq.com/s/Gel1eMHz6_eDWgDMaBQ5BQ 這篇文章主要給大家介紹了關於在Laravel 5中如何使用Laravel Excel實現Exc

關於syslog日誌功能 事件日誌分析、EventLog Analyzer

linux 活動 數據 linu type 監控 roc oracle windows系統 關於syslog日誌功能詳解 事件日誌分析、EventLog Analyzer 一、日誌管理保障網絡安全Windows系統日誌分析Syslog日誌分析應用程序日誌分析Windows