Redis開發設計規范及案例分析


作者:張家江

來自:樂得技術(ID:lede_tech)

 

redis不是垃圾桶也不是 SUPER MAN,能力和資源都有限,不合理的使用會降低它的健康度,嚴重時甚至會引起redis抖動、阻塞等進而導致服務不可用,每一個使用redis的開發人員都應當掌握規范的開發和使用方法。本文整理出redis開發過程中七個較常出現的使用不合理的場景,並輔以案例進行分析說明。

 

 

01合理使用集合類

 

案例

某活動需求,每天10點對昨天參加某活動的用戶進行推送提醒。開發人員使用redis存儲每天參加活動的用戶,通過ZRANGEBYSCORE命令獲取目標用戶進行提醒,提醒完后使用ZREMRANGEBYSCORE命令從redis中清除這批用戶。某一天ZRANGEBYSCORE、ZREMRANGEBYSCORE均出現了慢日志報警,排查發現這一天參加該活動的用戶約有5萬。

 

 分析

 

案例中使用了redis的sortedset來儲存用戶信息,其中value是用戶的賬號、score是用戶參加活動的時間,由於ZRANGEBYSCORE和ZREMRANGEBYSCORE命令的時間復雜度是 O(log(N) + M),其中M是操作的元素個數,N是集合元素總數,本例中當用戶數量為5萬時出現慢日志。可以通過縮小每次查詢的集合數量,可以將一天分成多段,分批次查詢,比如把查24小時范圍的用戶改為查4小時范圍的用戶,分別查6次處理即可。

 

Q

如果用戶參加活動的時間很集中,在某一

時間段比如晚18點到22點查出來

數量還是特別多怎么辦?

A

可以把粒度分得更細一些比如1小時或者30分鍾,如果確定用戶參加活動集中在某個時間點,可以考慮使用ZSCAN遍歷操作並刪除。另外,對於目標時間范圍有確定的首尾元素時,還可以通過ZRANK命令查出元素的位置,通過 ZRANGE 以及ZREMRANGEBYRANK來進行查詢和刪除操作,這樣每次操作可以控制操作數量,有效避免慢日志。

 

 

 小結

 

使用 sortedset、set、list、hash等集合類的O(N)操作時要評估當前元素個數的規模以及將來的增長規模,對於短期就可能變為大集合的key,要預估O(N)操作的元素數量,避免全量操作,可以使用HSCAN、SSCAN、ZSCAN進行漸進操作。集合元素數量過大在使用過程中會影響redis的實際性能,元素個數建議盡量不要超過5000,元素數量過大可考慮拆分成多個key進行處理。

 

 

02

合理設置過期時間

案例1

某投票功能,用於統計今日環比昨日的增長數量,開發人員使用redis存儲每天的投票數,key設計為vote_count_{date},其中{date}為當天的日期,由於沒有設置過期時間,一年以后產生了360多個key,實際在用的key始終只有2個。

 

 

 分析

 

該案例中,每個生成的key在2天以后都不會再使用了,可將key加上過期時間。

案例2

 

某統計功能,用戶會不定期的導入一批數據進 redis,每一批數據需要在30分鍾后、1天后、3天后、7天后進行計算統計,統計結果發給用戶。開發人員使用redis的同一個sortedset存儲這些導入的數據,每天定時任務執行計算任務。由於沒有清理,導致大量結束計算任務的廢棄數據殘留redis。

 

 分析

 

該案例中,每一批數據都有相應的生命周期,在導入的第7天執行完最后一次計算任務生命周期結束,由於集合里的元素不能單獨設置過期時間,可在代碼邏輯中對最后一次使用這批數據后進行清理操作。

 

 

 小結

 

如果key沒有設置超時時間,會導致一直占用內存。對於可以預估使用生命周期的key應當設置合理的過期時間或在最后一次操作時進行清理,避免垃圾數據殘留redis。

 

 

03

合理利用批操作命令

案例

 

某運營需求,需要給用戶生成短鏈,短鏈由短鏈前綴+短碼組成,根據短碼找到用戶對應的手機號,開發人員使用redis hash結構存儲短碼到手機號的映射。接口每次會導入5萬個手機號。

 

 分析

 

下面是開發人員的三種操作redis方案的偽代碼

 

方案1:直接使用redis的HSET逐個設置

for(50000;)
HSET(key,短碼,手機號)
結果:失敗。redis ops飆升,同時接口響應超時

 

方案2:改用redis的 HMSET一次將所有元素設置到hash中

map<短碼,手機號> 50000個元素
HMSET(key,map)
結果:失敗。出現redis慢日志

 

方案3:依然使用 HMSET,只是每次設置500個,循環100次

map<短碼,手機號> 500個元素
for(100;)
HMSET(key,map)
結果:成功

 

對於大量頻繁的hset操作可以使用 HMSET替代減少redis操作次數同時提升處理速度,但是要考慮單次請求操作的數量,避免慢日志。

 

 

 小結

 

在redis使用過程中,要正視網絡往返時間,合理利用批量操作命令,減少通訊時延和redis訪問頻次。redis為了減少大量小數據CMD操作的網絡通訊時間開銷 RTT (Round Trip Time),支持多種批操作技術:

  • MSET/HMSET等都支持一次輸入多個key,LPUSH/RPUSH/SADD等命令都支持一次輸入多個value,也要注意每次操作數量不要過多,建議控制在500個以內;

  • PipeLining 模式 可以一次輸入多個指令。redis提供一個 pipeline 的管道操作模式,將多個指令匯總到隊列中批量執行,可以減少tcp交互產生的時間,一般情況下能夠有10%~30%不等的性能提升;

  • 更快的是Lua Script模式,還可以包含邏輯。redis內嵌了 lua 解析器,可以執行lua 腳本,腳本可以通過eval等命令直接執行,也可以使用script load等方式上傳到服務器端的script cache中重復使用。

 

 

 

04

減少不必要的請求

案例

某業務系統,當用戶進入某個頁面時會同時請求多個接口,每個接口都會校驗用戶狀態是否有效,用戶狀態存在redis里並設置有過期時間,對於key未過期但是過期時間大於指定閾值的,需要重新設置有效時間,否則需要使用del命令刪除掉。但是部分key由於過期其實已經不存在了,所以出現部分無效del命令。用戶越多,就會有越多的無效命令。

 

 分析

 

 

ttl命令對於key不存在的情況會返回-2,若key不存在則不需要再調用del命令,可減少無效請求。

 

 

 小結

 

redis的所有請求對於不存在的key都會有輸出返回,合理利用返回值處理,避免不必要的請求,提升業務吞吐量。

 

 

 

05

避免value設置過大

案例

某開發人員將一個商品集合信息序列化后用redis的字符串類型存儲,使用的時候再反序列化成對象列表使用,大小超過1MB,在網絡傳輸的時候由於數據比較大會觸發拆包,會降低redis的吞吐量。

 

 分析

 

數量比較多時可以考慮改用hash結構存儲,每一個field是商品id,value是該商品對象,如果數量較大可使用hscan獲取。

 

 

 小結

 

String類型盡量控制在10KB以內。雖然redis對單個key可以緩存的對象長度能夠支持的很大,但是實際使用場合一定要合理拆分過大的緩存項,1k 基本是redis性能的一個拐點。當緩存項超過10k、100k、1m性能下降會特別明顯。關於吞吐量與數據大小的關系可見下面官方網站提供的示意圖。

 

 

 

吞吐量與數據大小的關系

 

在局域網環境下只要傳輸的包不超過一個 MTU(以太網下大約 1500 bytes),那么對於 10、100、1000 bytes不同包大小的處理吞吐能力實際結果差不多。

 

 

 

06

設計規范的key名

 

 

 可讀性

 

以業務名為前綴,用冒號分隔,可使用業務名:子業務名:id的結構命名,子業務下多單詞可再用下划線分隔

舉例:活動系統-人拉人紅包活動-id,可命名為 ACTIVITY:INVITE_REDPACKET:001

 

 

 簡潔性

保證語義的前提下,控制key的長度,當key較多時,內存占用也不容忽視

 

 

 不包含轉義字符

不包含空格、換行、單雙引號以及其他轉義字符

 

 

07

留心禁用命令

 

keys、monitor、flushall、flushdb應當通過redis的rename機制禁掉命令,若沒有禁用,開發人員要謹慎使用。其中flushall、flushdb會清空redis數據;keys命令可能會引起慢日志;monitor命令在開啟的情況下會降低redis的吞吐量,根據壓測結果大概會降低redis50%的吞吐量,越多客戶端開啟該命令,吞吐量下降會越多。

 

keys和monitor在一些必要的情況下還是有助於排查線上問題的,建議可在重命名后在必要情況下由redis相關負責人員在redis備機使用,monitor命令可借助redis-faina等腳本工具進行輔助分析,能更快排查線上ops飆升等問題。

 

 

  總      結  

本文整理出的幾點redis開發規范主要是涉及redis客戶端的使用部分,每個開發人員在使用redis開發過程中幾乎都會涉及到上述提到的幾個問題,需要多多留心,提高代碼質量,提升redis的健康度。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM