Redis 敢在線上做Keys正則匹配操作!你可以離職了!
一條鐵律
在業內,redis開發規范中有一條鐵律如下所示
線上Redis禁止使用Keys正則匹配操作
然而大家都知道,卻一直忘記,所以事故會不斷的發生。
下面講一講在線上執行正則匹配操作,引起緩存雪崩,最終數據庫宕機的原因。
分析原因
OK,先說兩句廢話
1、redis是單線程的,其所有操作都是原子的,不會因并發產生數據異常
2、使用高耗時的Redis命令是很危險的,會占用***的一個線程的大量處理時間,導致所有的請求都被拖慢。(例如時間復雜度為O(N)的KEYS命令,嚴格禁止在生產環境中使用)
有上面兩句作鋪墊,原因就顯而易見了。
- (1)運維人員進行keys *操作,該操作比較耗時,又因為redis是單線程的,所以redis被鎖住。
- (2)此時QPS比較高,又來了幾萬個對redis的讀寫請求,因為redis被鎖住,所以全部Hang在那。
- (3)因為太多線程Hang在那,CPU嚴重飆升,造成redis所在的服務器宕機
- (4)所有的線程在redis那取不到數據,一瞬間全去數據庫取數據,數據庫就宕機了。
需要注意的是,同樣危險的命令不僅有keys *,還有以下幾組
- Flushdb 命令用于清空當前數據庫中的所有key
- Flushall 命令用于清空整個 Redis 服務器的數據(刪除所有數據庫的所有 key )
- CONFIG 客戶端連接后可配置服務器
因此,一個合格的redis運維或者開發,應該懂得如何禁用上面的命令。所以我一直覺得出現新聞中那種情況的原因,一般是人員的水平問題。
怎么禁用這些命令呢?
就是在redis.conf中,在SECURITY這一項中,我們新增以下命令:
- rename-command FLUSHALL ""
- rename-command FLUSHDB ""
- rename-command CONFIG ""
- rename-command KEYS ""
另外,對于FLUSHALL命令,需要設置配置文件中appendonly no,否則服務器是無法啟動
注意了,上面的這些命令可能有遺漏,大家可以查官方文檔。除了Flushdb這類和redis安全隱患有關的命令意外,但凡發現時間復雜度為O(N)的命令,都要慎重,不要在生產上隨便使用。例如hgetall、lrange、smembers、zrange、sinter等命令,它們并非不能使用,但這些命令的時間復雜度都為O(N),使用這些命令需要明確N的值,否則也會出現緩存宕機。
改良建議
業內建議使用scan命令來改良keys和SMEMBERS命令
redis2.8版本以后有了一個新命令scan,可以用來分批次掃描redis記錄,這樣肯定會導致整個查詢消耗的總時間變大,但不會影響redis服務卡頓,影響服務使用。