Redis 如何處理大 Key
導讀 | 釋放記憶體只是第一步,為了更加高效地管理記憶體空間,在應用程式釋放記憶體時,作業系統需要把釋放掉的記憶體塊插入一個空閒記憶體塊的連結串列,以便後續進行管理和再分配。這個過程本身需要一定時間,而且會阻塞當前釋放記憶體的應用程式。 |
今天來聊聊,關於 Redis 大 key 的四個問題。
- 什麼是 Redis 大 key?
- 大 key 會造成什麼問題?
- 如何找到大 key ?
- 如何刪除大 key?
大 key 並不是指 key 的值很大,而是 key 對應的 value 很大。
一般而言,下面這兩種情況被稱為大 key:
String 型別的值大於 10 KB;
Hash、List、Set、ZSet 型別的元素的個數超過 5000個;
大 key 會帶來以下四種影響:
客戶端超時阻塞。由於 Redis 執行
是單執行緒處理,然後在操作大 key 時會比較耗時,那麼就會阻塞 Redis,從客戶端這一視角看,就是很久很久都沒有響應。
引發網路阻塞。每次獲取大 key 產生的網路流量較大,如果一個 key 的大小是 1 MB,每秒訪問量為 1000,那麼每秒會產生 1000MB 的流量,這對於普通千兆網路卡的伺服器來說是災難性的。
阻塞工作執行緒。如果使用 del 刪除大 key 時,會阻塞工作執行緒,這樣就沒辦法處理後續的
。
記憶體分佈不均。叢集模型在 slot 分片均勻情況下,會出現資料和查詢傾斜情況,部分有大 key 的 Redis 節點佔用記憶體多,QPS 也會比較大。
可以透過 redis-cli --bigkeys 命令查詢大 key:
redis-cli -h 127.0.0.1 -p6379 -a "password" -- bigkeys
使用的時候注意事項:
該方式的不足之處:
使用 SCAN 命令對資料庫掃描,然後用 TYPE 命令獲取返回的每一個 key 的型別。
對於 String 型別,可以直接使用 STRLEN 命令獲取字串的長度,也就是佔用的記憶體空間位元組數。
對於集合型別來說,有兩種方法可以獲得它佔用的記憶體大小:
使用 RdbTools 第三方開源工具,可以用來解析 Redis 快照(RDB)檔案,找到其中的大 key。
比如,下面這條命令,將大於 10 kb 的 key 輸出到一個表格檔案。
rdb dump.rdb -c memory --bytes 10240 -f redis.csv
刪除操作的本質是要釋放鍵值對佔用的記憶體空間,不要小瞧記憶體的釋放過程。
釋放記憶體只是第一步,為了更加高效地管理記憶體空間,在應用程式釋放記憶體時,作業系統需要把釋放掉的記憶體塊插入一個空閒記憶體塊的連結串列,以便後續進行管理和再分配。這個過程本身需要一定時間,而且會阻塞當前釋放記憶體的應用程式。
所以,如果一下子釋放了大量記憶體,空閒記憶體塊連結串列操作時間就會增加,相應地就會造成 Redis 主執行緒的阻塞,如果主執行緒發生了阻塞,其他所有請求可能都會超時,超時越來越多,會造成 Redis 連線耗盡,產生各種異常。
因此,刪除大 key 這一個動作,我們要小心。具體要怎麼做呢?這裡給出兩種方法:
對於刪除大 Hash,使用 hscan 命令,每次獲取 100 個欄位,再用 hdel 命令,每次刪除 1 個欄位。
Python程式碼:
def del_large_hash(): r = redis.StrictRedis(host='redis-host1', port=6379) large_hash_key ="xxx" #要刪除的大hash鍵名 cursor = '0' while cursor != 0: # 使用 hscan 命令,每次獲取 100 個欄位 cursor, data = r.hscan(large_hash_key, cursor=cursor, count=100) for item in data.items(): # 再用 hdel 命令,每次刪除1個欄位 r.hdel(large_hash_key, item[0])
對於刪除大 List,透過 ltrim 命令,每次刪除少量元素。
Python程式碼:
def del_large_list(): r = redis.StrictRedis(host='redis-host1', port=6379) large_list_key = 'xxx' #要刪除的大list的鍵名 while r.llen(large_list_key)>0: #每次只刪除最右100個元素 r.ltrim(large_list_key, 0, -101)
對於刪除大 Set,使用 sscan 命令,每次掃描集合中 100 個元素,再用 srem 命令每次刪除一個鍵。
Python程式碼:
def del_large_set(): r = redis.StrictRedis(host='redis-host1', port=6379) large_set_key = 'xxx' # 要刪除的大set的鍵名 cursor = '0' while cursor != 0: # 使用 sscan 命令,每次掃描集合中 100 個元素 cursor, data = r.sscan(large_set_key, cursor=cursor, count=100) for item in data: # 再用 srem 命令每次刪除一個鍵 r.srem(large_size_key, item)
對於刪除大 ZSet,使用 zremrangebyrank 命令,每次刪除 top 100個元素。
Python程式碼:
def del_large_sortedset(): r = redis.StrictRedis(host='large_sortedset_key', port=6379) large_sortedset_key='xxx' while r.zcard(large_sortedset_key)>0: # 使用 zremrangebyrank 命令,每次刪除 top 100個元素 r.zremrangebyrank(large_sortedset_key,0,99)
從 Redis 4.0 版本開始,可以採用非同步刪除法,用 unlink 命令代替 del 來刪除。
這樣 Redis 會將這個 key 放入到一個非同步執行緒中進行刪除,這樣不會阻塞主執行緒。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2911915/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 如何處理redis叢集中hot key和big keyRedis
- Redis熱點key大keyRedis
- Redis刪除大KeyRedis
- 淺析Redis大KeyRedis
- 如何利用Redis實現延時處理Redis
- redis雪崩處理Redis
- 如何快速定位 Redis 熱 key?Redis
- redis如何清除所有的keyRedis
- Redis 是如何處理命令的(客戶端)Redis客戶端
- Redis效能瓶頸揭秘:如何最佳化大key問題?Redis
- Redis之事務處理Redis
- redis如何檢視所有的keyRedis
- Python 如何處理大檔案Python
- Kafka和Redis如何解決流處理挑戰KafkaRedis
- Redis大key掃描Python指令碼RedisPython指令碼
- redis的事務處理Redis
- Redis 大key(bigkey)問題的排查與解決方案Redis
- java大資料處理:如何使用Java技術實現高效的大資料處理Java大資料
- SAP gateway處理multiple key的邏輯Gateway
- mysql : repair with keycache 的一個處理MySqlAI
- 高手如何處理快取:SpringBoot整合Redis實現快取處理(AOP技術)!快取Spring BootRedis
- REDIS key notificationRedis
- 關於primary key和foreign key的問題處理
- 走近原始碼:Redis如何清除過期key原始碼Redis
- redis的事件處理機制Redis事件
- go-Redis-parser(更高效的 Redis 解析工具,支援查詢大 key)GoRedis
- 3大問題!Redis快取異常及處理方案總結Redis快取
- 如何處理系統具有較大併發量?
- 如何處理大體積 XLSX/CSV/TXT 檔案?
- 資料庫如何處理大資料訪問資料庫大資料
- JSP 異常處理如何處理?JS
- 【原始碼】Redis命令處理過程原始碼Redis
- php redis 處理websocket聊天記錄PHPRedisWeb
- Redis命令——鍵(key)Redis
- Redis的鍵(key)Redis
- 【Redis】Redis的操作命令(一)——Redis Key命令Redis
- go 處理 jsonArray 無 key 的 JSON 串GoJSON
- 電腦hold escape key to prevent startlsback怎麼處理?TLS