大家好屹篓,我是漫步coding, 最近在整理2022年Redis最新面試題, 大家也可以通過我下面的博客地址在線閱讀, 今天講講第3篇 - Redis事務幅聘。本文首發(fā)于公眾號:漫步coding
2022年Redis最新面試題目錄
Redis數(shù)據(jù)結構
Redis事務
Redis數(shù)據(jù)持久化
Redis集群
Redis淘汰策略
Redis分布式鎖
Redis緩存問題
運維和部署
事務
怎么理解 Redis 事務?
Redis事務執(zhí)行過程
Redis事務的一些使用場景
Redis事務與Redis pipeline的區(qū)別
集群模式下Redis事務如何保證原子性
怎么理解 Redis 事務?
出現(xiàn)概率: ★★★★
Redis事務的本質(zhì)是一組命令的集合。事務支持一次執(zhí)行多個命令,一個事務中所有命令都會被序列化野舶。在事務執(zhí)行過程,會按照順序串行的執(zhí)行隊列中的命令宰衙,其他客戶端提交的命令請求不會插入到事務執(zhí)行命令序列中筒愚。
總結說:Redis事務就是一次性、順序性菩浙、排他性的執(zhí)行一個隊列中的一系列命令巢掺。
1)句伶、Redis事務相關命令和使用
MULTI 、 EXEC 陆淀、 DISCARD 和 WATCH 是 Redis 事務相關的命令考余。
MULTI: 開啟事務,redis會將后續(xù)的命令逐個放入隊列中轧苫,然后使用EXEC命令來原子化執(zhí)行這個命令系列楚堤。
EXEC: 執(zhí)行事務中的所有操作命令。
DISCARD: 取消事務含懊,放棄執(zhí)行事務塊中的所有命令身冬。
WATCH: 監(jiān)視一個或多個key,如果事務在執(zhí)行前,這個key(或多個key)被其他命令修改岔乔,則事務被中斷酥筝,不會執(zhí)行事務中的任何命令。
UNWATCH: 取消WATCH對所有key的監(jiān)視雏门。
example:
127.0.0.1:6379>MULTI
OK
127.0.0.1:6379>SET?name'漫步coding'
QUEUED
127.0.0.1:6379>SET?brief'一個專注于算法嘿歌、數(shù)據(jù)庫、職場的公眾號'
QUEUED
127.0.0.1:6379>GET?name
QUEUED
127.0.0.1:6379>EXEC
1)?OK
2)?OK
3)"漫步coding"
畫重點,?Redis事務不支持Rollback
事實上Redis命令在事務執(zhí)行時可能會失敗茁影,但仍會繼續(xù)執(zhí)行剩余命令而不是Rollback(事務回滾)宙帝。如果你使用過關系數(shù)據(jù)庫,這種情況可能會讓你感到很奇怪募闲。然而針對這種情況Redis官方也給出了解釋:
Redis命令可能會執(zhí)行失敗步脓,僅僅是由于錯誤的語法被調(diào)用(命令排隊時檢測不出來的錯誤),或者使用錯誤的數(shù)據(jù)類型操作某個Key:? ?這意味著浩螺,實際上失敗的命令都是編程錯誤造成的靴患,都是開發(fā)中能夠被檢測出來的,生產(chǎn)環(huán)境中不應該存在年扩。(這番話蚁廓,徹底甩鍋,“都是你們自己編程錯誤厨幻,與我們無關”相嵌。)
由于不必支持Rollback,Redis內(nèi)部簡潔并且更加高效。
Redis事務執(zhí)行過程
出現(xiàn)概率: ★★★
一個Redis事務從開始到執(zhí)行會經(jīng)歷以下三個階段:
1)開始事務况脆。
2)命令放入Queue饭宾。
3)執(zhí)行事務。
1)開始事務
MULTI命令的執(zhí)行標記著事務的開始:
127.0.0.1:6379>MULTI
OK
這個命令唯一做的就是格了, 將客戶端的 REDIS_MULTI 選項打開看铆, 讓客戶端從非事務狀態(tài)切換到事務狀態(tài)。
2)命令放入Queue
當客戶端處于非事務狀態(tài)下時盛末, 所有發(fā)送給服務器端的命令都會立即被服務器執(zhí)行:
127.0.0.1:6379>SET?name'漫步coding'
OK
127.0.0.1:6379>GET?name
"漫步coding"
但是弹惦, 當客戶端進入事務狀態(tài)之后否淤, 服務器在收到來自客戶端的命令時, 不會立即執(zhí)行命令棠隐, 而是將這些命令全部放進一個事務隊列里石抡, 然后返回QUEUED, 表示命令已入隊:
127.0.0.1:6379>MULTI
OK
127.0.0.1:6379>SETname"漫步coding"
QUEUED
127.0.0.1:6379>GETname
QUEUED
3)執(zhí)行事務
當客戶端進入事務狀態(tài)之后助泽, 客戶端發(fā)送的命令就會被放進事務隊列里啰扛。
EXEC 、 DISCARD 嗡贺、 MULTI 和 WATCH 這四個命令 —— 當這四個命令從客戶端發(fā)送到服務器時隐解, 它們會像客戶端處于非事務狀態(tài)一樣, 會被服務器立即執(zhí)行诫睬。
127.0.0.1:6379>EXEC
1)OK
2)OK
3)?"漫步coding"
4)煞茫、關于WATCH命令
WATCH指令,有點類似樂觀鎖岩臣,事務提交時溜嗜,如果 key 的值已被別的客戶端改變宵膨,比如某個 list 已被別的客戶端push/pop 過了架谎,整個事務隊列都不會被執(zhí)行。(當然也可以用 Redis 實現(xiàn)分布式鎖來保證安全性辟躏,屬于悲觀鎖)
WATCH機制的作用是谷扣,在事務執(zhí)行前,監(jiān)控一個或多個鍵的值變化情況捎琐,當事務調(diào)用EXEC命令執(zhí)行時会涎,WATCH機制會先檢查監(jiān)控的鍵是否被其它客戶端修改了。如果修改了瑞凑,就放棄事務執(zhí)行末秃,避免事務的隔離性被破壞。然后籽御,客戶端可以再次執(zhí)行事務练慕,此時,如果沒有并發(fā)修改事務數(shù)據(jù)的操作了技掏,事務就能正常執(zhí)行铃将,隔離性也得到了保證。
WATCH機制的具體實現(xiàn)是由WATCH命令實現(xiàn)的哑梳,我給你舉個例子劲阎,你可以看下面的圖,進一步理解下WATCH命令的使用鸠真。
example:
127.0.0.1:6379>setk1
OK
127.0.0.1:6379>WATCHk
OK
127.0.0.1:6379>setk2
OK
127.0.0.1:6379>MULTI
OK
127.0.0.1:6379>setk3
QUEUED
127.0.0.1:6379>EXEC
(nil)
127.0.0.1:6379>getk
"2"
提交事務悯仙,但k值不會被修改為3龄毡,因為在事務開啟之前k的值被修改了。
Redis事務的一些使用場景
出現(xiàn)概率: ★★★
可利用watch命令監(jiān)聽key锡垄,實現(xiàn)樂觀鎖稚虎,來保證不會出現(xiàn)沖突,應用場景比如秒殺來防止超賣偎捎。
秒殺場景偽代碼如下:
這塊代碼其實還沒有想好, 如果有經(jīng)驗的朋友蠢终,歡迎留言, 后續(xù)我研究透徹會也專門寫一篇秒殺場景的文章。
settotal_quantity100
WATCH?goods_quantity
MULTI
ifgoods_quantity?<?total_quantity?&&?user_idnotin'user_list'
incr?goods_quantity
set'user_list'user_id
end
EXEC
Redis事務與Redis pipeline的區(qū)別
出現(xiàn)概率: ★★★
Redis Pipeline主要用于批量發(fā)送命令茴她,一次性發(fā)送多個請求寻拂,一次性讀取所有返回結果≌衫危可以節(jié)省連接->發(fā)送命令->返回結果這個過程所產(chǎn)生的時間(RTT)祭钉,減少read()和write()的系統(tǒng)調(diào)用(從用戶態(tài)到內(nèi)核態(tài)之間的切換)次數(shù)。
Redis事務己沛、Redis Pipeline表面上它們可以作為批量執(zhí)行命令的方式慌核,但實際也有許多區(qū)別。
1)申尼、命令緩沖隊列方式不同
Redis事務包含的命令是緩沖在服務端內(nèi)存隊列垮卓,而Redis Pipeline則是緩沖在客戶端本地內(nèi)存中;
2)师幕、請求次數(shù)不同
Redis事務中每個命令都需要發(fā)送到服務端粟按,而Pipeline只需要發(fā)送一次,請求次數(shù)更少霹粥;
3)灭将、原子性保證
Redis事務可以保證命令原子化執(zhí)行,而Pipeline不保證原子性后控。
Redis事務庙曙、Pipeline都只能作用于單個節(jié)點。集群環(huán)境下浩淘,執(zhí)行Redis命令時捌朴,會根據(jù)key計算出一個槽位(slot),然后根據(jù)槽位重定向到特定的節(jié)點上執(zhí)行操作。
4)馋袜、在使用事務時男旗,建議配合 Pipeline 使用。
a) 如果不使用 Pipeline欣鳖,客戶端是先發(fā)一個 MULTI 命令到服務端察皇,客戶端收到 OK,然后客戶端再發(fā)送一個個操作命令,客戶端依次收到 QUEUED什荣,最后客戶端發(fā)送 EXEC 執(zhí)行整個事務(文章例子就是這樣演示的)矾缓,這樣消息每次都是一來一回,效率比較低稻爬,而且在這多次操作之間嗜闻,別的客戶端可能就把原本準備修改的值給修改了,所以無法保證隔離性桅锄。
b) 而使用 Pipeline 是一次性把所有命令打包好全部發(fā)送到服務端琉雳,服務端全部處理完成后返回。這么做好的好處友瘤,一是減少了來回網(wǎng)絡 IO 次數(shù)翠肘,提高操作性能。二是一次性發(fā)送所有命令到服務端辫秧,服務端在處理過程中束倍,是不會被別的請求打斷的(Redis單線程特性,此時別的請求進不來)盟戏,這本身就保證了隔離性绪妹。我們平時使用的 Redis SDK 在使用開啟事務時,一般都會默認開啟 Pipeline 的柿究,可以留意觀察一下邮旷。
集群模式下Redis事務如何保證原子性
出現(xiàn)概率: ★★★
Redis事務中每個命令都需要發(fā)送到服務端, 不過Redis事務可以保證命令原子化執(zhí)行
Redis事務只能作用于單個節(jié)點。集群環(huán)境下笛求,執(zhí)行Redis命令時廊移,會根據(jù)key計算出一個槽位(slot),然后根據(jù)槽位重定向到特定的節(jié)點上執(zhí)行操作糕簿。
也歡迎關注我的公眾號:?漫步coding探入。一起交流, 在coding的世界里漫步, ?? ?回復:?redis, 免費獲取最新Redis面試題(含答案)。