[TOC]
一锁右、Redis 基礎(chǔ)常問(wèn)
1.1疏旨、Redis 有哪些數(shù)據(jù)結(jié)構(gòu)
- 基礎(chǔ):字符串String很魂、字典Hash、列表List檐涝、集合Set遏匆、有序集合SortedSet
- 加分:HyperLogLog、Geo骤铃、Pub/Sub
- 高級(jí):BloomFilter、RedisSearch坷剧、Redis-ML
1.2惰爬、Redis 大量 key 設(shè)置同一時(shí)間過(guò)期
電商首頁(yè)經(jīng)常會(huì)使用定時(shí)任務(wù)刷新緩存,可能大量的數(shù)據(jù)失效時(shí)間都十分集中惫企,如果失效時(shí)間一樣撕瞧,又剛好在失效的時(shí)間點(diǎn)大量用戶涌入,就有可能造成緩存雪崩狞尔,一般需要在時(shí)間上加一個(gè)隨機(jī)值丛版,使得過(guò)期時(shí)間分散一些。
1.3偏序、Redis分布式鎖
先拿 setnx 來(lái)爭(zhēng)搶鎖页畦,搶到之后,再用 expire 給鎖加一個(gè)過(guò)期時(shí)間防止鎖忘記了釋放研儒。
但 setnx 不能同時(shí)完成 expire 設(shè)置失效時(shí)長(zhǎng)豫缨,不能保證 setnx 和 expire 的原子性,可以使用 set 命令完成 setnx 和 expire 的操作端朵,并且這種操作是原子操作好芭。
set key value [EX seconds] [PX milliseconds] [NX|XX]
EX seconds:設(shè)置失效時(shí)長(zhǎng),單位秒
PX milliseconds:設(shè)置失效時(shí)長(zhǎng)冲呢,單位毫秒
NX:key不存在時(shí)設(shè)置value舍败,成功返回OK,失敗返回(nil)
XX:key存在時(shí)設(shè)置value,成功返回OK邻薯,失敗返回(nil)
案例:設(shè)置name=p7+裙戏,失效時(shí)長(zhǎng)100s,不存在時(shí)設(shè)置
set name p7+ ex 100 nx
1.4弛说、Redis keys 和 scan
Redis 是單線程的挽懦。
keys 指令會(huì)導(dǎo)致線程阻塞一段時(shí)間,線上服務(wù)會(huì)停頓木人,直到指令執(zhí)行完畢信柿,服務(wù)才能恢復(fù)。
這個(gè)時(shí)候可以使用 scan 指令醒第, scan 指令可以無(wú)阻塞的提取出指定模式的 key 列表渔嚷,但是會(huì)有一定的重復(fù)概率,在客戶端做一次去重就可以了稠曼,但是整體所花費(fèi)的時(shí)間會(huì)比直接用 keys 指令長(zhǎng)形病。
不過(guò),增量式迭代命令也不是沒(méi)有缺點(diǎn)的: 舉個(gè)例子霞幅, 使用 SMEMBERS 命令可以返回集合鍵當(dāng)前包含的所有元素漠吻, 但是對(duì)于 SCAN 這類增量式迭代命令來(lái)說(shuō), 因?yàn)樵趯?duì)鍵進(jìn)行增量式迭代的過(guò)程中司恳, 鍵可能會(huì)被修改途乃, 所以增量式迭代命令只能對(duì)被返回的元素提供有限的保證 。
1.5扔傅、Redis 當(dāng)做異步隊(duì)列
一般使用 list 結(jié)構(gòu)作為隊(duì)列耍共, rpush 生產(chǎn)消息, lpop 消費(fèi)消息猎塞。當(dāng) lpop 沒(méi)有消息的時(shí)候试读,要適當(dāng) sleep 一會(huì)再重試。
不用 sleep 的話:list 還有個(gè)指令叫 blpop 荠耽,在沒(méi)有消息的時(shí)候钩骇,它會(huì)阻塞住直到消息到來(lái)。
1.6铝量、Redis 發(fā)布訂閱
使用 pub/sub 主題訂閱者模式伊履,可以實(shí)現(xiàn) 1:N 的消息隊(duì)列。
# 訂閱頻道名為 redisChat
SUBSCRIBE redisChat
# 在同一個(gè)頻道 redisChat 發(fā)布消息
PUBLISH redisChat "Redis is a great caching technique"
pub/sub 有什么缺點(diǎn)款违?
在消費(fèi)者下線的情況下唐瀑,生產(chǎn)的消息會(huì)丟失,得使用專業(yè)的消息隊(duì)列插爹。
1.7哄辣、Redis 實(shí)現(xiàn)延時(shí)隊(duì)列
Redis 實(shí)現(xiàn)延時(shí)任務(wù)请梢,是通過(guò)其數(shù)據(jù)結(jié)構(gòu) ZSET(sortedset) 來(lái)實(shí)現(xiàn)的。ZSET 會(huì)儲(chǔ)存一個(gè) score 和一個(gè) value力穗,可以將 value按照 score 進(jìn)行排序毅弧,而 SET 是無(wú)序的。
延時(shí)任務(wù)的實(shí)現(xiàn)分為以下幾步來(lái)實(shí)現(xiàn):
- 將任務(wù)的執(zhí)行時(shí)間作為score当窗,要執(zhí)行的任務(wù)數(shù)據(jù)作為value够坐,存放在zset中;
- 用一個(gè)進(jìn)程定時(shí)查詢zset的score分?jǐn)?shù)最小的元素崖面,可以用ZRANGEBYSCORE key -inf +inf limit 0 1 withscores命令來(lái)實(shí)現(xiàn);
- 如果最小的分?jǐn)?shù)小于等于當(dāng)前時(shí)間戳元咙,就將該任務(wù)取出來(lái)執(zhí)行,否則休眠一段時(shí)間后再查詢
1.8巫员、Redis 怎么持久化庶香?主從數(shù)據(jù)怎么交互?
RDB 做鏡像全量持久化简识,AOF 做增量持久化赶掖。
因?yàn)镽DB 會(huì)耗費(fèi)較長(zhǎng)時(shí)間,不夠?qū)崟r(shí)七扰,在停機(jī)的時(shí)候會(huì)導(dǎo)致大量丟失數(shù)據(jù)奢赂,所以需要AOF 來(lái)配合使用。在 redis 實(shí)例重啟時(shí)颈走,會(huì)使用 RDB 持久化文件重新構(gòu)建內(nèi)存膳灶,再使用 AOF 重放近期的操作指令來(lái)實(shí)現(xiàn)完整恢復(fù)重啟之前的狀態(tài)。
突然機(jī)器掉電會(huì)怎樣疫鹊?
AOF 日志 sync 屬性的配置袖瞻,如果不要求性能鲫惶,在每條寫指令時(shí)都 sync 一下磁盤百揭,就不會(huì)丟失數(shù)據(jù)骗村。但是在高性能的要求下每次都 sync 是不現(xiàn)實(shí)的,一般都使用定時(shí) sync枣耀,比如1s1次,這個(gè)時(shí)候最多就會(huì)丟失1s的數(shù)據(jù)庭再。
RDB的原理
fork 是指 redis 通過(guò)創(chuàng)建子進(jìn)程來(lái)進(jìn)行 RDB 操作捞奕,cow 指的是 copy on write,子進(jìn)程創(chuàng)建后拄轻,父子進(jìn)程共享數(shù)據(jù)段颅围,父進(jìn)程繼續(xù)提供讀寫服務(wù),逐漸和子進(jìn)程分離開(kāi)來(lái)恨搓。
1.9院促、Redis 同步機(jī)制
第一次同步時(shí)筏养,主節(jié)點(diǎn)做一次 bgsave,并同時(shí)將后續(xù)修改操作記錄到內(nèi)存 buffer常拓,待完成后將 RDB 文件全量同步到復(fù)制節(jié)點(diǎn)渐溶,復(fù)制節(jié)點(diǎn)接受完成后將 RDB 鏡像加載到內(nèi)存。加載完成后弄抬,再通知主節(jié)點(diǎn)將期間修改的操作記錄同步到復(fù)制節(jié)點(diǎn)進(jìn)行重放就完成了同步過(guò)程茎辐。
后續(xù)的增量數(shù)據(jù)通過(guò) AOF日志同步即可,有點(diǎn)類似數(shù)據(jù)庫(kù)的 binlog掂恕。
1.10拖陆、Redis 高可用
Redis Sentinal 著眼于高可用,在 master 宕機(jī)時(shí)會(huì)自動(dòng)將 slave 提升為master竹海,繼續(xù)提供服務(wù)慕蔚。
Redis Cluster 著眼于擴(kuò)展性,在單個(gè) redis 內(nèi)存不足時(shí)斋配,使用 Cluster 進(jìn)行分片存儲(chǔ)孔飒。
1.11、Redis 緩存雪崩
目前電商首頁(yè)以及熱點(diǎn)數(shù)據(jù)都會(huì)去做緩存 艰争,一般緩存都是定時(shí)任務(wù)去刷新坏瞄,或者是查不到之后去更新的,定時(shí)任務(wù)刷新就有一個(gè)問(wèn)題甩卓。緩存同一時(shí)間大面積失效鸠匀,那一瞬間 Redis 跟沒(méi)有一樣,那這個(gè)數(shù)量級(jí)別的請(qǐng)求直接打到數(shù)據(jù)庫(kù)造成數(shù)據(jù)庫(kù) down逾柿。這就是緩存雪崩缀棍。
舉個(gè)例子:如果所有首頁(yè)的 Key 失效時(shí)間都是12小時(shí),中午12點(diǎn)刷新的机错,零點(diǎn)有個(gè)秒殺活動(dòng)大量用戶涌入爬范,假設(shè)當(dāng)時(shí)每秒 6000 個(gè)請(qǐng)求,本來(lái)緩存在可以扛住每秒 5000 個(gè)請(qǐng)求弱匪,但是緩存當(dāng)時(shí)所有的 Key 都失效了青瀑。此時(shí) 1 秒 6000 個(gè)請(qǐng)求全部落數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)必然扛不住萧诫,它會(huì)報(bào)一下警斥难,真實(shí)情況可能 DBA 都沒(méi)反應(yīng)過(guò)來(lái)就直接掛了。此時(shí)帘饶,如果沒(méi)用什么特別的方案來(lái)處理這個(gè)故障哑诊,DBA 很著急,重啟數(shù)據(jù)庫(kù)及刻,但是數(shù)據(jù)庫(kù)立馬又被新的流量給打死了镀裤。
解決方法:
在批量往Redis
存數(shù)據(jù)的時(shí)候穷当,把每個(gè) Key 的失效時(shí)間都加個(gè)隨機(jī)值就好了,這樣可以保證數(shù)據(jù)不會(huì)在同一時(shí)間大面積失效:
setRedis(Key淹禾,value馁菜,time + Math.random() * 10000);
1.12铃岔、Redis 緩存穿透
緩存穿透是指緩存和數(shù)據(jù)庫(kù)中都沒(méi)有的數(shù)據(jù)汪疮,而用戶不斷發(fā)起請(qǐng)求,一般數(shù)據(jù)庫(kù)的 id 都是1開(kāi)始自增上去的毁习,如發(fā)起為 id值為 -1 的數(shù)據(jù)或 id 為特別大不存在的數(shù)據(jù)智嚷。像這種如果不對(duì)參數(shù)做校驗(yàn),數(shù)據(jù)庫(kù) id 都是大于0的纺且,一直用小于 0 的參數(shù)去請(qǐng)求盏道,每次都能繞開(kāi) Redis 直接打到數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)也查不到载碌,每次都這樣猜嘱,并發(fā)高點(diǎn)就容易崩掉了。
解決方法:
在接口層增加校驗(yàn)嫁艇,比如用戶鑒權(quán)校驗(yàn)朗伶,參數(shù)做校驗(yàn),不合法的參數(shù)直接代碼 Return步咪,比如:id 做基礎(chǔ)校驗(yàn)论皆,id <=0 的直接攔截等。
Redis 還有一個(gè)高級(jí)用法布隆過(guò)濾器(Bloom Filter)猾漫,這個(gè)也能很好的防止緩存穿透的發(fā)生点晴,原理是利用高效的數(shù)據(jù)結(jié)構(gòu)和算法快速判斷出你這個(gè) Key 是否在數(shù)據(jù)庫(kù)中存在,不存在 return 就好了悯周,存在就去查了DB 刷新 KV 再 return粒督。
1.13、Redis 緩存擊穿
緩存擊穿跟緩存雪崩有點(diǎn)像队橙,但是又有一點(diǎn)不一樣坠陈,緩存雪崩是因?yàn)榇竺娣e的緩存失效萨惑,打崩了 DB捐康,而緩存擊穿不同的是緩存擊穿是指一個(gè) Key 非常熱點(diǎn),在不停的扛著大并發(fā)庸蔼,大并發(fā)集中對(duì)這一個(gè)點(diǎn)進(jìn)行訪問(wèn)解总,當(dāng)這個(gè) Key 在失效的瞬間,持續(xù)的大并發(fā)就穿破緩存姐仅,直接請(qǐng)求數(shù)據(jù)庫(kù)花枫,就像在一個(gè)完好無(wú)損的桶上鑿開(kāi)了一個(gè)洞刻盐。
解決方法:
設(shè)置熱點(diǎn)數(shù)據(jù)永遠(yuǎn)不過(guò)期。
或者加上互斥鎖就能搞定了劳翰。
二敦锌、Redis 架構(gòu)
2.1、Redis 中常用的 5 種數(shù)據(jù)結(jié)構(gòu)和應(yīng)用場(chǎng)景
數(shù)據(jù)結(jié)構(gòu):
- String:緩存佳簸、計(jì)數(shù)器乙墙、分布式鎖等。
- List:鏈表生均、隊(duì)列听想、微博關(guān)注人時(shí)間軸列表等。
- Hash:用戶信息马胧、Hash 表等汉买。
- Set:去重、贊佩脊、踩蛙粘、共同好友等。
- Zset:訪問(wèn)量排行榜威彰、點(diǎn)擊量排行榜等组题。
應(yīng)用場(chǎng)景:
- 緩存
- 排行榜系統(tǒng):Redis提供了列表和有序集合數(shù)據(jù)結(jié)構(gòu),合理地使用這些數(shù)據(jù)結(jié)構(gòu)可以很方便地構(gòu)建各種排行
榜系統(tǒng) - 計(jì)數(shù)器應(yīng)用:Redis天然支持計(jì)數(shù)功能而且計(jì)數(shù)的性能也非常好抱冷,可以說(shuō)是計(jì)數(shù)器系統(tǒng)的重要選擇
- 社交網(wǎng)絡(luò):贊/踩崔列、粉絲、共同好友/喜好旺遮、推送赵讯、下拉刷新等,Redis提供的數(shù)據(jù)結(jié)構(gòu)可以相對(duì)比較容易地實(shí)現(xiàn)這些
- 消息隊(duì)列系統(tǒng)
2.2耿眉、Redis 為什么這么快
- 純內(nèi)存訪問(wèn)边翼,Redis 將所有數(shù)據(jù)放在內(nèi)存中,內(nèi)存的響應(yīng)時(shí)長(zhǎng)大約為100 納秒
- 數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)單鸣剪,對(duì)數(shù)據(jù)操作也簡(jiǎn)單组底,Redis 中的數(shù)據(jù)結(jié)構(gòu)是專門進(jìn)行優(yōu)化設(shè)計(jì)的
- 非阻塞 I/O,Redis 使用 epoll 作為 I/O 多路復(fù)用技術(shù)的實(shí)現(xiàn)筐骇,再加上 Redis 自身的事件處理模型將 epoll 中的連接债鸡、讀寫、關(guān)閉都轉(zhuǎn)換為事件铛纬,不在網(wǎng)絡(luò) I/O 上浪費(fèi)過(guò)多的時(shí)間
- 采用單線程厌均,避免了不必要的上下文切換和競(jìng)爭(zhēng)條件,也不存在多進(jìn)程或者多線程導(dǎo)致的切換而消耗 CPU告唆,不用去考慮各種鎖的問(wèn)題棺弊,不存在加鎖釋放鎖操作晶密,沒(méi)有因?yàn)榭赡艹霈F(xiàn)死鎖而導(dǎo)致的性能消耗
2.3、Redis 阻塞
Redis是典型的單線程架構(gòu)模她,所有的讀寫操作都是在一條主線程中完成的稻艰。當(dāng) Redis 用于高并發(fā)場(chǎng)景時(shí),這條線程就變成了它的生命線侈净。如果出現(xiàn)阻塞连锯,哪怕是很短時(shí)間,對(duì)于應(yīng)用來(lái)說(shuō)都是噩夢(mèng)用狱。
導(dǎo)致阻塞問(wèn)題的原因:
- 內(nèi)在原因:不合理地使用API或數(shù)據(jù)結(jié)構(gòu)运怖、CPU飽和、持久化阻塞等
- 外在原因:CPU競(jìng)爭(zhēng)夏伊、內(nèi)存交換摇展、網(wǎng)絡(luò)問(wèn)題等
2.3.1、內(nèi)在原因
1)API 或數(shù)據(jù)結(jié)構(gòu)使用不合理
通常Redis執(zhí)行命令速度非衬缬牵快咏连,但是,如果對(duì)一個(gè)包含上萬(wàn)個(gè)元素的hash結(jié)構(gòu)執(zhí)行hgetall操作鲁森,由于數(shù)據(jù)量比較大且命令算法復(fù)雜度是O(n)祟滴,這條命令執(zhí)行速度必然很慢,或者使用 keys 命令從所有 key 中匹配歌溉。
對(duì)于高并發(fā)的場(chǎng)景應(yīng)該盡量避免在大對(duì)象上執(zhí)行算法復(fù)雜度超過(guò)O(n)的命令垄懂,可以:
- 調(diào)整大對(duì)象:縮減大對(duì)象數(shù)據(jù)或把大對(duì)象拆分為多個(gè)小對(duì)象,防止一次命令操作過(guò)多的數(shù)據(jù)
- SCAN cursor [MATCH pattern] [COUNT count]
2)CPU 飽和
單線程的Redis處理命令時(shí)只能使用一個(gè)CPU痛垛。而CPU飽和是指Redis把單核CPU使用率跑到接近100%草慧。使用top命令很容易識(shí)別出對(duì)應(yīng)Redis進(jìn)程的CPU使用率。CPU飽和是非常危險(xiǎn)的匙头,將導(dǎo)致Redis無(wú)法處理更多的命令漫谷,嚴(yán)重影響吞吐量和應(yīng)用方的穩(wěn)定性。
3)持久化阻塞
對(duì)于開(kāi)啟了持久化功能的Redis節(jié)點(diǎn)蹂析,需要排查是否是持久化導(dǎo)致的阻塞舔示。
- fork阻塞:fork操作發(fā)生在RDB和AOF重寫時(shí),Redis主線程調(diào)用fork操作產(chǎn)生共享內(nèi)存的子進(jìn)程电抚,由子進(jìn)程完成持久化文件重寫工作惕稻。如果fork操作本身耗時(shí)過(guò)長(zhǎng),必然會(huì)導(dǎo)致主線程的阻塞喻频。
- AOF刷盤阻塞:當(dāng)我們開(kāi)啟AOF持久化功能時(shí)缩宜,文件刷盤的方式一般采用每秒一次肘迎,后臺(tái)線程每秒對(duì)AOF文件做fsync操作甥温。當(dāng)硬盤壓力過(guò)大時(shí)锻煌,fsync操作需要等待,直到寫入完成姻蚓。如果主線程發(fā)現(xiàn)距離上一次的fsync成功超過(guò)2秒宋梧,為了數(shù)據(jù)安全性它會(huì)阻塞直到后臺(tái)線程執(zhí)行fsync操作完成。這種阻塞行為主要是硬盤壓力引起狰挡。
- HugePage寫操作阻塞:子進(jìn)程在執(zhí)行重寫期間利用Linux寫時(shí)復(fù)制技術(shù)降低內(nèi)存開(kāi)銷捂龄,因此只有寫操作時(shí)Redis才復(fù)制要修改的內(nèi)存頁(yè)。對(duì)于開(kāi)啟Transparent HugePages的操作系統(tǒng)加叁,每次寫命令引起的復(fù)制內(nèi)存頁(yè)單位由4K變?yōu)?MB倦沧,放大了512倍,會(huì)拖慢寫操作的執(zhí)行時(shí)間它匕,導(dǎo)致大量寫操作慢查詢展融。
2.3.2、外在原因
1)CPU競(jìng)爭(zhēng)
- 進(jìn)程競(jìng)爭(zhēng):Redis是典型的CPU密集型應(yīng)用豫柬,不建議和其他多核CPU密集型服務(wù)部署在一起告希。當(dāng)其他進(jìn)程過(guò)度消耗CPU時(shí),將嚴(yán)重影響Redis吞吐量烧给⊙嗯迹可以通過(guò)top、sar等命令定位到CPU消耗的時(shí)間點(diǎn)和具體進(jìn)程础嫡,這個(gè)問(wèn)題比較容易發(fā)現(xiàn)指么,需要調(diào)整服務(wù)之間部署結(jié)構(gòu)。
- 綁定CPU:部署Redis時(shí)為了充分利用多核CPU榴鼎,通常一臺(tái)機(jī)器部署多個(gè)實(shí)例涧尿。常見(jiàn)的一種優(yōu)化是把Redis進(jìn)程綁定到CPU上,用于降低CPU頻繁上下文切換的開(kāi)銷檬贰。這個(gè)優(yōu)化技巧正常情況下沒(méi)有問(wèn)題姑廉,但是存在例外情況,當(dāng)Redis父進(jìn)程創(chuàng)建子進(jìn)程進(jìn)行RDB/AOF重寫時(shí)翁涤,如果做了CPU綁定桥言,會(huì)與父進(jìn)程共享使用一個(gè)CPU。子進(jìn)程重寫時(shí)對(duì)單核CPU使用率通常在90%以上葵礼,父進(jìn)程與子進(jìn)程將產(chǎn)生激烈CPU競(jìng)爭(zhēng)号阿,極大影響Redis穩(wěn)定性。因此對(duì)于開(kāi)啟了持久化或參與復(fù)制的主節(jié)點(diǎn)不建議綁定CPU鸳粉。
2)內(nèi)存交換
內(nèi)存交換(swap)對(duì)于Redis來(lái)說(shuō)是非常致命的扔涧,Redis保證高性能的一個(gè)重要前提是所有的數(shù)據(jù)在內(nèi)存中。如果操作系統(tǒng)把Redis使用的部分內(nèi)存換出到硬盤,由于內(nèi)存與硬盤讀寫速度差幾個(gè)數(shù)量級(jí)枯夜,會(huì)導(dǎo)致發(fā)生交換后的Redis性能急劇下降弯汰。
預(yù)防內(nèi)存交換:
- 保證機(jī)器充足的可用內(nèi)存。
- 確保所有Redis實(shí)例設(shè)置最大可用內(nèi)存(maxmemory)湖雹,防止極端情況下Redis內(nèi)存不可控的增長(zhǎng)咏闪。
- 降低系統(tǒng)使用swap優(yōu)先級(jí)。
3)網(wǎng)絡(luò)問(wèn)題
連接拒絕:
- 網(wǎng)絡(luò)閃斷(網(wǎng)絡(luò)割接或者帶寬耗盡)
- Redis連接拒絕(超過(guò)客戶端最大連接數(shù))
- 連接溢出(進(jìn)程限制或backlog隊(duì)列溢出)
網(wǎng)絡(luò)延遲:
網(wǎng)絡(luò)延遲取決于客戶端到Redis服務(wù)器之間的網(wǎng)絡(luò)環(huán)境摔吏。主要包括它們之間的物理拓?fù)浜蛶捳加们闆r鸽嫂。常見(jiàn)的物理拓?fù)浒淳W(wǎng)絡(luò)延遲由快到慢可分為:同物理機(jī)>同機(jī)架>跨機(jī)架>同機(jī)房>同城機(jī)房>異地機(jī)房。但它們?nèi)轂?zāi)性正好相反征讲,同物理機(jī)容災(zāi)性最低而異地機(jī)房容災(zāi)性最高据某。
網(wǎng)卡軟中斷:
網(wǎng)卡軟中斷是指由于單個(gè)網(wǎng)卡隊(duì)列只能使用一個(gè)CPU,高并發(fā)下網(wǎng)卡數(shù)據(jù)交互都集中在同一個(gè)CPU诗箍,導(dǎo)致無(wú)法充分利用多核CPU的情況哗脖。網(wǎng)卡軟中斷瓶頸一般出現(xiàn)在網(wǎng)絡(luò)高流量吞吐的場(chǎng)景。
2.4扳还、redis 和 memcached 有啥區(qū)別
Memcache
- Memcache可以利用多核優(yōu)勢(shì)才避,單實(shí)例吞吐量極高,可以達(dá)到幾十萬(wàn)QPS,適用于最大程度扛量
- 只支持簡(jiǎn)單的key/value數(shù)據(jù)結(jié)構(gòu)氨距,不像Redis可以支持豐富的數(shù)據(jù)類型桑逝。
- 無(wú)法進(jìn)行持久化,數(shù)據(jù)不能備份俏让,只能用于緩存使用楞遏,且重啟后數(shù)據(jù)全部丟失
Redis
- 支持多種數(shù)據(jù)結(jié)構(gòu),如string,list,dict,set,zset,hyperloglog
- 單線程請(qǐng)求首昔,所有命令串行執(zhí)行寡喝,并發(fā)情況下不需要考慮數(shù)據(jù)一致性問(wèn)題
- 支持持久化操作,可以進(jìn)行aof及rdb數(shù)據(jù)持久化到磁盤勒奇,從而進(jìn)行數(shù)據(jù)備份或數(shù)據(jù)恢復(fù)等操作预鬓,較好的防止數(shù)據(jù)丟失的手段
- 支持通過(guò)Replication進(jìn)行數(shù)據(jù)復(fù)制,通過(guò)master-slave機(jī)制赊颠,可以實(shí)時(shí)進(jìn)行數(shù)據(jù)的同步復(fù)制格二,支持多級(jí)復(fù)制和增量復(fù)制
三、Redis 持久化
3.1竣蹦、RDB
RDB是一種快照存儲(chǔ)持久化方式顶猜,具體就是將Redis某一時(shí)刻的內(nèi)存數(shù)據(jù)保存到硬盤的文件當(dāng)中,默認(rèn)保存的文件名為dump.rdb痘括,而在Redis服務(wù)器啟動(dòng)時(shí)长窄,會(huì)重新加載dump.rdb文件的數(shù)據(jù)到內(nèi)存當(dāng)中恢復(fù)數(shù)據(jù)滔吠。
3.1.1、開(kāi)啟RDB持久化方式
開(kāi)啟RDB持久化方式很簡(jiǎn)單挠日,客戶端可以通過(guò)向Redis服務(wù)器發(fā)送save或bgsave命令讓服務(wù)器生成rdb文件疮绷,或者通過(guò)服務(wù)器配置文件指定觸發(fā)RDB條件。
1)save:
save命令是一個(gè)同步操作肆资。當(dāng)客戶端向服務(wù)器發(fā)送save命令請(qǐng)求進(jìn)行持久化時(shí)矗愧,服務(wù)器會(huì)阻塞save命令之后的其他客戶端的請(qǐng)求灶芝,直到數(shù)據(jù)同步完成郑原。
如果數(shù)據(jù)量太大,同步數(shù)據(jù)會(huì)執(zhí)行很久夜涕,而這期間Redis服務(wù)器也無(wú)法接收其他請(qǐng)求犯犁,所以,最好不要在生產(chǎn)環(huán)境使用save命令女器。
2)bgsave:
與save命令不同酸役,bgsave命令是一個(gè)異步操作。當(dāng)客戶端發(fā)服務(wù)發(fā)出bgsave命令時(shí)驾胆,Redis服務(wù)器主進(jìn)程會(huì)forks一個(gè)子進(jìn)程來(lái)數(shù)據(jù)同步問(wèn)題涣澡,在將數(shù)據(jù)保存到rdb文件之后,子進(jìn)程會(huì)退出丧诺。
與save命令相比入桂,Redis服務(wù)器在處理bgsave采用子線程進(jìn)行IO寫入,而主進(jìn)程仍然可以接收其他請(qǐng)求驳阎,但forks子進(jìn)程是同步的抗愁,所以forks子進(jìn)程時(shí),一樣不能接收其他請(qǐng)求呵晚,這意味著蜘腌,如果forks一個(gè)子進(jìn)程花費(fèi)的時(shí)間太久(一般是很快的),bgsave命令仍然有阻塞其他客戶的請(qǐng)求的情況發(fā)生饵隙。
3)服務(wù)器配置自動(dòng)觸發(fā):
除了通過(guò)客戶端發(fā)送命令外撮珠,還有一種方式,就是在Redis配置文件中的save指定到達(dá)觸發(fā)RDB持久化的條件金矛,比如【多少秒內(nèi)至少達(dá)到多少寫操作】就開(kāi)啟RDB數(shù)據(jù)同步劫瞳。
例如可以在配置文件redis.conf指定如下的選項(xiàng):
# 900s內(nèi)至少達(dá)到一條寫命令
save 900 1
# 300s內(nèi)至少達(dá)到10條寫命令
save 300 10
# 60s內(nèi)至少達(dá)到10000條寫命令
save 60 10000
之后在啟動(dòng)服務(wù)器時(shí)加載配置文件。
# 啟動(dòng)服務(wù)器加載配置文件
redis-server redis.conf
這種通過(guò)服務(wù)器配置文件觸發(fā)RDB的方式绷柒,與bgsave命令類似志于,達(dá)到觸發(fā)條件時(shí),會(huì)forks一個(gè)子進(jìn)程進(jìn)行數(shù)據(jù)同步废睦。
3.1.2伺绽、RDB的優(yōu)缺點(diǎn)
RDB的幾個(gè)優(yōu)點(diǎn)
- 與AOF方式相比,通過(guò)rdb文件恢復(fù)數(shù)據(jù)比較快
- rdb文件非常緊湊,適合于數(shù)據(jù)備份
- 通過(guò)RDB進(jìn)行數(shù)據(jù)備奈应,由于使用子進(jìn)程生成澜掩,所以對(duì)Redis服務(wù)器性能影響較小
RDB的幾個(gè)缺點(diǎn)
- 如果服務(wù)器宕機(jī)的話,采用RDB的方式會(huì)造成某個(gè)時(shí)段內(nèi)數(shù)據(jù)的丟失杖挣,比如我們?cè)O(shè)置10分鐘同步一次或5分鐘達(dá)到1000次寫入就同步一次肩榕,那么如果還沒(méi)達(dá)到觸發(fā)條件服務(wù)器就死機(jī)了,那么這個(gè)時(shí)間段的數(shù)據(jù)會(huì)丟失
- 使用save命令會(huì)造成服務(wù)器阻塞惩妇,直接數(shù)據(jù)同步完成才能接收后續(xù)請(qǐng)求
- 使用bgsave命令在forks子進(jìn)程時(shí)株汉,如果數(shù)據(jù)量太大,forks的過(guò)程也會(huì)發(fā)生阻塞歌殃,另外乔妈,forks子進(jìn)程會(huì)耗費(fèi)內(nèi)存
3.2、AOF(Append-only file)
與RDB存儲(chǔ)某個(gè)時(shí)刻的快照不同氓皱,AOF持久化方式會(huì)記錄客戶端對(duì)服務(wù)器的每一次寫操作命令路召,并將這些寫操作以Redis協(xié)議追加保存到以后綴為aof文件末尾,在Redis服務(wù)器重啟時(shí)波材,會(huì)加載并運(yùn)行aof文件的命令股淡,以達(dá)到恢復(fù)數(shù)據(jù)的目的。
3.2.1廷区、開(kāi)啟AOF持久化方式
Redis默認(rèn)不開(kāi)啟AOF持久化方式唯灵,可以在配置文件中開(kāi)啟并進(jìn)行更加詳細(xì)的配置,如下面的redis.conf文件:
# 開(kāi)啟aof機(jī)制
appendonly yes
# aof文件名
appendfilename "appendonly.aof"
# 寫入策略,always表示每個(gè)寫操作都保存到aof文件中,也可以是everysec或no
appendfsync always
# 默認(rèn)不重寫aof文件
no-appendfsync-on-rewrite no
# 保存目錄
dir ~/redis/
三種寫入策略
在上面的配置文件中躲因,可以通過(guò)appendfsync選項(xiàng)指定寫入策略早敬,有三個(gè)選項(xiàng)
appendfsync always
# appendfsync everysec
# appendfsync no
- always:客戶端的每一個(gè)寫操作都保存到aof文件當(dāng),這種策略很安全大脉,但是每個(gè)寫請(qǐng)注都有IO操作搞监,所以也很慢
- everysec:appendfsync的默認(rèn)寫入策略,每秒寫入一次aof文件镰矿,因此琐驴,最多可能會(huì)丟失1s的數(shù)據(jù)
- no:Redis服務(wù)器不負(fù)責(zé)寫入aof,而是交由操作系統(tǒng)來(lái)處理什么時(shí)候?qū)懭隺of文件秤标,更快绝淡,但也是最不安全的選擇,不推薦使用
3.2.2苍姜、AOF文件重寫
AOF將客戶端的每一個(gè)寫操作都追加到aof文件末尾牢酵,比如對(duì)一個(gè)key多次執(zhí)行incr命令,這時(shí)候衙猪,aof保存每一次命令到aof文件中馍乙,aof文件會(huì)變得非常大布近。
incr num 1
incr num 2
incr num 3
incr num 4
incr num 5
incr num 6
...
incr num 100000
aof文件太大,加載aof文件恢復(fù)數(shù)據(jù)時(shí)丝格,就會(huì)非常慢撑瞧,為了解決這個(gè)問(wèn)題,Redis支持aof文件重寫显蝌,通過(guò)重寫aof预伺,可以生成一個(gè)恢復(fù)當(dāng)前數(shù)據(jù)的最少命令集,比如上面的例子中那么多條命令曼尊,可以重寫為:
set num 100000
aof文件是一個(gè)二進(jìn)制文件酬诀,并不是像上面的例子一樣,直接保存每個(gè)命令涩禀,而使用Redis自己的格式料滥,上面只是方便演示然眼。
3.2.3艾船、兩種重寫方式
通過(guò)在redis.conf配置文件中的選項(xiàng)no-appendfsync-on-rewrite可以設(shè)置是否開(kāi)啟重寫,這種方式會(huì)在每次fsync時(shí)都重寫高每,影響服務(wù)器性以屿岂,因此默認(rèn)值為no,不推薦使用鲸匿。
# 默認(rèn)不重寫aof文件
no-appendfsync-on-rewrite no
客戶端向服務(wù)器發(fā)送bgrewriteaof命令爷怀,也可以讓服務(wù)器進(jìn)行AOF重寫。
# 讓服務(wù)器異步重寫追加aof文件命令
> bgrewriteaof
AOF重寫方式也是異步操作带欢,即如果要寫入aof文件运授,則Redis主進(jìn)程會(huì)forks一個(gè)子進(jìn)程來(lái)處理,如下所示:
重寫aof文件的好處
- 壓縮aof文件乔煞,減少磁盤占用量吁朦。
- 將aof的命令壓縮為最小命令集,加快了數(shù)據(jù)恢復(fù)的速度渡贾。
3.2.4逗宜、AOF文件損壞
在寫入aof日志文件時(shí),如果Redis服務(wù)器宕機(jī)空骚,則aof日志文件文件會(huì)出格式錯(cuò)誤纺讲,在重啟Redis服務(wù)器時(shí),Redis服務(wù)器會(huì)拒絕載入這個(gè)aof文件囤屹,可以通過(guò)以下步驟修復(fù)aof并恢復(fù)數(shù)據(jù)熬甚。
1、備份現(xiàn)在aof文件肋坚,以防萬(wàn)一乡括。
2复局、使用redis-check-aof命令修復(fù)aof文件,該命令格式如下:
# 修復(fù)aof日志文件
$ redis-check-aof -fix file.aof
3粟判、重啟Redis服務(wù)器亿昏,加載已經(jīng)修復(fù)的aof文件,恢復(fù)數(shù)據(jù)档礁。
3.2.5角钩、AOF的優(yōu)缺點(diǎn)
AOF的優(yōu)點(diǎn):
- AOF只是追加日志文件,因此對(duì)服務(wù)器性能影響較小呻澜,速度比RDB要快递礼,消耗的內(nèi)存較少。
AOF的缺點(diǎn):
- AOF方式生成的日志文件太大羹幸,即使通過(guò)AFO重寫脊髓,文件體積仍然很大。
- 恢復(fù)數(shù)據(jù)的速度比RDB慢栅受。
四将硝、Redis Key 過(guò)期策略和內(nèi)存淘汰機(jī)制
4.1、Redis設(shè)置過(guò)期時(shí)間
- expire key time(以秒為單位)–這是最常用的方式
- setex(String key, int seconds, String value)–字符串獨(dú)有的方式
注:除了字符串自己獨(dú)有設(shè)置過(guò)期時(shí)間的方法外屏镊,其他方法都需要依靠expire方法來(lái)設(shè)置時(shí)間依疼,如果沒(méi)有設(shè)置時(shí)間,那緩存就是永不過(guò)期而芥,如果設(shè)置了過(guò)期時(shí)間律罢,之后又想讓緩存永不過(guò)期,使用persist key棍丐。
4.2仍劈、過(guò)期策略
定時(shí)刪除
- 含義:在設(shè)置key的過(guò)期時(shí)間的同時(shí)绍填,為該key創(chuàng)建一個(gè)定時(shí)器脆淹,讓定時(shí)器在key的過(guò)期時(shí)間來(lái)臨時(shí)规脸,對(duì)key進(jìn)行刪除
- 優(yōu)點(diǎn):保證內(nèi)存被盡快釋放
- 缺點(diǎn):
- 若過(guò)期key很多,刪除這些key會(huì)占用很多的CPU時(shí)間趋翻,在CPU時(shí)間緊張的情況下睛琳,CPU不能把所有的時(shí)間用來(lái)做要緊的事兒,還需要去花時(shí)間刪除這些key
- 定時(shí)器的創(chuàng)建耗時(shí)踏烙,若為每一個(gè)設(shè)置過(guò)期時(shí)間的key創(chuàng)建一個(gè)定時(shí)器(將會(huì)有大量的定時(shí)器產(chǎn)生)师骗,性能影響嚴(yán)重
- 沒(méi)人用
惰性刪除
- 含義:key過(guò)期的時(shí)候不刪除,每次從數(shù)據(jù)庫(kù)獲取key的時(shí)候去檢查是否過(guò)期讨惩,若過(guò)期辟癌,則刪除,返回null荐捻。
- 優(yōu)點(diǎn):刪除操作只發(fā)生在從數(shù)據(jù)庫(kù)取出key的時(shí)候發(fā)生黍少,而且只刪除當(dāng)前key寡夹,所以對(duì)CPU時(shí)間的占用是比較少的,而且此時(shí)的刪除是已經(jīng)到了非做不可的地步(如果此時(shí)還不刪除的話厂置,我們就會(huì)獲取到了已經(jīng)過(guò)期的key了)
- 缺點(diǎn):若大量的key在超出超時(shí)時(shí)間后菩掏,很久一段時(shí)間內(nèi),都沒(méi)有被獲取過(guò)昵济,那么可能發(fā)生內(nèi)存泄露(無(wú)用的垃圾占用了大量的內(nèi)存)
定期刪除
- 含義:每隔一段時(shí)間執(zhí)行一次刪除(在redis.conf配置文件設(shè)置hz智绸,1s刷新的頻率)過(guò)期key操作
- 優(yōu)點(diǎn):
- 通過(guò)限制刪除操作的時(shí)長(zhǎng)和頻率,來(lái)減少刪除操作對(duì)CPU時(shí)間的占用--處理"定時(shí)刪除"的缺點(diǎn)
- 定期刪除過(guò)期key--處理"惰性刪除"的缺點(diǎn)
- 缺點(diǎn)
- 在內(nèi)存友好方面访忿,不如"定時(shí)刪除"
- 在CPU時(shí)間友好方面瞧栗,不如"惰性刪除"
- 難點(diǎn)
- 合理設(shè)置刪除操作的執(zhí)行時(shí)長(zhǎng)(每次刪除執(zhí)行多長(zhǎng)時(shí)間)和執(zhí)行頻率(每隔多長(zhǎng)時(shí)間做一次刪除)(這個(gè)要根據(jù)服務(wù)器運(yùn)行情況來(lái)定了)
看完上面三種策略后可以得出以下結(jié)論:
- 定時(shí)刪除和定期刪除為主動(dòng)刪除:Redis會(huì)定期主動(dòng)淘汰一批已過(guò)去的key
- 惰性刪除為被動(dòng)刪除:用到的時(shí)候才會(huì)去檢驗(yàn)key是不是已過(guò)期,過(guò)期就刪除
- 惰性刪除為redis服務(wù)器內(nèi)置策略
定期刪除可以通過(guò):
- 第一海铆、配置redis.conf 的hz選項(xiàng)迹恐,默認(rèn)為10 (即1秒執(zhí)行10次,100ms一次卧斟,值越大說(shuō)明刷新頻率越快殴边,最Redis性能損耗也越大)
- 第二、配置redis.conf的maxmemory最大值唆涝,當(dāng)已用內(nèi)存超過(guò)maxmemory限定時(shí)找都,就會(huì)觸發(fā)主動(dòng)清理策略
4.3唇辨、Redis 采用的過(guò)期策略
惰性刪除+定期刪除:
- 惰性刪除流程
- 在進(jìn)行g(shù)et或setnx等操作時(shí)廊酣,先檢查key是否過(guò)期
- 若過(guò)期,刪除key赏枚,然后執(zhí)行相應(yīng)操作
- 若沒(méi)過(guò)期亡驰,直接執(zhí)行相應(yīng)操作
- 定期刪除流程(簡(jiǎn)單而言,對(duì)指定個(gè)數(shù)個(gè)庫(kù)的每一個(gè)庫(kù)隨機(jī)刪除小于等于指定個(gè)數(shù)個(gè)過(guò)期key)
- 遍歷每個(gè)數(shù)據(jù)庫(kù)(就是redis.conf中配置的"database"數(shù)量饿幅,默認(rèn)為16)
- 檢查當(dāng)前庫(kù)中的指定個(gè)數(shù)個(gè)key(默認(rèn)是每個(gè)庫(kù)檢查20個(gè)key凡辱,注意相當(dāng)于該循環(huán)執(zhí)行20次,循環(huán)體時(shí)下邊的描述)
- 如果當(dāng)前庫(kù)中沒(méi)有一個(gè)key設(shè)置了過(guò)期時(shí)間栗恩,直接執(zhí)行下一個(gè)庫(kù)的遍歷
- 隨機(jī)獲取一個(gè)設(shè)置了過(guò)期時(shí)間的key透乾,檢查該key是否過(guò)期,如果過(guò)期磕秤,刪除key
- 判斷定期刪除操作是否已經(jīng)達(dá)到指定時(shí)長(zhǎng)乳乌,若已經(jīng)達(dá)到,直接退出定期刪除市咆。
- 檢查當(dāng)前庫(kù)中的指定個(gè)數(shù)個(gè)key(默認(rèn)是每個(gè)庫(kù)檢查20個(gè)key凡辱,注意相當(dāng)于該循環(huán)執(zhí)行20次,循環(huán)體時(shí)下邊的描述)
- 遍歷每個(gè)數(shù)據(jù)庫(kù)(就是redis.conf中配置的"database"數(shù)量饿幅,默認(rèn)為16)
4.4汉操、RDB 對(duì)過(guò)期 key 的處理
過(guò)期 key 對(duì) RDB 沒(méi)有任何影響
- 從內(nèi)存數(shù)據(jù)庫(kù)持久化數(shù)據(jù)到 RDB 文件
- 持久化 key 之前,會(huì)檢查是否過(guò)期蒙兰,過(guò)期的 key 不進(jìn)入 RDB 文件
- 從 RDB 文件恢復(fù)數(shù)據(jù)到內(nèi)存數(shù)據(jù)庫(kù)
- 數(shù)據(jù)載入數(shù)據(jù)庫(kù)之前磷瘤,會(huì)對(duì) key 先進(jìn)行過(guò)期檢查芒篷,如果過(guò)期,不導(dǎo)入數(shù)據(jù)庫(kù)(主庫(kù)情況)
4.5采缚、AOF 對(duì)過(guò)期 key 的處理
過(guò)期 key 對(duì) AOF 沒(méi)有任何影響
- 從內(nèi)存數(shù)據(jù)庫(kù)持久化數(shù)據(jù)到 AOF 文件:
- 當(dāng) key 過(guò)期后针炉,還沒(méi)有被刪除,此時(shí)進(jìn)行執(zhí)行持久化操作(該 key 是不會(huì)進(jìn)入 aof 文件的扳抽,因?yàn)闆](méi)有發(fā)生修改命令)
- 當(dāng) key 過(guò)期后糊识,在發(fā)生刪除操作時(shí),程序會(huì)向 aof 文件追加一條 del 命令(在將來(lái)的以 aof 文件恢復(fù)數(shù)據(jù)的時(shí)候該過(guò)期的鍵就會(huì)被刪掉)
- AOF 重寫
- 重寫時(shí)摔蓝,會(huì)先判斷 key 是否過(guò)期赂苗,已過(guò)期的 key 不會(huì)重寫到 aof 文件
4.6、Redis 的內(nèi)存淘汰機(jī)制
Redis 定義了6 種 redis 內(nèi)存淘汰策略方案:
- noeviction(默認(rèn)策略):對(duì)于寫請(qǐng)求不再提供服務(wù)贮尉,直接返回錯(cuò)誤(DEL 請(qǐng)求和部分特殊請(qǐng)求除外)
- allkeys-lru:從所有 key 中使用 LRU 算法進(jìn)行淘汰
- volatile-lru:從設(shè)置了過(guò)期時(shí)間的 key 中使用 LRU 算法進(jìn)行淘汰
- allkeys-random:從所有 key 中隨機(jī)淘汰數(shù)據(jù)
- volatile-random:從設(shè)置了過(guò)期時(shí)間的 key 中隨機(jī)淘汰
- volatile-ttl:在設(shè)置了過(guò)期時(shí)間的 key 中拌滋,根據(jù) key 的過(guò)期時(shí)間進(jìn)行淘汰,越早過(guò)期的越優(yōu)先被淘汰
五猜谚、Redis 高可用
5.1败砂、Redis 主從復(fù)制
Redis
主從復(fù)制 可將 主節(jié)點(diǎn) 數(shù)據(jù)同步給 從節(jié)點(diǎn),從節(jié)點(diǎn)此時(shí)有兩個(gè)作用:
- 一旦 主節(jié)點(diǎn)宕機(jī)魏铅,從節(jié)點(diǎn) 作為 主節(jié)點(diǎn) 的 備份 可以隨時(shí)頂上來(lái)昌犹。
- 擴(kuò)展 主節(jié)點(diǎn) 的 讀能力,分擔(dān)主節(jié)點(diǎn)讀壓力览芳。
5.1.1斜姥、主從復(fù)制過(guò)程
主從復(fù)制過(guò)程大體可以分為3個(gè)階段:連接建立階段(即準(zhǔn)備階段)、數(shù)據(jù)同步階段沧竟、命令傳播階段铸敏。
5.1.1.1、連接建立階段
該階段的主要作用是在主從節(jié)點(diǎn)之間建立連接悟泵,為數(shù)據(jù)同步做好準(zhǔn)備杈笔。
-
步驟1,保存主節(jié)點(diǎn)信息:
- 從節(jié)點(diǎn)服務(wù)器內(nèi)部維護(hù)了兩個(gè)字段糕非,即masterhost和masterport字段蒙具,用于存儲(chǔ)主節(jié)點(diǎn)的ip和port信息。
- 需要注意的是朽肥,slaveof****是異步命令禁筏,從節(jié)點(diǎn)完成主節(jié)點(diǎn)ip和port的保存后,向發(fā)送slaveof命令的客戶端直接返回OK鞠呈,實(shí)際的復(fù)制操作在這之后才開(kāi)始進(jìn)行融师。
-
步驟2,建立socket連接蚁吝,從節(jié)點(diǎn)每秒1次調(diào)用復(fù)制定時(shí)函數(shù)replicationCron()旱爆,如果發(fā)現(xiàn)了有主節(jié)點(diǎn)可以連接舀射,便會(huì)根據(jù)主節(jié)點(diǎn)的ip和port,創(chuàng)建socket連接怀伦。如果連接成功脆烟,則:
- 從節(jié)點(diǎn):為該socket建立一個(gè)專門處理復(fù)制工作的文件事件處理器,負(fù)責(zé)后續(xù)的復(fù)制工作房待,如接收RDB文件邢羔、接收命令傳播等。
- 主節(jié)點(diǎn):接收到從節(jié)點(diǎn)的socket連接后(即accept之后)桑孩,為該socket創(chuàng)建相應(yīng)的客戶端狀態(tài)拜鹤,并將從節(jié)點(diǎn)看做是連接到主節(jié)點(diǎn)的一個(gè)客戶端,后面的步驟會(huì)以從節(jié)點(diǎn)向主節(jié)點(diǎn)發(fā)送命令請(qǐng)求的形式來(lái)進(jìn)行流椒。
-
步驟3敏簿,發(fā)送ping命令,從節(jié)點(diǎn)成為主節(jié)點(diǎn)的客戶端之后宣虾,發(fā)送ping命令進(jìn)行首次請(qǐng)求惯裕,目的是:檢查socket連接是否可用,以及主節(jié)點(diǎn)當(dāng)前是否能夠處理請(qǐng)求绣硝。從節(jié)點(diǎn)發(fā)送ping命令后蜻势,可能出現(xiàn)3種情況:
- 返回pong:說(shuō)明socket連接正常,且主節(jié)點(diǎn)當(dāng)前可以處理請(qǐng)求鹉胖,復(fù)制過(guò)程繼續(xù)握玛。
- 超時(shí):一定時(shí)間后從節(jié)點(diǎn)仍未收到主節(jié)點(diǎn)的回復(fù),說(shuō)明socket連接不可用次员,則從節(jié)點(diǎn)斷開(kāi)socket連接败许,并重連。
- 返回pong以外的結(jié)果:如果主節(jié)點(diǎn)返回其他結(jié)果淑蔚,如正在處理超時(shí)運(yùn)行的腳本,說(shuō)明主節(jié)點(diǎn)當(dāng)前無(wú)法處理命令愕撰,則從節(jié)點(diǎn)斷開(kāi)socket連接刹衫,并重連。
-
步驟4搞挣,身份驗(yàn)證:
- 如果從節(jié)點(diǎn)中設(shè)置了masterauth選項(xiàng)带迟,則從節(jié)點(diǎn)需要向主節(jié)點(diǎn)進(jìn)行身份驗(yàn)證;沒(méi)有設(shè)置該選項(xiàng)囱桨,則不需要驗(yàn)證仓犬。從節(jié)點(diǎn)進(jìn)行身份驗(yàn)證是通過(guò)向主節(jié)點(diǎn)發(fā)送auth命令進(jìn)行的,auth命令的參數(shù)即為配置文件中的masterauth的值舍肠。
- 如果主節(jié)點(diǎn)設(shè)置密碼的狀態(tài)搀继,與從節(jié)點(diǎn)masterauth的狀態(tài)一致(一致是指都存在窘面,且密碼相同,或者都不存在)叽躯,則身份驗(yàn)證通過(guò)财边,復(fù)制過(guò)程繼續(xù);如果不一致点骑,則從節(jié)點(diǎn)斷開(kāi)socket連接酣难,并重連。
-
步驟5黑滴,發(fā)送從節(jié)點(diǎn)端口信息:
- 身份驗(yàn)證之后憨募,從節(jié)點(diǎn)會(huì)向主節(jié)點(diǎn)發(fā)送其監(jiān)聽(tīng)的端口號(hào)(前述例子中為6380),主節(jié)點(diǎn)將該信息保存到該從節(jié)點(diǎn)對(duì)應(yīng)的客戶端的slave_listening_port字段中袁辈;該端口信息除了在主節(jié)點(diǎn)中執(zhí)行info Replication時(shí)顯示以外馋嗜,沒(méi)有其他作用。
5.1.1.2吵瞻、數(shù)據(jù)同步階段
主從節(jié)點(diǎn)之間的連接建立以后葛菇,便可以開(kāi)始進(jìn)行數(shù)據(jù)同步,該階段可以理解為從節(jié)點(diǎn)數(shù)據(jù)的初始化橡羞。具體執(zhí)行的方式是:從節(jié)點(diǎn)向主節(jié)點(diǎn)發(fā)送psync命令(Redis2.8以前是sync命令)眯停,開(kāi)始同步。
數(shù)據(jù)同步階段是主從復(fù)制最核心的階段卿泽,根據(jù)主從節(jié)點(diǎn)當(dāng)前狀態(tài)的不同莺债,可以分為全量復(fù)制和部分復(fù)制。
在Redis2.8 以前签夭,從節(jié)點(diǎn)向主節(jié)點(diǎn)發(fā)送sync命令請(qǐng)求同步數(shù)據(jù)齐邦,此時(shí)的同步方式是全量復(fù)制;在Redis2.8及以后第租,從節(jié)點(diǎn)可以發(fā)送psync命令請(qǐng)求同步數(shù)據(jù)措拇,此時(shí)根據(jù)主從節(jié)點(diǎn)當(dāng)前狀態(tài)的不同,同步方式可能是全量復(fù)制或部分復(fù)制慎宾。
- 全量復(fù)制:用于初次復(fù)制或其他無(wú)法進(jìn)行部分復(fù)制的情況丐吓,將主節(jié)點(diǎn)中的所有數(shù)據(jù)都發(fā)送給從節(jié)點(diǎn),是一個(gè)非常重型的操作趟据。
- 部分復(fù)制:用于網(wǎng)絡(luò)中斷等情況后的復(fù)制券犁,只將中斷期間主節(jié)點(diǎn)執(zhí)行的寫命令發(fā)送給從節(jié)點(diǎn),與全量復(fù)制相比更加高效汹碱。需要注意的是粘衬,如果網(wǎng)絡(luò)中斷時(shí)間過(guò)長(zhǎng),導(dǎo)致主節(jié)點(diǎn)沒(méi)有能夠完整地保存中斷期間執(zhí)行的寫命令,則無(wú)法進(jìn)行部分復(fù)制稚新,仍使用全量復(fù)制勘伺。
1)全量復(fù)制
Redis通過(guò) psync 命令進(jìn)行全量復(fù)制的過(guò)程如下:
- 從節(jié)點(diǎn)判斷無(wú)法進(jìn)行部分復(fù)制,向主節(jié)點(diǎn)發(fā)送全量復(fù)制的請(qǐng)求枷莉;或從節(jié)點(diǎn)發(fā)送部分復(fù)制的請(qǐng)求娇昙,但主節(jié)點(diǎn)判斷無(wú)法進(jìn)行部分復(fù)制
- 主節(jié)點(diǎn)收到全量復(fù)制的命令后,執(zhí)行 bgsave笤妙,在后臺(tái)生成 RDB 文件冒掌,并使用一個(gè)緩沖區(qū)(稱為復(fù)制緩沖區(qū))記錄從現(xiàn)在開(kāi)始執(zhí)行的所有寫命令
- 主節(jié)點(diǎn)的 bgsave 執(zhí)行完成后,將 RDB 文件發(fā)送給從節(jié)點(diǎn)蹲盘;從節(jié)點(diǎn)首先清除自己的舊數(shù)據(jù)股毫,然后載入接收的RDB文件,將數(shù)據(jù)庫(kù)狀態(tài)更新至主節(jié)點(diǎn)執(zhí)行bgsave時(shí)的數(shù)據(jù)庫(kù)狀態(tài)
- 主節(jié)點(diǎn)將前述復(fù)制緩沖區(qū)中的所有寫命令發(fā)送給從節(jié)點(diǎn)召衔,從節(jié)點(diǎn)執(zhí)行這些寫命令铃诬,將數(shù)據(jù)庫(kù)狀態(tài)更新至主節(jié)點(diǎn)的最新?tīng)顟B(tài)
- 如果從節(jié)點(diǎn)開(kāi)啟了AOF,則會(huì)觸發(fā) bgrewriteaof 的執(zhí)行苍凛,從而保證AOF文件更新至主節(jié)點(diǎn)的最新?tīng)顟B(tài)
通過(guò)全量復(fù)制的過(guò)程可以看出趣席,全量復(fù)制是非常重型的操作:
- 主節(jié)點(diǎn)通過(guò) bgsave 命令 fork 子進(jìn)程進(jìn)行 RDB 持久化,該過(guò)程是非常消耗 CPU醇蝴、內(nèi)存(頁(yè)表復(fù)制)宣肚、硬盤 IO 的;關(guān)于 bgsave 的性能問(wèn)題
- 主節(jié)點(diǎn)通過(guò)網(wǎng)絡(luò)將 RDB 文件發(fā)送給從節(jié)點(diǎn)悠栓,對(duì)主從節(jié)點(diǎn)的帶寬都會(huì)帶來(lái)很大的消耗
- 從節(jié)點(diǎn)清空老數(shù)據(jù)霉涨、載入新 RDB 文件的過(guò)程是阻塞的,無(wú)法響應(yīng)客戶端的命令惭适;如果從節(jié)點(diǎn)執(zhí)行 bgrewriteaof笙瑟,也會(huì)帶來(lái)額外的消耗
2)部分復(fù)制
由于全量復(fù)制在主節(jié)點(diǎn)數(shù)據(jù)量較大時(shí)效率太低,因此 Redis2.8 開(kāi)始提供部分復(fù)制癞志,用于處理網(wǎng)絡(luò)中斷時(shí)的數(shù)據(jù)同步往枷。
部分復(fù)制的實(shí)現(xiàn),依賴于三個(gè)重要的概念:
-
復(fù)制偏移量
- 主節(jié)點(diǎn)和從節(jié)點(diǎn)分別維護(hù)一個(gè)復(fù)制偏移量(offset)今阳,代表的是主節(jié)點(diǎn)向從節(jié)點(diǎn)傳遞的字節(jié)數(shù)师溅;主節(jié)點(diǎn)每次向從節(jié)點(diǎn)傳播N個(gè)字節(jié)數(shù)據(jù)時(shí),主節(jié)點(diǎn)的 offset 增加N盾舌;從節(jié)點(diǎn)每次收到主節(jié)點(diǎn)傳來(lái)的N個(gè)字節(jié)數(shù)據(jù)時(shí),從節(jié)點(diǎn)的 offset 增加N蘸鲸。
- offset 用于判斷主從節(jié)點(diǎn)的數(shù)據(jù)庫(kù)狀態(tài)是否一致:如果二者 offset 相同妖谴,則一致;如果 offset 不同,則不一致膝舅,此時(shí)可以根據(jù)兩個(gè) offset 找出從節(jié)點(diǎn)缺少的那部分?jǐn)?shù)據(jù)嗡载。例如,如果主節(jié)點(diǎn)的 offset 是1000仍稀,而從節(jié)點(diǎn)的 offset 是500洼滚,那么部分復(fù)制就需要將 offset 為501-1000的數(shù)據(jù)傳遞給從節(jié)點(diǎn)。
-
復(fù)制積壓緩沖區(qū)
- 復(fù)制積壓緩沖區(qū)是由主節(jié)點(diǎn)維護(hù)的技潘、固定長(zhǎng)度的遥巴、先進(jìn)先出(FIFO)隊(duì)列,默認(rèn)大小1MB享幽;當(dāng)主節(jié)點(diǎn)開(kāi)始有從節(jié)點(diǎn)時(shí)創(chuàng)建铲掐,其作用是備份主節(jié)點(diǎn)最近發(fā)送給從節(jié)點(diǎn)的數(shù)據(jù)。注意值桩,無(wú)論主節(jié)點(diǎn)有一個(gè)還是多個(gè)從節(jié)點(diǎn)摆霉,都只需要一個(gè)復(fù)制積壓緩沖區(qū)。
- 在命令傳播階段奔坟,主節(jié)點(diǎn)除了將寫命令發(fā)送給從節(jié)點(diǎn)携栋,還會(huì)發(fā)送一份給復(fù)制積壓緩沖區(qū),作為寫命令的備份咳秉;除了存儲(chǔ)寫命令婉支,復(fù)制積壓緩沖區(qū)中還存儲(chǔ)了其中的每個(gè)字節(jié)對(duì)應(yīng)的復(fù)制偏移量(offset)。由于復(fù)制積壓緩沖區(qū)定長(zhǎng)且是先進(jìn)先出滴某,所以它保存的是主節(jié)點(diǎn)最近執(zhí)行的寫命令磅摹;時(shí)間較早的寫命令會(huì)被擠出緩沖區(qū)。
- 由于該緩沖區(qū)長(zhǎng)度固定且有限霎奢,因此可以備份的寫命令也有限户誓,當(dāng)主從節(jié)點(diǎn) offset 的差距過(guò)大超過(guò)緩沖區(qū)長(zhǎng)度時(shí),將無(wú)法執(zhí)行部分復(fù)制幕侠,只能執(zhí)行全量復(fù)制帝美。反過(guò)來(lái)說(shuō),為了提高網(wǎng)絡(luò)中斷時(shí)部分復(fù)制執(zhí)行的概率晤硕,可以根據(jù)需要增大復(fù)制積壓緩沖區(qū)的大小(通過(guò)配置 repl-backlog-size)悼潭;例如如果網(wǎng)絡(luò)中斷的平均時(shí)間是60s,而主節(jié)點(diǎn)平均每秒產(chǎn)生的寫命令(特定協(xié)議格式)所占的字節(jié)數(shù)為100KB舞箍,則復(fù)制積壓緩沖區(qū)的平均需求為 6MB舰褪,保險(xiǎn)起見(jiàn),可以設(shè)置為12MB疏橄,來(lái)保證絕大多數(shù)斷線情況都可以使用部分復(fù)制占拍。
- 從節(jié)點(diǎn)將 offset 發(fā)送給主節(jié)點(diǎn)后略就,主節(jié)點(diǎn)根據(jù) offset 和緩沖區(qū)大小決定能否執(zhí)行部分復(fù)制:
- 如果 offset 偏移量之后的數(shù)據(jù),仍然都在復(fù)制積壓緩沖區(qū)里晃酒,則執(zhí)行部分復(fù)制表牢;
- 如果 offset 偏移量之后的數(shù)據(jù)已不在復(fù)制積壓緩沖區(qū)中(數(shù)據(jù)已被擠出),則執(zhí)行全量復(fù)制贝次。
-
服務(wù)器運(yùn)行 ID(runid)
- 每個(gè) Redis 節(jié)點(diǎn)(無(wú)論主從)崔兴,在啟動(dòng)時(shí)都會(huì)自動(dòng)生成一個(gè)隨機(jī)ID(每次啟動(dòng)都不一樣),由40個(gè)隨機(jī)的十六進(jìn)制字符組成蛔翅;runid 用來(lái)唯一識(shí)別一個(gè) Redis 節(jié)點(diǎn)敲茄。通過(guò) info Server 命令,可以查看節(jié)點(diǎn)的 runid
- 主從節(jié)點(diǎn)初次復(fù)制時(shí)搁宾,主節(jié)點(diǎn)將自己的 runid 發(fā)送給從節(jié)點(diǎn)折汞,從節(jié)點(diǎn)將這個(gè) runid 保存起來(lái);當(dāng)斷線重連時(shí)盖腿,從節(jié)點(diǎn)會(huì)將這個(gè) runid 發(fā)送給主節(jié)點(diǎn)爽待;主節(jié)點(diǎn)根據(jù) runid 判斷能否進(jìn)行部分復(fù)制:
- 如果從節(jié)點(diǎn)保存的 runid 與主節(jié)點(diǎn)現(xiàn)在的 runid 相同,說(shuō)明主從節(jié)點(diǎn)之前同步過(guò)翩腐,主節(jié)點(diǎn)會(huì)繼續(xù)嘗試使用部分復(fù)制(到底能不能部分復(fù)制還要看 offset 和復(fù)制積壓緩沖區(qū)的情況)鸟款;
- 如果從節(jié)點(diǎn)保存的 runid 與主節(jié)點(diǎn)現(xiàn)在的 runid 不同,說(shuō)明從節(jié)點(diǎn)在斷線前同步的 Redis 節(jié)點(diǎn)并不是當(dāng)前的主節(jié)點(diǎn)茂卦,只能進(jìn)行全量復(fù)制何什。
5.1.1.3、命令傳播階段
數(shù)據(jù)同步階段完成后等龙,主從節(jié)點(diǎn)進(jìn)入命令傳播階段处渣;在這個(gè)階段主節(jié)點(diǎn)將自己執(zhí)行的寫命令發(fā)送給從節(jié)點(diǎn),從節(jié)點(diǎn)接收命令并執(zhí)行蛛砰,從而保證主從節(jié)點(diǎn)數(shù)據(jù)的一致性罐栈。
在命令傳播階段,除了發(fā)送寫命令泥畅,主從節(jié)點(diǎn)還維持著心跳機(jī)制:PING 和 REPLCONF ACK荠诬。
5.1.2、主從復(fù)制面臨的問(wèn)題
- 一旦 主節(jié)點(diǎn)宕機(jī)位仁,從節(jié)點(diǎn) 晉升成 主節(jié)點(diǎn)柑贞,同時(shí)需要修改 應(yīng)用方 的 主節(jié)點(diǎn)地址,還需要命令所有 從節(jié)點(diǎn) 去 復(fù)制 新的主節(jié)點(diǎn)聂抢,整個(gè)過(guò)程需要 人工干預(yù)钧嘶。
- 主節(jié)點(diǎn) 的 寫能力 受到 單機(jī)的限制。
- 主節(jié)點(diǎn) 的 存儲(chǔ)能力 受到 單機(jī)的限制琳疏。
-
原生復(fù)制 的弊端在早期的版本中也會(huì)比較突出康辑,比如:
Redis
復(fù)制中斷 后摄欲,從節(jié)點(diǎn) 會(huì)發(fā)起psync
轿亮。此時(shí)如果 同步不成功疮薇,則會(huì)進(jìn)行 全量同步,主庫(kù) 執(zhí)行 全量備份 的同時(shí)我注,可能會(huì)造成毫秒或秒級(jí)的 卡頓按咒。
5.2、Redis Sentinel 的高可用
5.2.1但骨、Redis Sentinel的架構(gòu)
當(dāng)主節(jié)點(diǎn)出現(xiàn)故障時(shí)励七,Redis Sentinel 能自動(dòng)完成故障發(fā)現(xiàn)和故障轉(zhuǎn)移,并通知應(yīng)用方奔缠,從而實(shí)現(xiàn)真正的高可用掠抬。Redis Sentine 是一個(gè)分布式架構(gòu),其中包含若干個(gè) Sentinel 節(jié)點(diǎn)和 Redis 數(shù)據(jù)節(jié)點(diǎn)校哎,每個(gè) Sentinel 節(jié)點(diǎn)會(huì)對(duì)數(shù)據(jù)節(jié)點(diǎn)和其余Sentinel 節(jié)點(diǎn)進(jìn)行監(jiān)控两波,當(dāng)它發(fā)現(xiàn)節(jié)點(diǎn)不可達(dá)時(shí),會(huì)對(duì)節(jié)點(diǎn)做下線標(biāo)識(shí)闷哆。如果被標(biāo)識(shí)的是“主節(jié)點(diǎn)”腰奋,它還會(huì)和其他的Sentinel 節(jié)點(diǎn)進(jìn)行“協(xié)商”,當(dāng)大多數(shù) Sentinel 節(jié)點(diǎn)都認(rèn)為主節(jié)點(diǎn)不可達(dá)時(shí)抱怔,它們會(huì)選舉一個(gè) Sentinel 節(jié)點(diǎn)來(lái)完成自動(dòng)故障轉(zhuǎn)移的工作劣坊,同時(shí)會(huì)將這個(gè)變化實(shí)時(shí)通知給 Redis 應(yīng)用方。整個(gè)過(guò)程是自動(dòng)的屈留,不需要人工干預(yù)局冰,解決了 Redis 的高可用問(wèn)題。
5.2.2灌危、Redis Sentinel 功能
Sentinel
的主要功能包括 主節(jié)點(diǎn)存活檢測(cè)康二、主從運(yùn)行情況檢測(cè)、自動(dòng)故障轉(zhuǎn)移 (failover
)乍狐、主從切換赠摇。Redis
的 Sentinel
最小配置是 一主一從。
Redis
的 Sentinel
系統(tǒng)可以用來(lái)管理多個(gè) Redis
服務(wù)器浅蚪,該系統(tǒng)可以執(zhí)行以下四個(gè)任務(wù):
- 監(jiān)控
Sentinel
會(huì)不斷的檢查 主服務(wù)器 和 從服務(wù)器 是否正常運(yùn)行藕帜。
- 通知
當(dāng)被監(jiān)控的某個(gè) Redis
服務(wù)器出現(xiàn)問(wèn)題,Sentinel
通過(guò) API
腳本 向 管理員 或者其他的 應(yīng)用程序 發(fā)送通知惜傲。
- 自動(dòng)故障轉(zhuǎn)移
當(dāng) 主節(jié)點(diǎn) 不能正常工作時(shí)洽故,Sentinel
會(huì)開(kāi)始一次 自動(dòng)的 故障轉(zhuǎn)移操作,它會(huì)將與 失效主節(jié)點(diǎn) 是 主從關(guān)系 的其中一個(gè) 從節(jié)點(diǎn) 升級(jí)為新的 主節(jié)點(diǎn)盗誊,并且將其他的 從節(jié)點(diǎn) 指向 新的主節(jié)點(diǎn)时甚。
- 配置提供者
在 Redis Sentinel
模式下隘弊,客戶端應(yīng)用 在初始化時(shí)連接的是 Sentinel
節(jié)點(diǎn)集合,從中獲取 主節(jié)點(diǎn) 的信息荒适。
5.2.3梨熙、Redis Sentinel 核心知識(shí)
- 哨兵至少需要3個(gè)實(shí)例,來(lái)保證自己的健壯性
- 哨兵 + redis 主從的部署架構(gòu)刀诬,是不會(huì)保證數(shù)據(jù)零丟失的咽扇,只能保證 redis 集群的高可用性
- 對(duì)于哨兵 + redis 主從這種復(fù)雜的部署架構(gòu),盡量在測(cè)試環(huán)境和生產(chǎn)環(huán)境陕壹,都進(jìn)行充足的測(cè)試和演練
5.2.4质欲、Redis Sentinel 的工作原理
Redis Sentinel 通過(guò)三個(gè)定時(shí)監(jiān)控任務(wù)完成對(duì)各個(gè)節(jié)點(diǎn)的發(fā)現(xiàn)和監(jiān)控:
-
每秒鐘,每個(gè)
Sentinel
向它所知的 主服務(wù)器糠馆、從服務(wù)器 以及其他Sentinel
實(shí)例 發(fā)送一次PING
命令嘶伟。(這個(gè)定時(shí)任務(wù)是節(jié)點(diǎn)失敗判定的重要依據(jù),實(shí)現(xiàn)了對(duì)每個(gè)節(jié)點(diǎn)的監(jiān)控)- 如果一個(gè) 實(shí)例(
instance
)距離 最后一次 有效回復(fù)PING
命令的時(shí)間超過(guò)down-after-milliseconds
所指定的值又碌,那么這個(gè)實(shí)例會(huì)被Sentinel
標(biāo)記為 主觀下線九昧。 - 如果一個(gè) 主服務(wù)器 被標(biāo)記為 主觀下線,那么正在 監(jiān)視 這個(gè) 主服務(wù)器 的所有
Sentinel
節(jié)點(diǎn)赠橙,要以 每秒一次的頻率確認(rèn) 主服務(wù)器 的確進(jìn)入了 主觀下線 狀態(tài)耽装。 - 如果一個(gè) 主服務(wù)器 被標(biāo)記為 主觀下線,并且有 足夠數(shù)量 的
Sentinel
(至少要達(dá)到 配置文件 指定的數(shù)量)在指定的 時(shí)間范圍 內(nèi)同意這一判斷期揪,那么這個(gè) 主服務(wù)器 被標(biāo)記為 客觀下線掉奄。
- 如果一個(gè) 實(shí)例(
- 每隔10秒,每個(gè)
Sentinel
會(huì)向它已知的所有 主服務(wù)器 和 從服務(wù)器 發(fā)送一次INFO
命令獲取最新的拓?fù)浣Y(jié)構(gòu)凤薛。當(dāng)一個(gè) 主服務(wù)器 被Sentinel
標(biāo)記為 客觀下線 時(shí)姓建,Sentinel
向 下線主服務(wù)器 的所有 從服務(wù)器 發(fā)送INFO
命令的頻率,會(huì)從10
秒一次改為 每秒一次缤苫。
-
每隔2秒速兔,每個(gè) Sentinel 節(jié)點(diǎn)會(huì)向 Redis 數(shù)據(jù)節(jié)點(diǎn)的 sentinel:hello 頻道上發(fā)送該 Senitnel 節(jié)點(diǎn)對(duì)于主節(jié)點(diǎn)的判斷,以及當(dāng)前 Sentinel 節(jié)點(diǎn)的信息活玲,同時(shí)每個(gè) Sentinel 節(jié)點(diǎn)也會(huì)訂閱該頻道涣狗,來(lái)了解其他 Sentinel 節(jié)點(diǎn)以及他們對(duì)主節(jié)點(diǎn)的判斷。這個(gè)定時(shí)任務(wù)可以完成以下兩個(gè)工作:
- 發(fā)現(xiàn)新的 Sentinel 節(jié)點(diǎn):通過(guò)訂閱主節(jié)點(diǎn)的 Sentinel:hello 了解其他 Sentinel 節(jié)點(diǎn)信息舒憾。如果是新加入的 Sentinel 節(jié)點(diǎn)镀钓,將該 Sentinel 節(jié)點(diǎn)信息保存起來(lái),并與該 Sentinel 節(jié)點(diǎn)創(chuàng)建連接
- Sentinel 節(jié)點(diǎn)之間交換主節(jié)點(diǎn)狀態(tài)镀迂,作為后面客觀下線以及領(lǐng)導(dǎo)者選舉的依據(jù)丁溅。
5.3、Redis 集群
Redis 的哨兵模式基本已經(jīng)可以實(shí)現(xiàn)高可用探遵,讀寫分離 窟赏,但是在這種模式下每臺(tái) Redis 服務(wù)器都存儲(chǔ)相同的數(shù)據(jù)妓柜,很浪費(fèi)內(nèi)存,所以在redis3.0上加入了 Cluster 集群模式涯穷,實(shí)現(xiàn)了 Redis 的分布式存儲(chǔ)棍掐,對(duì)數(shù)據(jù)進(jìn)行分片,也就是說(shuō)每臺(tái) Redis 節(jié)點(diǎn)上存儲(chǔ)不同的內(nèi)容求豫;
在 Redis 的每一個(gè)節(jié)點(diǎn)上塌衰,都有這么兩個(gè)東西,一個(gè)是插槽(slot)蝠嘉,它的的取值范圍是:0-16383,還有一個(gè)就是cluster杯巨,可以理解為是一個(gè)集群管理的插件蚤告,類似哨兵。
當(dāng)我們的存取的 Key到達(dá)的時(shí)候服爷,Redis 會(huì)根據(jù) crc16的算法對(duì)計(jì)算后得出一個(gè)結(jié)果杜恰,然后把結(jié)果和16384 求余數(shù),這樣每個(gè) key 都會(huì)對(duì)應(yīng)一個(gè)編號(hào)在 0-16383 之間的哈希槽仍源,通過(guò)這個(gè)值心褐,去找到對(duì)應(yīng)的插槽所對(duì)應(yīng)的節(jié)點(diǎn),然后直接自動(dòng)跳轉(zhuǎn)到這個(gè)對(duì)應(yīng)的節(jié)點(diǎn)上進(jìn)行存取操作笼踩。
當(dāng)數(shù)據(jù)寫入到對(duì)應(yīng)的master節(jié)點(diǎn)后逗爹,這個(gè)數(shù)據(jù)會(huì)同步給這個(gè)master對(duì)應(yīng)的所有slave節(jié)點(diǎn)。
為了保證高可用嚎于,redis-cluster集群引入了主從模式掘而,一個(gè)主節(jié)點(diǎn)對(duì)應(yīng)一個(gè)或者多個(gè)從節(jié)點(diǎn)。當(dāng)其它主節(jié)點(diǎn)ping主節(jié)點(diǎn)master 1 時(shí)于购,如果半數(shù)以上的主節(jié)點(diǎn)與 master 1 通信超時(shí)袍睡,那么認(rèn)為master 1宕機(jī)了,就會(huì)啟用master 1的從節(jié)點(diǎn)slave 1肋僧,將slave 1變成主節(jié)點(diǎn)繼續(xù)提供服務(wù)斑胜。
如果master 1和它的從節(jié)點(diǎn)slave 1都宕機(jī)了,整個(gè)集群就會(huì)進(jìn)入fail狀態(tài)嫌吠,因?yàn)榧旱膕lot映射不完整止潘。如果集群超過(guò)半數(shù)以上的master掛掉,無(wú)論是否有slave居兆,集群都會(huì)進(jìn)入fail狀態(tài)覆山。
redis-cluster采用去中心化的思想,沒(méi)有中心節(jié)點(diǎn)的說(shuō)法泥栖,客戶端與Redis節(jié)點(diǎn)直連簇宽,不需要中間代理層勋篓,客戶端不需要連接集群所有節(jié)點(diǎn),連接集群中任何一個(gè)可用節(jié)點(diǎn)即可魏割。
5.4譬嚣、總結(jié)
主從模式:master節(jié)點(diǎn)掛掉后,需要手動(dòng)指定新的master钞它,可用性不高拜银,基本不用。
哨兵模式:master節(jié)點(diǎn)掛掉后遭垛,哨兵進(jìn)程會(huì)主動(dòng)選舉新的master尼桶,可用性高,但是每個(gè)節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)是一樣的锯仪,浪費(fèi)內(nèi)存空間泵督。數(shù)據(jù)量不是很多,集群規(guī)模不是很大庶喜,需要自動(dòng)容錯(cuò)容災(zāi)的時(shí)候使用小腊。
集群模式:數(shù)據(jù)量比較大,QPS要求較高的時(shí)候使用久窟。 Redis Cluster是Redis 3.0以后才正式推出秩冈,時(shí)間較晚,目前能證明在大規(guī)模生產(chǎn)環(huán)境下成功的案例還不是很多斥扛,需要時(shí)間檢驗(yàn)入问。
六、參考來(lái)源
redis 系列之——高可用(主從犹赖、哨兵队他、集群)
深入剖析Redis系列(二) - Redis哨兵模式與高可用集群