Redis使用規(guī)范

常見問題及建議

連接泄露

有些客戶端應(yīng)用沒有使用連接池,redis連接用完后沒有及時釋放,導致服務(wù)側(cè)的存活連接越來越多;
建議客戶端使用連接池,或者在服務(wù)側(cè)配置最大空閑存活時間,由服務(wù)側(cè)主動斷開(該配置默認關(guān)閉);

熱key導致單點打爆

應(yīng)用中最熱路徑(比如點擊量最大頁面)上的key訪問,在大促等活動時可能會產(chǎn)生10倍以上的訪問流量,那么對應(yīng)的redis節(jié)點可能出現(xiàn)
cpu、帶寬等耗盡,導致業(yè)務(wù)不可用;
建議客戶進行單節(jié)點的cpu、帶寬監(jiān)控,及時發(fā)現(xiàn)負載不均衡性;并使用本地二級緩存或者多副本存儲等方式進行優(yōu)化;
控制臺上“緩存分析”,可以幫助發(fā)現(xiàn)熱key;

大key導致單點內(nèi)存耗盡

對于使用list、set、zset(sortedset)、hash,需要從架構(gòu)、用戶量和訪問量等分析,是否會出現(xiàn)無限制插入; ? 監(jiān)控單節(jié)點的容量并配置告警,以發(fā)現(xiàn)容量不均衡;
控制臺上“節(jié)點管理”進行key個數(shù)、容量分析,可以判斷大key是否存在;
控制臺上“緩存分析”,可以幫助發(fā)現(xiàn)各種數(shù)據(jù)類型的大key;

過大的pipeline

可以使用pipeline提升redis訪問性能,proxy集群在proxy節(jié)點上進行pipeline支持和后端redis的請求分發(fā)和響應(yīng)排序聚合,過大的
pipeline時,單個耗時請求會影響較多請求,proxy上也會占用更多的內(nèi)存,默認支持最大pipeline為1024;如確認有需求,也可以配 置提升該閾值

Redis緩存在業(yè)務(wù)系統(tǒng)會遇到的問題

緩存雪崩:

緩存雪崩是指在我們設(shè)置緩存時采用了相同的過期時間,導致緩存在某一時刻同時失效, 請求全部轉(zhuǎn)發(fā)到DB,DB瞬時壓力過重雪崩。

緩存穿透

緩存穿透是指查詢一個一定不存在的數(shù)據(jù),由于緩存是不命中時被動寫的,并且出于容錯 考慮,如果從存儲層查不到數(shù)據(jù)則不寫入緩存,這將導致這個不存在的數(shù)據(jù)每次請求都要 到存儲層去查詢,失去了緩存的意義。在流量大時,可能DB就掛掉了,要是有人利用不存在 的key頻繁攻擊我們的應(yīng)用,這就是漏洞

緩存擊穿

對于一些設(shè)置了過期時間的key,如果這些key可能會在某些時間點被超高并發(fā)地訪問,是 一種非?!盁狳c”的數(shù)據(jù)。這個時候,需要考慮緩存被“擊穿”的問題,這個和緩存雪崩的 區(qū)別在于這里針對某一key緩存,前者則是很多key。

如何使用好Redis緩存

冷熱數(shù)據(jù)區(qū)分

雖然 Redis支持持久化,但將所有數(shù)據(jù)存儲在 Redis 中,成本非常昂貴。建議將熱數(shù)據(jù)的數(shù)據(jù)加載到 Redis 中。低頻數(shù)
據(jù)可存儲在 Mysql、 ElasticSearch中。

業(yè)務(wù)數(shù)據(jù)分離

不要將不相關(guān)的數(shù)據(jù)業(yè)務(wù)都放到一個 Redis中。一方面避免業(yè)務(wù)相互影響,另一方面避免單實例膨脹,并能在故障時降
低影響面,快速恢復(fù)。

消息大小限制

由于 Redis 是單線程服務(wù),消息過大會阻塞并拖慢其他操作。保持消息內(nèi)容在 1KB 以下是個好的習慣。消息過大還會
引起網(wǎng)絡(luò)帶寬的高占用,持久化到磁盤時的 IO 問題。

連接數(shù)限制

連接的頻繁創(chuàng)建和銷毀,會浪費大量的系統(tǒng)資源,極限情況會造成宿主機宕機。請確保使用了正確的 Redis 客戶端連接
池配置。

緩存 Key 設(shè)置失效時間

作為緩存使用的 Key,必須要設(shè)置失效時間。失效時間并不是越長越好,請根據(jù)業(yè)務(wù)性質(zhì)進行設(shè)置。

Redis緩存操作限制

嚴禁使用 Keys

Keys 命令效率極低,屬于 O(N)操作,會阻塞其他正常命令,在 cluster 上,會是災(zāi)難性的操作。

嚴禁使用 Flush

flush 命令會清空所有數(shù)據(jù),屬于高危操作。

嚴禁作為消息隊列使用

如沒有非常特殊的需求,嚴禁將 Redis 當作消息隊列使用。Redis 當作消息隊列使用,會有容量、網(wǎng)絡(luò)、效率、功能方面的多種問題。如需要消息隊列,可使用高吞吐的 Kafka 或者高可靠的 RocketMQ。

嚴禁不設(shè)置范圍的批量操作

Redis 那么快,慢查詢除了網(wǎng)絡(luò)延遲,就屬于這些批量操作函數(shù)。大多數(shù)線上問題都是由于這些函數(shù)引起。

Redis開發(fā)使用規(guī)范-強制

?所有的key需設(shè)置過期時間。

注意過期時間進行打散,防止同一時間過期大量的key , key過期會占用主線程,如果同一時間過期key太多,會短時間內(nèi)阻塞用戶業(yè)務(wù)

?禁止使用keys、flushall、hgetall等命令,執(zhí)行O(N)時間復(fù)雜度命令,需要注意N的大小。
?禁止使用select功能來在單redis實例做多db區(qū)分。 生產(chǎn)系統(tǒng)中需要開啟redis密碼保護機制。
?禁止開發(fā)人員私自連到線上Redis服務(wù)。
?設(shè)計上避免引入大key和熱key,防止出現(xiàn)單節(jié)點瓶頸。
?對于已有大key和熱Key處理,建議:

  1. 進行本地緩存,且為了防止本級緩存穿透到Redis造成雪崩,應(yīng)采用定時異步進行刷新本地緩存的方式。
  2. 大key上不執(zhí)行復(fù)雜命令,如:O(N) ,O(log(N)+M),O(M*log(N))命令,當N或M較大時。

Redis開發(fā)使用規(guī)范-建議

? string類型控制在10KB以內(nèi),hash、list、set、zset元素盡量不超過5000。
? 使用批量操作提高效率(帶m的如mset,mget,hmset,hmget)。
? key的命名前綴為業(yè)務(wù)縮寫,禁止包含特殊字符(比如空格、換行、單雙引號以及其他轉(zhuǎn)義字符)。 ? Redis事務(wù)功能較弱,不建議過多使用。
? 短連接性能差,推薦使用帶有連接池的客戶端。
? 如果只是用于數(shù)據(jù)緩存,容忍數(shù)據(jù)丟失,建議關(guān)閉持久化。

Redis大key熱Key處理

大Key熱Key的風險:
讀寫大key會導致超時嚴重,甚至阻塞服務(wù)。 如果刪除大key,DEL命令可能阻塞Redis進程數(shù)十秒,使得其他請求阻塞,對應(yīng)用程序和Redis集群可用性造成 嚴重的影響。
建議每個key不要超過M級別。 單分片的處理能力是有限的,只能做到分片橫向擴展,所以系統(tǒng)需要避免由于熱key引發(fā)的性能問題 業(yè)務(wù)在使用Redis過程中應(yīng)當避免大key熱key的出現(xiàn),拖慢整個系統(tǒng)的響應(yīng)時間

使用scan替代keys *

在key數(shù)量較少的情況下,我們可以偷懶直接使用keys *來快速查看模式匹配的key列表,但是一旦key數(shù)量上升,或 者在高并發(fā)的環(huán)境下,keys *會帶來整個系統(tǒng)的阻塞。因為keys命令時間復(fù)雜度是:
Time complexity:O(N) with N being the number of keys in the database, under the assumption that
the key names in the database and the given pattern have limited length. 直接跟database中key數(shù)量相關(guān)的。替代方案是使用scan命令,首先看看scan的時間復(fù)雜度:
Time complexity:O(1) for every call. O(N) for a complete iteration, including enough command calls
for the cursor to return back to 0. N is the number of elements inside the collection. 雖然scan不能一次性返回所有匹配的key,但是scan提供cursor機制來遍歷整個database,最重要的是每次scan操 作的時間復(fù)雜度是O(1)的,因此只需要多次scan即可得到所有匹配的key。類似的命令還有sscan,hscan,zscan等分 別用于增量迭代set,hash,sorted set等集合元素。

數(shù)據(jù)淘汰機制

Redis提供了如下數(shù)據(jù)淘汰策略:
? volatile-lru:根據(jù)LRU算法刪除設(shè)置了過期時間的鍵值。
? allkeys-lru:根據(jù)LRU算法刪除任一鍵值。
? volatile-random:刪除設(shè)置了過期時間的隨機鍵值。
? allkeys-random:刪除一個隨機鍵值。
? volatile-ttl:刪除即將過期的鍵值,即TTL值最小的鍵值。
? noeviction:不刪除任何鍵值,只是返回一個寫錯誤。
? volatile-lfu: 根據(jù)LFU算法刪除設(shè)置了過期時間的鍵值。
? allkeys-lfu: 根據(jù)LFU算法刪除任一鍵值。
最好為Redis指定一種有效的數(shù)據(jù)淘汰策略以配合maxmemory設(shè)置,避免在內(nèi)存使用滿后發(fā)生寫入失敗的情況。 一般來說,推薦使用的策略是volatile-lru,并辨識Redis中保存的數(shù)據(jù)的重要性。對于那些重要的,絕對不能丟棄的 數(shù)據(jù)(如配置類數(shù)據(jù)等),應(yīng)不設(shè)置有效期,這樣Redis就永遠不會淘汰這些數(shù)據(jù)。對于那些相對不是那么重要的, 并且能夠熱加載的數(shù)據(jù)(比如緩存最近登錄的用戶信息,當在Redis中找不到時,程序會去DB中讀取),可以設(shè)置 上有效期,這樣在內(nèi)存不夠時Redis就會淘汰這部分數(shù)據(jù)。

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

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