1、什么是Redis季眷?
Redis是一個(gè)高可用的key-value內(nèi)存數(shù)據(jù)庫(kù)。value可以支持多種類型卷胯。包括字符串(string)子刮、鏈表(list)、集合(set)窑睁、有序集合(zset sorted set)和哈希(hash)挺峡。類似于java中的HashMap也是key-value,value可以存放多種數(shù)據(jù)結(jié)構(gòu)葵孤。
Redis是內(nèi)存數(shù)據(jù)庫(kù),并且是key-value類型橱赠,沒有復(fù)雜的關(guān)系尤仍。所以讀取與存入比mysql這種傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)快。
相比于memcached內(nèi)存數(shù)據(jù)庫(kù)狭姨,它可以通過(guò)RDB或AOF的方式將內(nèi)存數(shù)據(jù)存入磁盤空間吓著,達(dá)到數(shù)據(jù)的持久化。并且Redis也可以通過(guò)主從復(fù)制送挑,哨兵,集群等方式實(shí)現(xiàn)高可用暖眼。
2惕耕、Redis數(shù)據(jù)庫(kù)
2.1 Redis數(shù)據(jù)庫(kù)
Redis默認(rèn)有16個(gè)數(shù)據(jù)庫(kù)。
redisServer結(jié)構(gòu)中保存著一個(gè)redisDb數(shù)組诫肠,int dbnum 保存著數(shù)據(jù)庫(kù)數(shù)量司澎。dbnum默認(rèn)是16。
struct redisServer{
// 一個(gè)數(shù)組栋豫,保存著服務(wù)器中的所有數(shù)據(jù)庫(kù)
redisDb *db ;
//服務(wù)器的數(shù)據(jù)庫(kù)數(shù)量
int dbnum ;
}
每個(gè)數(shù)據(jù)庫(kù)對(duì)應(yīng)一個(gè)redisDb結(jié)構(gòu)挤安,redisDb結(jié)構(gòu)中的dict字典(鍵空間)保存了改數(shù)據(jù)庫(kù)的所有的鍵值對(duì) 。
struct redisDb{
// 數(shù)據(jù)庫(kù)鍵空間丧鸯,保存著數(shù)據(jù)庫(kù)中的所有鍵值對(duì)
dict *dict ;
}
切換數(shù)據(jù)庫(kù)select 1
當(dāng)客戶端切換到1號(hào)數(shù)據(jù)庫(kù)時(shí)蛤铜,數(shù)據(jù)結(jié)構(gòu)示意圖:
切換數(shù)據(jù)庫(kù)select 2
當(dāng)客戶端切換到2號(hào)數(shù)據(jù)庫(kù)時(shí),數(shù)據(jù)結(jié)構(gòu)示意圖:
2.2 數(shù)據(jù)庫(kù)建空間示意圖
- alphabet 是一個(gè)列表鍵丛肢,鍵的名字是字符串'alphabet'围肥,鍵的值是一個(gè)包含三個(gè)元素的列表對(duì)象。
- book是一個(gè)哈希表鍵蜂怎,鍵的名字是字符串'book'穆刻,鍵的值是一個(gè)包含三個(gè)元素的哈希表對(duì)象。
-
message是一個(gè)字符串鍵杠步,鍵的名字是字符串'message'氢伟,鍵的值是一個(gè)字符串對(duì)象'hello world'
2.3 數(shù)據(jù)庫(kù)操作
執(zhí)行命令set date "2013.12.1"
添加一個(gè)新鍵值對(duì)到數(shù)據(jù)庫(kù),就是將鍵值對(duì)添加到對(duì)應(yīng)數(shù)據(jù)庫(kù)(redisDb)的字典(dict)中
刪除book鍵del book
更新message鍵set message "blah blah"
取值alphabet lrange alphabet 0 -1
清空數(shù)據(jù)庫(kù)flushdb
針對(duì)數(shù)據(jù)庫(kù)本身的redis命令幽歼,基本上都是針對(duì)redisDb的字典(dict)進(jìn)行操作朵锣。
2.4 鍵生存時(shí)間及過(guò)期策略
設(shè)置鍵過(guò)期時(shí)間,可以以秒或者毫秒精度
命令 | 描述 |
---|---|
expire <key> <ttl> | 設(shè)置鍵key的生存時(shí)間為ttl 秒 |
pexpire <key> <ttl> | 設(shè)置鍵key的生存時(shí)間為ttl 毫秒 |
expireat <key> <timestamp> | 設(shè)置鍵key的過(guò)期時(shí)間為timestamp所指定的秒數(shù)時(shí)間戳 |
pexpireat <key> <timestamp> | 設(shè)置鍵key的過(guò)期時(shí)間為timestamp所指定的毫秒數(shù)時(shí)間戳 |
expire test 5
:設(shè)置key test過(guò)期時(shí)間為5秒以后
pexpire test 6000
:設(shè)置key test過(guò)期時(shí)間為6000毫秒以后
expireat test 1377333100
:設(shè)置key test過(guò)期時(shí)間為1377333100
pexpireat test 1377333100000
:設(shè)置key test過(guò)期時(shí)間為1377333100000
實(shí)際上expire试躏,pexpire 猪勇,expireat 三個(gè)命令都是使用pexpireat 命令實(shí)現(xiàn)的,redis會(huì)將其他類型的過(guò)期時(shí)間最終都轉(zhuǎn)化為毫秒時(shí)間戳保存颠蕴。
過(guò)期時(shí)間的保存
redisDb結(jié)構(gòu)的expires字典保存了數(shù)據(jù)庫(kù)中的所有鍵的過(guò)期時(shí)間泣刹,稱為過(guò)期字典助析。
過(guò)期字典的key為指針,指向鍵空間的某個(gè)鍵對(duì)象椅您。
過(guò)期字典的value為long long 整數(shù)外冀,保存著過(guò)期時(shí)間戳-毫秒精度的unix時(shí)間戳。
struct redisDb{
//過(guò)期字典掀泳,保存著鍵的過(guò)期時(shí)間
dict *expires ;
}
為了展示方面雪隧,圖示中的鍵空間與過(guò)期字典會(huì)出現(xiàn)兩次alphabet及book對(duì)象,實(shí)際中员舵,鍵空間的key與過(guò)期字典的key指向的是同一個(gè)鍵對(duì)象脑沿,不會(huì)出現(xiàn)重復(fù)對(duì)象。
過(guò)期鍵的刪除策略
刪除策略 | 描述 | 優(yōu)點(diǎn) | 缺點(diǎn) |
---|---|---|---|
定時(shí)刪除 | 設(shè)置鍵的過(guò)期時(shí)马僻,創(chuàng)建一個(gè)定時(shí)器(timer),讓定時(shí)器在鍵的過(guò)期時(shí)間來(lái)臨時(shí)庄拇,立即執(zhí)行對(duì)鍵的刪除操作 | 及時(shí)刪除過(guò)期鍵,釋放內(nèi)存 | 過(guò)期鍵數(shù)量較大時(shí)韭邓,會(huì)創(chuàng)建大量定時(shí)器措近,占用相當(dāng)一部分cpu時(shí)間,不采用 |
惰性刪除 | 放任過(guò)期鍵不管女淑,當(dāng)獲取鍵時(shí)瞭郑,判斷是否過(guò)期,過(guò)期的話鸭你,就刪除掉屈张,未過(guò)期,返回該鍵 | 不用創(chuàng)建定時(shí)器袱巨,不占用cpu時(shí)間 | 過(guò)期鍵會(huì)占用大量?jī)?nèi)存袜茧,導(dǎo)致數(shù)據(jù)積壓 |
定期刪除 | 每隔一段時(shí)間,程序?qū)?shù)據(jù)庫(kù)進(jìn)行一次檢查瓣窄,刪除過(guò)期鍵笛厦,至于刪除多少過(guò)期鍵,檢查多少個(gè)數(shù)據(jù)庫(kù)俺夕,有算法決定 | 是前兩種策略的折中方案裳凸,既能比較及時(shí)釋放內(nèi)存,又能不占用大量cpu時(shí)間 | 難點(diǎn)在于確定操作執(zhí)行的時(shí)長(zhǎng)和頻率劝贸,既不能讓刪除操作執(zhí)行太頻繁而占用cpu時(shí)間姨谷,又不能執(zhí)行太少,浪費(fèi)內(nèi)存 |
Redis服務(wù)器使用了惰性刪除及定期刪除兩種策略映九。
惰性刪除:所有讀寫Redis命令在執(zhí)行之前都會(huì)調(diào)用expireIfNeeded函數(shù)對(duì)輸入鍵進(jìn)行檢查梦湘。expireIfNeeded就像一個(gè)過(guò)濾器,將過(guò)期鍵刪除。
定期刪除:redis的周期性函數(shù)serverCron會(huì)在規(guī)定時(shí)間內(nèi)多次遍歷各個(gè)數(shù)據(jù)庫(kù)捌议,從數(shù)據(jù)庫(kù)的expires字典中隨機(jī)檢查一部分鍵的過(guò)期時(shí)間哼拔,并刪除其中的過(guò)期鍵。
RDB對(duì)過(guò)期鍵的處理
生成RDB文件
save
及bgsave
命令只會(huì)對(duì)未過(guò)期的鍵進(jìn)行保存操作瓣颅,保存至rdb文件倦逐。
載入RDB文件
如果服務(wù)器以主服務(wù)器模式運(yùn)行,那么載入RDB文件時(shí)宫补,不會(huì)將過(guò)期鍵導(dǎo)入檬姥。
如果服務(wù)器以從服務(wù)器模式運(yùn)行,那么載入RDB文件時(shí)粉怕,會(huì)將過(guò)期鍵導(dǎo)入健民,等主服務(wù)器同步數(shù)據(jù)時(shí),再刪除掉過(guò)期數(shù)據(jù)贫贝。
AOF對(duì)過(guò)期鍵的處理
AOF文件寫入
當(dāng)服務(wù)器以AOF持久化模式運(yùn)行時(shí)荞雏,對(duì)于未被刪除的過(guò)期數(shù)據(jù),AOF不會(huì)因?yàn)檫^(guò)期鍵產(chǎn)生任何影響平酿。
對(duì)于已被刪除的數(shù)據(jù),程序會(huì)像AOF追加(append)一條DEL命令悦陋,來(lái)顯示地記錄該鍵已被刪除蜈彼。
AOF重寫
在執(zhí)行AOF重寫的過(guò)程中,程序會(huì)對(duì)數(shù)據(jù)庫(kù)中的鍵進(jìn)行檢查俺驶,已過(guò)期的鍵不會(huì)被保存至重寫后的AOF文件中幸逆。
復(fù)制對(duì)過(guò)期鍵的處理
當(dāng)服務(wù)器運(yùn)行在復(fù)制模式下,從服務(wù)器的過(guò)期刪除動(dòng)作由主服務(wù)器控制暮现。
主服務(wù)器在刪除一個(gè)過(guò)期鍵時(shí)还绘,會(huì)向從服務(wù)器發(fā)送一個(gè)DEl命令,告知從服務(wù)器刪除過(guò)期鍵
從服務(wù)器執(zhí)行客戶端發(fā)送的命令時(shí)栖袋,即使碰見過(guò)期鍵也不會(huì)將過(guò)期鍵刪除拍顷,而是會(huì)繼續(xù)像處理未過(guò)期鍵一樣進(jìn)行處理。
從服務(wù)只有接收到主服務(wù)器的DEl命令塘幅,才會(huì)刪除過(guò)期鍵昔案。