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