欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報激活碼778899分享:面試 緩存 最全Redis原理

柚子快報激活碼778899分享:面試 緩存 最全Redis原理

http://yzkb.51969.com/

什么是 Redis?

Redis 是完全開源免費(fèi)的,遵守 BSD 協(xié)議,是一個高性能的 key-value 數(shù)據(jù)庫。

Redis 與其他 key - value 緩存產(chǎn)品相比有以下三個特點(diǎn):

Redis 支持?jǐn)?shù)據(jù)的持久化,可以將內(nèi)存中的數(shù)據(jù)保存在磁盤中,重啟的時候可以再次加載進(jìn)行使用。

Redis 不僅僅支持簡單的 key-value 類型的數(shù)據(jù),同時還提供 list,set,zset,hash 等數(shù)據(jù)結(jié)構(gòu)的存儲。

Redis 支持?jǐn)?shù)據(jù)的備份,即 master-slave 模式的數(shù)據(jù)備份。

Redis 優(yōu)勢:

性能極高:Redis 能讀的速度是 110000 次/s,寫的速度是 81000 次/s。

豐富的數(shù)據(jù)類型:Redis 支持二進(jìn)制案例的 Strings,Lists,Hashes,Sets 及 Ordered Sets 數(shù)據(jù)類型操作。

原子:Redis 的所有操作都是原子性的,意思就是要么成功執(zhí)行要么失敗完全不執(zhí)行。單個操作是原子性的。多個操作也支持事務(wù),即原子性,通過 MULTI 和 EXEC 指令包起來。

豐富的特性:Redis 還支持 publish/subscribe,通知,key 過期等等特性。

Redis 與其他 key-value 存儲有什么不同?

Redis 有著更為復(fù)雜的數(shù)據(jù)結(jié)構(gòu)并且提供對他們的原子性操作,這是一個不同于其他數(shù)據(jù)庫的進(jìn)化路徑。Redis 的數(shù)據(jù)類型都是基于基本數(shù)據(jù)結(jié)構(gòu)的同時對程序員透明,無需進(jìn)行額外的抽象。

Redis 運(yùn)行在內(nèi)存中但是可以持久化到磁盤,所以在對不同數(shù)據(jù)集進(jìn)行高速讀寫時需要權(quán)衡內(nèi)存,因為數(shù)據(jù)量不能大于硬件內(nèi)存。在內(nèi)存數(shù)據(jù)庫方面的另一個優(yōu)點(diǎn)是,相比在磁盤上相同的復(fù)雜的數(shù)據(jù)結(jié)構(gòu),在內(nèi)存中操作起來非常簡單,這樣 Redis 可以做很多內(nèi)部復(fù)雜性很強(qiáng)的事情。同時,在磁盤格式方面他們是緊湊的以追加的方式產(chǎn)生的,因為他們并不需要進(jìn)行隨機(jī)訪問。

Redis 的數(shù)據(jù)類型?

1.Redis 支持五種數(shù)據(jù)類型:

string(字符串),

hash(哈希),

list(列表),

set(集合),

zsetsorted set(有序集合)

2.有哪些應(yīng)用場景?

1)String:緩存、限流、分布式鎖、計數(shù)器、分布式 Session 等。

2)Hash:用戶信息、用戶主頁訪問量、組合查詢等。

3)List:簡單隊列、關(guān)注列表時間軸。

4)Set:贊、踩、標(biāo)簽等。

ZSet:排行榜、好友關(guān)系鏈表。

3.常用命令

終端連接

`redis-cli -h 127.0.0.1 -p 6379`

key

keys * # 獲取所有的key

select 0 # 選擇第一個庫

move myString 1 # 將當(dāng)前的數(shù)據(jù)庫key移動到某個數(shù)據(jù)庫,目標(biāo)庫有,則不能移動

flush db # 清除指定庫

randomkey # 隨機(jī)key

type key # 類型

set key1 value1 # 設(shè)置key

get key1 # 獲取key

mset key1 value1 key2 value2 key3 value3

mget key1 key2 key3

del key1 # 刪除key

exists key # 判斷是否存在key

expire key 10 # 10s 過期

pexpire key # 1000 毫秒

persist key # 刪除過期時間

訂閱發(fā)布

subscribe chat1 # 訂閱頻道

publish chat1 "hell0 ni hao" # 發(fā)布消息

pubsub channels # 查看頻道

pubsub numsub chat1 # 查看某個頻道的訂閱者數(shù)量

unsubscrible chat1 # 退訂指定頻道 或 punsubscribe java.*

psubscribe java.* # 訂閱一組頻道

ref redis常用命令大全

使用 Redis 有哪些好處?

速度快,因為數(shù)據(jù)存在內(nèi)存中,類似于 HashMap,HashMap 的優(yōu)勢就是查找和操作的時間復(fù)雜度都是 O1)

支持豐富數(shù)據(jù)類型,支持 string,list,set,Zset,hash 等

支持事務(wù),操作都是原子性,所謂的原子性就是對數(shù)據(jù)的更改要么全部執(zhí)行,要么全部不執(zhí)行

豐富的特性,可用于緩存,消息,按 key 設(shè)置過期時間,過期后將會自動刪除

Redis 與Memcached?

存儲方式 Memecache 把數(shù)據(jù)全部存在內(nèi)存之中,斷電后會掛掉,數(shù)據(jù)不能超過內(nèi)存大小。Redis 有部分存在硬盤上,這樣能保證數(shù)據(jù)的持久性。

數(shù)據(jù)支持類型 Memcache 對數(shù)據(jù)類型支持相對簡單。Redis 有復(fù)雜的數(shù)據(jù)類型。

使用底層模型不同 它們之間底層實現(xiàn)方式 以及與客戶端之間通信的應(yīng)用協(xié)議不一樣。Redis 直接自己構(gòu)建了 VM 機(jī)制 ,因為一般的系統(tǒng)調(diào)用系統(tǒng)函數(shù)的話,會浪費(fèi)一定的時間去移動和請求。

Redis 線程?

為何使用單線程?

官方答案

因為 Redis 是基于內(nèi)存的操作,CPU 不會成為 Redis 的瓶頸,而最有可能是機(jī)器內(nèi)存的大小或者網(wǎng)絡(luò)帶寬。既然單線程容易實現(xiàn),而且 CPU 不會成為瓶頸,那就順理成章地采用單線程的方案了。

詳細(xì)原因

1)不需要各種鎖的性能消耗

Redis 的數(shù)據(jù)結(jié)構(gòu)并不全是簡單的 Key-Value,還有 List,Hash 等復(fù)雜的結(jié)構(gòu),這些結(jié)構(gòu)有可能會進(jìn)行很細(xì)粒度的操作,比如在很長的列表后面添加一個元素,在hash當(dāng)中添加或者刪除一個對象。這些操作可能就需要加非常多的鎖,導(dǎo)致的結(jié)果是同步開銷大大增加。

2)單線程多進(jìn)程集群方案

單線程的威力實際上非常強(qiáng)大,每核心效率也非常高,多線程自然是可以比單線程有更高的性能上限,但是在今天的計算環(huán)境中,即使是單機(jī)多線程的上限也往往不能滿足需要了,需要進(jìn)一步摸索的是多服務(wù)器集群化的方案,這些方案中多線程的技術(shù)照樣是用不上的。

所以單線程、多進(jìn)程的集群不失為一個時髦的解決方案。

多線程

1.Redis 6 之前真的是單線程嗎?

Redis 在處理客戶端的請求時,包括獲取 (socket 讀)、解析、執(zhí)行、內(nèi)容返回 (socket 寫) 等都由一個順序串行的主線程處理,這就是所謂的單線程。但如果嚴(yán)格來講從 Redis 4 之后并不是單線程,除了主線程外,它也有后臺線程在處理一些較為緩慢的操作,例如清理臟數(shù)據(jù)、無用連接的釋放、大 key 的刪除等等。

2.Redis 6 之前為什么使用單線程?

使用了單線程后,可維護(hù)性高。多線程模型雖然在某些方面表現(xiàn)優(yōu)異,但是它卻引入了程序執(zhí)行順序的不確定性,帶來了并發(fā)讀寫的一系列問題,增加了系統(tǒng)復(fù)雜度、同時可能存在線程切換、甚至加鎖解鎖、死鎖造成的性能損耗。

同時 Redis 通過 AE 事件模型以及 IO 多路復(fù)用等技術(shù),即使單線程處理性能也非常高,因此沒有必要使用多線程。單線程機(jī)制使得 Redis 內(nèi)部實現(xiàn)的復(fù)雜度大大降低,Hash 的惰性 Rehash、Lpush 等等 “線程不安全” 的命令都可以無鎖進(jìn)行。

3.Redis 6 為何引入多線程?

隨著目前行業(yè)內(nèi)越來越復(fù)雜的業(yè)務(wù)場景,有些公司動不動就上億的交易量,因此需要更大的 QPS。常見的解決方案是在分布式架構(gòu)中對數(shù)據(jù)進(jìn)行分區(qū)并采用多個服務(wù)器,但該方案有非常大的缺點(diǎn),比如:

1)要管理的 Redis 服務(wù)器太多,維護(hù)代價大;

2)某些適用于單個 Redis 服務(wù)器的命令不適用于數(shù)據(jù)分區(qū);

3)數(shù)據(jù)分區(qū)無法解決熱點(diǎn)讀/寫問題;

4)數(shù)據(jù)偏斜,重新分配和放大/縮小變得更加復(fù)雜等等。

從 Redis 自身角度來說,因為讀寫網(wǎng)絡(luò)的 read/write 系統(tǒng)調(diào)用占用了 Redis 執(zhí)行期間大部分 CPU 時間,瓶頸主要在于網(wǎng)絡(luò)的 IO 消耗, 優(yōu)化主要有兩個方向:

1)提高網(wǎng)絡(luò) IO 性能,典型的實現(xiàn)比如使用 DPDK 來替代內(nèi)核網(wǎng)絡(luò)棧的方式;

2)使用多線程充分利用多核,典型的實現(xiàn)比如 Memcached。

協(xié)議棧優(yōu)化的這種方式跟 Redis 關(guān)系不大,支持多線程是一種最有效最便捷的操作方式。所以總結(jié)起來,Redis 支持多線程主要就是兩個原因:

可以充分利用服務(wù)器 CPU 資源,目前主線程只能利用一個核;

多線程任務(wù)可以分?jǐn)?Redis 同步 IO 讀寫負(fù)荷。

4.多線程如何開啟以及配置?

Redis 6 的多線程默認(rèn)是禁用的,只使用主線程。如需開啟需要修改 redis.conf 配置文件中的 io-threads-do-reads yes。

開啟多線程后,還需要設(shè)置線程數(shù),否則是不生效的。同樣修改 redis.conf 文件中的 io-threads [n] 配置。

關(guān)于線程數(shù)的設(shè)置,官方有一個建議:4 核的機(jī)器建議設(shè)置為 2 或 3 個線程,8 核的建議設(shè)置為 6 個線程,線程數(shù)一定要小于機(jī)器核數(shù)。還需要注意的是,線程數(shù)并不是越大越好,官方認(rèn)為超過了 8 個基本就沒什么意義了。

5.Redis 多線程的實現(xiàn)機(jī)制?

大致流程如下:

1)主線程負(fù)責(zé)接收建立連接請求,獲取 socket 放入全局等待讀處理隊列;

2)主線程處理完讀事件之后,通過 RR(Round Robin) 將這些連接分配給這些 IO 線程;

3)主線程阻塞等待 IO 線程讀取 socket 完畢;

4)主線程通過單線程的方式執(zhí)行請求命令,請求數(shù)據(jù)讀取并解析完成,但并不執(zhí)行;

5)主線程阻塞等待 IO 線程將數(shù)據(jù)回寫 socket 完畢;

6)解除綁定,清空等待隊列。

該設(shè)計的特點(diǎn):

1)IO 線程要么同時在讀 socket,要么同時在寫,不會同時讀或?qū)憽?/p>

2)IO 線程只負(fù)責(zé)讀寫 socket 解析命令,不負(fù)責(zé)命令處理。

6.多線程是否會導(dǎo)致線程安全問題?

從上面的實現(xiàn)機(jī)制可以看出,Redis 的多線程部分只是用來處理網(wǎng)絡(luò)數(shù)據(jù)的讀寫和協(xié)議解析,執(zhí)行命令仍然是單線程順序執(zhí)行。所以我們不需要去考慮控制 key、lua、事務(wù),LPUSH/LPOP 等等的并發(fā)及線程安全問題。

7.Redis 和 Memcached 多線程區(qū)別?

相同點(diǎn):都采用了 master 線程 - worker 線程的模型。

不同點(diǎn):Memcached 執(zhí)行主邏輯也是在 worker 線程里,模型更加簡單,實現(xiàn)了真正的線程隔離,符合我們對線程隔離的常規(guī)理解。而 Redis 把處理邏輯交還給 master 線程,雖然一定程度上增加了模型復(fù)雜度,但也解決了線程并發(fā)安全等問題。

ref Redis 6.0 新特性-多線程連環(huán)13問!

Redis集群?

1. 集群模式

1.Redis 集群搭建有幾種模式?

主從模式

和 MySQL 需要主從復(fù)制的原因一樣,Redis 雖然讀寫速度非???,但是也會產(chǎn)生性能瓶頸,特別是在讀壓力上,為了分擔(dān)壓力,Redis 支持主從復(fù)制。Redis 的主從結(jié)構(gòu)一主一從,一主多從或級聯(lián)結(jié)構(gòu),復(fù)制類型可以根據(jù)是否是全量而分為全量同步和增量同步。

哨兵模式

在主從復(fù)制實現(xiàn)之后,如果想對 master 進(jìn)行監(jiān)控,Redis 提供了一種哨兵機(jī)制,哨兵的含義就是監(jiān)控 Redis 系統(tǒng)的運(yùn)行狀態(tài),通過投票機(jī)制,從 slave 中選舉出新的 master 以保證集群正常運(yùn)行。

還可以啟用多個哨兵進(jìn)行監(jiān)控以保證集群足夠穩(wěn)健,這種情況下,哨兵不僅監(jiān)控主從服務(wù),哨兵之間也會相互監(jiān)控。

Cluster 集群模式

ref Redis集群搭建的三種方式

2.Redis 主從復(fù)制的實現(xiàn)?

主從復(fù)制可以根據(jù)需要分為全量同步的增量同步兩種方式。

全量同步

Redis 全量復(fù)制一般發(fā)生在 slave 的初始階段,這時 slave 需要將 master 上的數(shù)據(jù)都復(fù)制一份,具體步驟如下:

1)slave 連接 master,發(fā)送 SYNC 命令;

2)master 接到 SYNC 命令后執(zhí)行 BGSAVE 命令生產(chǎn) RDB 文件,并使用緩沖區(qū)記錄此后執(zhí)行的所有寫命令;

3)master 執(zhí)行完 BGSAVE 后,向所有的 slave 發(fā)送快照文件,并在發(fā)送過程中繼續(xù)記錄執(zhí)行的寫命令;

4)slave 收到快照后,丟棄所有的舊數(shù)據(jù),載入收到的數(shù)據(jù);

5)master 快照發(fā)送完成后就會開始向 slave 發(fā)送緩沖區(qū)的寫命令;

6)slave 完成對快照的載入,并開始接受命令請求,執(zhí)行來自 master 緩沖區(qū)的寫命令;

7)slave 完成上面的數(shù)據(jù)初始化后就可以開始接受用戶的讀請求了。

增量同步

增量復(fù)制實際上就是在 slave 初始化完成后開始正常工作時 master 發(fā)生寫操作同步到 slave 的過程。增量復(fù)制的過程主要是 master 每執(zhí)行一個寫命令就會向 slave 發(fā)送相同的寫命令,slave 接受并執(zhí)行寫命令,從而保持主從一致。

ref Redis主從復(fù)制原理總結(jié)

3.Redis 的主從同步策略?

主從同步剛連接的時候進(jìn)行全量同步,全量同步結(jié)束后開始增量同步。

如果有需要,slave 在任何時候都可以發(fā)起全量同步,其主要策略就是無論如何首先會嘗試進(jìn)行增量同步,如果失敗則會要求 slave 進(jìn)行全量同步,之后再進(jìn)行增量同步。

注意:如果多個 slave 同時斷線需要重啟的時候,因為只要 slave 啟動,就會和 master 建立連接發(fā)送SYNC請求和主機(jī)全量同步,如果多個同時發(fā)送 SYNC 請求,可能導(dǎo)致 master IO 突增而發(fā)送宕機(jī)。所以我們要避免多個 slave 同時恢復(fù)重啟的情況。

4.哨兵模式的原理?

哨兵主要用于管理多個 Redis 服務(wù)器,主要有以下三個任務(wù):監(jiān)控、提醒以及故障轉(zhuǎn)移。

每個哨兵會向其它哨兵、master、slave 定時發(fā)送消息,以確認(rèn)對方是否還存活。如果發(fā)現(xiàn)對方在配置的指定時間內(nèi)未回應(yīng),則暫時認(rèn)為對方已掛。若“哨兵群”中的多數(shù) sentinel 都報告某一 master 沒響應(yīng),系統(tǒng)才認(rèn)為該 master “徹底死亡”,通過一定的 vote 算法從剩下的 slave 節(jié)點(diǎn)中選一臺提升為 master,然后自動修改相關(guān)配置。

5.哨兵模式故障遷移流程?

1)首先是從主服務(wù)器的從服務(wù)器中選出一個從服務(wù)器作為新的主服務(wù)器。

選點(diǎn)的依據(jù)依次是:

網(wǎng)絡(luò)連接正常 -> 5 秒內(nèi)回復(fù)過 INFO 命令 -> 10*down-after-milliseconds 內(nèi)與主連接過的 -> 從服務(wù)器優(yōu)先級 -> 復(fù)制偏移量 -> 運(yùn)行id較小的。

2)選出之后通過 slaveif no ont 將該從服務(wù)器升為新主服務(wù)器;

3)然后再通過 slaveof ip port 命令讓其他從服務(wù)器復(fù)制該信主服務(wù)器。

缺點(diǎn)

主從服務(wù)器的數(shù)據(jù)要經(jīng)常進(jìn)行主從復(fù)制,這樣會造成性能下降

當(dāng)主服務(wù)器宕機(jī)后,從服務(wù)器切換成主服務(wù)器的那段時間,服務(wù)是不可用的

2.2 Cluster 集群

1、什么是一致性 Hash 以及解決什么問題?

一致性 hash 其實是普通 hash 算法的改良版,其 hash 計算方法沒有變化,但是 hash 空間發(fā)生了變化,由原來的線性的變成了環(huán)。

緩存 key 通過 hash 計算之后得到在 hash 環(huán)中的位置,然后順時針方向找到第一個節(jié)點(diǎn),這個節(jié)點(diǎn)就是存放 key 的節(jié)點(diǎn)。

由此可見,一致性 hash 主要是為了解決普通 hash 中擴(kuò)容和宕機(jī)的問題。

同時還可以通過虛擬節(jié)點(diǎn)來解決數(shù)據(jù)傾斜的問題:就是在節(jié)點(diǎn)稀疏的 hash 環(huán)上對物理節(jié)點(diǎn)虛擬出一部分虛擬節(jié)點(diǎn),key 會打到虛擬節(jié)點(diǎn)上面,而虛擬節(jié)點(diǎn)上的 key 實際也是映射到物理節(jié)點(diǎn)上的,這樣就避免了數(shù)據(jù)傾斜導(dǎo)致單節(jié)點(diǎn)壓力過大導(dǎo)致節(jié)點(diǎn)雪崩的問題。

ref 什么是一致性hash

2.Cluster 模式的原理?

其實現(xiàn)原理就是一致性 Hash。Redis Cluster 中有一個 16384 長度的槽的概念,他們的編號為 0、1、2、3 …… 16382、16383。這個槽是一個虛擬的槽,并不是真正存在的。正常工作的時候,Redis Cluster 中的每個 Master 節(jié)點(diǎn)都會負(fù)責(zé)一部分的槽,當(dāng)有某個 key 被映射到某個 Master 負(fù)責(zé)的槽,那么這個 Master 負(fù)責(zé)為這個 key 提供服務(wù)。

至于哪個 Master 節(jié)點(diǎn)負(fù)責(zé)哪個槽,這是可以由用戶指定的,也可以在初始化的時候自動生成(redis-trib.rb腳本)。這里值得一提的是,在 Redis Cluster 中,只有 Master 才擁有槽的所有權(quán),如果是某個 Master 的 slave,這個slave只負(fù)責(zé)槽的使用,但是沒有所有權(quán)。

3.Cluster 的分片機(jī)制?

為了使得集群能夠水平擴(kuò)展,首要解決的問題就是如何將整個數(shù)據(jù)集按照一定的規(guī)則分配到多個節(jié)點(diǎn)上。對于客戶端請求的 key,根據(jù)公式 HASH_SLOT=CRC16(key) mod 16384,計算出映射到哪個分片上。而對于 CRC16 算法產(chǎn)生的 hash 值會有 16bit,可以產(chǎn)生 2^16-=65536 個值。

Redis 集群提供了靈活的節(jié)點(diǎn)擴(kuò)容和收縮方案。在不影響集群對外服務(wù)的情況下,可以為集群添加節(jié)點(diǎn)進(jìn)行擴(kuò)容也可以下線部分節(jié)點(diǎn)進(jìn)行縮容??梢哉f,槽是 Redis 集群管理數(shù)據(jù)的基本單位,集群伸縮就是槽和數(shù)據(jù)在節(jié)點(diǎn)之間的移動。

4、Cluster 集群的擴(kuò)容流程?

當(dāng)一個 Redis 新節(jié)點(diǎn)運(yùn)行并加入現(xiàn)有集群后,我們需要為其遷移槽和數(shù)據(jù)。首先要為新節(jié)點(diǎn)指定槽的遷移計劃,確保遷移后每個節(jié)點(diǎn)負(fù)責(zé)相似數(shù)量的槽,從而保證這些節(jié)點(diǎn)的數(shù)據(jù)均勻。

1)首先啟動一個 Redis 節(jié)點(diǎn),記為 M4。

2)使用 cluster meet 命令,讓新 Redis 節(jié)點(diǎn)加入到集群中。新節(jié)點(diǎn)剛開始都是主節(jié)點(diǎn)狀態(tài),由于沒有負(fù)責(zé)的槽,所以不能接受任何讀寫操作,后續(xù)給他遷移槽和填充數(shù)據(jù)。

3)對 M4 節(jié)點(diǎn)發(fā)送 cluster setslot { slot } importing { sourceNodeId } 命令,讓目標(biāo)節(jié)點(diǎn)準(zhǔn)備導(dǎo)入槽的數(shù)據(jù)。

4)對源節(jié)點(diǎn),也就是 M1,M2,M3 節(jié)點(diǎn)發(fā)送 cluster setslot { slot } migrating { targetNodeId } 命令,讓源節(jié)點(diǎn)準(zhǔn)備遷出槽的數(shù)據(jù)。

5)源節(jié)點(diǎn)執(zhí)行 cluster getkeysinslot { slot } { count } 命令,獲取 count 個屬于槽 { slot } 的鍵,然后執(zhí)行步驟 6)的操作進(jìn)行遷移鍵值數(shù)據(jù)。

6)在源節(jié)點(diǎn)上執(zhí)行 migrate { targetNodeIp} " " 0 { timeout } keys { key... } 命令,把獲取的鍵通過 pipeline 機(jī)制批量遷移到目標(biāo)節(jié)點(diǎn),批量遷移版本的 migrate 命令在 Redis 3.0.6 以上版本提供。

7)重復(fù)執(zhí)行步驟 5)和步驟 6)直到槽下所有的鍵值數(shù)據(jù)遷移到目標(biāo)節(jié)點(diǎn)。

8)向集群內(nèi)所有主節(jié)點(diǎn)發(fā)送 cluster setslot { slot } node { targetNodeId } 命令,通知槽分配給目標(biāo)節(jié)點(diǎn)。為了保證槽節(jié)點(diǎn)映射變更及時傳播,需要遍歷發(fā)送給所有主節(jié)點(diǎn)更新被遷移的槽執(zhí)行新節(jié)點(diǎn)。

5、Cluster 集群收縮流程?

收縮節(jié)點(diǎn)就是將 Redis 節(jié)點(diǎn)下線,整個流程需要如下操作流程。

1)首先需要確認(rèn)下線節(jié)點(diǎn)是否有負(fù)責(zé)的槽,如果是,需要把槽遷移到其他節(jié)點(diǎn),保證節(jié)點(diǎn)下線后整個集群槽節(jié)點(diǎn)映射的完整性。

2)當(dāng)下線節(jié)點(diǎn)不再負(fù)責(zé)槽或者本身是從節(jié)點(diǎn)時,就可以通知集群內(nèi)其他節(jié)點(diǎn)忘記下線節(jié)點(diǎn),當(dāng)所有的節(jié)點(diǎn)忘記改節(jié)點(diǎn)后可以正常關(guān)閉。

ref Redis Cluster數(shù)據(jù)分片機(jī)制

6、客戶端如何路由?

既然 Redis 集群中的數(shù)據(jù)是分片存儲的,那我們該如何知道某個 key 存在哪個節(jié)點(diǎn)上呢?即我們需要一個查詢路由,該路由根據(jù)給定的 key,返回存儲該鍵值的機(jī)器地址。

常規(guī)的實現(xiàn)方式便是采用如下圖所示的代理方案,即采用一個中央節(jié)點(diǎn)(比如HDFS中的NameNode)來管理所有的元數(shù)據(jù),但是這樣的方案帶來的最大問題就是代理節(jié)點(diǎn)很容易成為訪問的瓶頸,當(dāng)讀寫并發(fā)量高的時候,代理節(jié)點(diǎn)會嚴(yán)重的拖慢整個系統(tǒng)的性能。

Redis 并沒有選擇使用代理,而是客戶端直接連接每個節(jié)點(diǎn)。Redis 的每個節(jié)點(diǎn)中都存儲著整個集群的狀態(tài),集群狀態(tài)中一個重要的信息就是每個桶的負(fù)責(zé)節(jié)點(diǎn)。在具體的實現(xiàn)中,Redis 用一個大小固定為 CLUSTER_SLOTS 的 clusterNode 數(shù)組 slots 來保存每個桶的負(fù)責(zé)節(jié)點(diǎn)。

typedef struct clusterNode {

...

unsigned char slots[CLUSTER_SLOTS/8];

...

} clusterNode;

typedef struct clusterState {

// slots記錄每個桶被哪個節(jié)點(diǎn)存儲

clusterNode *slots[CLUSTER_SLOTS];

...

} clusterState;

在集群模式下,Redis 接收任何鍵相關(guān)命令時首先計算鍵對應(yīng)的桶編號,再根據(jù)桶找出所對應(yīng)的節(jié)點(diǎn),如果節(jié)點(diǎn)是自身,則處理鍵命令;否則回復(fù) MOVED 重定向錯誤,通知客戶端請求正確的節(jié)點(diǎn),這個過程稱為 MOVED 重定向。重定向信息包含了鍵所對應(yīng)的桶以及負(fù)責(zé)該桶的節(jié)點(diǎn)地址,根據(jù)這些信息客戶端就可以向正確的節(jié)點(diǎn)發(fā)起請求。

ref Redis集群詳解(上)

7、為什么是 163834 個槽位?

從前面的 Cluster 集群原理我們已經(jīng)了解到集群中的所有節(jié)點(diǎn)在握手成功后悔定期發(fā)送 ping/pong 消息,交換數(shù)據(jù)信息。

先來了解一下消息體傳遞了哪些數(shù)據(jù):

typedef struct {

//消息的長度(包括這個消息頭的長度和消息正文的長度)

uint32_t totlen;

//消息的類型

uint16_t type;

//消息正文包含的節(jié)點(diǎn)信息數(shù)量

//只在發(fā)送MEET 、PING 、PONG 這三種Gossip 協(xié)議消息時使用

uint16_t count;

//發(fā)送者所處的配置紀(jì)元

uint64_t currentEpoch;

//如果發(fā)送者是一個主節(jié)點(diǎn),那么這里記錄的是發(fā)送者的配置紀(jì)元

//如果發(fā)送者是一個從節(jié)點(diǎn),那么這里記錄的是發(fā)送者正在復(fù)制的主節(jié)點(diǎn)的配置紀(jì)元

uint64_t configEpoch;

//發(fā)送者的名字(ID )

char sender[REDIS_CLUSTER_NAMELEN];

//發(fā)送者目前的槽指派信息

unsigned char myslots[REDIS_CLUSTER_SLOTS/8];

//如果發(fā)送者是一個從節(jié)點(diǎn),那么這里記錄的是發(fā)送者正在復(fù)制的主節(jié)點(diǎn)的名字

//如果發(fā)送者是一個主節(jié)點(diǎn),那么這里記錄的是REDIS_NODE_NULL_NAME

//(一個40 字節(jié)長,值全為0 的字節(jié)數(shù)組)

char slaveof[REDIS_CLUSTER_NAMELEN];

//發(fā)送者的端口號

uint16_t port;

//發(fā)送者的標(biāo)識值

uint16_t flags;

//發(fā)送者所處集群的狀態(tài)

unsigned char state;

//消息的正文(或者說,內(nèi)容)

union clusterMsgData data;

} clusterMsg;

上圖展示的消息體結(jié)構(gòu)無外乎是一些節(jié)點(diǎn)標(biāo)識,IP,端口號,發(fā)送時間等,但需要注意一下標(biāo)紅的 myslots 的 char 數(shù)組,長度為 16383/8,這其實是一個 bitmap,每一個位代表一個槽,如果該位為1,表示這個槽是屬于這個節(jié)點(diǎn)的。

消息體大小上的考量

至于這個消息體有多大?顯然最占空間的就是 myslots 數(shù)組:16384÷8÷1024=2kb。如果槽位達(dá)到 65536,則所占空間提升到 65536÷8÷1024=8kb,極大浪費(fèi)帶寬。

Redis 集群主節(jié)點(diǎn)數(shù)量基本不可能超過 1000 個

集群節(jié)點(diǎn)越多,心跳包的消息體內(nèi)攜帶的數(shù)據(jù)越多。如果節(jié)點(diǎn)過1000個,也會導(dǎo)致網(wǎng)絡(luò)擁堵。

槽位越小,節(jié)點(diǎn)少的情況下,壓縮比高

ref 為什么Redis集群有16384個槽

ref 集群之間的消息

8、集群的故障發(fā)現(xiàn)與遷移?

故障發(fā)現(xiàn)

當(dāng)集群內(nèi)某個節(jié)點(diǎn)出現(xiàn)問題時,需要通過一種健壯的方式保證識別出節(jié)點(diǎn)是否發(fā)生了故障。Redis 集群內(nèi)節(jié)點(diǎn)通過 ping/pong 消息實現(xiàn)節(jié)點(diǎn)通信,消息不但可以傳播節(jié)點(diǎn)槽信息,還可以傳播其他狀態(tài)如:主從狀態(tài)、節(jié)點(diǎn)故障等。因此故障發(fā)現(xiàn)也是通過消息傳播機(jī)制實現(xiàn)的。 主要環(huán)節(jié)包括:

主觀下線(PFAIL-Possibly Fail)

集群中每個節(jié)點(diǎn)都會定期向其他節(jié)點(diǎn)發(fā)送ping消息,接收節(jié)點(diǎn)回復(fù)pong消息作為響應(yīng)。如果在cluster-node-timeout時間內(nèi)通信一直失敗,則發(fā)送節(jié)點(diǎn)會認(rèn)為接收節(jié)點(diǎn)存在故障,把接收節(jié)點(diǎn)標(biāo)記為主觀下線(PFail)狀態(tài)。

客觀下線(Fail)

Redis 集群對于節(jié)點(diǎn)最終是否故障判斷非常嚴(yán)謹(jǐn),只有一個節(jié)點(diǎn)認(rèn)為主觀下線并不能準(zhǔn)確判斷是否故障。當(dāng)某個節(jié)點(diǎn)判斷另一個節(jié)點(diǎn)主觀下線后,相應(yīng)的節(jié)點(diǎn)狀態(tài)會跟隨消息在集群內(nèi)傳播,通過Gossip消息傳播,集群內(nèi)節(jié)點(diǎn)不斷收集到故障節(jié)點(diǎn)的下線報告。當(dāng)半數(shù)以上持有槽的主節(jié)點(diǎn)都標(biāo)記某個節(jié)點(diǎn)是主觀下線時。觸發(fā)客觀下線流程。

故障恢復(fù)

故障節(jié)點(diǎn)變?yōu)榭陀^下線后,如果下線節(jié)點(diǎn)是持有槽的主節(jié)點(diǎn)則需要在它的從節(jié)點(diǎn)中選出一個替換它,從而保證集群的高可用。下線主節(jié)點(diǎn)的所有從節(jié)點(diǎn)承擔(dān)故障恢復(fù)的義務(wù),當(dāng)從節(jié)點(diǎn)通過內(nèi)部定時任務(wù)發(fā)現(xiàn)自身復(fù)制的主節(jié)點(diǎn)進(jìn)入客觀下線時,將會觸發(fā)故障恢復(fù)流程。

ref 018.Redis Cluster故障轉(zhuǎn)移原理

Redis 的持久化機(jī)制是什么?各自的優(yōu)缺點(diǎn)?

1. Redis 的 RDB?

RDB 持久化是指在指定的時間間隔內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫入磁盤。也是默認(rèn)的持久化方式。也就是將內(nèi)存中數(shù)據(jù)以快照的方式寫入到二進(jìn)制文件中,默認(rèn)的文件名為 dump.rdb。

RDB 支持 同步(save 命令)、后臺異步(bgsave)以及自動配置三種方式觸發(fā)。

優(yōu)點(diǎn)

RDB 文件緊湊,全量備份,非常適合用于進(jìn)行備份和災(zāi)難恢復(fù)

生成 RDB 文件時支持異步處理,主進(jìn)程不需要進(jìn)行任何磁盤IO操作

RDB 在恢復(fù)大數(shù)據(jù)集時的速度比 AOF 的恢復(fù)速度要快

缺點(diǎn)

RDB 快照是一次全量備份,存儲的是內(nèi)存數(shù)據(jù)的二進(jìn)制序列化形式,存儲上非常緊湊。且在快照持久化期間修改的數(shù)據(jù)不會被保存,可能丟失數(shù)據(jù)。

2.Redis 的 AOF?

全量備份總是耗時的,有時候我們提供一種更加高效的方式 AOF,其工作機(jī)制更加簡單:會將每一個收到的寫命令追加到文件中。

隨著時間推移,AOF 持久化文件也會變的越來越大。為了解決此問題,Redis 提供了 bgrewriteaof 命令,作用是 fork 出一條新進(jìn)程將內(nèi)存中的數(shù)據(jù)以命令的方式保存到臨時文件中,完成對AOF 文件的重寫。

AOF 也有三種觸發(fā)方式:1)每修改同步 always 2)每秒同步 everysec 3)不同no:從不同步。

優(yōu)點(diǎn)

AOF 可以更好的保護(hù)數(shù)據(jù)不丟失,一般 AOF 隔 1 秒通過一個后臺線程執(zhí)行一次 fsync 操作

AOF 日志文件沒有任何磁盤尋址的開銷,寫入性能非常高,文件不容易破損

AOF 日志文件即使過大的時候,出現(xiàn)后臺重寫操作,也不會影響客戶端的讀寫

AOF 日志文件的命令通過非??勺x的方式進(jìn)行記錄,這個特性非常適合做災(zāi)難性的誤刪除的緊急恢復(fù)

缺點(diǎn)

對于同一份數(shù)據(jù)來說,AOF 日志文件通常比 RDB 數(shù)據(jù)快照文件更大

AOF開啟后,支持的寫 QPS 會比RDB支持的寫 QPS 低,因為 AOF 一般會配置成每秒 fsync 一次日志文件,當(dāng)然,每秒一次 fsync,性能也還是很高的

RDB 和 AOF 該如何選擇?

命令RDBAOF啟動優(yōu)先級低高體積小大恢復(fù)速度快慢數(shù)據(jù)安全性丟數(shù)據(jù)取決于刷盤策略輕重重輕

Redis 常見性能問題和解決方案

Master 最好不要寫內(nèi)存快照,如果 Master 寫內(nèi)存快照,save 命令調(diào)度 rdbSave函數(shù),會阻塞主線程的工作,當(dāng)快照比較大時對性能影響是非常大的,會間斷性暫停服務(wù)。

如果數(shù)據(jù)比較重要,某個 Slave 開啟 AOF 備份數(shù)據(jù),策略設(shè)置為每秒同步一。

為了主從復(fù)制的速度和連接的穩(wěn)定性,Master 和 Slave 最好在同一個局域網(wǎng)。

盡量避免在壓力很大的主庫上增加從。

主從復(fù)制不要用圖狀結(jié)構(gòu),用單向鏈表結(jié)構(gòu)更為穩(wěn)定,即:Master <- Slave1<- Slave2 <- Slave3……這樣的結(jié)構(gòu)方便解決單點(diǎn)故障問題,實現(xiàn) Slave 對 Master 的替換。如果 Master 掛了,可以立刻啟用 Slave1 做 Master,其他不變。

Redis 過期鍵的刪除策略?

定時刪除:在設(shè)置鍵的過期時間的同時,創(chuàng)建一個定時器 timer。讓定時器在鍵的過期時間來臨時,立即執(zhí)行對鍵的刪除操作。

惰性刪除:放任鍵過期不管,但是每次從鍵空間中獲取鍵時,都檢查取得的鍵是否過期,如果過期的話,就刪除該鍵;如果沒有過期,就返回該鍵。

定期刪除:每隔一段時間程序就對數(shù)據(jù)庫進(jìn)行一次檢查,刪除里面的過期鍵。至于要刪除多少過期鍵,以及要檢查多少個數(shù)據(jù)庫,則由算法決定。

Redis 的回收策略(淘汰策略)?

volatile-lru:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰

volatile-ttl:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中挑選將要過期的數(shù)據(jù)淘汰

volatile-random:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中任意選擇數(shù)據(jù)淘汰

allkeys-lru:從數(shù)據(jù)集(server.db[i].dict)中挑選最近最少使用的數(shù)據(jù)淘汰

allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰

no-enviction(驅(qū)逐):禁止驅(qū)逐數(shù)據(jù)

注意這里的 6 種機(jī)制,volatile 和 allkeys 規(guī)定了是對已設(shè)置過期時間的數(shù)據(jù)集淘汰數(shù)據(jù)還是從全部數(shù)據(jù)集淘汰數(shù)據(jù),后面的 lru、ttl 以及 random 是三種不同的淘汰策略,再加上一種 no-enviction 永不回收的策略。

使用策略規(guī)則:

如果數(shù)據(jù)呈現(xiàn)冪律分布,也就是一部分?jǐn)?shù)據(jù)訪問頻率高,一部分?jǐn)?shù)據(jù)訪問頻率低,則使用 allkeys-lru

如果數(shù)據(jù)呈現(xiàn)平等分布,也就是所有的數(shù)據(jù)訪問頻率都相同,則使用 allkeys-random

Redis 事務(wù)

1.怎么理解 Redis 事務(wù)?

事務(wù)是一個單獨(dú)的隔離操作:事務(wù)中的所有命令都會序列化、按順序地執(zhí)行。事務(wù)在執(zhí)行的過程中,不會被其他客戶端發(fā)送來的命令請求所打斷。

事務(wù)是一個原子操作:事務(wù)中的命令要么全部被執(zhí)行,要么全部都不執(zhí)行。

2.Redis 事務(wù)相關(guān)的命令有哪幾個?

MULTI、EXEC、DISCARD、WATCH。

Redis分布式鎖

先拿 setnx 來爭搶鎖,搶到之后,再用 expire 給鎖加一個過期時間防止鎖忘記了釋放。

如何實現(xiàn)分布式鎖:

「互斥性」: 任意時刻,只有一個客戶端能持有鎖

「鎖超時釋放」:持有鎖超時,可以釋放,防止不必要的資源浪費(fèi),也可以防止死鎖

「可重入性」:一個線程如果獲取了鎖之后,可以再次對其請求加鎖

「高性能和高可用」:加鎖和解鎖需要開銷盡可能低,同時也要保證高可用,避免分布式鎖失效

「安全性」:鎖只能被持有的客戶端刪除,不能被其他客戶端刪除

RedLock 加鎖步驟:

1)按順序向集群中所有 master 節(jié)點(diǎn)請求加鎖;

2)根據(jù)設(shè)置的超時時間來判斷,是不是要跳過該 master 節(jié)點(diǎn);

3)如果大于等于半數(shù)節(jié)點(diǎn)( N/2+1 )加鎖成功,并且使用的時間小于鎖的有效期,即可認(rèn)定加鎖成功啦;

4)如果獲取鎖失敗,解鎖!

緩存三大問題以及解決方案?

緩存穿透:查詢數(shù)據(jù)不存在

緩存空值

key 值校驗,如布隆篩選器 ref

緩存擊穿:緩存過期,伴隨大量對該 key 的請求

互斥鎖

熱點(diǎn)數(shù)據(jù)永不過期

熔斷降級

緩存雪崩:同一時間大批量的 key 過期

熱點(diǎn)數(shù)據(jù)不過期

隨機(jī)分散過期時間

柚子快報激活碼778899分享:面試 緩存 最全Redis原理

http://yzkb.51969.com/

好文推薦

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://m.gantiao.com.cn/post/17835349.html

發(fā)布評論

您暫未設(shè)置收款碼

請在主題配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄