Redis如何解決BigKey
一 面試題引入
- 阿里廣告平臺,海量數(shù)據(jù)里查詢某一固定前綴的key。
- 小紅書,你如何在生產(chǎn)上限制keys * / flushdb / flushall等危險(xiǎn)命令以防止誤刪誤用?
- 美團(tuán):MEMORY USAGE 命令你用過嗎?
- BigKey 問題,多大算big,如何發(fā)現(xiàn),如何刪除,如何處理?
- BigKey 你做過調(diào)優(yōu)嗎?惰性釋放lazyfree了解過嗎?
- Morekey問題,生產(chǎn)上redis數(shù)據(jù)庫有1000W記錄,該如何遍歷?key*可以嗎?
二 MoreKey案例
2.1 大批量往redis里面插入2000W測試數(shù)據(jù)key
2.1.1 Linux Bash下執(zhí)行,插入100W
for((i=1;i<=100*10000;i++)); do echo "set K$i V$i" >> /tmp/redisTest.txt ; done;
2.1.2 通過redis提供的管道 --pipe命令插入100W大批量數(shù)據(jù)
cat /tmp/redisTest.txt | /opt/redis-7.0.0/src/redis-cli -h 127.0.0.1 -p 6379 -a 111111 --pipe
2.2 key *
key * 這個(gè)指令有致命的弊端,在實(shí)際環(huán)境中最好不要使用
這個(gè)指令沒有offset、limit參數(shù),是要一次性吐出所有滿足條件的key,由于redis是單線程的,其所有操作都是原子的,而keys算法是遍歷算法,復(fù)雜度是O(n),如果實(shí)例中有千萬級以上的key,這個(gè)指令就會導(dǎo)致Redis服務(wù)卡頓,所有讀寫Redis的其它的指令都會被延后甚至?xí)瑫r(shí)報(bào)錯,可能會引起緩存雪崩甚至數(shù)據(jù)庫宕機(jī)。
2.3 生產(chǎn)上如何限制keys*/flushdb/flushall等危險(xiǎn)命令以防止誤刪誤用?
通過配置設(shè)置禁用這些命令,redis.conf在SECURITY這一項(xiàng)中:
2.4 不用keys * 不滿卡頓,那該用什么?
2.4.1 scan命令
類似mysql limit ,但不完全相同。
Redis SCAN命令及其相關(guān)命令 SSCAN,HSCAN,ZSCAN命令都是用于增量遍歷集合中的元素。
- SCAN:用于迭代當(dāng)前數(shù)據(jù)庫中的數(shù)據(jù)庫鍵
- SSCAN:用于迭代集合鍵中的元素
- HSCAN:用于迭代哈希鍵中的鍵值對
- ZSCAN:用于迭代有序集合中的元素(包括元素成員和元素分值)
2.4.2 scan命令用于迭代數(shù)據(jù)庫中的數(shù)據(jù)庫鍵
redis SCAN 命令基本語法如下:
SCAN cousor [MATCH pattern] [COUNT count]
- cursor:游標(biāo)
- pattern:匹配的模式
- count:指定從數(shù)據(jù)集里返回多少元素,默認(rèn)值是10
基于游標(biāo)的迭代器,需要基于上一次的游標(biāo)延續(xù)之前的迭代過程以0作為游標(biāo)開始一次新的迭代,直到命令返回游標(biāo)0完成一次遍歷,不保證每次執(zhí)行都返回某個(gè)給定數(shù)量的元素,支持模糊查詢。一次返回的數(shù)量不可控,只能是大概率符合count參數(shù)。
- SCAN命令是一個(gè)基于游標(biāo)的迭代器,每次被調(diào)用之后,都會想用戶返回一個(gè)新的游標(biāo),用戶在下次迭代時(shí)需要使用這個(gè)新游標(biāo)作為SCAN命令的游標(biāo)參數(shù),以此來延續(xù)之前的迭代過程。
- SCAN返回一個(gè)包含兩個(gè)元素的數(shù)組
- 第一個(gè)元素:用于進(jìn)行下一次迭代的新游標(biāo)
- 第二個(gè)元素:是一個(gè)數(shù)組,這個(gè)數(shù)組中包含了所有被迭代的元素。如果新游標(biāo)返回零表示迭代已結(jié)束。
SCAN的遍歷順序:非常特別,它不是從第一維數(shù)組的第零位一直遍歷到末尾,而是采用了高位進(jìn)位加法來遍歷,之所以使用這樣特殊的方式進(jìn)行遍歷,是考慮到字典的擴(kuò)容和縮容時(shí)避免槽位的遍歷重復(fù)和遺漏。
三 BigKey
3.1 多大算Big
- 阿里云Redis開發(fā)規(guī)范:
拒絕bigkey(防止網(wǎng)卡流量,慢查詢)
string類型控制在10KB以內(nèi),hash、list、set、zset元素個(gè)數(shù)不要超過5000。
非字符串的bigkey,不要使用del刪除,使用hscan、sscan、zscan方式漸進(jìn)式刪除,同時(shí)要注意防止bigkey過期時(shí)間自動刪除問題(例如一個(gè)200萬的zset設(shè)置1小時(shí)過期,會觸發(fā)del操作,造成阻塞,而且該操作不會出現(xiàn)在慢查詢中(latency可查))。
- string和二級結(jié)構(gòu)
- string是value,最大512MB 但是大于10KB就是bigkey。
- list/hash/set和zset,個(gè)數(shù)超過5000就是bigkey
3.2 bigkey的危害
- 內(nèi)存不均,集群遷移困難
- 超時(shí)刪除,大key刪除作梗
- 網(wǎng)絡(luò)流量阻塞
3.3 如何產(chǎn)生
- 社交類:典型案例粉絲逐步遞增
- 匯總統(tǒng)計(jì):某個(gè)報(bào)表,月日年的積累
3.4 如何發(fā)現(xiàn)
redis-cli --bigkeys
- 好處:給出每種數(shù)據(jù)結(jié)構(gòu)Top 1 bigkey,同時(shí)給出每種數(shù)據(jù)類型的鍵值個(gè)數(shù) + 平均大小
- 不足:想查詢大于10KB的所有key,–bigkeys參數(shù)就無能為力了。
需要用到memory usage來計(jì)算每個(gè)鍵值的字節(jié)數(shù)
MOMROY USAGE :給出一個(gè)key和它的值在RAM中所占用的字節(jié)數(shù)(計(jì)算每個(gè)鍵值的字節(jié)數(shù))。
3.5 如何刪除
非字符串的bigkey,不要使用del刪除,使用hscan、sscan、zscan方式漸進(jìn)式刪除。
- string:一般用del,如果過于龐大使用unlink
- hash:使用hscan每次獲取少量field-value,再使用hdel刪除每個(gè)field
list:使用ltrim漸進(jìn)式逐步刪除,直到全部刪除完成。
Ltrim對一個(gè)列表進(jìn)行修剪(trim),就是說,讓列表只保留指定區(qū)域內(nèi)的元素,不在指定區(qū)間之內(nèi)的元素都將被刪除。下標(biāo)0表示列表的第一個(gè)元素,以1表示列表的第二個(gè)元素,以此類推。也可以使用負(fù)數(shù)下標(biāo),以-1表示列表的最后一個(gè)元素,-2表示列表的倒數(shù)第二個(gè)元素,以此類推。
語法:LTRIM key_NAME START STOP
set:使用sscan每次獲取部分元素,再使用srem命令刪除每個(gè)元素
zset:使用zscan每次獲取部分元素,再使用ZREMRANGEBYRANK命令刪除每個(gè)元素
四 BigKey生產(chǎn)調(diào)優(yōu)
在redis.conf配置文件LAZY FREEING相關(guān)說明:
到此這篇關(guān)于Redis如何解決BigKey的文章就介紹到這了,更多相關(guān)Redis BigKey內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis常見數(shù)據(jù)類型List列表使用詳解
Redis的List是一種有序的字符串集合,支持兩端高效插入和刪除,適用于隊(duì)列和棧,這篇文章主要介紹了Redis常見數(shù)據(jù)類型List列表使用的相關(guān)資料,需要的朋友可以參考下2024-12-12聊聊使用RedisTemplat實(shí)現(xiàn)簡單的分布式鎖的問題
這篇文章主要介紹了使用RedisTemplat實(shí)現(xiàn)簡單的分布式鎖問題,文中給大家介紹在SpringBootTest中編寫測試模塊的詳細(xì)代碼,需要的朋友可以參考下2021-11-11