本篇文章從以下幾個(gè)方面介紹一下Redis哲思。
1卦溢、Redis數(shù)據(jù)類型
2、Redis持久化
3泵殴、Redis集群
4涮帘、Redis常見問題
前言:
Redis是基于內(nèi)存的非關(guān)系型數(shù)據(jù)庫,一般是簡單的存取操作笑诅,時(shí)間主要花費(fèi)在I/O上调缨,所以讀取速度快。Redis使用非阻塞I/O吆你,I/O多路復(fù)用弦叶,使用單線程來輪詢描述符,將數(shù)據(jù)庫的開妇多、關(guān)湾蔓、讀、寫都轉(zhuǎn)換成事件砌梆,減少線程切換上下文的時(shí)間默责。此外,Redis全程使用hash結(jié)構(gòu)咸包,讀取速度快桃序。
一、Redis數(shù)據(jù)結(jié)構(gòu)
String類型烂瘫,可以是字符串媒熊、整數(shù)、浮點(diǎn)數(shù)坟比,可對字符串或字符串的一部分進(jìn)行操作芦鳍,對整數(shù)和浮點(diǎn)數(shù)執(zhí)行自增或自減操作。
List類型葛账,一個(gè)鏈表柠衅,鏈表上每個(gè)節(jié)點(diǎn)都包含一個(gè)字符串。從鏈表的兩端推入或彈出籍琳;根據(jù)偏移量對鏈表進(jìn)行修剪菲宴;讀取單個(gè)或多個(gè)元素贷祈;根據(jù)值查找或移除元素。
Set類型喝峦,包含字符串的無序收集器势誊,并且被包含的每個(gè)字符串都是獨(dú)一無二各不相同的。添加谣蠢、獲取粟耻、移除單個(gè)元素,檢查一個(gè)元素是否存在集合中眉踱,計(jì)算交集挤忙、并集、差集勋锤,從集合中隨機(jī)獲取元素。
Hash類型侥祭,包含鍵值對的無序散列表叁执,添加、獲取矮冬、移除單個(gè)鍵值對谈宛,獲取所有鍵值對。
Zset類型胎署,字符串成員和浮點(diǎn)數(shù)分值之間的有序映射吆录,元素的排列順序由分值的大小決定。添加琼牧、獲取恢筝、刪除單個(gè)元素,根據(jù)分值范圍或成員來獲取元素巨坊。
二撬槽、Redis持久化
Redis提供兩種持久化方式:快照(RDB文件)和追加式文件(AOF文件)
RDB:會(huì)在特定的時(shí)間間隔保存那個(gè)時(shí)間點(diǎn)的數(shù)據(jù)快照。原理:redis調(diào)用fork()方法趾撵,產(chǎn)出一個(gè)子進(jìn)程講數(shù)據(jù)寫到臨時(shí)RDB文件侄柔,更新后替換舊的RDB文件。 優(yōu)點(diǎn):單文件占调、適合做備份暂题;主進(jìn)程不會(huì)有I/O操作;數(shù)據(jù)量大時(shí)究珊,啟動(dòng)快薪者。 缺點(diǎn):容易造成數(shù)據(jù)丟失(當(dāng)服務(wù)器在持久化之前掛掉,那掛掉瞬間到上次持久化這段時(shí)間的數(shù)據(jù)就丟失了)剿涮、數(shù)據(jù)量很大時(shí)啸胧,會(huì)造成redis服務(wù)停止
AOF:每次有更新或?qū)懖僮鞲险荆苯訉⒉僮髯芳拥紸OF文件末尾,當(dāng)文件達(dá)到一定大小纺念,會(huì)優(yōu)化文件贝椿,對命令進(jìn)行匯集,減小文件大小陷谱。 優(yōu)點(diǎn):比RDB可靠烙博,可制定不同的同步策略。 缺點(diǎn):相同數(shù)據(jù)集下烟逊,AOF文件更大渣窜;某些同步策略下,AOF速度比RDB慢宪躯。
三乔宿、Redis集群
集群的設(shè)計(jì),旨在為適應(yīng)高并發(fā)高吞吐量場景設(shè)計(jì)访雪,大多數(shù)業(yè)務(wù)場景下都是讀操作详瑞,redis集群可由子節(jié)點(diǎn)分擔(dān)訪問壓力,主節(jié)點(diǎn)處理更新和寫操作臣缀,再同步給子節(jié)點(diǎn)坝橡。
數(shù)據(jù)分區(qū):當(dāng)數(shù)據(jù)量十分巨大,單節(jié)點(diǎn)無法承載時(shí)精置,可使用數(shù)據(jù)分片來實(shí)現(xiàn)计寇。一個(gè)集群包含16384個(gè)哈希槽,每一臺(tái)主節(jié)點(diǎn)機(jī)器分配一個(gè)范圍脂倦,使用CRC(key)%16384來計(jì)算鍵屬于那個(gè)槽番宁。同時(shí)redis客戶端在訪問后也會(huì)緩存一個(gè)哈希糟與節(jié)點(diǎn)IP的映射表,以提高訪問速度赖阻。當(dāng)集群要擴(kuò)容時(shí)贝淤,集群會(huì)停止服務(wù),通過配置表重新分配哈希槽政供,再轉(zhuǎn)移數(shù)據(jù)播聪,擴(kuò)容完畢,集群恢復(fù)可用(故建議在凌晨訪問量低的情況下進(jìn)行擴(kuò)容)布隔。
容錯(cuò)機(jī)制:redis提供了每個(gè)節(jié)點(diǎn)之間放松ping命令以測試健康狀態(tài)的機(jī)制离陶。當(dāng)子節(jié)點(diǎn)向主節(jié)點(diǎn)發(fā)送ping命令沒有得到pong返回是,子節(jié)點(diǎn)會(huì)通知其他節(jié)點(diǎn)給主節(jié)點(diǎn)方式ping衅檀。如果集群超過半數(shù)節(jié)點(diǎn)給主節(jié)點(diǎn)發(fā)送ping都沒有得到返回招刨,坐實(shí)主節(jié)點(diǎn)掛掉,立馬啟動(dòng)備份服務(wù)器哀军。
主從復(fù)制:為了使得集群在一部分節(jié)點(diǎn)無法與集群大多數(shù)節(jié)點(diǎn)通訊的情況下仍然運(yùn)作沉眶,集群中的每一個(gè)節(jié)點(diǎn)都有1到N個(gè)復(fù)制打却。主節(jié)點(diǎn)會(huì)把數(shù)據(jù)同步給子節(jié)點(diǎn),但是在同步數(shù)據(jù)之前谎倔,主節(jié)點(diǎn)就掛掉了柳击,未同步的數(shù)據(jù)就會(huì)丟失。對于追求高可用性這點(diǎn)片习,redis并不合適捌肴,同時(shí)redis只保證最終一致性。
四藕咏、Redis常見問題
1状知、緩存雪崩:指緩存集中失效,全部的請求都訪問到數(shù)據(jù)庫孽查,導(dǎo)致數(shù)據(jù)庫崩潰饥悴。
緩存集中失效,是因?yàn)榫彺鏀?shù)據(jù)設(shè)置了相同的過期時(shí)間盲再,導(dǎo)致redis將這部分?jǐn)?shù)據(jù)全部刪光西设。這里可以設(shè)置一下redis對過期鍵的策略,主要有惰性刪除和定期刪除洲胖。定期刪除其實(shí)很難做到济榨,以為當(dāng)數(shù)據(jù)量大時(shí)坯沪,redis不可能一直去遍歷所有的鍵绿映,判斷是否過期再刪除掉。所以設(shè)置定期刪除腐晾,會(huì)限制執(zhí)行時(shí)長和頻率叉弦。惰性刪除,主要是在取鍵的時(shí)候藻糖,判斷該鍵是否過期淹冰,過期則刪除。
預(yù)防雪崩問題:①給過期時(shí)間添加一個(gè)隨機(jī)值 ②設(shè)置本地緩存+限流(hystrix)③設(shè)置redis集群巨柒,避免單機(jī)
2樱拴、緩存穿透:指未命中緩存,導(dǎo)致請求訪問到數(shù)據(jù)庫洋满。
預(yù)防穿透問題:①過濾不合法請求 ②數(shù)據(jù)庫查詢?yōu)榭諘r(shí)晶乔,也存儲(chǔ)到緩存
3、緩存與數(shù)據(jù)庫雙寫一致
在做更新操作時(shí)牺勾,數(shù)據(jù)庫與緩存數(shù)據(jù)不一致
①先刪除緩存后更新數(shù)據(jù)庫正罢。
線程A刪除緩存,線程B查詢緩存驻民,發(fā)現(xiàn)不存在翻具,查詢數(shù)據(jù)庫得到舊值履怯,線程B寫入緩存,線程A寫入數(shù)據(jù)庫裆泳。解決思路叹洲,將刪除緩存、修改數(shù)據(jù)庫晾虑、讀緩存等操作積壓到對列疹味,實(shí)現(xiàn)串行化。
②先更新數(shù)據(jù)庫后刪除緩存帜篇。
緩存剛好失效糙捺,線程A查詢數(shù)據(jù)庫,得到一個(gè)舊值笙隙,線程B將新值寫入數(shù)據(jù)庫洪灯,線程B刪除緩存,線程A將舊值寫入緩存竟痰。解決思路签钩,將要?jiǎng)h除的key放到消息隊(duì)列,重試直到成功坏快。
總結(jié)
這部分知識其實(shí)在團(tuán)隊(duì)里就整理過铅檩,還做了分享,當(dāng)初對集群莽鸿、一致性還是懵懵懂懂的∶林迹現(xiàn)在再看,特別是配合raft協(xié)議祥得、zab協(xié)議兔沃,對redis的局限性有了更深一點(diǎn)的認(rèn)知。
參考:
1级及、《Redis實(shí)戰(zhàn)》
2乒疏、Java3y