redis.io/topics/memo… 不一樣大小,底層數據結構不一樣:node
hash-max-ziplist-value 64
zset-max-ziplist-value 64
複製代碼
不要阻塞,特別是 lua 腳本,不要有長時間睡眠操做,否則其它操做所有阻塞! 謹慎使用範圍操做 SLOWLOG get 10 默認10ms,默認只保留最後的128條python
以業務名(或數據庫名)爲前綴(防止key衝突),用冒號分隔,好比業務名:表名:idredis
保證語義的前提下,控制key的長度,當key較多時,內存佔用也不容忽視數據庫
好比:包含空格、換行、單雙引號以及其餘轉義字符緩存
多個業務系統,共用一個redis,仍是應該分開。規劃好key,特別是前綴,a.b.c.dbash
若是緩存數據變大了,就能夠分區,但注意按業務垂直拆分,避免 key 的衝突。 通常小公司研發團隊都是須要申請緩存資源直接獲得對應的 ip 地址,但大公司最多隻能獲得key/token。markdown
那麼什麼樣的Key纔算是Big Key呢? 通常key的值大於10KB時能夠算是Big Key了。 以下場景都有可能遇到Big Key,好比:網絡
出現了Big Key你也不用很是緊張,由於某些場景下不得不使用,而不該該是你的使用不當形成的。下面咱們看一下如何進行發現與優化數據結構
可使用腳本進行查詢,大概思路就是使用 scan 遊標查詢 key,而後使用 memory usage key 獲取這個 key 與 value 的字節數,這樣就能很方便的得出結論進行優化。好比異步
import sys
import redis
def check_big_key(r, k):
bigKey = False
length = 0
try:
type = r.type(k)
if type == "string":
length = r.strlen(k)
elif type == "hash":
length = r.hlen(k)
elif type == "list":
length = r.llen(k)
elif type == "set":
length = r.scard(k)
elif type == "zset":
length = r.zcard(k)
except:
return
if length > 10240:
bigKey = True
if bigKey :
print db,k,type,length
def find_big_key_normal(db_host, db_port, db_password, db_num):
r = redis.StrictRedis(host=db_host, port=db_port, password=db_password, db=db_num)
for k in r.scan_iter(count=1000):
check_big_key(r, k)
def find_big_key_sharding(db_host, db_port, db_password, db_num, nodecount):
r = redis.StrictRedis(host=db_host, port=db_port, password=db_password, db=db_num)
cursor = 0
for node in range(0, nodecount) :
while True:
iscan = r.execute_command("iscan",str(node), str(cursor), "count", "1000")
for k in iscan[1]:
check_big_key(r, k)
cursor = iscan[0]
print cursor, db, node, len(iscan[1])
if cursor == "0":
break;
if __name__ == '__main__':
if len(sys.argv) != 4:
print 'Usage: python ', sys.argv[0], ' host port password '
exit(1)
db_host = sys.argv[1]
db_port = sys.argv[2]
db_password = sys.argv[3]
r = redis.StrictRedis(host=db_host, port=int(db_port), password=db_password)
nodecount = r.info()['nodecount']
keyspace_info = r.info("keyspace")
for db in keyspace_info:
print 'check ', db, ' ', keyspace_info[db]
if nodecount > 1:
find_big_key_sharding(db_host, db_port, db_password, db.replace("db",""), nodecount)
else:
find_big_key_normal(db_host, db_port, db_password, db.replace("db", ""))
複製代碼
能夠經過 python find_bigkey host 6379 password 來執行,默認大 key 的閾值爲 10240(10KB),也就是對於 string 類型的 value 大於 10240 的認爲是大 key,對於 list 的話若是 list 長度大於 10240 認爲是大 key,對於 hash 的話若是 field 的數目大於 10240 認爲是大 key。另外默認該腳本每次搜索 1000 個 key,對業務的影響比較低,不過最好在業務低峯期進行操做,避免 scan 命令對業務的影響。
Redis4.0 新特性 - Lazy Free 當刪除鍵的時候, redis 提供異步延時釋放 key 內存的功能,把 key 釋放操做放在 bio(Background I/O) 單獨的子線程處理中,減小刪除 big key 對 redis 主線程的阻塞。有效地避免刪除 big key 帶來的性能和可用性問題。所以刪除 Big Key 時使用 unlink 操做。
Redis 複製分爲全量複製和部分複製,但全量複製的開銷很大。如何儘可能避免全量複製呢?
既然第一次沒法避免,那就選在集羣低峯時間(凌晨)掛載 Replica
若是有某個Replica已經有了主節點數據了,那就將其選舉爲 master。經過人爲或者哨兵實現選舉。
master 生成 RDB 同步到 Replica,Replica 加載 RDB 這段時間裏,master 的全部寫命令都會保存到一個複製緩衝隊列(若是主從之間網絡抖動,進行部分複製也是執行該邏輯),待 Replica 加載完 RDB,拿 offset 值到該隊列判斷,若在該隊列,則把該隊列從 offset 到末尾所有同步過來,這個隊列的默認值爲 1M。若發現 offset 不在隊列,就會發起全量複製。 因此增大複製緩衝區的配置 repl_backlog_size 默認是 1M,能夠設置大一些,從而增大 offset 的命中率。那麼如何估算該值呢?通常咱們網絡故障時間通常是min級別,因此以下公式:
理想值 = 根據當前QPS估算每分鐘可寫入多少字節 ✖️ 可能發生故障的min
複製代碼
通常發生在 Master 掛在多個 Replica 場景。 當 Master 重啓恢復後,其 master 下全部 Replica 檢測到 RunID 變化,致使全部 Replica 向 master 作全量複製。此時 Master 會爲 Replica 建立 RDB 快照,若在快照建立完畢前,有多個 Replica 嘗試與 Master 進行全量同步,那麼其餘的 Replica 將共享這份 RDB 快照。儘管 Redis 對這個問題作了優化,即只生成一份 RDB,但仍需屢次傳輸,開銷很大。同時給多個 Replica 發送快照,可能會使 Master 的網絡帶寬消耗嚴重,形成 Master 延遲變大,極端狀況會出現主從斷開,致使複製失敗。
一臺機器,多個主節點(樹狀複製結構)。 由於Redis是單線程結構,因此發揮不了 CPU多核的優點,因而有的人爲了省錢就在同一機器部署多個 redis 主節點了。
儘可能每一個業務集羣單獨使用本身的Redis,不混用;
控制Redis資源的申請與使用,規範環境和Key的管理(以一線互聯網爲例);
監控CPU 100%(單線程),因此此時基本不響應了,須要優化高延遲操做。