來自公眾號:阿飛的博客
作者:阿飛
Key命名設計:可讀性质蕉、可管理性诗祸、簡介性
規(guī)范建議使用冒號即:進行分割拼接骡显,因為很多Redis客戶端是根據(jù)冒號分類的。比如有幾個Key:apps:app:1浆西、apps:app:2和apps:app:3。Redis Desktop Manager能自動歸類到apps目錄下顽腾。如下圖所示:
<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; line-height: inherit; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; box-sizing: border-box !important; word-wrap: break-word !important;">Redis Desktop Manager</figcaption>
Value設計:拒絕bigkey
規(guī)范建議String類型的Value控制在10KB范圍以內近零。這是因為Redis隨著Value不斷增長,在超過10KB后抄肖,有一個非常奇妙的性能拐點久信,如下圖所示(圖片來自Redis官網(wǎng):http://redis.cn/topics/benchmarks.html):
<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; line-height: inherit; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; box-sizing: border-box !important; word-wrap: break-word !important;">Redis_Data_size</figcaption>
假設內網(wǎng)貸款是千兆網(wǎng)卡,即1000MB漓摩。假設你的Redis中有一個大Key的Value長度是10KB裙士,并且這個Key的QPS是10W,那么這一個Key就會把帶寬打滿:10KB*100000=1000MB管毙。
控制Key的生命周期:設定過期時間
盡可能對每一個Key都設置過期時間腿椎,這個是非常有益處的桌硫。否則,你想想一下啃炸,半年以后铆隘,一年以后,你的Redis集群中有上百G甚至更多的數(shù)據(jù)南用,誰都不知道這些數(shù)據(jù)哪些是有價值的膀钠,哪些已經(jīng)成為垃圾。如果你的每個Key都設置了過期時間裹虫,那么就不會出現(xiàn)這個問題了肿嘲。集群在運行過程中,或自動淘汰那些已經(jīng)不再使用的垃圾緩存數(shù)據(jù)筑公。
時間復雜度為O(n)的命令需要注意N的數(shù)量
這個建議的意思是雳窟,以List類型為例,LINDEX十酣、LREM等命令的時間復雜度就是O(n)涩拙。也就是說,隨著List中元素數(shù)量越來越多耸采,這些命令的性能越來越差兴泥。而Redis又是單線程的,如果出現(xiàn)一個慢命令虾宇,會導致在這個命令之后執(zhí)行的命令耗時也會增長搓彻,這是使用Redis的大忌。
事實上這也是JDK8為什么要對HashMap進行鏈條沖突優(yōu)化:當entry數(shù)量不少于64時嘱朽,如果沖突鏈表長度達到8旭贬,就會將其轉成紅黑樹。因為鏈表長度越長搪泳,性能會越來越差稀轨。
禁用命令:KEYS、FLUSHDB岸军、FLUSHALL等
這些命令應該在搭建Redis環(huán)境的時候就要禁用掉(在config配置文件中通過rename-command禁用)奋刽。FLUSHDB和FLUSHALL這兩個命令會清空數(shù)據(jù),后果可想而知艰赞。
至于KEYS命令佣谐,還記得那個由于使用這個命令導致幾百萬損失的案例嘛?而且方妖,這個命令的不當使用導致的損失狭魂,會隨著你的業(yè)務并發(fā)越大價值越大而導致?lián)p失越大:
<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; line-height: inherit; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; box-sizing: border-box !important; word-wrap: break-word !important;">KEYS引發(fā)的災難</figcaption>
合理使用select
select的作用是選擇redis的db,這是只有在非cluster模式下才能起作用的。默認db數(shù)量為16雌澄,可以通過redis.conf中的databases進行配置斋泄。
阿里云Redis規(guī)范建議謹慎多個業(yè)務運行在同一個Redis實例的多個db上。這是因為redis整個實例是單線程處理命令的掷伙,這就意味著是己,如果某個db上有慢命令,那么會影響其他db上的實例任柜。當然卒废,Redis6.0準備支持多線程,但是還是不建議這樣做宙地!
不推薦使用事務
如果你有使用關系式數(shù)據(jù)庫的經(jīng)驗摔认,那么“Redis在事務失敗時不進行回滾,而是繼續(xù)執(zhí)行余下的命令”這種做法可能會讓你覺得有點奇怪宅粥。以下是官方給出的Redis不支持這種做法的優(yōu)點:
Redis命令只會因為錯誤的語法而失敗参袱,或是命令用在了錯誤類型的鍵上面:這也就是說,從實用性的角度來說秽梅,失敗的命令是由編程錯誤造成的抹蚀,而這些錯誤應該在開發(fā)的過程中被發(fā)現(xiàn),而不應該出現(xiàn)在生產(chǎn)環(huán)境中企垦。
因為不需要對回滾進行支持环壤,所以 Redis 的內部可以保持簡單且快速。
刪除bigkey
如果Redis中有大key钞诡,那么刪除可能會產(chǎn)生毛刺郑现。當然,如果你的Redis是4.0以上荧降,并使用UNLINK命令刪除key接箫,那么不會有什么問題。那Redis4.0以下該怎么刪除大key呢朵诫?
如果是hash結構辛友,那么先利用scan命令遍歷得到一批field,然后利用hdel命令進行刪除剪返;如果是list結構瞎领,那么先利用llen得到list中元素總個數(shù),然后利用ltrim命令批量刪除随夸;
如果是set結構,那么先利用sscan命令遍歷得到一批key震放,然后利用srem命令批量刪除宾毒;如果是sorted set結構,那么先利用zscan命令遍歷得到一批key殿遂,然后利用zrem命令批量刪除诈铛;如果是string結構呢乙各?沒有什么很好的辦法!
設置合理的內存淘汰策略
Redis的內存剔除策略(maxmemory-policy)有:volatile-lru幢竹、volatile-random耳峦、volatile-ttl、allkeys-lru焕毫、allkeys-random蹲坷、noeviction。命名以volatile開頭的3個策略主要作用于帶有失效時間屬性的key邑飒,命名以allkeys開頭的2個策略作用于所有key循签,最后一個策略noeviction不會剔除任何數(shù)據(jù),只是當內存使用滿了以后拒絕所有寫入操作并返回客戶端錯誤信息"(error) OOM command not allowed when used memory"疙咸,此時Redis只響應讀操作县匠。
事實上每種方案都有一定的局限性,所以我們除了根據(jù)自己的業(yè)務選擇合適的剔除策略以后撒轮,還需要對Redis使用的內存進行監(jiān)控乞旦,主要監(jiān)控info中info Memory段的used_memory_peak,即Redis使用內存峰值题山,建議設置其告警閾值為maxmemory的90%兰粉。
使用批量操作提升操作效率
批量命令主要分為兩類,原生命令和非原生命令:
原生命令包括:例如mget臀蛛、mset亲桦、hmget、hmset浊仆、LPUSH key value集合等客峭。
非原生命令包括:Pipeline。
合理使用這些命令對操作性能提升是極其巨大的抡柿,尤其在單機Redis或者Sentinel模式下舔琅。因為這兩種架構不涉及跨Slot,Redis集群性能也有提升洲劣,但是使用會受到一些限制备蚓,例如不支持跨Slot的操作等,官方并不太建議在Rdis集群環(huán)境下使用Pileline和multi key操作囱稽。
當然批量雖好郊尝,但不要貪多。俗話說的好战惊,貪多嚼不爛流昏。一般不要超過1000,具體限制還與操作數(shù)據(jù)大小有關。
monitor命令控制使用時間
monitor命令一般是用來觀察redis服務端都在執(zhí)行哪些命令并實時輸出况凉。例如在其他redis-cli中執(zhí)行兩個set命令谚鄙,在monitor中監(jiān)控結果如下:
afeiMacBook-Pro:redis-3.2.11 afei$ src/redis-cli monitor
OK
1573915193.053188 [0 127.0.0.1:55357] "COMMAND"
1573915197.087383 [0 127.0.0.1:55357] "set" "name" "afei"
1573915217.938838 [0 127.0.0.1:55357] "set" "公眾號" "阿飛的博客"
之所以規(guī)范建議控制monitor命令的使用時間,是因為隨著monitor命令執(zhí)行時間越來越長刁绒,會導致越來越多的數(shù)據(jù)積壓在輸出緩沖區(qū)闷营,從而導致輸出緩沖區(qū)占用內存越來越大。而且知市,這種影響會由于Redis并發(fā)越高傻盟,而更加放大。關于這個問題初狰,美團有一個很經(jīng)典的案例莫杈,感興趣的同學可以搜索關鍵詞:“美團在REDIS上踩過的一些坑-3.REDIS內存占用飆升”。
寫在最后
總而言之奢入,任何一門技術都有利有弊筝闹,技術的世界里沒有銀彈。所以腥光,我們對使用到生產(chǎn)環(huán)境的任何一個技術关顷,都要非常熟悉:知道它所擅長的和它的弱點,這樣才能結合自己的項目特點武福,設計出更合理的架構议双,編寫出最合理的代碼,不給生產(chǎn)環(huán)境造成影響捉片,不給公司帶來損失 -- 千萬不要成為那個執(zhí)行KEYS命令導致給公司造成金錢損失的人平痰!