1. 程式人生 > 資料庫 >Redis 為什麼不能在線上做Keys正則匹配操作

Redis 為什麼不能在線上做Keys正則匹配操作

一個新聞

新聞內容如下
php工程師執行redis keys * 導致資料庫宕機
某公司技術部發生2起本年度PO級特大事故,造成公司資金損失400萬,原因如下:

由於php工程師直接操作上線redis,執行

keys * wxdb(此處省略)cf8*

這樣的命令,導致redis鎖住,導致CPU飆升,引起所有支付鏈路卡住,等十幾秒結束後,所有的請求流量全部擠壓到了rds資料庫中,使資料庫產生了雪崩效應,發生了資料庫宕機事件。

該公司表示,如再犯類似事故,將直接開除,並表示之後會逐步收回運維部各項許可權。

正文

一條鐵律

在業內,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)的命令,都要慎重,不要在生產上隨便使用。例如hgetalllrangesmemberszrangesinter等命令,它們並非不能使用,但這些命令的時間複雜度都為O(N),使用這些命令需要明確N的值,否則也會出現快取宕機。

改良建議

業內建議使用scan命令來改良keysSMEMBERS命令

redis2.8版本以後有了一個新命令scan,可以用來分批次掃描redis記錄,這樣肯定會導致整個查詢消耗的總時間變大,但不會影響redis服務卡頓,影響服務使用。

具體使用,大家詳情可以自己查閱下面這份文件
http://doc.redisfans.com/key/scan.html