2022年Redis最新面試題第3篇 - Redis事務(wù)

大家好,我是漫步coding, 最近在整理2022年Redis最新面試題, 大家也可以通過我下面的博客地址在線閱讀, 今天講講第3篇 - Redis事務(wù)。本文首發(fā)于公眾號(hào):漫步coding

2022年Redis最新面試題目錄

Redis基礎(chǔ)知識(shí)

Redis數(shù)據(jù)結(jié)構(gòu)

Redis事務(wù)

Redis數(shù)據(jù)持久化

Redis集群

Redis淘汰策略

Redis分布式鎖

Redis緩存問題

運(yùn)維和部署

事務(wù)

怎么理解 Redis 事務(wù)?

Redis事務(wù)執(zhí)行過程

Redis事務(wù)的一些使用場(chǎng)景

Redis事務(wù)與Redis pipeline的區(qū)別

集群模式下Redis事務(wù)如何保證原子性

怎么理解 Redis 事務(wù)?

出現(xiàn)概率: ★★★★

Redis事務(wù)的本質(zhì)是一組命令的集合。事務(wù)支持一次執(zhí)行多個(gè)命令,一個(gè)事務(wù)中所有命令都會(huì)被序列化。在事務(wù)執(zhí)行過程,會(huì)按照順序串行的執(zhí)行隊(duì)列中的命令,其他客戶端提交的命令請(qǐng)求不會(huì)插入到事務(wù)執(zhí)行命令序列中。

總結(jié)說:Redis事務(wù)就是一次性、順序性、排他性的執(zhí)行一個(gè)隊(duì)列中的一系列命令。

1)、Redis事務(wù)相關(guān)命令和使用

MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事務(wù)相關(guān)的命令。

MULTI: 開啟事務(wù),redis會(huì)將后續(xù)的命令逐個(gè)放入隊(duì)列中,然后使用EXEC命令來原子化執(zhí)行這個(gè)命令系列。

EXEC: 執(zhí)行事務(wù)中的所有操作命令。

DISCARD: 取消事務(wù),放棄執(zhí)行事務(wù)塊中的所有命令。

WATCH: 監(jiān)視一個(gè)或多個(gè)key,如果事務(wù)在執(zhí)行前,這個(gè)key(或多個(gè)key)被其他命令修改,則事務(wù)被中斷,不會(huì)執(zhí)行事務(wù)中的任何命令。

UNWATCH: 取消WATCH對(duì)所有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'一個(gè)專注于算法、數(shù)據(jù)庫(kù)、職場(chǎng)的公眾號(hào)'

QUEUED

127.0.0.1:6379>GET?name

QUEUED

127.0.0.1:6379>EXEC

1)?OK

2)?OK

3)"漫步coding"

畫重點(diǎn),?Redis事務(wù)不支持Rollback

事實(shí)上Redis命令在事務(wù)執(zhí)行時(shí)可能會(huì)失敗,但仍會(huì)繼續(xù)執(zhí)行剩余命令而不是Rollback(事務(wù)回滾)。如果你使用過關(guān)系數(shù)據(jù)庫(kù),這種情況可能會(huì)讓你感到很奇怪。然而針對(duì)這種情況Redis官方也給出了解釋:

Redis命令可能會(huì)執(zhí)行失敗,僅僅是由于錯(cuò)誤的語法被調(diào)用(命令排隊(duì)時(shí)檢測(cè)不出來的錯(cuò)誤),或者使用錯(cuò)誤的數(shù)據(jù)類型操作某個(gè)Key:? ?這意味著,實(shí)際上失敗的命令都是編程錯(cuò)誤造成的,都是開發(fā)中能夠被檢測(cè)出來的,生產(chǎn)環(huán)境中不應(yīng)該存在。(這番話,徹底甩鍋,“都是你們自己編程錯(cuò)誤,與我們無關(guān)”。)

由于不必支持Rollback,Redis內(nèi)部簡(jiǎn)潔并且更加高效。

Redis事務(wù)執(zhí)行過程

出現(xiàn)概率: ★★★

一個(gè)Redis事務(wù)從開始到執(zhí)行會(huì)經(jīng)歷以下三個(gè)階段:

1)開始事務(wù)。

2)命令放入Queue。

3)執(zhí)行事務(wù)。

1)開始事務(wù)

MULTI命令的執(zhí)行標(biāo)記著事務(wù)的開始:

127.0.0.1:6379>MULTI

OK

這個(gè)命令唯一做的就是, 將客戶端的 REDIS_MULTI 選項(xiàng)打開, 讓客戶端從非事務(wù)狀態(tài)切換到事務(wù)狀態(tài)。

2)命令放入Queue

當(dāng)客戶端處于非事務(wù)狀態(tài)下時(shí), 所有發(fā)送給服務(wù)器端的命令都會(huì)立即被服務(wù)器執(zhí)行:

127.0.0.1:6379>SET?name'漫步coding'

OK

127.0.0.1:6379>GET?name

"漫步coding"

但是, 當(dāng)客戶端進(jìn)入事務(wù)狀態(tài)之后, 服務(wù)器在收到來自客戶端的命令時(shí), 不會(huì)立即執(zhí)行命令, 而是將這些命令全部放進(jìn)一個(gè)事務(wù)隊(duì)列里, 然后返回QUEUED, 表示命令已入隊(duì):

127.0.0.1:6379>MULTI

OK

127.0.0.1:6379>SETname"漫步coding"

QUEUED

127.0.0.1:6379>GETname

QUEUED

3)執(zhí)行事務(wù)

當(dāng)客戶端進(jìn)入事務(wù)狀態(tài)之后, 客戶端發(fā)送的命令就會(huì)被放進(jìn)事務(wù)隊(duì)列里。

EXEC 、 DISCARD 、 MULTI 和 WATCH 這四個(gè)命令 —— 當(dāng)這四個(gè)命令從客戶端發(fā)送到服務(wù)器時(shí), 它們會(huì)像客戶端處于非事務(wù)狀態(tài)一樣, 會(huì)被服務(wù)器立即執(zhí)行。

127.0.0.1:6379>EXEC

1)OK

2)OK

3)?"漫步coding"

4)、關(guān)于WATCH命令

WATCH指令,有點(diǎn)類似樂觀鎖,事務(wù)提交時(shí),如果 key 的值已被別的客戶端改變,比如某個(gè) list 已被別的客戶端push/pop 過了,整個(gè)事務(wù)隊(duì)列都不會(huì)被執(zhí)行。(當(dāng)然也可以用 Redis 實(shí)現(xiàn)分布式鎖來保證安全性,屬于悲觀鎖)

WATCH機(jī)制的作用是,在事務(wù)執(zhí)行前,監(jiān)控一個(gè)或多個(gè)鍵的值變化情況,當(dāng)事務(wù)調(diào)用EXEC命令執(zhí)行時(shí),WATCH機(jī)制會(huì)先檢查監(jiān)控的鍵是否被其它客戶端修改了。如果修改了,就放棄事務(wù)執(zhí)行,避免事務(wù)的隔離性被破壞。然后,客戶端可以再次執(zhí)行事務(wù),此時(shí),如果沒有并發(fā)修改事務(wù)數(shù)據(jù)的操作了,事務(wù)就能正常執(zhí)行,隔離性也得到了保證。

WATCH機(jī)制的具體實(shí)現(xiàn)是由WATCH命令實(shí)現(xiàn)的,我給你舉個(gè)例子,你可以看下面的圖,進(jì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"

提交事務(wù),但k值不會(huì)被修改為3,因?yàn)樵谑聞?wù)開啟之前k的值被修改了。

Redis事務(wù)的一些使用場(chǎng)景

出現(xiàn)概率: ★★★

可利用watch命令監(jiān)聽key,實(shí)現(xiàn)樂觀鎖,來保證不會(huì)出現(xiàn)沖突,應(yīng)用場(chǎng)景比如秒殺來防止超賣。

秒殺場(chǎng)景偽代碼如下:

這塊代碼其實(shí)還沒有想好, 如果有經(jīng)驗(yàn)的朋友,歡迎留言, 后續(xù)我研究透徹會(huì)也專門寫一篇秒殺場(chǎng)景的文章。

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事務(wù)與Redis pipeline的區(qū)別

出現(xiàn)概率: ★★★

Redis Pipeline主要用于批量發(fā)送命令,一次性發(fā)送多個(gè)請(qǐng)求,一次性讀取所有返回結(jié)果。可以節(jié)省連接->發(fā)送命令->返回結(jié)果這個(gè)過程所產(chǎn)生的時(shí)間(RTT),減少read()和write()的系統(tǒng)調(diào)用(從用戶態(tài)到內(nèi)核態(tài)之間的切換)次數(shù)。

Redis事務(wù)、Redis Pipeline表面上它們可以作為批量執(zhí)行命令的方式,但實(shí)際也有許多區(qū)別。

1)、命令緩沖隊(duì)列方式不同

Redis事務(wù)包含的命令是緩沖在服務(wù)端內(nèi)存隊(duì)列,而Redis Pipeline則是緩沖在客戶端本地內(nèi)存中;

2)、請(qǐng)求次數(shù)不同

Redis事務(wù)中每個(gè)命令都需要發(fā)送到服務(wù)端,而Pipeline只需要發(fā)送一次,請(qǐng)求次數(shù)更少;

3)、原子性保證

Redis事務(wù)可以保證命令原子化執(zhí)行,而Pipeline不保證原子性。

Redis事務(wù)、Pipeline都只能作用于單個(gè)節(jié)點(diǎn)。集群環(huán)境下,執(zhí)行Redis命令時(shí),會(huì)根據(jù)key計(jì)算出一個(gè)槽位(slot),然后根據(jù)槽位重定向到特定的節(jié)點(diǎn)上執(zhí)行操作。

4)、在使用事務(wù)時(shí),建議配合 Pipeline 使用。

a) 如果不使用 Pipeline,客戶端是先發(fā)一個(gè) MULTI 命令到服務(wù)端,客戶端收到 OK,然后客戶端再發(fā)送一個(gè)個(gè)操作命令,客戶端依次收到 QUEUED,最后客戶端發(fā)送 EXEC 執(zhí)行整個(gè)事務(wù)(文章例子就是這樣演示的),這樣消息每次都是一來一回,效率比較低,而且在這多次操作之間,別的客戶端可能就把原本準(zhǔn)備修改的值給修改了,所以無法保證隔離性。

b) 而使用 Pipeline 是一次性把所有命令打包好全部發(fā)送到服務(wù)端,服務(wù)端全部處理完成后返回。這么做好的好處,一是減少了來回網(wǎng)絡(luò) IO 次數(shù),提高操作性能。二是一次性發(fā)送所有命令到服務(wù)端,服務(wù)端在處理過程中,是不會(huì)被別的請(qǐng)求打斷的(Redis單線程特性,此時(shí)別的請(qǐng)求進(jìn)不來),這本身就保證了隔離性。我們平時(shí)使用的 Redis SDK 在使用開啟事務(wù)時(shí),一般都會(huì)默認(rèn)開啟 Pipeline 的,可以留意觀察一下。

集群模式下Redis事務(wù)如何保證原子性

出現(xiàn)概率: ★★★

Redis事務(wù)中每個(gè)命令都需要發(fā)送到服務(wù)端, 不過Redis事務(wù)可以保證命令原子化執(zhí)行

Redis事務(wù)只能作用于單個(gè)節(jié)點(diǎn)。集群環(huán)境下,執(zhí)行Redis命令時(shí),會(huì)根據(jù)key計(jì)算出一個(gè)槽位(slot),然后根據(jù)槽位重定向到特定的節(jié)點(diǎn)上執(zhí)行操作。

也歡迎關(guān)注我的公眾號(hào):?漫步coding。一起交流, 在coding的世界里漫步, ?? ?回復(fù):?redis, 免費(fèi)獲取最新Redis面試題(含答案)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容