redis事務 redis 優化

2021-10-06 10:38:39 字數 4495 閱讀 2944

redis提供許多批量操作的命令,如mset/mget/hmset/hmget等等,這些命令存在的意義是減少維護網路連線和傳輸資料所消耗的資源和時間。

例如連續使用5次set命令設定5個不同的key,比起使用一次mset命令設定5個不同的key,效果是一樣的,但前者會消耗更多的rtt(round trip time)時長,永遠應優先使用後者。

然而,如果客戶端要連續執行的多次操作無法通過redis命令組合在一起,例如:

set a 「abc」

incr b

hset c name 「hi」

此時便可以使用redis提供的pipelining功能來實現在一次互動中執行多條命令。

使用pipelining時,只需要從客戶端一次向redis傳送多條命令(以\r\n)分隔,redis就會依次執行這些命令,並且把每個命令的返回按順序組裝在一起一次返回,比如:

$ (printf 「ping\r\nping\r\nping\r\n」; sleep 1) | nc localhost 6379

+pong

+pong

+pong

大部分的redis客戶端都對pipelining提供支援,所以開發者通常並不需要自己手工拼裝命令列表。

pipelining的侷限性

pipelining只能用於執行連續且無相關性的命令,當某個命令的生成需要依賴於前乙個命令的返回時,就無法使用pipelining了。

通過scripting功能,可以規避這一侷限性

pipelining能夠讓redis在一次互動中處理多條命令,然而在一些場景下,我們可能需要在此基礎上確保這一組命令是連續執行的。

比如獲取當前累計的pv數並將其清0

> get vcount

12384

> set vcount 0

ok

如果在get和set命令之間插進來乙個incr vcount,就會使客戶端拿到的vcount不準確。

redis的事務可以確保複數命令執行時的原子性。也就是說redis能夠保證:乙個事務中的一組命令是絕對連續執行的,在這些命令執行完成之前,絕對不會有來自於其他連線的其他命令插進去執行。

通過multi和exec命令來把這兩個命令加入乙個事務中:

> multi

ok> get vcount

queued

> set vcount 0

queued

> exec 1)

12384

2)ok

redis在接收到multi命令後便會開啟乙個事務,這之後的所有讀寫命令都會儲存在佇列中但並不執行,直到接收到exec命令後,redis會把佇列中的所有命令連續順序執行,並以陣列形式返回每個命令的返回結果。

可以使用discard命令放棄當前的事務,將儲存的命令佇列清空。

需要注意的是,redis事務不支援回滾:

如果乙個事務中的命令出現了語法錯誤,大部分客戶端驅動會返回錯誤,2.6.5版本以上的redis也會在執行exec時檢查佇列中的命令是否存在語法錯誤,如果存在,則會自動放棄事務並返回錯誤。

但如果乙個事務中的命令有非語法類的錯誤(比如對string執行hset操作),無論客戶端驅動還是redis都無法在真正執行這條命令之前發現,所以事務中的所有命令仍然會被依次執行。在這種情況下,會出現乙個事務中部分命令成功部分命令失敗的情況,然而與rdbms不同,redis不提供事務回滾的功能,所以只能通過其他方法進行資料的回滾。

通過事務實現cas

redis提供了watch命令與事務搭配使用,實現cas樂觀鎖的機制。

假設要實現將某個商品的狀態改為已售:

if

(exec

(hget stock:

1001 state)

=="in stock"

)exec

(hset stock:

1001 state "sold"

);

這一偽**執行時,無法確保併發安全性,有可能多個客戶端都獲取到了"in stock"的狀態,導致乙個庫存被售賣多次。

使用watch命令和事務可以解決這一問題:

exec

(watch stock:

1001);

if(exec

(hget stock:

1001 state)

=="in stock"

)

watch的機制是:在事務exec命令執行時,redis會檢查被watch的key,只有被watch的key從watch起始時至今沒有發生過變更,exec才會被執行。如果watch的key在watch命令到exec命令之間發生過變化,則exec命令會返回失敗。

scripting

通過eval與evalsha命令,可以讓redis執行lua指令碼。這就類似於rdbms的儲存過程一樣,可以把客戶端與redis之間密集的讀/寫互動放在服務端進行,避免過多的資料互動,提公升效能。

scripting功能是作為事務功能的替代者誕生的,事務提供的所有能力scripting都可以做到。redis官方推薦使用lua script來代替事務,前者的效率和便利性都超過了事務。

儘管redis是乙個非常快速的記憶體資料儲存媒介,也並不代表redis不會產生效能問題。

前文中提到過,redis採用單執行緒模型,所有的命令都是由乙個執行緒序列執行的,所以當某個命令執行耗時較長時,會拖慢其後的所有命令,這使得redis對每個任務的執行效率更加敏感。

針對redis的效能優化,主要從下面幾個層面入手:

長耗時命令

redis絕大多數讀寫命令的時間複雜度都在o(1)到o(n)之間,在文字和官方文件中均對每個命令的時間複雜度有說明。

通常來說,o(1)的命令是安全的,o(n)命令在使用時需要注意,如果n的數量級不可預知,則應避免使用。例如對乙個field數未知的hash資料執行hgetall/hkeys/hvals命令,通常來說這些命令執行的很快,但如果這個hash中的field數量極多,耗時就會成倍增長。

又如使用sunion對兩個set執行union操作,或使用sort對list/set執行排序操作等時,都應該嚴加注意。

避免在使用這些o(n)命令時發生問題主要有幾個辦法:

redis提供了scan命令,可以對redis中儲存的所有key進行游標式的遍歷,避免使用keys命令帶來的效能問題。同時還有sscan/hscan/zscan等命令,分別用於對set/hash/sorted set中的元素進行游標式遍歷。scan類命令的使用請參考官方文件:

slowlog-log-slower-than ***ms  #執行時間慢於***毫秒的命令計入slow log

slowlog-

max-

len *** #slow log的長度,即最大紀錄多少條slow log

使用slowlog get [number]命令,可以輸出最近進入slow log的number條命令。

使用slowlog reset命令,可以重置slow log

網路引發的延遲

資料持久化引發的延遲

redis的資料持久化工作本身就會帶來延遲,需要根據資料的安全級別和效能要求制定合理的持久化策略:

redis在fork子程序時需要將記憶體分頁表拷貝至子程序,以占用了24gb記憶體的redis例項為例,共需要拷貝24gb / 4kb * 8 = 48mb的資料。在使用單xeon 2.27ghz的物理機上,這一fork操作耗時216ms。

可以通過info命令返回的latest_fork_usec欄位檢視上一次fork操作的耗時(微秒)

swap引發的延遲

當linux將redis所用的記憶體分頁移至swap空間時,將會阻塞redis程序,導致redis出現不正常的延遲。swap通常在物理記憶體不足或一些程序在進行大量i/o操作時發生,應盡可能避免上述兩種情況的出現。

/proc//smaps檔案中會儲存程序的swap記錄,通過檢視這個檔案,能夠判斷redis的延遲是否由swap產生。如果這個檔案中記錄了較大的swap size,則說明延遲很有可能是swap造成的。

資料淘汰引發的延遲

當同一秒內有大量key過期時,也會引發redis的延遲。在使用時應盡量將key的失效時間錯開。

引入讀寫分離機制

redis的主從複製能力可以實現一主多從的多節點架構,在這一架構下,主節點接收所有寫請求,並將資料同步給多個從節點。

在這一基礎上,我們可以讓從節點提供對實時性要求不高的讀請求服務,以減小主節點的壓力。

尤其是針對一些使用了長耗時命令的統計類任務,完全可以指定在乙個或多個從節點上執行,避免這些長耗時命令影響其他請求的響應。

關於讀寫分離的具體說明,請參見後續章節

Redis(十三)redis事務

redis作為乙個非關係型資料庫,其也是有事務操作的。redis 事務可以一次執行多個命令,並且帶有以下三個重要的保證 1 批量操作在傳送 exec 命令前被放入佇列快取。2 收到 exec 命令後進入事務執行,事務中任意命令執行失敗,其餘的命令依然被執行。3 在事務執行過程,其他客戶端提交的命令請...

redis11 Redis事務 事務鎖

一旦成功所有的成功,乙個失敗,所有一些列連續動作都失敗 事務的基本操作 multi exec 事務定義過程中發現問題,怎麼辦?discard 事務的工作流程 事務的注意事項 手動進行事務回滾 業務場景1 業務分析 基於特定條件的事務執行 鎖 解決方案 watch key1 key2 unwatch ...

Redis學習筆記 Redis事務

redis事務可以一次執行多個命令 按順序地序列執行,執行中不會被其他命令插入,不許加塞 1.簡介 redis事務可以一次執行多個命令 允許在一次單獨的步驟中執行一組命令 特徵 1 批量操作在傳送exec命令前被放入佇列快取 2 收到exec命令後進入事務執行,事務中任意命令執行失敗,其餘的命令依然...