Redis深度歷險記(一)基礎


本篇是對"Redis深度歷險"的學習與思考
Remote dictionary service

install

書中提供了docker,源代碼,直接安裝三種方式,其他兩種我都玩過,現在說下源代碼安裝.
書中給出的貌似2.8版本,但是現在已經是6.0版本了,所以我執行的命令和 書中略有不同.
關於6.0的新特性還沒去仔細瞭解,貌似加入了多線程和ACL

# 這個指令和書中不一樣
git clone https://github.com/antirez/redis.git
cd redis
# 速度巨慢,我吃了飯回來纔好,看來源碼安裝被拋棄是有道理的
make
# 書中並沒有make test這一步,我是在執行make後按照提示執行了下一步,但我執行後報了兩次Error,心塞
make test
cd src
./redis-server --daemonize yes

基礎數據結構

書中講到有5種,這應該是老版本的了

string

Redis的字符串是動態字符串…內部結構的實現類似於Java的ArrayList,採用預分配冗餘空間的方式來減少內存的頻繁分配.

如果這樣的話不知道Redis能否預先制定value的capacity從而進一步減少重分配

字符串最大長度爲512MB

這些指令對於其他數據結構有些也是適用的

set

引號

[qbit@manjaro src]$ ./redis-cli 
127.0.0.1:6379> set Qbit qqq
OK
127.0.0.1:6379> get Qbit
"qqq"
127.0.0.1:6379> set Qbit "qqq"
OK
127.0.0.1:6379> get Qbit
"qqq"
127.0.0.1:6379> set Qbit "qqq
Invalid argument(s)
127.0.0.1:6379> set Qbit "thiis"whatisaid"1"
Invalid argument(s)

127.0.0.1:6379> set "Qbit" m
OK
127.0.0.1:6379> get Qbit
"m"
set Qb"it m
Invalid argument(s)

通過上面例子可以看出,如果key和value被雙引號引起來,和沒有雙引號是一個效果.如果雙引號不匹配或者出現其他位置就是非法的了

exists

官網說明
判斷是否存在,後面可以接上n個key,然後返回存在的key的個數,對於最普通的情況(也就是3.0之前的版本),下面是官方例子幫助理解

redis> SET key1 "Hello"
"OK"
redis> EXISTS key1
(integer) 1
redis> EXISTS nosuchkey
(integer) 0
redis> SET key2 "World"
"OK"
redis> EXISTS key1 key2 nosuchkey
(integer) 2

list

Redis的列表相當於Java語言裏面的LinkedList

quicklist

redis內部做了一些優化,當存儲數據較少的時候傾向於使用ziplist,另外這兩個會結合時候,後面再具體說

rpush rpop lpop lpush

xpush時可以接多個參數,依次push,一般優先用r

lindex lrange ltrim llen

看名字大概知道什麼意思,具體適用到時候再參見官網

blpop brpop

書中也介紹了list也可以作爲一個簡單的MQ,
需要注意的一點是消費者在pop無法獲得詩句的時候需要sleep一下,這樣同時減輕自己和Redis的CPU消耗
更好的方案是使用blpop brpop,其中b是blocking的意思,但是這裏還有一個坑,即使Redis的服務端對於長時間空閒的鏈接可能斷開

hash

這裏面有很多x開頭的操作對應了redis本身的一些操作,例如hincrby對應incr

set

zset

這是一個帶排序的set,排序規則就是分數,對應的,會有各種z開頭的操作,這裏講下常用的.

zrange zrevrange

分別升序和降序輸出,一般後面接0 -1表示從第0個到倒數第一個都輸出

zcard

相當於count

限流

滑動窗口

在這裏插入圖片描述
zset的一個用處是用來限流.限流是針對特定操作的限流,比如下面代碼就是針對特定user_id的特定action

import time
import redis
client=redis.StrictRedis()
def is_allowed(user_id,action,period,max_count):
	#這個key的意思是對這個user_id的這個action進行限流
	key='hist:%s:%s'%(user_id,action)
	now=int(time.time()*1000)
	with client.pipeline() as pipe:
		#記錄本次操作
		pipe.zadd(key,now,now)
		#移除窗口外的操作
		pipe.zremrangebyscore(key,0,now-period*1000)
		#獲取窗口內數量
		pipe.zcard(key)
		#設置過期時間用於剔除冷數據
		pipe.expire(key,period+1)
		#執行
		_,_,count,_=pipe.execute()
	return count<max_count

可以看出來,如果進行不停的操作,即使由於限流導致操作不成功,也會對後期操作有負面影響.

HyperLogLog

這種數據結構涉及到三個pf開頭的指令(pf表示其發明人Philippe Flajolet):pfadd,pfcount,pfmerge,其中pfcount可以跟隨多個key,相當於先把他們merge在得到數

Bloom Filter

當布隆過濾器所某個值存在時,這個值可能不存在;當它說某個值不存在時,那就肯定不存在.

讓我詫異的是這些bf開頭的指令居然不是官方原生支持的,我使用源碼安裝後不支持,以後再繼續研究吧.不過書中提到使用bf.reserve來控制error_rate,可以記下來.
簡單說下原理,附上書中的圖
在這裏插入圖片描述
就是會對每個key做hash(圖中使用了f,g,h三個hash函數),然後把對應位圖中位置設置爲1,查找的時候看看對應的位圖是否爲1就可以了.所以位圖夠大才能避免碰撞,另外hash函數越多則越精確.
這裏有個網站幫助計算
在這裏插入圖片描述

GeoHash

毫無疑問,這又涉及到一些geo開頭的數據,需要提到的是刪除使用了zset的zrem指令來刪除
另外一個問題是對於geo的key而言,value往往很大,在集羣模式下遷移會有卡頓,所以建議單獨非集羣部署

keys vs scan

scan提供了查找功能,但是不像keys那樣會阻塞,並且支持分頁.不過這裏有個坑爹的特性就是返回的條數並不精準,特別是返回集爲空是並不代表沒有後續數據.因爲其limit其實是指定的slot的數量而不是記錄條數,另外它採用的是高位加法(相應的,普通加法可以理解爲低位加法),如圖所示
在這裏插入圖片描述

rehash

由於Redis採用了漸進式rehash,所以scan時要去新舊兩個槽裏去找

大key的查找

redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.1

上面的i參數是指每scan100就休眠0.1s,避免避免ops飆升觸發運維監控的報警,當然這樣會慢一些.所以也可以去掉.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章