這是一份Redis學(xué)習(xí)總結(jié),請(qǐng)查收

最近又復(fù)習(xí)了一下redis中比較重要的幾個(gè)知識(shí)點(diǎn),知識(shí)點(diǎn)多且碎,在這里做一個(gè)簡(jiǎn)單的總結(jié),便于以后復(fù)習(xí)。

主流應(yīng)用架構(gòu)

我們都知道多數(shù)情況下redis是作為緩存應(yīng)用來(lái)使用的,下面則顯示出當(dāng)前主流的應(yīng)用架構(gòu)(客戶端、緩存、存儲(chǔ)層).


主流應(yīng)用架構(gòu).png

對(duì)比緩存中間件 Memcache和Redis的區(qū)別

??Memcache: 在代碼層次上比較類似于Hash
  • 支持簡(jiǎn)單的數(shù)據(jù)類型
  • 不支持?jǐn)?shù)據(jù)持久化存儲(chǔ)
  • 不支持主從
  • 不支持分片
??Redis
  • 數(shù)據(jù)類型豐富
  • 支持?jǐn)?shù)據(jù)磁盤持久化存儲(chǔ)(RDB、AOF)
  • 支持主從
  • 支持分片

我們知道,Redis是內(nèi)存級(jí)數(shù)據(jù)庫(kù),它的QPS(Query Per Second)可以達(dá)到100000+,那它為啥那么快呢?

原因如下:

  1. 完全基于內(nèi)存,絕大多數(shù)是存粹的內(nèi)存操作
  2. 數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)單,對(duì)數(shù)據(jù)操作簡(jiǎn)單(如利用了Hash的查找為O(1)的特性)
  3. 采用單線程(在處理網(wǎng)絡(luò)請(qǐng)求時(shí)是單線程),單線程也能處理高并發(fā)的需求,如果想要多核的話可以啟動(dòng)多個(gè)實(shí)例
  4. 使用多路I/O復(fù)用模型,非阻塞I/O

下面我們便開始聊一聊Redis的多路I/O復(fù)用模型,在聊這個(gè)之前,我們首先應(yīng)該清楚一個(gè)概念:

FD 文件描述符(File Descripto):一個(gè)打開的文件通過(guò)唯一的描述符進(jìn)行引用,該描述符是打開文件元數(shù)據(jù)到文件本身的映射.

I/O模型有:1.傳統(tǒng)的I/O阻塞模型 2.多路I/O復(fù)用模型(可以同時(shí)對(duì)多個(gè)fd的狀態(tài)進(jìn)行監(jiān)控)

IO多路復(fù)用.png

Redis采用的I/O多路復(fù)用函數(shù): epoll/kqueue/evport/select

優(yōu)先選擇O(1)的I/O多路復(fù)用函數(shù)作為底層實(shí)現(xiàn),以時(shí)間復(fù)雜度為O(n)的來(lái)保底,基于react設(shè)計(jì)監(jiān)聽(tīng)I(yíng)/O事件(監(jiān)聽(tīng)多個(gè)fd)

簡(jiǎn)單聊一下Redis的數(shù)據(jù)類型

1.String k,v 最基本的類型,二進(jìn)制安全(可存圖片) [incr 可用作網(wǎng)站用戶量統(tǒng)計(jì)]
2.Hash String元素組成的字典,適合存儲(chǔ)對(duì)象。hmset lilei name "lilei" age 26 title "senior"
3.List列表 按照插入順序排序 lpush rpush. 查詢0-10的記錄 orange mylist 0 10
4.Set String元素的無(wú)序集合,不重復(fù)??梢赃M(jìn)行交、差、并等操作。sadd myset 111。smembers myset —>遍歷所有元素
5.Sorted Set 通過(guò)分?jǐn)?shù)為元素大小排序,不重復(fù) zadd myzset 3 abc ; zrangebyscore myset 0 10
還有一些比較高級(jí)的如用于計(jì)數(shù)的HyperLogLog和用于支持存儲(chǔ)地理位置的Geo

此外可以看一下<<Redis的設(shè)計(jì)與實(shí)現(xiàn)>>這本書中對(duì)于Redis底層數(shù)據(jù)類型基礎(chǔ)的介紹,以上的所有對(duì)象都是基于更加底層的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的

如何從海量數(shù)據(jù)里(2000w+)查詢出某一個(gè)固定前綴的key

遇到這種問(wèn)題時(shí),應(yīng)該首先問(wèn)清楚數(shù)據(jù)量的范圍規(guī)模,問(wèn)清楚邊界,再進(jìn)行思考和回答

KEYS pattern : 查找所有符合給定模式pattern 的key, 例如 keys k1 查找所有以k1開頭的key*

使用keys 對(duì)線上業(yè)務(wù)有什么影響?

keys指令會(huì)一次性返回所有匹配的key,鍵的數(shù)量太大會(huì)導(dǎo)致服務(wù)卡頓

為了解決這個(gè)問(wèn)題 引入了SCAN cursor
  • 基于游標(biāo)cursor的迭代器,需要基于上一次游標(biāo)延續(xù)之前的迭代過(guò)程,以0作為游標(biāo)作為一次新的迭代,直到返回游標(biāo)0完成一次遍歷。

  • 不保證每次執(zhí)行都返回某個(gè)給定數(shù)量的元素,支持模糊查詢。

  • 一次返回的數(shù)量不可控,只能是大概率符合count參數(shù)

    Scan 0 match k1* count 10

    可能獲取的數(shù)據(jù)數(shù)量不是10條,可能獲得重復(fù)元素,要在程序中去重

如何通過(guò)Redis實(shí)現(xiàn)分布式鎖?

要想實(shí)現(xiàn)分布式鎖,我們需要考慮到以下需求:

  • 互斥性
  • 安全性
  • 注意死鎖問(wèn)題
  • 容錯(cuò)

可以利用Redis如下命令的特性實(shí)現(xiàn)一個(gè)分布式鎖

SETNX key value :如果key不存在,創(chuàng)建并且賦值(用key作為鎖)

但這樣是占有了一個(gè)鎖,如何釋放掉它呢?也就是說(shuō)如何解決SETNX長(zhǎng)期有效的問(wèn)題

EXPIRE key seconds :設(shè)置過(guò)期時(shí)間刪除模擬鎖的釋放

下面看一個(gè)偽代碼的實(shí)現(xiàn)

long status = redisService.setnx(key,"1");
//注釋1
if(status==1){
    redisService.expire(key,expire);
    doSomething();//......
}

上面的代碼看上去似乎沒(méi)有什么問(wèn)題,但是仔細(xì)想想,如果執(zhí)行到注釋1的地方的時(shí)候,redis服務(wù)器發(fā)生了宕機(jī)怎么辦? 所以我們要保證setnx操作和expire的設(shè)置是原子的

所以redis引入了以下命令

set locktarget 12345(可以寫線程的標(biāo)識(shí)) ex 10 nx  //該操作是個(gè)原子操作,成功返回OK,失敗返回nil

偽代碼實(shí)現(xiàn):

String result = redisService.set(lockkey,requestId,SET_IF_NOT_EXIST,SET_WITH_EXPIRE_TIME,expiretime);

if("OK".equals(result)){
    doSomething();//....
}

大量的key同時(shí)過(guò)期怎么處理?

key集中過(guò)期,清除大量的key很耗時(shí),會(huì)出現(xiàn)短暫的卡頓現(xiàn)象

解決方案: 在設(shè)置key的過(guò)期時(shí)間的時(shí)候,給每個(gè)key加上隨機(jī)的值

如何用Redis做異步隊(duì)列?

使用list做異步隊(duì)列, rpush生產(chǎn)消息,lpop消費(fèi)消息

缺點(diǎn):沒(méi)有等待隊(duì)列里有值就進(jìn)行直接消費(fèi)

彌補(bǔ):可以在應(yīng)用層引入sleep機(jī)制去調(diào)用lpop重試

也可以用以下命令

BLPOP key[key...] timeout : 阻塞直到隊(duì)列有消息或者超時(shí)

缺點(diǎn):只能供一個(gè)消費(fèi)者消費(fèi)

Pub/Sub 主題訂閱模式

主題訂閱模式.png

這里有三個(gè)客戶端連接 分別為cli-1、cli-2、cli-3

cli1:6379-> subscribe myTopic
cli2:6379-> subscribe myTopic
cli3:6379-> publish myTopic "Hello"

然后cli1 和 cli3便會(huì)接收到hello消息

這里請(qǐng)注意: 消息的發(fā)布是無(wú)狀態(tài)的,無(wú)法保證可達(dá)

Redis如何做持久化?

1.RDB(快照)持久化:保存某個(gè)時(shí)間點(diǎn)的全量數(shù)據(jù)快照
在redis.conf 中可以配置 RDB持久化方式的持久化策略
  • save 900 1 //在900s內(nèi)進(jìn)行一次寫操作觸發(fā)持久化
  • save 300 10
  • Save 60 10000
stop-writes-on-bgsave-error yes

當(dāng)備份進(jìn)程出錯(cuò)誤時(shí),主進(jìn)程停止接受新的寫入操作(保證持久化的數(shù)據(jù)一致性問(wèn)題)

rdbcompression no

建議設(shè)置為no,關(guān)閉壓縮,降低cpu損耗(因?yàn)镽edis本身就是CPU密集型)

手動(dòng)持久化的命令

1.SAVE : 阻塞Redis的服務(wù)器進(jìn)程直到RDB文件被創(chuàng)建完畢

2.BGSAVE: fork出一個(gè)子進(jìn)程來(lái)創(chuàng)建RDB文件,不阻塞服務(wù)器進(jìn)程

自動(dòng)觸發(fā)RDB持久化的方式
  • 根據(jù)redis.conf配置的save m n 定時(shí)觸發(fā)(用的bgsave)
  • 主從復(fù)制時(shí),主節(jié)點(diǎn)自動(dòng)觸發(fā)
  • 執(zhí)行debug reload
  • 執(zhí)行shutdown 且沒(méi)有開啟ROF持久化

什么是 Copy-On-Write 寫時(shí)復(fù)制?

如果有多個(gè)調(diào)用者同時(shí)獲取相同的資源的時(shí)候,他們會(huì)獲取相同的指針指向相同的資源,直到某個(gè)調(diào)用者試圖修改資源的內(nèi)容的時(shí)候,系統(tǒng)才會(huì)真正復(fù)制一份專有副本給調(diào)用者,而其他調(diào)用者見(jiàn)到的最初資源保持不變。

當(dāng)redis做持久化時(shí),redis會(huì)fork一個(gè)子進(jìn)程,將數(shù)據(jù)寫入磁盤中的一個(gè)臨時(shí)的rdb文件中,當(dāng)子進(jìn)程完成寫臨時(shí)文件之后,將原來(lái)的rdb替換掉,這樣的好處是可以實(shí)現(xiàn)copy-on-write,子進(jìn)程繼續(xù)可以接受其他請(qǐng)求,確保了redis性能。

缺點(diǎn):內(nèi)存數(shù)據(jù)的全量同步,當(dāng)數(shù)據(jù)量大的時(shí)候會(huì)由于I/O而嚴(yán)重影響性能,可能會(huì)因?yàn)閞edis掛掉而丟失從當(dāng)前至最近一次快照期間的數(shù)據(jù)。

2.AOF(Append-Only-File)持久化:保存寫狀態(tài)
  • 記錄下除了查詢以外所有變更數(shù)據(jù)庫(kù)狀態(tài)的指令
  • 以append的形式追加保存到AOF文件中(增量)

AOF的持久化默認(rèn)是關(guān)閉的. vim redis.conf

appendonlyno. —>修改為 appendonly yes 生效

appendfilename "append only.aof"

appendfsync:可以指定AOF寫入方式 :

1.always 2.everysec 3.no

AOF日志重寫 bgrewrite aof

日志重寫解決AOF文件大小不斷增大的問(wèn)題,原理如下:

  1. 調(diào)用fork(),創(chuàng)建一個(gè)子進(jìn)程
  2. 子進(jìn)程把新的AOF寫到一個(gè)臨時(shí)文件里,不依賴原來(lái)的AOF文件
  3. 主進(jìn)程持續(xù)把新的變動(dòng)同時(shí)寫入內(nèi)存和原來(lái)的AOF里
  4. 主進(jìn)程獲取子進(jìn)程的重寫AOF的完成信號(hào),往新的AOF同步增量變動(dòng)
  5. 使用新的AOF文件替換掉舊的AOF文件

Redis數(shù)據(jù)的恢復(fù)

RDB和AOF文件共存情況下的恢復(fù)流程
Redis數(shù)據(jù)的恢復(fù)流程.png

RDB-AOF混合持久化的方式

BGSAVE做鏡像全量持久化,AOF做增量持久化

總結(jié)RDB和AOF的優(yōu)缺點(diǎn)

  • RDB優(yōu)點(diǎn):全量數(shù)據(jù)快照,文件小,恢復(fù)快
  • RDB缺點(diǎn):無(wú)法保存最近一次快照后的數(shù)據(jù)
  • AOF優(yōu)點(diǎn):可讀性高,適合保存增量數(shù)據(jù),數(shù)據(jù)不易丟失
  • AOF缺點(diǎn):文件體積大,恢復(fù)時(shí)間長(zhǎng)

Redis主從復(fù)制同步

1.全同步過(guò)程
  1. Slave發(fā)送sync命令到master
  2. master啟動(dòng)一個(gè)后臺(tái)進(jìn)程,將redis中的數(shù)據(jù)快照保存到文件中
  3. master將保存快照期間收到的命令緩存起來(lái)
  4. master完成寫文件操作后,將該文件發(fā)送給salve
  5. 使用新的AOF文件替換掉舊的AOF文件
  6. master將這期間收到的寫命令發(fā)送給salve,進(jìn)行回放
2.增量同步的過(guò)程
  1. master接受用戶的操作指令,判斷是否需要傳播到salve
  2. 將操作記錄追加到aof文件
  3. 將操作傳播到其他slave:1.對(duì)齊主從庫(kù) 2.往響應(yīng)緩存中寫入指令
  4. 將緩存中的數(shù)據(jù)發(fā)送給slave

主從模式不具備高可用性,當(dāng)master掛掉以后,slave將無(wú)法對(duì)外提供寫入操作,為解決該問(wèn)題,引入redis sentinel(哨兵)解決主從同步宕機(jī)后的主從切換問(wèn)題

  • 監(jiān)控:檢查主從服務(wù)器是否運(yùn)行正常
  • 提醒:通過(guò)API向管理員或者其他應(yīng)用程序發(fā)送故障通知
  • 自動(dòng)故障轉(zhuǎn)移:主從切換

流言協(xié)議 Gossip 在雜亂無(wú)章中尋求一致

每個(gè)節(jié)點(diǎn)都隨機(jī)與對(duì)方通信,最終所有節(jié)點(diǎn)的狀態(tài)達(dá)成一致。

種子節(jié)點(diǎn)定期隨機(jī)向其他節(jié)點(diǎn)發(fā)送節(jié)點(diǎn)列表以及需要傳播的信息

不保證信息一定會(huì)傳遞給所有的節(jié)點(diǎn),但最終會(huì)趨于一致性。

關(guān)于redis集群的更多總結(jié)我會(huì)放到下一篇文章里,今天的總結(jié)就到這里了!

lhsjohn 轉(zhuǎn)載請(qǐng)注明出處 謝謝!
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、Redis高可用概述 在介紹Redis高可用之前,先說(shuō)明一下在Redis的語(yǔ)境中高可用的含義。 我們知道,在w...
    空語(yǔ)閱讀 1,686評(píng)論 0 2
  • 原帖地址:http://m.itdecent.cn/p/2f14bc570563 redis概述 Redis...
    onlyHalfSoul閱讀 2,232評(píng)論 0 28
  • 企業(yè)級(jí)redis集群架構(gòu)的特點(diǎn) 海量數(shù)據(jù) 高并發(fā) 高可用 要達(dá)到高可用,持久化是不可減少的,持久化主要是做災(zāi)難恢復(fù)...
    lucode閱讀 2,285評(píng)論 0 7
  • Redis是啥 Redis是一個(gè)開源的key-value存儲(chǔ)系統(tǒng),由于擁有豐富的數(shù)據(jù)結(jié)構(gòu),又被其作者戲稱為數(shù)據(jù)結(jié)構(gòu)...
    一凡呀閱讀 1,240評(píng)論 0 5
  • 【作者】夏曉 【導(dǎo)師】王玉印 【總舵主】焦楊 易琳 【分舵主】向燚 參考別人的導(dǎo)圖原理和要素。發(fā)散,收斂,關(guān)鍵詞重...
    文魁大腦夏曉閱讀 490評(píng)論 0 0

友情鏈接更多精彩內(nèi)容