只有光頭才能變強html
今天繼續來學習Redis,上一篇從零單排學Redis【青銅】已經將Redis經常使用的數據結構過了一遍了。若是還沒看的同窗能夠先去看一遍再回來~git
這篇主要講的內容有:程序員
本文力求簡單講清每一個知識點,但願你們看完能有所收穫github
咱們應該都用過MySQL,MySQL咱們能夠在裏邊建立好幾個庫:redis
一樣地,Redis服務器中也有數據庫這麼一個概念。若是不指定具體的數量,默認會有16個數據庫。sql
上面的命令咱們也能夠發現:當切換到15號數據庫,存進15號庫的數據,再切換到0號數據庫時,是獲取不到的!數據庫
Redis服務器用redisServer結構體來表示,其中redisDb是一個數組,用來保存全部的數據庫,dbnum表明數據庫的數量(這個能夠配置,默認是16)數組
struct redisServer{ //redisDb數組,表示服務器中全部的數據庫 redisDb *db; //服務器中數據庫的數量 int dbnum; };
咱們知道Redis是C/S結構,Redis客戶端經過redisClient結構體來表示:緩存
typedef struct redisClient{ //客戶端當前所選數據庫 redisDb *db; }redisClient;
Redis客戶端鏈接Redis服務端時的示例圖:安全
Redis中對每一個數據庫用redisDb結構體來表示:
typedef struct redisDb { int id; // 數據庫ID標識 dict *dict; // 鍵空間,存放着全部的鍵值對 dict *expires; // 過時哈希表,保存着鍵的過時時間 dict *watched_keys; // 被watch命令監控的key和相應client long long avg_ttl; // 數據庫內全部鍵的平均TTL(生存時間) } redisDb;
從代碼上咱們能夠發現最重要的應該是dict *dict
,它用來存放着全部的鍵值對。對於dict
數據結構(哈希表)咱們在上一篇也已經詳細說了。通常咱們將存儲全部鍵值對的dict
稱爲鍵空間。
鍵空間示意圖:
Redis的數據庫就是使用字典(哈希表)來做爲底層實現的,對數據庫的增刪改查都是構建在字典(哈希表)的操做之上的。
例如:
redis > GET message "hello world"
Redis是基於內存,內存是比較昂貴的,容量確定比不上硬盤的。就咱們如今一臺普通的機子,可能就8G內存,但硬盤隨隨便便都1T了。
由於咱們的內存是有限的。因此咱們會幹掉不經常使用的數據,保留經常使用的數據。這就須要咱們設置一下鍵的過時(生存)時間了。
EXPIRE
或者PEXPIRE
命令。EXPIREAT
或者PEXPIREAT
命令。其實EXPIRE
、PEXPIRE
、EXPIREAT
這三個命令都是經過PEXPIREAT
命令來實現的。
咱們在redisDb結構體中還發現了dict *expires;
屬性,存放全部鍵過時的時間。
舉個例子基本就能夠理解了:
redis > PEXPIREAT message 1391234400000 (integer) 1
設置了message鍵的過時時間爲1391234400000
既然有設置過時(生存)時間的命令,那確定也有移除過時時間,查看剩餘生存時間的命令了:
上面咱們已經可以瞭解到:過時鍵是保存在哈希表中了。那這些過時鍵到了過時的時間,就會立馬被刪除掉嗎??
要回答上面的問題,須要咱們瞭解一下刪除策略的知識,刪除策略可分爲三種
Redis採用的是惰性刪除+按期刪除兩種策略,因此說,在Redis裏邊若是過時鍵到了過時的時間了,未必被立馬刪除的!
若是按期刪除漏掉了不少過時key,也沒及時去查(沒走惰性刪除),大量過時key堆積在內存裏,致使redis內存塊耗盡了,咋整?
咱們能夠設置內存最大使用量,當內存使用量超出時,會施行數據淘汰策略。
Redis的內存淘汰機制有如下幾種:
通常場景:
使用 Redis 緩存數據時,爲了提升緩存命中率,須要保證緩存數據都是熱點數據。能夠將內存最大使用量設置爲熱點數據佔用的內存量,而後啓用allkeys-lru淘汰策略,將最近最少使用的數據淘汰
Redis是基於內存的,若是不想辦法將數據保存在硬盤上,一旦Redis重啓(退出/故障),內存的數據將會所有丟失。
Redis提供了兩種不一樣的持久化方法來說數據存儲到硬盤裏邊:
RDB持久化能夠手動執行,也能夠根據服務器配置按期執行。RDB持久化所生成的RDB文件是一個通過壓縮的二進制文件,Redis能夠經過這個文件還原數據庫的數據。
有兩個命令能夠生成RDB文件:
SAVE
會阻塞Redis服務器進程,服務器不能接收任何請求,直到RDB文件建立完畢爲止。BGSAVE
建立出一個子進程,由子進程來負責建立RDB文件,服務器進程能夠繼續接收請求。Redis服務器在啓動的時候,若是發現有RDB文件,就會自動載入RDB文件(不須要人工干預)
除了手動調用SAVE
或者BGSAVE
命令生成RDB文件以外,咱們可使用配置的方式來按期執行:
在默認的配置下,若是如下的條件被觸發,就會執行BGSAVE
命令
save 900 1 #在900秒(15分鐘)以後,至少有1個key發生變化, save 300 10 #在300秒(5分鐘)以後,至少有10個key發生變化 save 60 10000 #在60秒(1分鐘)以後,至少有10000個key發生變化
原理大概就是這樣子的(結合上面的配置來看):
struct redisServer{ // 修改計數器 long long dirty; // 上一次執行保存的時間 time_t lastsave; // 參數的配置 struct saveparam *saveparams; };
遍歷參數數組,判斷修改次數和時間是否符合,若是符合則調用besave()
來生成RDB文件
總結:經過手動調用SAVE
或者BGSAVE
命令或者配置條件觸發,將數據庫某一時刻的數據快照,生成RDB文件實現持久化。
上面已經介紹了RDB持久化是經過將某一時刻數據庫的數據「快照」來實現的,下面咱們來看看AOF是怎麼實現的。
好比說咱們對空白的數據庫執行如下寫命令:
redis> SET meg "hello" OK redis> SADD fruits "apple" "banana" "cherry" (integer) 3 redis> RPUSH numbers 128 256 512 (integer) 3
Redis會產生如下內容的AOF文件:
這些都是以Redis的命令請求協議格式保存的。Redis協議規範(RESP)參考資料:
AOF持久化功能的實現能夠分爲3個步驟:
flushAppendOnlyFile函數的行爲由服務器配置的appendfsyn選項來決定的:
appendfsync always # 每次有數據修改發生時都會寫入AOF文件。 appendfsync everysec # 每秒鐘同步一次,該策略爲AOF的默認策略。 appendfsync no # 從不一樣步。高效可是數據不會被持久化。
從字面上應該就更好理解了,這裏我就不細說了...
下面來看一下AOF是如何載入與數據還原的:
從前面的示例看出,咱們寫了三條命令,AOF文件就保存了三條命令。若是咱們的命令是這樣子的:
redis > RPUSH list "Java" "3y" (integer)2 redis > RPUSH list "Java3y" integer(3) redis > RPUSH list "yyy" integer(4)
一樣地,AOF也會保存3條命令。咱們會發現一個問題:上面的命令是能夠合併起來成爲1條命令的,並不須要3條。這樣就能夠讓AOF文件的體積變得更小。
AOF重寫由Redis自行觸發(參數配置),也能夠用BGREWRITEAOF
命令手動觸發重寫操做。
好比說如今有一個Redis數據庫的數據以下:
新的AOF文件的命令以下,沒有一條是多餘的!
Redis將AOF重寫程序放到子進程裏執行(BGREWRITEAOF
命令),像BGSAVE
命令同樣fork出一個子進程來完成重寫AOF的操做,從而不會影響到主進程。
AOF後臺重寫是不會阻塞主進程接收請求的,新的寫命令請求可能會致使當前數據庫和重寫後的AOF文件的數據不一致!
爲了解決數據不一致的問題,Redis服務器設置了一個AOF重寫緩衝區,這個緩存區會在服務器建立出子進程以後使用。
RDB持久化對過時鍵的策略:
SAVE
或者BGSAVE
命令建立出的RDB文件,程序會對數據庫中的過時鍵檢查,已過時的鍵不會保存在RDB文件中。RDB持久化對過時鍵的策略:
複製模式:
RDB和AOF並不互斥,它倆能夠同時使用。
若是Redis服務器同時開啓了RDB和AOF持久化,服務器會優先使用AOF文件來還原數據(由於AOF更新頻率比RDB更新頻率要高,還原的數據更完善)
可能涉及到RDB和AOF的配置:
redis持久化,兩種方式 一、rdb快照方式 二、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 #每個命令都當即同步到aof,安全速度慢 appendfsync everysec appendfsync no 寫入工做交給操做系統,由操做系統判斷緩衝區大小,統一寫入到aof 同步頻率低,速度快 no-appendfsync-on-rewrite yes 正在導出rdb快照的時候不要寫aof auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb ./bin/redis-benchmark -n 20000
官網文檔:
如今臨近雙十一買阿里雲服務器就特別省錢!以前我買學生機也要9.8塊錢一個月,如今最低價只須要8.3一個月!
不管是Nginx/Elasticsearch/Redis這些技術都是在Linux下完美運行的,若是仍是程序員新手,買一個學習Linux基礎命令,學習搭建環境也是不錯的選擇。
若是有要買服務器的同窗可經過個人連接直接享受最低價:https://m.aliyun.com/act/team1111/#/share?params=N.FF7yxCciiM.pfn5xpli
若是你們有更好的理解方式或者文章有錯誤的地方還請你們不吝在評論區留言,你們互相學習交流~~~
參考資料:
一個堅持原創的Java技術公衆號:Java3y,歡迎你們關注
3y全部的原創文章: