真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

從零單排學(xué)Redis【白銀】

前言

只有光頭才能變強(qiáng)

創(chuàng)新互聯(lián)公司堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站建設(shè)、做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的南岸網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

今天繼續(xù)來(lái)學(xué)習(xí)redis,上一篇從零單排學(xué)Redis【青銅】已經(jīng)將Redis常用的數(shù)據(jù)結(jié)構(gòu)過(guò)了一遍了。如果還沒(méi)看的同學(xué)可以先去看一遍再回來(lái)~

這篇主要講的內(nèi)容有:

  • Redis服務(wù)器的數(shù)據(jù)庫(kù)

  • Redis對(duì)過(guò)期鍵的處理

  • Redis持久化策略(RDB和AOF)

本文力求簡(jiǎn)單講清每個(gè)知識(shí)點(diǎn),希望大家看完能有所收獲

一、Redis服務(wù)器中的數(shù)據(jù)庫(kù)

我們應(yīng)該都用過(guò)MySQL,MySQL我們可以在里邊創(chuàng)建好幾個(gè)庫(kù):

從零單排學(xué)Redis【白銀】

同樣地,Redis服務(wù)器中也有數(shù)據(jù)庫(kù)這么一個(gè)概念。如果不指定具體的數(shù)量,默認(rèn)會(huì)有16個(gè)數(shù)據(jù)庫(kù)。

從零單排學(xué)Redis【白銀】

上面的命令我們也可以發(fā)現(xiàn):當(dāng)切換到15號(hào)數(shù)據(jù)庫(kù),存進(jìn)15號(hào)庫(kù)的數(shù)據(jù),再切換到0號(hào)數(shù)據(jù)庫(kù)時(shí),是獲取不到的!

  • 這說(shuō)明,數(shù)據(jù)庫(kù)與數(shù)據(jù)庫(kù)之間的數(shù)據(jù)是隔離的。

1.1Redis數(shù)據(jù)庫(kù)的原理

Redis服務(wù)器用redisServer結(jié)構(gòu)體來(lái)表示,其中redisDb是一個(gè)數(shù)組,用來(lái)保存所有的數(shù)據(jù)庫(kù),dbnum代表數(shù)據(jù)庫(kù)的數(shù)量(這個(gè)可以配置,默認(rèn)是16)

struct redisServer{  

    //redisDb數(shù)組,表示服務(wù)器中所有的數(shù)據(jù)庫(kù)
    redisDb *db;  

    //服務(wù)器中數(shù)據(jù)庫(kù)的數(shù)量
    int dbnum;  

}; 

我們知道Redis是C/S結(jié)構(gòu),Redis客戶端通過(guò)redisClient結(jié)構(gòu)體來(lái)表示:

typedef struct redisClient{  

    //客戶端當(dāng)前所選數(shù)據(jù)庫(kù)
    redisDb *db;  

}redisClient;

Redis客戶端連接Redis服務(wù)端時(shí)的示例圖:

從零單排學(xué)Redis【白銀】

Redis中對(duì)每個(gè)數(shù)據(jù)庫(kù)用redisDb結(jié)構(gòu)體來(lái)表示:

typedef struct redisDb { 
    int id;         // 數(shù)據(jù)庫(kù)ID標(biāo)識(shí)
    dict *dict;     // 鍵空間,存放著所有的鍵值對(duì)              
    dict *expires;  // 過(guò)期哈希表,保存著鍵的過(guò)期時(shí)間                          
    dict *watched_keys; // 被watch命令監(jiān)控的key和相應(yīng)client    
    long long avg_ttl;  // 數(shù)據(jù)庫(kù)內(nèi)所有鍵的平均TTL(生存時(shí)間)     
} redisDb;

從代碼上我們可以發(fā)現(xiàn)最重要的應(yīng)該是dict *dict,它用來(lái)存放著所有的鍵值對(duì)。對(duì)于dict數(shù)據(jù)結(jié)構(gòu)(哈希表)我們?cè)谏弦黄惨呀?jīng)詳細(xì)說(shuō)了。一般我們將存儲(chǔ)所有鍵值對(duì)的dict稱為鍵空間。

鍵空間示意圖:

從零單排學(xué)Redis【白銀】

Redis的數(shù)據(jù)庫(kù)就是使用字典(哈希表)來(lái)作為底層實(shí)現(xiàn)的,對(duì)數(shù)據(jù)庫(kù)的增刪改查都是構(gòu)建在字典(哈希表)的操作之上的。

例如:

redis > GET message

"hello world"
從零單排學(xué)Redis【白銀】

1.2鍵的過(guò)期時(shí)間

Redis是基于內(nèi)存,內(nèi)存是比較昂貴的,容量肯定比不上硬盤的。就我們現(xiàn)在一臺(tái)普通的機(jī)子,可能就8G內(nèi)存,但硬盤隨隨便便都1T了。

因?yàn)槲覀兊膬?nèi)存是有限的。所以我們會(huì)干掉不常用的數(shù)據(jù),保留常用的數(shù)據(jù)。這就需要我們?cè)O(shè)置一下鍵的過(guò)期(生存)時(shí)間了。

  • 設(shè)置鍵的生存時(shí)間可以通過(guò)EXPIRE或者PEXPIRE命令。

  • 設(shè)置鍵的過(guò)期時(shí)間可以通過(guò)EXPIREAT或者PEXPIREAT命令。

其實(shí)EXPIRE、PEXPIRE、EXPIREAT這三個(gè)命令都是通過(guò)PEXPIREAT命令來(lái)實(shí)現(xiàn)的。

我們?cè)趓edisDb結(jié)構(gòu)體中還發(fā)現(xiàn)了dict *expires;屬性,存放所有鍵過(guò)期的時(shí)間。

舉個(gè)例子基本就可以理解了:

redis > PEXPIREAT message 1391234400000
(integer) 1

設(shè)置了message鍵的過(guò)期時(shí)間為1391234400000

從零單排學(xué)Redis【白銀】

既然有設(shè)置過(guò)期(生存)時(shí)間的命令,那肯定也有移除過(guò)期時(shí)間,查看剩余生存時(shí)間的命令了:

  • PERSIST(移除過(guò)期時(shí)間)

  • TTL(Time To Live)返回剩余生存時(shí)間,以秒為單位

  • PTTL以毫秒為單位返回鍵的剩余生存時(shí)間

1.2.1過(guò)期策略

上面我們已經(jīng)能夠了解到:過(guò)期鍵是保存在哈希表中了。那這些過(guò)期鍵到了過(guò)期的時(shí)間,就會(huì)立馬被刪除掉嗎??

要回答上面的問(wèn)題,需要我們了解一下刪除策略的知識(shí),刪除策略可分為三種

  • 定時(shí)刪除(對(duì)內(nèi)存友好,對(duì)CPU不友好)

    • 到時(shí)間點(diǎn)上就把所有過(guò)期的鍵刪除了。

  • 惰性刪除(對(duì)CPU極度友好,對(duì)內(nèi)存極度不友好)

    • 每次從鍵空間取鍵的時(shí)候,判斷一下該鍵是否過(guò)期了,如果過(guò)期了就刪除。

  • 定期刪除(折中)

    • 每隔一段時(shí)間去刪除過(guò)期鍵,限制刪除的執(zhí)行時(shí)長(zhǎng)和頻率。

Redis采用的是惰性刪除+定期刪除兩種策略,所以說(shuō),在Redis里邊如果過(guò)期鍵到了過(guò)期的時(shí)間了,未必被立馬刪除的!

1.2.2內(nèi)存淘汰機(jī)制

如果定期刪除漏掉了很多過(guò)期key,也沒(méi)及時(shí)去查(沒(méi)走惰性刪除),大量過(guò)期key堆積在內(nèi)存里,導(dǎo)致redis內(nèi)存塊耗盡了,咋整?

我們可以設(shè)置內(nèi)存最大使用量,當(dāng)內(nèi)存使用量超出時(shí),會(huì)施行數(shù)據(jù)淘汰策略

Redis的內(nèi)存淘汰機(jī)制有以下幾種:

從零單排學(xué)Redis【白銀】

一般場(chǎng)景:

使用 Redis 緩存數(shù)據(jù)時(shí),為了提高緩存命中率,需要保證緩存數(shù)據(jù)都是熱點(diǎn)數(shù)據(jù)??梢詫?nèi)存最大使用量設(shè)置為熱點(diǎn)數(shù)據(jù)占用的內(nèi)存量,然后啟用allkeys-lru淘汰策略,將最近最少使用的數(shù)據(jù)淘汰

二、Redis持久化

Redis是基于內(nèi)存的,如果不想辦法將數(shù)據(jù)保存在硬盤上,一旦Redis重啟(退出/故障),內(nèi)存的數(shù)據(jù)將會(huì)全部丟失。

  • 我們肯定不想Redis里頭的數(shù)據(jù)由于某些故障全部丟失(導(dǎo)致所有請(qǐng)求都走M(jìn)ySQL),即便發(fā)生了故障也希望可以將Redis原有的數(shù)據(jù)恢復(fù)過(guò)來(lái),這就是持久化的作用。

Redis提供了兩種不同的持久化方法來(lái)講數(shù)據(jù)存儲(chǔ)到硬盤里邊:

  • RDB(基于快照),將某一時(shí)刻的所有數(shù)據(jù)保存到一個(gè)RDB文件中。

  • AOF(append-only-file),當(dāng)Redis服務(wù)器執(zhí)行寫命令的時(shí)候,將執(zhí)行的寫命令保存到AOF文件中。

2.1RDB(快照持久化)

RDB持久化可以手動(dòng)執(zhí)行,也可以根據(jù)服務(wù)器配置定期執(zhí)行。RDB持久化所生成的RDB文件是一個(gè)經(jīng)過(guò)壓縮的二進(jìn)制文件,Redis可以通過(guò)這個(gè)文件還原數(shù)據(jù)庫(kù)的數(shù)據(jù)。

從零單排學(xué)Redis【白銀】

有兩個(gè)命令可以生成RDB文件:

  • SAVE會(huì)阻塞Redis服務(wù)器進(jìn)程,服務(wù)器不能接收任何請(qǐng)求,直到RDB文件創(chuàng)建完畢為止。

  • BGSAVE創(chuàng)建出一個(gè)子進(jìn)程,由子進(jìn)程來(lái)負(fù)責(zé)創(chuàng)建RDB文件,服務(wù)器進(jìn)程可以繼續(xù)接收請(qǐng)求。

Redis服務(wù)器在啟動(dòng)的時(shí)候,如果發(fā)現(xiàn)有RDB文件,就會(huì)自動(dòng)載入RDB文件(不需要人工干預(yù))

  • 服務(wù)器在載入RDB文件期間,會(huì)處于阻塞狀態(tài),直到載入工作完成。

除了手動(dòng)調(diào)用SAVE或者BGSAVE命令生成RDB文件之外,我們可以使用配置的方式來(lái)定期執(zhí)行:

在默認(rèn)的配置下,如果以下的條件被觸發(fā),就會(huì)執(zhí)行BGSAVE命令

    save 900 1              #在900秒(15分鐘)之后,至少有1個(gè)key發(fā)生變化,
    save 300 10            #在300秒(5分鐘)之后,至少有10個(gè)key發(fā)生變化
    save 60 10000        #在60秒(1分鐘)之后,至少有10000個(gè)key發(fā)生變化

原理大概就是這樣子的(結(jié)合上面的配置來(lái)看):

struct redisServer{
    // 修改計(jì)數(shù)器
    long long dirty;

    // 上一次執(zhí)行保存的時(shí)間
    time_t lastsave;

    // 參數(shù)的配置
    struct saveparam *saveparams;
};

遍歷參數(shù)數(shù)組,判斷修改次數(shù)和時(shí)間是否符合,如果符合則調(diào)用besave()來(lái)生成RDB文件

從零單排學(xué)Redis【白銀】

總結(jié):通過(guò)手動(dòng)調(diào)用SAVE或者BGSAVE命令或者配置條件觸發(fā),將數(shù)據(jù)庫(kù)某一時(shí)刻的數(shù)據(jù)快照,生成RDB文件實(shí)現(xiàn)持久化。

2.2AOF(文件追加)

上面已經(jīng)介紹了RDB持久化是通過(guò)將某一時(shí)刻數(shù)據(jù)庫(kù)的數(shù)據(jù)“快照”來(lái)實(shí)現(xiàn)的,下面我們來(lái)看看AOF是怎么實(shí)現(xiàn)的。

  • AOF是通過(guò)保存Redis服務(wù)器所執(zhí)行的寫命令來(lái)記錄數(shù)據(jù)庫(kù)的數(shù)據(jù)的。

從零單排學(xué)Redis【白銀】

比如說(shuō)我們對(duì)空白的數(shù)據(jù)庫(kù)執(zhí)行以下寫命令:

redis> SET meg "hello"
OK

redis> SADD fruits "apple" "banana" "cherry"
(integer) 3

redis> RPUSH numbers 128 256 512
(integer) 3 

Redis會(huì)產(chǎn)生以下內(nèi)容的AOF文件:

從零單排學(xué)Redis【白銀】

這些都是以Redis的命令請(qǐng)求協(xié)議格式保存的。Redis協(xié)議規(guī)范(RESP)參考資料:

  • https://www.cnblogs.com/tommy-huang/p/6051577.html

AOF持久化功能的實(shí)現(xiàn)可以分為3個(gè)步驟:

  • 命令追加:命令寫入aof_buf緩沖區(qū)

  • 文件寫入:調(diào)用flushAppendOnlyFile函數(shù),考慮是否要將aof_buf緩沖區(qū)寫入AOF文件中

  • 文件同步:考慮是否將內(nèi)存緩沖區(qū)的數(shù)據(jù)真正寫入到硬盤

從零單排學(xué)Redis【白銀】

flushAppendOnlyFile函數(shù)的行為由服務(wù)器配置的appendfsyn選項(xiàng)來(lái)決定的:

    appendfsync always     # 每次有數(shù)據(jù)修改發(fā)生時(shí)都會(huì)寫入AOF文件。
    appendfsync everysec   # 每秒鐘同步一次,該策略為AOF的默認(rèn)策略。
    appendfsync no         # 從不同步。高效但是數(shù)據(jù)不會(huì)被持久化。

從字面上應(yīng)該就更好理解了,這里我就不細(xì)說(shuō)了…

下面來(lái)看一下AOF是如何載入與數(shù)據(jù)還原的:

  • 創(chuàng)建一個(gè)偽客戶端(本地)來(lái)執(zhí)行AOF的命令,直到AOF命令被全部執(zhí)行完畢。

從零單排學(xué)Redis【白銀】

2.2.1AOF重寫

從前面的示例看出,我們寫了三條命令,AOF文件就保存了三條命令。如果我們的命令是這樣子的:

redis > RPUSH list "Java" "3y"
(integer)2

redis > RPUSH list "Java3y"
integer(3)

redis > RPUSH list "yyy"
integer(4)

同樣地,AOF也會(huì)保存3條命令。我們會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題:上面的命令是可以合并起來(lái)成為1條命令的,并不需要3條。這樣就可以讓AOF文件的體積變得更小。

AOF重寫由Redis自行觸發(fā)(參數(shù)配置),也可以用BGREWRITEAOF命令手動(dòng)觸發(fā)重寫操作。

  • 要值得說(shuō)明的是:AOF重寫不需要對(duì)現(xiàn)有的AOF文件進(jìn)行任何的讀取、分析。AOF重寫是通過(guò)讀取服務(wù)器當(dāng)前數(shù)據(jù)庫(kù)的數(shù)據(jù)來(lái)實(shí)現(xiàn)的!

比如說(shuō)現(xiàn)在有一個(gè)Redis數(shù)據(jù)庫(kù)的數(shù)據(jù)如下:

從零單排學(xué)Redis【白銀】

新的AOF文件的命令如下,沒(méi)有一條是多余的!

從零單排學(xué)Redis【白銀】

2.2.2AOF后臺(tái)重寫

Redis將AOF重寫程序放到子進(jìn)程里執(zhí)行(BGREWRITEAOF命令),像BGSAVE命令一樣fork出一個(gè)子進(jìn)程來(lái)完成重寫AOF的操作,從而不會(huì)影響到主進(jìn)程。

AOF后臺(tái)重寫是不會(huì)阻塞主進(jìn)程接收請(qǐng)求的,新的寫命令請(qǐng)求可能會(huì)導(dǎo)致當(dāng)前數(shù)據(jù)庫(kù)和重寫后的AOF文件的數(shù)據(jù)不一致

為了解決數(shù)據(jù)不一致的問(wèn)題,Redis服務(wù)器設(shè)置了一個(gè)AOF重寫緩沖區(qū),這個(gè)緩存區(qū)會(huì)在服務(wù)器創(chuàng)建出子進(jìn)程之后使用

從零單排學(xué)Redis【白銀】

2.3RDB和AOF對(duì)過(guò)期鍵的策略

RDB持久化對(duì)過(guò)期鍵的策略:

  • 執(zhí)行SAVE或者BGSAVE命令創(chuàng)建出的RDB文件,程序會(huì)對(duì)數(shù)據(jù)庫(kù)中的過(guò)期鍵檢查,已過(guò)期的鍵不會(huì)保存在RDB文件中。

  • 載入RDB文件時(shí),程序同樣會(huì)對(duì)RDB文件中的鍵進(jìn)行檢查,過(guò)期的鍵會(huì)被忽略。

RDB持久化對(duì)過(guò)期鍵的策略:

  • 如果數(shù)據(jù)庫(kù)的鍵已過(guò)期,但還沒(méi)被惰性/定期刪除,AOF文件不會(huì)因?yàn)檫@個(gè)過(guò)期鍵產(chǎn)生任何影響(也就說(shuō)會(huì)保留),當(dāng)過(guò)期的鍵被刪除了以后,會(huì)追加一條DEL命令來(lái)顯示記錄該鍵被刪除了

  • 重寫AOF文件時(shí),程序會(huì)對(duì)RDB文件中的鍵進(jìn)行檢查,過(guò)期的鍵會(huì)被忽略

復(fù)制模式:

  • 主服務(wù)器來(lái)控制從服務(wù)器統(tǒng)一刪除過(guò)期鍵(保證主從服務(wù)器數(shù)據(jù)的一致性)

2.4RDB和AOF用哪個(gè)?

RDB和AOF并不互斥,它倆可以同時(shí)使用。

  • RDB的優(yōu)點(diǎn):載入時(shí)恢復(fù)數(shù)據(jù)快、文件體積小。

  • RDB的缺點(diǎn):會(huì)一定程度上丟失數(shù)據(jù)(因?yàn)橄到y(tǒng)一旦在定時(shí)持久化之前出現(xiàn)宕機(jī)現(xiàn)象,此前沒(méi)有來(lái)得及寫入磁盤的數(shù)據(jù)都將丟失。)

  • AOF的優(yōu)點(diǎn):丟失數(shù)據(jù)少(默認(rèn)配置只丟失一秒的數(shù)據(jù))。

  • AOF的缺點(diǎn):恢復(fù)數(shù)據(jù)相對(duì)較慢,文件體積大

如果Redis服務(wù)器同時(shí)開啟了RDB和AOF持久化,服務(wù)器會(huì)優(yōu)先使用AOF文件來(lái)還原數(shù)據(jù)(因?yàn)锳OF更新頻率比RDB更新頻率要高,還原的數(shù)據(jù)更完善)

可能涉及到RDB和AOF的配置:

redis持久化,兩種方式
1、rdb快照方式
2、aof日志方式

----------rdb快照------------
save 900 1
save 300 10
save 60 10000

stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/rdb/

-----------Aof的配置-----------
appendonly no # 是否打開 aof日志功能

appendfsync always #每一個(gè)命令都立即同步到aof,安全速度慢
appendfsync everysec
appendfsync no 寫入工作交給操作系統(tǒng),由操作系統(tǒng)判斷緩沖區(qū)大小,統(tǒng)一寫入到aof  同步頻率低,速度快


no-appendfsync-on-rewrite yes 正在導(dǎo)出rdb快照的時(shí)候不要寫aof
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb 


./bin/redis-benchmark -n 20000

官網(wǎng)文檔:

  • https://redis.io/topics/persistence#rdb-advantages


當(dāng)前名稱:從零單排學(xué)Redis【白銀】
網(wǎng)址分享:http://weahome.cn/article/pgssjs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部