-
1 # 懂點IT
-
2 # 給自己的福音
Redis是單執行緒的,所以一條語句保證了自身的原子性。對於多條語句,使用multi……exec,它會快取每一條語句並檢查中間是否有錯,如果有其他執行緒修改了某個指,標記為髒。那麼最終exec是返回nil。所以原子性雖然保證了,但是隔離性沒有。儘量使用單個操作命令完成業務就好了
-
3 # 山水莊園齊老闆原子性:
原子性是資料庫的事務中的特性。在資料庫事務的情景下,原子性指的是:一個事務(transaction)中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節。
對於Redis而言,命令的原子性指的是:一個操作的不可以再分,操作要麼執行,要麼不執行。
Redis操作原子性的原因: Redis的操作之所以是原子性的,是因為Redis是單執行緒的。 Redis在併發中的表現: Redis的API是原子性的操作,那麼多個命令在併發中也是原子性的嗎? 有以下程式碼:
$redis= newRedis;
$redis->connect("127.0.0.1",6379);
for($i= 0;$iget("val");
$num++;
$redis->set("val",$num);
usleep(10000);
}
用兩個終端執行上面的程式,發現val的結果是小於2000的值,那麼可以知道,在程式中執行多個Redis命令並非是原子性的,這也和普通資料庫的表現是一樣的。 如果想在上面的程式中實現原子性,可以將get和set改成單命令操作,比如incr,或者使用Redis的事務,或者使用Redis+Lua的方式實現。
對Redis來說,執行get、set以及eval等API,都是一個一個的任務,這些任務都會由Redis的執行緒去負責執行,任務要麼執行成功,要麼執行失敗,這就是Redis的命令是原子性的原因。
Redis本身提供的所有API都是原子操作,Redis中的事務其實是要保證批次操作的原子性。
回覆列表
什麼是原子性?
說到原子性就不得不提事務操作,原子性操作指在一個事務中,多個步驟操作要麼一起成功完成,要麼一起失敗,不能出現部分成功或部分失敗,對於redis來說,事務佇列中的命令要麼全部執行,要麼都不執行,所以redis的事務具有原子性。
Reids如何執行事務?弄清楚redis如何保證原子性操作之前,我們先來了解下redis事務操作的流程。
一個事務從開始到結束會經歷以下三個階段:
事務開始命令入列(先進先出)事務執行舉個例子:
redis > muti //開啟一個事務(此命令會修改客戶端狀態屬性,將其狀態變為事務開啟)
ok //並且立即執行後返回結果
reids > set name hunk
queued //此命令送入佇列排隊等候,不會立即執行
redis > get name
queued //送入佇列排隊...
redis > exec //從佇列中取出命令全部執行,最後執行結果全部返回給客戶端
ok //返回結果
這裡需要注意的是,redis接受到一個命令後,伺服器端判斷該命令是立即執行還是放入佇列,是根據客戶端是否開啟了事務狀態來決定的,例如:
當一個客戶端處於事務開啟狀態時,如果伺服器接收到exec命令,服務端將遍歷這個關聯的事務佇列,並執行當中的所有命令,最後全部返回給客戶端:
如何保證事務原子性?我們已經知道了redis事務是如何執行的:客戶端透過muti命令開啟事務狀態,服務端透過事務佇列儲存客戶端所有命令,然後客戶端發起exec命令後,伺服器執行佇列的中所有的命令,最後取消客戶端事務狀態、清理佇列、返回結果到客戶端。
watch命令:wathc命令是一個樂觀鎖,透過鎖我們可以實現原子性操作,wantch可以在exec執行之前監視任意數量的資料庫鍵key,並在exec執行時,檢查被監視的key是否已經被修改,如果是,伺服器就會拒絕執行當前事務中所有命令,返回客戶端執行失敗的回覆。比如以下兩個客戶端執行命令的過程,如下圖:
T4時刻,客戶端B修改了name鍵值,而客戶端A已經監聽了name鍵,T5時刻客戶端A執行exec命令時,伺服器發現name已經被修改,因此伺服器會拒絕執行A的事務,每個redis資料庫都有一個watch_keys的字典,透過該字典,redis伺服器可以知道資料庫中哪些鍵正在被監視,如下圖:
比如,如果“name”被修改,那麼客戶端a,b的redis_dirty_cas標識被開啟,當伺服器收到客戶端a或b發來的exec的命令時,伺服器判斷客戶端是否打開了該標識來決定是否執行事務,如下圖:
一致性保證:一致性是指資料符合預定義的要求,沒有無效的或非法資料,這是保證原子操作的必然結果,redis事務中會出現不可預知的錯誤,如何保證資料一致性呢?我們從三個redis事務可能出錯的地方來看看
入隊錯誤:如果事務在入隊命令時,命令不存在或格式不正確,那麼redis將拒絕執行這個事務。redis > muti ok
redis > set name "aa" queued
redis > liuneng (error) err unknown command "liuneng"
redis > get name queued
redis > exec (error) execabort transaction discarded because of previous errors.
伺服器未發現未知命令 liuneng 所有拒絕執行佇列中命令,也就終止了此項事務,保證了原子性、資料一致性。
執行錯誤:如果redis在執行佇列中的命令過程中出現了錯誤,它會繼續執行佇列中剩下的命令,已執行的命令和結果不會被出錯的命令所影響,因為出錯的命令會被伺服器識別出來並予以錯誤處理,不會對資料庫做任何修改,也不會影響資料一致性。服務停器機:伺服器停機後redis在重啟時會根據持久化模式,選擇對應的AOF或RDB檔案來恢復資料,事務中途發生的停機不會影響資料庫一致性。