一. 事務
1. 概念補充
(1). 原子性
一個事務(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被恢復(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
2. redis事務說明
Redis的事務並不是我們傳統意義上理解的事務,我們都知道 單個 Redis 命令的執行是原子性的,但 Redis 沒有在事務上增加任何維持原子性的機制,所以 Redis 事務的執行並不是原子性的。事務可以理解為一個打包的批量執行腳本,但批量指令並非原子化的操作,中間某條指令的失敗不會導致前面已做指令的回滾,也不會造成后續的指令不做。
總結:
(1). Redis事務中如果有某一條命令執行失敗,之前的命令不會回滾,其后的命令仍然會被繼續執行→ →鑒於這個原因,所以說redis的事務嚴格意義上來說是不具備原子性的。
(2). Redis事務中所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。
(3). 在事務開啟之前,如果客戶端與服務器之間出現通訊故障並導致網絡斷開,其后所有待執行的語句都將不會被服務器執行。然而如果網絡中斷事件是發生在客戶端執行EXEC命令之后,那么該事務中的所有命令都會被服務器執行。
(4). 當使用Append-Only模式時,Redis會通過調用系統函數write將該事務內的所有寫操作在本次調用中全部寫入磁盤。然而如果在寫入的過程中出現系統崩潰,如電源故障導致的宕機,那么此時也許只有部分數據被寫入到磁盤,而另外一部分數據卻已經丟失。Redis服務器會在重新啟動時執行一系列必要的一致性檢測,一旦發現類似問題,就會立即退出並給出相應的錯誤提示。此時,我們就要充分利用Redis工具包中提供的redis-check-aof工具,該工具可以幫助我們定位到數據不一致的錯誤,並將已經寫入的部分數據進行回滾。修復之后我們就可以再次重新啟動Redis服務器了。
3. 流程/指令
(1)multi 開啟事務
(2)大量指令入隊
(3)exec執行事務塊內命令,截止此處一個事務已經結束。
(4)discard 取消事務
(5)watch 監視一個或多個key,如果事務執行前key被改動,事務將打斷。unwatch 取消監視。
4. 測試
(1). 正常事務執行
(2). 取消事務
5. Redis為什么不支持事務回滾?(官方解釋)
這種做法的優點:
(1). Redis 命令只會因為錯誤的語法而失敗,或是命令用在了錯誤類型的鍵上面,這些問題不能在入隊時發現,這也就是說,從實用性的角度來說,失敗的命令是由編程錯誤造成的,而這些錯誤應該在開發的過程中被發現,而不應該出現在生產環境中.
(2). 因為不需要對回滾進行支持,所以 Redis 的內部可以保持簡單且快速。
有種觀點認為 Redis 處理事務的做法會產生 bug , 然而需要注意的是, 在通常情況下, 回滾並不能解決編程錯誤帶來的問題。 舉個例子, 如果你本來想通過 INCR 命令將鍵的值加上 1 , 卻不小心加上了 2 , 又或者對錯誤類型的鍵執行了 INCR , 回滾是沒有辦法處理這些情況的。鑒於沒有任何機制能避免程序員自己造成的錯誤, 並且這類錯誤通常不會在生產環境中出現, 所以 Redis 選擇了更簡單、更快速的無回滾方式來處理事務。
補充一種情況:錯誤指令在入隊的時候,redis是能檢測出來的,當exec的時候,全部命令都不會執行。但是開發層次的錯誤如同上面所說 incr 1,但是不小 incr 2, redis無法判斷。
參考:https://www.runoob.com/redis/redis-transactions.html
二. 發布訂閱(pub/sub)
1. 簡介
Redis 發布訂閱 (pub/sub) 是一種消息通信模式:發送者 (pub) 發送消息,訂閱者 (sub) 接收消息,Redis 客戶端可以訂閱任意數量的頻道。
Redis 本身的 發布訂閱 (pub/sub) 來實現消息隊列的功能,有個缺點就是消息無法持久化,如果出現網絡斷開、Redis 宕機等,消息就會被丟棄。Redis Stream這個新的數據結構 提供了消息的持久化和主備復制功能,可以讓任何客戶端訪問任何時刻的數據,並且能記住每一個客戶端的訪問位置,還能保證消息不丟失。但還是建議使用專業的消息隊列,如:RabbitMq 、RocketMq等等。
2. 指令說明
(1). subscribe:訂閱給定的一個或多個頻道的信息(頻道不存在的時候會創建頻道),返回接收到的信息。
SUBSCRIBE channel [channel2 ....]
(2). publish:將信息 message 發送到指定的頻道 channel,接收到信息 message 的訂閱者數量。
publish channel message
(3). unsubscribe:指示客戶端退訂給定的頻道。
unsubscribe [channel [channel ...]]
(4). psubscribe:訂閱一個或多個符合給定模式的頻道。
每個模式以 * 作為匹配符,比如 it* 匹配所有以 it 開頭的頻道( it.news 、it.blog 、 it.tweets 等等), news.* 匹配所有以 news. 開頭的頻道( news.it 、news.global.today 等等),諸如此類。
psubscribe pattern [pattern ...]
(5). punsubscribe:指示客戶端退訂所有給定模式。
punsubscribe [pattern [pattern ...]]
3. 實操
(1). 開啟客戶端A和客戶端B,對頻道 chanel1 和 chanel2同時進行訂閱。
subscribe chanel1 chanel2
(2). 開啟一個客戶端C,向chanel1頻道進行發送信息 。
(3). 查看接收到的消息。
參考:https://www.runoob.com/redis/redis-pub-sub.html 和 redis指令文檔
三. PipeLine-管道
1. redis常規請求模型
Redis是一種基於客戶端-服務端模型以及請求/響應協議的TCP服務。這意味着通常情況下一個請求會遵循以下步驟:
(1). 客戶端向服務端發送一個查詢請求,並監聽Socket返回,通常是以阻塞模式,等待服務端響應。
(2). 服務端處理命令,並將結果返回給客戶端。
2. 管道模型
Redis 管道技術可以在服務端未響應時,客戶端可以繼續向服務端發送請求,並最終一次性讀取所有服務端的響應。
客戶端可以一次性發送多個請求而不用等待服務器的響應,待所有命令都發送完后再一次性讀取服務的響應,這樣可以極大的降低多條命令執行的網絡傳輸開銷,管道執行多條命令的網絡開銷實際上只相當於一次命令執行的網絡開銷。需要注意到是用pipeline方式打包命令發送,redis必須在處理完所有命令前先緩存起所有命令的處理結果。打包的命令越多,緩存消耗內存也越多。所以並不是打包的命令越多越好。pipeline中發送的每個command都會被server立即執行,如果執行失敗,將會在此后的響應中得到信息;也就是pipeline並不是表達“所有command都一起成功”的語義,管道中前面命令失敗,后面命令不會有影響,繼續執行。
jedis代碼:
Pipeline pl = jedis.pipelined(); for (int i = 0; i < 10; i++) { pl.incr("pipelineKey"); pl.set("zhuge" + i, "zhuge"); } List<Object> results = pl.syncAndReturnAll(); System.out.println(results);
參考:https://www.runoob.com/redis/redis-pipelining.html
四. benchmark性能測試
1. 說明
benchmark是位於redis安裝目錄下的一個性能測試工具,可以同時執行n個請求來檢測redis的性能。
常用指令:
#1. 用10000個請求檢測本機redis的各種指令的性能 ./redis-benchmark -n 10000 -q #2. 測試指定地址指定請求的redis性能(測試set和get性能) ./redis-benchmark -h 127.0.0.1 -p 6379 -t set,get -n 10000 -q
參數說明:
2. 測試在win10下的redis3.2的性能
電腦配置:4核16G
redis默認配置情況下用10000個請求進行測試,測試結果如下圖:
3. 測試centos8下redis5.0的性能
電腦配置:2核8G
redis默認配置情況下用10000個請求進行測試,測試結果如下圖:
4.測試centos8下redis6.0的性能
電腦配置:2核8G,默認多線程是關閉的,需要手動開啟:
redis默認配置情況下用10000個請求進行測試,測試結果如下圖:
!
- 作 者 : Yaopengfei(姚鵬飛)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
- 聲 明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。