redis快取詳解(從入門到精通)
引言
Redis 是一個開源(BSD許可)的,記憶體中的資料結構儲存系統,它可以用作資料庫、快取和訊息中介軟體。 它支援多種型別的資料結構,如 字串(strings), 雜湊(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 與範圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢。 Redis 內建了 複製(replication),LUA指令碼(Lua scripting), LRU驅動事件(LRU eviction),事務(transactions) 和不同級別的 磁碟持久化(persistence), 並通過 Redis哨兵(Sentinel)和自動 分割槽(Cluster)提供高可用性(high availability)。
資料結構
Redis是基於記憶體的資料儲存服務,它支援key-value查詢操作,value存在以下五種資料型別
- 字串(strings)
- 雜湊(hashes)
- 表(lists)
- 集合(sets)
- 有序集合(sorted sets)
redis安裝
下載
地址:http://download.redis.io/releases/
解壓
##解壓
tar -xzvf redis-6.0.6.tar.gz
編譯
進入解壓的目錄,執行make命令
##使用gcc編譯,gcc版本需要大於5.0,檢視 gcc版本:gcc -v make ##若需要指定安裝目錄,則加PREFIX選項 make install PREFIX=/usr/local/redis ##如果gcc小於5,需要先升級gcc,依次執行以下命令 yum install centos-release-scl yum install devtoolset-7-gcc* scl enable devtoolset-7 bash
常用命令
String
Redis 字串資料型別的相關命令用於管理 redis 字串值,常用操作命令如下:
set key value ##設定key的值為value mset key1 value1 key2 value2 [key value] ##同裡設定多個 get key ##獲取key的value值 mget key1 key2 key3 [key] ##同裡獲取多個key的value值 del key ##刪除key,跟value型別無關 incr key ##對num型的key進行++1操作,decr減1 incrby key incrememt ##對num型的key加上increment,decrby減n append key value ##將value的值進行字串連線操作,加在原value末尾 strlen key ##獲取value字串長度 setnx key value ##只有key不存在時設定key的值 exists key1 key2 key3 ##判斷某個key是否存在,跟value型別無關,返回存在key的個數
Hash
hash 是一個 string 型別的 field(欄位) 和 value(值) 的對映表,hash 特別適合用於儲存物件
hset key field1 value1 field2 value2 [field value] ##新增key,給key設定欄位以及相應的value值,可以同裡設定多個field,hmset同樣
hget key field ##獲得key的其中一個field欄位的value值
hmget key field ##獲得key的一個或多個field欄位的value值
hdel key field1 field2 ##刪除key的一個或多個field欄位
hexists key field ##判斷某個key中的field欄位是否存在
hkeys key ##獲取key的所有存在的field欄位
hvals key ##獲取key的所有value
hlen key ##獲取key存在的欄位field個數
hsetnx key field value ##當只有key中的field欄位不存在的時候,將field值設為value
hincrby key field increment ##將key中的某個num欄位filed,自增increment
List
Redis列表是簡單的字串列表,按照插入順序排序。你可以新增一個元素到列表的頭部(左邊)或者尾部(右邊)
lpush key element1 element2 element3 ##從左邊往右邊推,依次推e1 e2 e3,(lpushx,如果list存在,才插入)
rpush key element1 element2 element3 ##從右邊往左邊推,依次推e1 e2 e3 (rpushx,如果list存在,才插入)
lpop key ##從左邊往外彈(取),取出最左邊的元素,取了該元素就沒了
lpop key ##從右邊往外彈(取),取出最右邊的元素,取了該元素就沒了
lrange start end ##取出list中某幾個值,start和end可以是正反向索引,(正向索引從最左邊0開始,反向索引從最右邊-1開始),start end都是include
lindex key index ##根據索引取出list中的元素
llen key ##list的長度
LSET key index value ##設定設定list某個位置的元素
##根據引數COUNT的值,移除列表中與引數 VALUE 相等的元素。
###count > 0 : 從表頭開始向表尾搜尋,移除與 VALUE 相等的元素,數量為 COUNT 。
###count < 0 : 從表尾開始向表頭搜尋,移除與 VALUE 相等的元素,數量為 COUNT 的絕對值。
###count = 0 : 移除表中所有與 VALUE 相等的值。
lrem key count value
##將source列表中最右邊的元素取出來,再放入到destination列表中最左邊
RPOPLPUSH source destination
##將值 value 插入到列表 key 當中,位於值 pivot 之前或之後。
LINSERT key BEFORE|AFTER pivot value
BLPOP key timeout ##彈出list中最左邊的值,如果不存在,則阻塞timout秒
BRLPOP key timeout ##彈出list中最右邊的值,如果不存在,則阻塞timout秒
BRPOPLPUSH source destination timeout ##將source列表中最右邊的元素取出來,再放入到destination列表中最左邊,如果source沒有元素,則阻塞timeout秒。
Set
集合Set 是 String 型別的無序集合。集合成員是唯一的,這就意味著集合中不能出現重複的資料。
Redis中集合是通過雜湊表實現的,所以新增,刪除,查詢的複雜度都是 O(1)
sadd key member1 member2 member3 ##向集合中新增1個或多個成員,自動去重
srem key memeber1 memeber2 ##移除集中中一個或多個元素
scrad key ##獲取集合的成員數
SMEMBERS key ##獲取集中中的所有成員
SISMEMBER key member ##判斷memeber是否是集合key中的成員
sdiff key1 key2 ##差集(返回集合1中有的,而集合2中沒有的資料)
SDIFFSTORE destination key1 [key2] ##將差集存在destination當中
SINTER key1 [key2] ##交集
SINTERSTORE destination key1 [key2] ##將交集儲存在destination
SUNION key1 key2 ##並集
SUNIONSTORE destination key1 [key2] ##將並集儲存在destination
SMOVE source destination member ##將元素memeber從source集合移動到destination中
spop key ##移除並返回集合中的一個隨機元素
##返回集合中一個或多個隨機元素
###如果count>0 且 count<size,則返回count個不重複的元素,如果count>size,則返回集合的全部元素(不重複)
###如果count<0,則返回count絕對值個元素,無論count絕對值是否大於size,都有可能重複。
SRANDMEMBER key [count]
Sorted Set
有序集合和集合一樣也是 string 型別元素的集合,且不允許重複的成員。
不同的是每個元素都會關聯一個 double 型別的分數。redis 正是通過分數來為集合中的成員進行從小到大的排序。
有序集合的成員是唯一的,但分數(score)卻可以重複
ZADD key score1 member1 [score2 member2] ##向有序集合新增一個或多個成員,或者更新已存在成員的分數
zcard key ##返回有序集合中的成員數量
zrange key start end [withscores] ##返回指定索引區間的memeber,withscores可以把sroce也返回來,,ZREVRANGE從高到低
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] ##返回分數在指定範圍內的成員
scount key min max ##返回分數在min和max區間範圍內的成員,min和max都是Including
ZINCRBY key increment member ##對有序集合中key的member成員分數加上increment
zrank key member ##返回member的索引(它的索引是score排過序後的索引),ZREVRANK,從高到低
zrem key member [member ...] ##移除有序集合中一個或多個成員
zremrangebyrank key start top ##移除有序集合中指定rank區間的成員
zremrangebyscore key min max ##移除有序集中中指定score區間的成員,ZREVRANGEBYSCORE從高到低
zscore key member ##返回有序集合,成員的分數值
HyperLogLog
HyperLogLog 是用來做基數統計的演算法,HyperLogLog 的優點是,在輸入元素的數量或者體積非常非常大時,計算基數所需的空間總是固定 的、並且是很小的。
在 Redis 裡面,每個 HyperLogLog 鍵只需要花費 12 KB 記憶體,就可以計算接近 2^64 個不同元素的基 數。這和計算基數時,元素越多耗費記憶體就越多的集合形成鮮明對比。
但是,因為 HyperLogLog 只會根據輸入元素來計算基數,而不會儲存輸入元素本身,所以 HyperLogLog 不能像集合那樣,返回輸入的各個元素。
比如資料集 {1, 3, 5, 7, 5, 7, 8}, 那麼這個資料集的基數集為 {1, 3, 5 ,7, 8}, 基數(不重複元素)為5。 基數估計就是在誤差可接受的範圍內,快速計算基數。
PFADD key element1 element2 element3 ##新增元素
PFCOUNT key ##計算基數
PFMERGE destination key1 key2 ##將多個 HyperLogLog 合併為一個 HyperLogLog
bitmap
bitmap就是通過最小的單位bit來進行0或者1的設定,表示某個元素對應的值或者狀態。
一個bit的值,或者是0,或者是1;也就是說一個bit能儲存的最多資訊是2。
setbit key offset value ##將key這個bitmap上的offset位置設為value,value只能是0或1
getbit key offset ##獲取第offset位置上的value值
##以下的區間是的位元組為b為單位,即0 0,則第1個8個二進位制位
bitcount key [start end] ##統計bit為1的個數,可以指定區間,如果沒有指定,則獲取全部
BITPOS key bit [start end] ##查詢bitmap中,首個值為bit(0或1)的位置(索引),可以指定區間
bitOp ##對二進位制位進行位運算 and or
redis事務
multi ##標記一個事務塊開始
exec ##執行事務塊中的所有命令
DISCARD ##取消事務
unwatch ##取消watch命令對所有key的監視
watch key1 key2 ... ##監視一個或多個key,如果在事務執行之前這個(或這些) key 被其他命令所改動,那麼事務將被打斷。類似Java中的cas操作
其它操作
auth password ##如果有密碼,登陸後,要輸入密碼
select index ##選擇資料庫 0- 15
dbsize ##當前庫中key的數量
keys parttern ##檢視當前庫中parttern匹配成功的所有key
flushdb ##刪除當前庫中的所有資料
flushall ##刪除整個redis的資料
expire key seconds ##設定過期時間,單位秒,pexpire毫秒
EXPIREAT timestamp ##設定過期時間,在指定時間點過期,接受unix timestamp,pexpireat毫秒時間戳
ttl key ##返回key的過期時間,pttl毫秒
PERSIST key ##移除key的過期時間
exists key ##檢查key是否存在
move key dbindex ##將當前資料庫中的Key-value移至指定的db中
rename key newname ##為key修改名字,新名字newname
type key ##返回key所儲存值的型別
save ##立即生成記憶體快照rdb檔案
redis配置
基本配置
bind 0.0.0.0 ##繫結IP
port 6379 ##監聽埠
pidfile /var/run/redis_6379.pid ##pid檔案位置
logfile "" ##log檔案位置,預設沒有,則輸出到 /dev/null
databases 16 ##資料庫個數,預設16,即0-15
daemonize no ##是否後臺執行
supervised no ## no upstart systemd auto
requirepass 123456 ##設定auth認證時的密碼123456,預設沒有密碼
rename-command FLUSHDB FSAEWQFREWQFEWQ23 ##禁用flushdb
rename-command FLUSHALL FSAEWQFREWQFEWQ32s ##禁用flushall
maxmemory 200m ##最大可佔用記憶體,一般設為實體記憶體的80%左右,預設大小等於實體記憶體
maxclients 10000 ##最大client連線數量
maxmemory-policy noeviction 記憶體滿了後,資料淘汰策略
redis持久化
RDB持久化方式能夠在指定的時間間隔能對你的資料進行快照儲存.
AOF持久化方式記錄每次對伺服器寫的操作,當伺服器重啟的時候會重新執行這些命令來恢復原始的資料,AOF命令以redis協議追加儲存每次寫的操作到檔案末尾.Redis還能對AOF檔案進行後臺重寫,使得AOF檔案的體積不至於過大.
如果你只希望你的資料在伺服器執行的時候存在,你也可以不使用任何持久化方式.
你也可以同時開啟兩種持久化方式, 在這種情況下, 當redis重啟的時候會優先載入AOF檔案來恢復原始的資料,因為在通常情況下AOF檔案儲存的資料集要比RDB檔案儲存的資料集要完整.
RDB記憶體快照
RDB是redis預設開啟的持久化方式
工作方式
當 Redis 需要儲存 dump.rdb 檔案時, 伺服器執行以下操作:
- Redis 呼叫forks. 同時擁有父程序和子程序。
- 子程序將資料集寫入到一個臨時 RDB 檔案中。
- 當子程序完成對新 RDB 檔案的寫入時,Redis 用新 RDB 檔案替換原來的 RDB 檔案,並刪除舊的 RDB 檔案。
這種工作方式使得 Redis 可以從寫時複製(copy-on-write)機制中獲益,與AOF相比,在恢復大的資料集的時候,RDB方式會更快一些.
RDB是一個非常緊湊的檔案,它儲存了某個時間點得資料集,非常適用於資料集的備份,比如你可以在每個小時報儲存一下過去24小時內的資料,同時每天儲存過去30天的資料,這樣即使出了問題你也可以根據需求恢復到不同版本的資料集.
在命令列裡,可以通過 save
或 bgsave
,命令來手動立刻觸發生成記憶體快照
RDB配置
dbfilename dump.rdb ##記憶體快照物理檔案地址
save 60 1000 ##該設定會讓 Redis 在滿足“ 60 秒內有至少有 1000 個鍵被改動”這一條件時, 自動儲存一次資料集,可以設定多個
##配置檔案裡面,有以下預設配置
save 900 1
save 300 10
save 60 10000
AOF日誌追加
工作方式
AOF 重寫和 RDB 建立快照一樣,都巧妙地利用了寫時複製機制:
- Redis 執行 fork() ,現在同時擁有父程序和子程序。
- 子程序開始將新 AOF 檔案的內容寫入到臨時檔案。
- 對於所有新執行的寫入命令,父程序一邊將它們累積到一個記憶體快取中,一邊將這些改動追加到現有 AOF 檔案的末尾,這樣樣即使在重寫的中途發生停機,現有的 AOF 檔案也還是安全的。
- 當子程序完成重寫工作時,它給父程序傳送一個訊號,父程序在接收到訊號之後,將記憶體快取中的所有資料追加到新 AOF 檔案的末尾。
- 搞定!現在 Redis 原子地用新檔案替換舊檔案,之後所有命令都會直接追加到新 AOF 檔案的末尾。
AOF吸取RDB的優點,在第一次使用AOF的時候,
AOF配置
appendfilename "appendonly.aof" ##aof檔案儲存位置
appendonly yes ##開啟aof功能,預設no
###aof寫入磁碟的機制,關閉aof後,可以將他們都註釋,預設是appendfsync everysec,以下三種方式3選1
# appendfsync always ##每次有新命令追加到 AOF 檔案時就執行一次 fsync :非常慢,也非常安全
# appendfsync everysec ##每秒 fsync 一次:足夠快(和使用 RDB 持久化差不多),並且在故障時只會丟失 1 秒鐘的資料。(預設)
# appendfsync no ##從不 fsync :將資料交給作業系統來處理。更快,也更不安全的選擇。
推薦(並且也是預設)的措施為每秒 fsync 一次, 這種 fsync 策略可以兼顧速度和安全性。
aof-use-rdb-preamble yes ##aof結合rdb的功能,默然開啟,建議開啟
在redis的配置檔案中,大概1000多行的位置,有一個描述
redis的AOF持久功能,實際是結合了rdb的功能的,在首次進行AOF追加的時候,會將記憶體現有的資料以RDB快照的形式儲存在aof檔案的開始位置,然後如果有追加,就會在AOF檔案中將command加入到末尾。
也可以通過命令BGREWRITEAOF
,將redis現在的資料,以RDB快照的形式重寫進aof檔案中,並覆蓋aof檔案中原有的資料(命令記錄就消失,只有rdb快照,檔案變小了))。
存有rdb快照的aof檔案內容如下:
redis叢集
redis主從模式
在 Redis 複製的基礎上,使用和配置主從複製非常簡單,能使得從 Redis 伺服器(下文稱 slave)能精確得複製主 Redis 伺服器(下文稱 master)的內容。每次當 slave 和 master 之間的連線斷開時, slave 會自動重連到 master 上,並且無論這期間 master 發生了什麼, slave 都將嘗試讓自身成為 master 的精確副本。
這個系統的執行依靠三個主要的機制:
- 當一個 master 例項和一個 slave 例項連線正常時, master 會發送一連串的命令流來保持對 slave 的更新,以便於將自身資料集的改變複製給 slave , :包括客戶端的寫入、key 的過期或被逐出等等。
- 當 master 和 slave 之間的連線斷開之後,因為網路問題、或者是主從意識到連線超時, slave 重新連線上 master 並會嘗試進行部分重同步:這意味著它會嘗試只獲取在斷開連線期間內丟失的命令流。
- 當無法進行部分重同步時, slave 會請求進行全量重同步。這會涉及到一個更復雜的過程,例如 master 需要建立所有資料的快照,將之傳送給 slave ,之後在資料集更改時持續傳送命令流到 slave 。
配置檔案(slave從機上配置即可)
replicaof 172.17.0.5 6379 ##在從機上指定master主機的IP和埠
masterauth 123456 ##指定主機的認證密碼
replica-read-only yes ##從機使用只讀模式
Sentinel哨兵模式
Redis 的 Sentinel 系統用於管理多個 Redis 伺服器(instance), 該系統執行以下三個任務:
- 監控(Monitoring): Sentinel 會不斷地檢查你的主伺服器和從伺服器是否運作正常。
- 提醒(Notification): 當被監控的某個 Redis 伺服器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程式傳送通知。
- 自動故障遷移(Automatic failover): 當一個主伺服器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主伺服器的其中一個從伺服器升級為新的主伺服器, 並讓失效主伺服器的其他從伺服器改為複製新的主伺服器; 當客戶端試圖連線失效的主伺服器時, 叢集也會向客戶端返回新主伺服器的地址, 使得叢集可以使用新主伺服器代替失效伺服器。
Redis Sentinel 是一個分散式系統, 你可以在一個架構中執行多個 Sentinel 程序(progress), 這些程序使用流言協議(gossip protocols)來接收關於主伺服器是否下線的資訊, 並使用投票協議(agreement protocols)來決定是否執行自動故障遷移, 以及選擇哪個從伺服器作為新的主伺服器。
雖然 Redis Sentinel 釋出為一個單獨的可執行檔案 redis-sentinel , 但實際上它只是一個執行在特殊模式下的 Redis 伺服器, 你可以在啟動一個普通 Redis 伺服器時通過給定 –sentinel 選項來啟動 Redis Sentinel 。
配置檔案(sentinel.conf)
##Sentinel 去監視一個名為 mymaster 的主伺服器,
##這個主伺服器的 IP 地址為 127.0.0.1 , 埠號為 6379 ,
##而將這個主伺服器判斷為失效至少需要 2 個 Sentinel 同意 (只要同意 Sentinel 的數量不達標,自動故障遷移就不會執行)
sentinel monitor mymaster 127.0.0.1 6379 2
##master伺服器的認證密碼
sentinel auth-pass mymaster 123456
##指定Sentinel 認為伺服器已經斷線所需的毫秒數。
##不過只有一個 Sentinel 將伺服器標記為主觀下線並不一定會引起伺服器的自動故障遷移:
##只有在足夠數量的 Sentinel 都將一個伺服器標記為主觀下線之後,
##伺服器才會被標記為客觀下線(objectively down, 簡稱 ODOWN ), 這時自動故障遷移才會執行。
sentinel down-after-milliseconds mymaster 60000
##多個sentinel之間投票表決超時時間
sentinel failover-timeout mymaster 180000
##parallel-syncs 選項指定了在執行故障轉移時,
##最多可以有多少個從伺服器同時對新的主伺服器進行同步, 這個數字越小, 完成故障轉移所需的時間就越長。
sentinel parallel-syncs mymaster 1
啟動方式
##第一種
redis-server /path/to/sentinel.conf --sentinel
##第二種
redis-sentinel /path/to/sentinel.conf
叢集啟動順序
1. 啟動sentinel叢集
2. 啟動redis master主機
3. 啟動redis slave從機
下以是當主機掛掉後,在sentinel控制檯列印的日誌資訊
需要注意的是:
sentinel監聽到master主機掉線後,會通過選舉演算法,產生新的master主機,並通知其它線上的從機(除剛剛被選為master的那臺以外)連線到新的主機上面,所以在master和slave上的認證密碼應該相同,需要在master和slave所有redis機器上面配置 masterauth password
,剛剛斷掉的主機如果重新啟動的話,會被sentinel叢集當作從機,並連線到選舉產生的主機上面。同裡sentinel會將現在的master監聽資訊固化(持久化)到自己的sentinel.conf配置檔案裡
Cluster模式
為什麼要實現redis cluster?
1. 主從複製不能實現高可用
2. 隨著公司發展,使用者數量增多,併發越來越多,業務需要更高的QPS,而主從複製中單機的QPS可能無法滿足業務需求
3. 資料量的考慮,現有伺服器記憶體不能滿足業務資料的需要時,單純向伺服器新增記憶體不能達到要求,此時需要考慮分散式需求,把資料分佈到不同伺服器上
4. 網路流量需求:業務的流量已經超過伺服器的網絡卡的上限值,可以考慮使用分散式來進行分流
5. 離線計算,需要中間環節緩衝等別的需求
常見的分割槽方式
全量資料,單機Redis節點無法滿足要求,按照分割槽規則把資料分到若干個子集當中
- 節點取餘分割槽:
節點取餘方式是非常簡單的一種分割槽方式
節點取餘分割槽方式有一個問題:即當增加或減少節點時,原來節點中的80%的資料會進行遷移操作,對所有資料重新進行分佈
節點取餘分割槽方式建議使用多倍擴容的方式,例如以前用3個節點儲存資料,擴容為比以前多一倍的節點即6個節點來儲存資料,這樣只需要適移50%的資料。資料遷移之後,第一次無法從快取中讀取資料,必須先從資料庫中讀取資料,然後回寫到快取中,然後才能從快取中讀取遷移之後的資料 - 一致性雜湊分割槽:
對每一個key進行hash運算,被雜湊後的結果在哪個token的範圍內,則按順時針去找最近的節點,這個key將會被儲存在這個節點上。
在上面的圖中,有4個key被hash之後的值在在n1節點和n2節點之間,按照順時針規則,這4個key都會被儲存在n2節點上,
如果在n1節點和n2節點之間新增n5節點,當下次有key被hash之後的值在n1節點和n5節點之間,這些key就會被儲存在n5節點上面了
在上面的例子裡,新增n5節點之後,資料遷移會在n1節點和n2節點之間進行,n3節點和n4節點不受影響,資料遷移範圍被縮小很多
同理,如果有1000個節點,此時新增一個節點,受影響的節點範圍最多隻有千分之2
一致性雜湊一般用在節點比較多的時候 - 虛擬槽位分配:
虛擬槽分割槽是Redis Cluster採用的分割槽方式
預設虛擬槽,每個槽就相當於一個數字,有一定範圍。每個槽對映一個數據子集,一般比節點數大
- 把16384槽按照節點數量進行平均分配,由節點進行管理
- 對每個key按照CRC16規則進行hash運算
- 把hash結果對16383進行取餘
- 把餘數傳送給Redis節點
- 節點接收到資料,驗證是否在自己管理的槽編號的範圍
如果在自己管理的槽編號範圍內,則把資料儲存到資料槽中,然後返回執行結果
如果在自己管理的槽編號範圍外,則會把資料傳送給正確的節點,由正確的節點來把資料儲存在對應的槽中
需要注意的是:Redis Cluster的節點之間會共享訊息,每個節點都會知道是哪個節點負責哪個範圍內的資料槽
redis cluster槽位管理
把16384個槽平均分配給節點進行管理,每個節點只能對自己負責的槽進行讀寫操作
由於每個節點之間都彼此通訊,每個節點都知道另外節點負責管理的槽範圍
客戶端訪問任意節點時,對資料key按照CRC16規則進行hash運算,然後對運算結果對16383進行取作,如果餘數在當前訪問的節點管理的槽範圍內,則直接返回對應的資料
如果不在當前節點負責管理的槽範圍內,則會告訴客戶端去哪個節點獲取資料,由客戶端去正確的節點獲取資料
1.每個節點通過通訊都會共享Redis Cluster中槽和叢集中對應節點的關係
2.客戶端向Redis Cluster的任意節點發送命令,接收命令的節點會根據CRC16規則進行hash運算與16383取餘,計算自己的槽和對應節點
3.如果儲存資料的槽被分配給當前節點,則去槽中執行命令,並把命令執行結果返回給客戶端
4.如果儲存資料的槽不在當前節點的管理範圍內,則向客戶端返回moved重定向異常
5.客戶端接收到節點返回的結果,如果是moved異常,則從moved異常中獲取目標節點的資訊
6.客戶端向目標節點發送命令,獲取命令執行結果
key過期策略
定期刪除(主動)
redis 會將每個設定了過期時間的 key 放入到一個獨立的字典中,以後會定期遍歷這個字典來刪除到期的 key。
Redis 預設會每秒進行十次過期掃描(100ms一次),過期掃描不會遍歷過期字典中所有的 key,而是採用了一種簡單的貪心策略。
- 從過期字典中隨機 20 個 key;
- 刪除這 20 個 key 中已經過期的 key;
- 如果過期的 key 比率超過 1/4,那就重複步驟 1;
配置檔案
hz 10 ##預設情況下,每秒執行10次過期key掃描(100ms/次)
redis預設是每隔 100ms就隨機抽取一些設定了過期時間的key,檢查其是否過期,如果過期就刪除。注意這裡是隨機抽取的。為什麼要隨機呢?你想一想假如 redis 存了幾十萬個 key ,每隔100ms就遍歷所有的設定過期時間的 key 的話,就會給 CPU 帶來很大的負載。
惰性刪除(被動)
所謂惰性策略就是在客戶端訪問這個key的時候,redis對key的過期時間進行檢查,如果過期了就立即刪除,不會給你返回任何東西。
總結:定期刪除是集中處理,惰性刪除是零散處理。
記憶體淘汰策略
為什麼需要記憶體淘汰策略
有了以上過期策略的說明後,就很容易理解為什麼需要淘汰策略了,因為不管是定期取樣刪除還是惰性刪除都不是一種完全精準的刪除,就還是會存在key沒有被刪除掉的場景,同裡redis伺服器記憶體容量有限,所以就需要記憶體淘汰策略進行補充。
通過閱讀redis的配置檔案,所提供的記憶體淘汰策略一共有8種
淘汰策略
- noeviction:當記憶體使用超過配置的時候會返回錯誤,不會驅逐任何鍵
- allkeys-lru:加入鍵的時候,如果過限,首先通過LRU演算法驅逐最久沒有使用的鍵
- volatile-lru:加入鍵的時候如果過限,首先從設定了過期時間的鍵集合中驅逐最久沒有使用的鍵
- allkeys-random:加入鍵的時候如果過限,從所有key隨機刪除
- volatile-random:加入鍵的時候如果過限,從過期鍵的集合中隨機驅逐
- volatile-ttl:從配置了過期時間的鍵中驅逐馬上就要過期的鍵
- volatile-lfu:從所有配置了過期時間的鍵中驅逐使用頻率最少的鍵
- allkeys-lfu:從所有鍵中驅逐使用頻率最少的鍵
LRU:最久沒有使用
LFU:使用頻率最少
配置檔案
maxmemory-policy noeviction ##redis預設採用的是noeviction策略,即容量滿了後,返回錯誤。不會淘汰任何key。