前言
說到分布式緩存,可能大多數人腦海浮現的就是redis了,為什么redis能夠在競爭激烈的緩存大戰中脫穎而出呢?原因無非有一下幾點:性能好,豐富的特性跟數據結構,api操作簡單。但是用的人多了,就會出現很多不規范或者疏忽的地方,嚴重的時候甚至會導致生產事故,所以我們有必要來聊聊在Redis使用過程中的一些“正確姿勢“。
切忌裸奔
大家別笑... 很多初學者或者沒經驗的開發人員在服務器上用root用戶裝了redis以后,打開默認端口直接就愉快的運行起來了,開放了外網及默認端口的連接,甚至對於生產環境也這樣,貪圖一時的方便,這種情況比較多的出現在一些初創公司 (包括N年前的我也這么干過...)
那么會出現什么問題呢?最常見的就是Redis未授權訪問漏洞。攻擊者掃描到互聯網開放的ip以及默認的6379端口后,直接在本地遠程連接你服務器的redis,通過redis的命令將本機生成的公鑰寫入到服務器的authorized.keys中,這時候本機就可以ssh免密登錄進來了。接下來可以寫入反彈shell,提權,然后就可以為所欲為了,這就是為什么你的服務器上面會突然出現有挖礦程序的一個原因。
為了防止出現上述的風險,我們可以從以下幾個地方來處理。
-
修改默認端口6379
-
綁定內網訪問 bing 127.0.0.1
-
添加redis的密碼驗證
-
以低權限的用戶運行redis
-
必要時設置防火牆策略
禁止“ key *” ,用“scan”代替
說到這個,筆者也是滿滿的淚,在年少無知的時候曾經在生產環境執行過這個命令,后來差點收拾背包提前下班了。為什么這個操作這么可怕呢?“key *” 操作的意思是返回數據庫中所有匹配的key,它會掃一次性掃描所有的記錄,當你庫里的數據量很大的時候,會造成redis的阻塞,cpu使用率飆升,慢慢的拖垮項目中對redis的相關請求直至出現各種timeout...
在Redis2.8版本以后,提供了一個更好的遍歷key的操作"scan",它類似於我們jdbc中ResultSet,通過一個游標來迭代。使用方法為“SCAN cursor [MATCH pattern] [COUNT count]”。
redis 127.0.0.1:6379> scan 0
1) "17"
2) 1) "key:12"
2) "key:8"
3) "key:4"
4) "key:14"
5) "key:16"
6) "key:17"
7) "key:15"
8) "key:10"
9) "key:3"
10) "key:7"
11) "key:1"
redis 127.0.0.1:6379> scan 17
1) "0"
2) 1) "key:5"
2) "key:18"
3) "key:0"
4) "key:2"
5) "key:19"
6) "key:13"
7) "key:6"
8) "key:9"
9) "key:11"
“scan 0 ”表示開始一個新的迭代,當返回的第一參數為0時,則表示迭代結束,若不為0,下一次迭代的時候帶上這個游標開始下一次遍歷,直到返回0.第二個參數則是當前遍歷出來的值。使用的時候需要注意版本,當版本低於2.8時,需升級才能使用。
key的設計
首先用“:”來分割key是一個約定俗成的東西,自己使用的時候就盡量不要用一些比較特殊的字符來代替。關於我們的key設計可以參照我們的關系型數據庫。
假如有一個user表,有userid,age,username字段,那么我們key就可以"user:userid:useridValue:username"這么來設計,把表名作為key的前綴,查詢的條件放在最后。中間用字段跟它所對應的value分割開來,所有的設計都是為了在查詢的時候可以更便捷。
合理使用多個db
redis的db下標默認0-15,也就是有16個。通常大部分人都是使用db0,所有的k-v都在一個庫中。這其實沒多大問題,但是redis不是關系型數據庫,存儲的數據相互耦合不那么大,所以建議可以按照不同的業務把數據分散到各個庫中,這樣我們可以select 不同的 db 來執行不同的業務模塊操作。
善用5種數據結構
redis提供了5種數據結構,但是根據以往的面試結果來看,很多應聘者幾乎在項目中只用到string類型,甚至對其他類型一知半解。其實當我們能在不同的場景善用不同的結構的話,效率會有很大的提升。下面簡單介紹幾個例子。
SortSet
它提供了一個優先級(score)來排序,我們可以把score的值設置成時間戳,這樣我們可以通過一些定時的操作來取出某段時間里面數據,在我們項目的機器人模塊中有大量的此類操作。還有常用的地方是排行榜,通過score值的變化來快速高效的更新榜單。
list
它的實現是一個雙向鏈表,我們可以把一些需要執行的任務通過lpush,rpush存放進來,組成符合我們需求的順序,最后我們在依次取出來執行,類似於mq。
set
用來做一些自動去重的操作,比如redis的交集命令,可以取出2個人的共同好友。
禁用高危命令
redis中有很多高危命令。如“flushdb”,“config”等,我們可以禁止或者重命名這些命令來使得操作更加安全。
我們需要修改redis的配置文件redis.conf,在SECURITY這一項中,新增
rename-command FLUSHALL "" rename-command CONFIG ""
假如是重命名的話
rename-command FLUSHALL abcdefg
配置完重啟后生效。
結語
對於redis的話題,其實還有很多,比如發布訂閱,持久化機制,集群等。很多最佳實踐都需要結合自身的業務不斷摸索,還是那句話,適合自己的才是最好的。
文章始發於微信公眾號《深夜里的程序猿》,轉載請注明出處,侵權必究。
