一文聊聊 Redis 的緩存場景
序言
夏日炎炎,無風(fēng)。從空調(diào)房間出來,再到接近四十度的高溫,這個過程,緩存預(yù)熱了解一下……
為什么要用緩存?因為追求性能,因為要追求極致的用戶體驗。
緩存理論
1、緩存適合的場景
緩存,就是將一些需要讀取數(shù)據(jù)放在磁盤或者內(nèi)存中,由于是追求速度,從而一般放在內(nèi)存中。
在讀取數(shù)據(jù)的時候,一般是從關(guān)系型數(shù)據(jù)庫中讀取數(shù)據(jù),在數(shù)據(jù)庫層面也可以進(jìn)行各種優(yōu)化,例如讀性能不足,那么可以添加幾個從庫,從而數(shù)據(jù)庫的一主多從;例如寫性能不足,那么可以分庫分表。
在有些場景中,要使用緩存,是因為無法解決讀的速度,例如count(*)
的操作,無論從數(shù)據(jù)庫的層面如何優(yōu)化,都不可能提高;還有一種就是sql的執(zhí)行本身就必須消耗很多資源和時間,例如各種關(guān)聯(lián)查詢子查詢,這些時候,都可以將這些數(shù)據(jù)放在緩存當(dāng)中,從而大大的減輕數(shù)據(jù)庫的壓力。
2、緩存穿透問題
在使用緩存的時候,第一個問題就是緩存穿透的問題,就是使用了緩存和沒使用緩存是一樣的,應(yīng)用程序到緩存中查詢數(shù)據(jù),發(fā)現(xiàn)數(shù)據(jù)么有,那么就去數(shù)據(jù)庫查詢,在這里,穿透了緩存,緩存沒起到保護數(shù)據(jù)庫的作用。
在爬蟲爬取網(wǎng)頁的時候,每個分頁都會爬取,而對于緩存的分頁數(shù)據(jù),一般只緩存了熱點數(shù)據(jù),也就是前幾頁的數(shù)據(jù)在緩存當(dāng)中,如果全部爬取,那么就會造成緩存不命中,導(dǎo)致查詢數(shù)據(jù)庫;還有一種就是故意搜索一些不存在的關(guān)鍵字,而這些搜索的結(jié)果都沒有數(shù)據(jù),在數(shù)據(jù)庫中也不存在數(shù)據(jù),從而造成緩存穿透。
此種解決方法就是:當(dāng)用戶進(jìn)行第一次查詢的時候發(fā)現(xiàn)結(jié)果為空,那么可以將結(jié)果放在緩存中,設(shè)置一個短暫的過期時間,從而可以緩解穿透的問題;而對于爬蟲的爬取數(shù)據(jù),只能進(jìn)行監(jiān)控,然后進(jìn)行訪問的IP,依舊只能緩解,不能完全解決。
3、緩存雪崩的問題
緩存雪崩指的是當(dāng)緩存失效之后,從而引起系統(tǒng)性能的急劇下降,導(dǎo)致數(shù)據(jù)庫不可用從而系統(tǒng)掛掉。
緩存最關(guān)鍵的地方就是內(nèi)存,當(dāng)內(nèi)存滿了之后,會有各種策略將緩存進(jìn)行失效,在分布式環(huán)境下,如果有一個緩存失效,而恰好這個緩存是一個熱點數(shù)據(jù),前端有10個應(yīng)用都需要訪問這個緩存,并且TPS很高的話,那么全部的線程都會去訪問數(shù)據(jù)庫,從而能直接將數(shù)據(jù)庫拖垮。
應(yīng)對緩存雪崩,有很多策略,例如可以設(shè)置兩個緩存的key,而具有不同的失效時間,當(dāng)key1失效之后,訪問key2,然后更新key1和key2;可以使用分布式鎖,從而當(dāng)應(yīng)用發(fā)現(xiàn)緩存失效之后,拿到鎖的線程才去更新緩存;可以使用消息通知機制,當(dāng)應(yīng)用發(fā)現(xiàn)緩存失效之后,發(fā)送消息,然后后臺線程進(jìn)行更新緩存,后臺線程會檢測緩存中是否存在緩存,如果存在就不更新;專門用一個后臺線程來更新緩存,快速的檢測緩存是否存在,然后更新緩存,此種也可以解決緩存不一致的問題。
4、緩存命名和失效時間
在使用緩存的時候,都需要一個key,那么這個key怎么命名呢?key太長,占用內(nèi)存,會使得緩存中能存儲的數(shù)據(jù)減少;key一般的命名規(guī)則可以為SQL:1782,表示為這是緩存一個sql的結(jié)果,然后用冒號分割,然后表示為緩存的編號,可以為各種sql條件的hash后的結(jié)果,這種命名規(guī)則的好處就是,在每次在緩存里查詢的時候,可以使用通配符,從而可以查詢到有多少個緩存在系統(tǒng)中。
緩存的失效時間,這個和業(yè)務(wù)強相關(guān),對于一些時效性比較高的數(shù)據(jù),就不能放在緩存當(dāng)中,而對于一些不經(jīng)常變化的數(shù)據(jù),可以放在緩存當(dāng)中,例如一天,緩存主要是應(yīng)對讀多寫上的應(yīng)用,從而大部分的數(shù)據(jù)例如在搜索的結(jié)果的分頁數(shù)據(jù),這種實時性無須太高,可以放在緩存當(dāng)中。。。主要看業(yè)務(wù)的容忍程度,也影響到一部分的用戶體驗,可能我放入了緩存,更新了,刷新下,還沒有更新。
5、緩存預(yù)熱和緩存熱點問題
緩存預(yù)熱,在系統(tǒng)宕機剛上線的時候,流量全部涌入,而此時緩存中還沒有緩存數(shù)據(jù),從而可能導(dǎo)致直接壓垮數(shù)據(jù)庫,從而在應(yīng)用程序啟動之后,要進(jìn)行緩存預(yù)熱,最簡單的方法就是點點界面,然后搜索一下結(jié)果;最好的方式,就是寫一個后臺線程,進(jìn)行緩存預(yù)熱,在這個后臺線程里,會將常用的熱點數(shù)據(jù)都直接加載進(jìn)緩存當(dāng)中。
緩存熱點,當(dāng)使用的是緩存集群的時候,如果緩存分布的有問題,那么可能一臺緩存服務(wù)器承擔(dān)了大部分的壓力,而另外一些緩存服務(wù)器則沒有壓力,從而也有可能導(dǎo)致緩存雪崩,直接壓垮一臺緩存服務(wù)器,上線,又壓垮一臺,死循環(huán)。。。
在進(jìn)行緩存數(shù)據(jù)的時候,需要分析熱點數(shù)據(jù),并且要分析緩存的數(shù)據(jù)量的大小,否則無論是網(wǎng)絡(luò)還是內(nèi)存,都可能造成緩存雪崩的潛在影響點。
redis主備
reids是一個鍵值存儲的內(nèi)存cache或者持久化存儲,用redis做緩存是簡單的。而redis再此時也無需持久化機制,從而直接在容器中使用。
兩條指令運行一個redis的主從緩存,配置文件使用默認(rèn)的配置文件,在master的配置文件中修改bind即可,在slave的配置文件中,修改bind和slaveof即可。
如何來檢測這個redis是ok?用容器來運行一個測試redis的功能,執(zhí)行的效果如下所示:
專門使用一個testredis的容器來運行一個測試任務(wù),在正常的情況下,容器的退出碼為0,當(dāng)redis異常的時候,容器的退出碼為1,從而可以在生產(chǎn)中進(jìn)行功能性測試,當(dāng)然,你也可以進(jìn)行自動修復(fù),例如拉起失敗的redis容器即可。
檢測腳本的內(nèi)容:
在運行這個測試容器的時候,需要注意的是,要使用host的網(wǎng)絡(luò),如下所示:
以后要進(jìn)行運行測試容器的時候,只要start這個容器即可。
此種過程進(jìn)行優(yōu)化,例如使用一個腳本,就直接創(chuàng)建master,slave和測試容器,還能進(jìn)一步將master和slave分布在不同的機器上,還能進(jìn)一步直接創(chuàng)建sentinel進(jìn)行自動切換和故障轉(zhuǎn)移,還能直接創(chuàng)建一個redis cluster模式。
在使用config rewrite寫入配置文件的時候,注意selinux可能會阻止你寫入配置文件。
在使用的緩存策略為noeviction的時候,那么一旦可用內(nèi)存使用完畢,就會顯示OOM,內(nèi)存超過了最大使用內(nèi)存,默認(rèn)配置并不會使用LRU算法。
在查看鍵的數(shù)量的時候,切記keys是高危指令,會阻塞所有的請求,影響生產(chǎn)環(huán)境的服務(wù),不信?到生產(chǎn)上試試,指令為keys *。
在查看大量鍵的時候,使用scan指令,每次返回一個游標(biāo),相當(dāng)于分頁查看咯。
在進(jìn)行轉(zhuǎn)儲的時候,不要用save指令,切記要使用bgsave和bgrewriteaof,雖然這兩個不會阻塞服務(wù),其實也會阻塞,不過時間很短,主要耗費的時間在fork的時候,400ms了解一下。。。fork一般需要多少ms?求解
閑聊
緩存命中率?不可能的。。。這輩子都不可能命中的……
依稀記得有人挑戰(zhàn),但是我忘記了是個具體什么樣的問題。其實捍衛(wèi)不捍衛(wèi)真的無所謂,不捍衛(wèi)自己的觀點在于,暴露對方的無知,如果捍衛(wèi)我自己的觀點,那就會暴露自己的無知,當(dāng)然,一般我都是先表現(xiàn)出我的無知,這樣才能引入新奇的觀點,否則,一無所獲。
再談自動化運維,有人說,你就兩個命令的事兒,你還費勁巴拉的寫成一個界面,寫成一個按鈕,有意思么,有意思,相當(dāng)有意思。
防止誤操作,這是主要功能,自動化平臺承擔(dān)大部分責(zé)任,封裝所有的高危操作指令,可以進(jìn)行二次確認(rèn)。
權(quán)限控制,哪些人能使用這個,哪些人不能使用。
一臺機器兩個指令,三臺你試試,三百臺你試試,三千臺呢?
有的時候,感覺思維層次不同,不想解釋,解釋就是掩飾
一個緩存系統(tǒng),能玩多久?能玩很久很久。
一個系統(tǒng),里面包含著無數(shù)個小系統(tǒng),緩存系統(tǒng)?可以用redis和memcache,你怎么選?
一個系統(tǒng),里面又包含著無數(shù)的知識點,redis是單進(jìn)程單線程的服務(wù),那么那些會阻塞服務(wù)?在客戶端請求過來,tcp連接滿了怎么辦?參數(shù)backlop是否要響應(yīng)增加?
一個系統(tǒng),要追求高可用,高性能,那么就會引入其他的組件,例如使用sentinel達(dá)成高可用,使用redis cluster來進(jìn)行搭建,使用前端的各種中間件。
一個系統(tǒng)的配置,又包含了各種樣的東西,redis的持久化有兩種,一種是rdb,一種是aof,有何區(qū)別,哪種更好?如果持久化會丟失數(shù)據(jù)否?丟失多久的數(shù)據(jù)可以接受?
一個系統(tǒng)的構(gòu)成,各種各樣的方式,如何進(jìn)行主備復(fù)制?sentinel如何來檢測master是否宕機?sentinel為何要用3個或者5個節(jié)點?
子子孫孫無窮盡也,可能很多時候,都碰不到這種場景?高并發(fā),不可能的,這輩子都不可能的,風(fēng)都么有,備用知識命中率,了解一下。