如何評估數據適不適合放入Redis中?

95後程序猿小A


當項目中引入了 Redis 做分佈式緩存,那麼就會面臨這樣的問題:

  • 哪些數據應該放到緩存中?依據是什麼?
  • 緩存數據是採用主動刷新還是過期自動失效?
  • 如果採用過期自動失效,那麼失效時間如何制定?

正好這兩週我們項目做了相關的評估,把過程記錄下來和大家分享分享;當然過程中用到了很多“笨辦法”,如果你有更好的辦法,也希望能分享給我。


01. 項目背景

我們的項目是一個純服務平臺,也就是隻提供接口服務,並沒有操作頁面的,項目的接口日調用量大約在 200 萬次,高峰期也就 1000 萬出頭,因為大部分接口是面向內部系統的,所以大部分請求集中在工作日的 9 點到 21 點,高峰期的時候系統的 QPS 在 300-400 之間。


因為我們項目數據存儲使用的是 MongoDB,理論上支撐這個量級的 QPS 應該是綽綽有餘,但是我有這麼幾點觀察和考慮:

MongoDB 中雖然是整合好的數據,但是很多場景也不是單條查詢,誇張的時候一個接口可能會返回上百條數據,回參報文就有兩萬多行(不要問我能不能分頁返回......明確告訴你不能);

  • MongoDB 中雖然是整合好的數據,但是很多場景也不是單條查詢,誇張的時候一個接口可能會返回上百條數據,回參報文就有兩萬多行(不要問我能不能分頁返回......明確告訴你不能);

  • 目前項目 99.95% 的接口響應時間都在幾十到幾百毫秒,基本可以滿足業務的需要,但是還是有 0.05% 的請求會超過 1s 響應,偶爾甚至會達到 5s、10s;

  • 觀察這些響應時間長的請求,大部分時間消耗在查詢 MongoDB 上,但是當我將請求報文取出,再次手動調用接口的時候,依然是毫秒級返回;MongoDB 的配置一般,時刻都有數據更新,而且我觀察過,響應時間長的這些接口,那個時間點請求量特別大;

  • MongoDB 查詢偶爾會慢的原因我我還在確認,我現在能想到的原因比如:大量寫操作影響讀操作、鎖表、內存小於索引大小等等,暫時就認為是當時那一刻 MongoDB 有壓力;我觀察過,響應時間長的這些接口,那個時間點請求量特別大,這一點就不在這裡具體分析了。

雖然一萬次的請求只有四五次響應時間異常,但是隨著項目接入的請求越來越大,保不齊以後量變產生質變,所以還是儘量將危機扼殺在搖籃裡,所以果斷上了 Redis 做分佈式緩存。


02. 接口梳理

下一步就是對生產環境現有接口進行統計和梳理,確定哪些接口是可以放到緩存中的,所以首先要對每一個接口的調用量有大概的統計,因為沒有接入日誌平臺,所以我採用了最笨的辦法,一個一個接口的數嘛。

  • 把工作日某一天全天的日誌拉下來,我們四臺應用服務器,每天的日誌大概 1 個G,還好還好;

  • 通過 EditPlus 這個工具的【在文件中查找】的功能,查詢每個接口當天的調用量,已上線 30 個接口,有幾分鐘就統計出來了,反正是一次性的工作,索性就手動統計了;

  • 一天也調不了幾次的接口,就直接忽略掉了,我基本上只把日調用量上萬的接口都留下來,進行下一步的分析。


03. 字典表、配置類的數據

這一類的數據是最適合放在緩存中的,因為更新頻率特別低,甚至有時候 insert 了之後就再也不做 update ,如果這類數據的調用量比較大,是一定要放到 Redis 中的;

至於緩存策略,可以在更新的時候雙寫數據庫和 Redis,也可以採用自動失效的方式,當然這個失效時間可以放得比較長一些;針對我們項目,我採用的是半夜 12 點統一失效的策略,第一因為我們系統這類數據,是夜間通過 ETL 抽取過來的,每天同步一次,第二就是我們不怕緩存雪崩,沒有那麼大的訪問量,夜間更沒有什麼訪問量了。


04. 明顯是熱點數據的數據

有一類數據,很明顯就是熱點數據;

我們就有一個接口,雖然是業務數據,不過數據總量只有幾千條,但是每天的調用量大約在 40 萬,而且更新頻率不是很高,這類數據放入 Redis 中也就再適合不過了;至於緩存策略麼,因為數據也是從其他系統同步過來的,根據數據同步的時間,我們最終採用一個小時的失效時間。


05. 其餘數據的評估

其實前兩種數據很容易就能評估出來,關鍵是這類數據的評估:

  • 我們有一個接口日調用量 20-30 萬,量不大,但是查詢和處理邏輯比較複雜;

  • 基礎數據量太大,無法把所有數據都放入 Redis 中;

  • 無法把基礎數據直接放入 Redis 中,因為有多重查詢維度(條件);

  • 無法確定每條數據的調用頻率是怎麼樣的,最悲觀的結果,每條數據當天只調用一次,這樣就沒有緩存的必要了。

但是咱也不能一拍腦袋就說:“調用量挺大的,直接放到 Redis 中吧”,或者“不好評估,算了吧,別放緩存了”,做任何一個決定還是需要有依據的,於是我是這樣做的:


Step 1. 把該接口當天的所有日誌都找出來

幾十個日誌文件肯定不能一個一個翻,要麼就自己寫個程序把需要的數據扒出來,但是考慮到這個工作可能只做一次,我還是儘量節省一些時間吧。

依然使用 EditPlus 這個工具的【在文件中查找】的功能,在查詢結果框中【複製所有內容】,花了兩分鐘,就把 24 萬條日誌找出來了。


Step 2. 把數據導入到數據庫中進行下一步分析

每一條日誌大概是這樣的:

XXXX.log"(64190,95):2020-3-17 16:44:10.092 http-nio-8080-exec-5 INFO 包名.類名 : 請求參數:args1={"字段1":"XXX\

會點代碼的大叔


會話緩存

Redis最明顯的用例之一是將其用作會話緩存。與其他會話存儲(例如Memcached)相比,使用Redis的優勢在於Redis提供了持久性。儘管就一致性而言,維護高速緩存通常不是關鍵任務,但如果所有購物車會話都消失了,大多數用戶將不會完全滿意,現在他們會嗎?

幸運的是,隨著Redis多年來的發展,很容易找到有關如何正確使用Redis進行會話緩存的文檔。甚至著名的電子商務平臺Magento都有Redis的插件!

全頁緩存(FPC)

在基本會話令牌之外,Redis提供了一個非常易於操作的FPC平臺。即使在重新啟動Redis實例時,也可以恢復一致性,而磁盤持久性不會使用戶看到頁面加載速度的降低,這是非常麻煩的從類似PHP的本地FPC更改。

再次以Magento為例,Magento提供了一個插件,可將Redis用作全頁緩存後端。

同樣,對於在那裡的WordPress用戶,WordPress有一個名為wp-redis的超讚插件,可幫助您實現前所未有的最快頁面加載速度!

隊列

利用Redis的內存存儲引擎來執行列表和設置操作,使其成為用於消息隊列的絕佳平臺。對於習慣使用Redis進行推入/彈出操作與Python等編程語言中的列表進行交互的人,應該感到與Redis作為隊列進行交互。

如果您對“ Redis隊列”進行快速的Google搜索,您很快就會發現那裡有大量的開源項目,這些項目旨在使Redis成為滿足所有排隊需求的出色後端實用程序。舉例來說,Celery的後端就是使用Redis作為代理。

還有就是Redis的發佈/訂閱功能。Pub / Sub的用例確實是無限的。我見過人們將其用於社交網絡連接,基於Pub / Sub事件觸發腳本,甚至使用Redis Pub / Sub構建的聊天系統!

排行榜/計數

由於Redis在內存中,因此它在遞增和遞減方面做得非常出色。集合和排序集合在嘗試執行此類操作時也使我們的生活更輕鬆,而Redis恰好同時提供了這兩種數據結構。因此,要從排序後的集合中抽取前10名用戶(我們將其稱為“ user_scores”),只需運行以下命令即可:

ZRANGE user_scores 0 10

當然,這是假設您要按增量分數對用戶進行排名。如果您想同時返回用戶及其分數,則可以運行以下命令:

ZRANGE user_scores 0 10 WITHSCORES

Agora Games有一個使用Ruby的驚人示例,該示例使用了Redis作為其數據存儲區的排行榜,可以在此處找到。

像這些都是Redis平常常見的使用場景,如果是在這些場景下,Redis可以很好Hold機器性能並提高它,這時候你就可以選擇把數據放入到Redis去,這是一個非常明智的選擇。


大魔王Hacker


一個非常好的問題。我是工作多年的Web應用架構師,來回答一下這個問題。歡迎關注我,瞭解更多IT專業知識。


Redis是一個高性能的key-value數據庫,常用於搭建緩存系統,提高併發響應速度。除了用作緩存系統,Redis還可以用在很多業務場景中。


以最近開發的中央廚房訂單管理系統為例,在設計訂單流轉信息模塊時,使用了Redis保存當前待處理和待配送的訂單信息,流轉結束後不需要持久化保存。使用Redis優點如下:

1,支持數據恢復

如果直接將訂單流轉信息保存到內存,雖然讀寫效率高,但是有兩個問題,一是佔用不必要的內存資源,二是當服務重啟或者發生故障時,數據不能恢復,需要訂單派發系統重新發送訂單,顯然使用Redis的方案更好。

2,支持集群化擴展

為了支持服務集群化部署,服務不應該包含狀態數據。將訂單流轉信息保存到Redis中後,數據集中存放,多個服務共享Redis存儲,而且實現了數據更新時的自動同步。當生產環境中業務量增加時,Redis集群也能方便的擴展。

3,那麼使用MySQL呢?

相比MySQL,Redis是一個高性能的NoSQL數據庫,讀寫效率更高,支持高併發響應,簡單輕量,部署維護方便,更符合這個應用場景。


一個典型的Web服務數據層往往是MySQL和Redis並存的,MySQL數據庫保存持久化信息,Redis保存高頻率讀寫但是需要獨立存儲的熱數據,程序運行過程中的臨時數據則直接在內存中。需要平滑高峰期負載時,引入消息隊列,比如ActiveMQ。

常見架構示意圖如下:


急速馬力快de源碼客


非常有興趣回答這個問題。

Redis是目前最為流行的分佈式緩存的解決方案,其憑藉其出色的性能深受大家的歡迎。雖然Redis自身也提供了發佈/訂閱相應的功能,不過相對緩存來說,受歡迎程度就不那麼高了。接下來,我來回答題主問題,說明樣的數據適合放入Redis中(可以延伸到:何種類型的數據適合進行緩存處理)。

一、靜態數據

最常見的就是各種參數、字典,這類數據往往在維護後數據量就恆定了,而且在系統運行過程中基本都是查詢類型的操作。

在緩存算法方面,因為其數據量比較固定,而且不需要有過期的設定,所以這類數據不需要對其緩存算法(FIFO/LFU/LRU)有過多的要求,存下來就可以了。

在緩存策略方面,通常會選擇Cache-Aside作為這類數據的緩存策略,應用有限讀取緩存中的數據,如果數據不存在則從數據庫中進行讀取,讀取後同步到緩存當中(在應用程序中通常會通過面向切面的方式來實現)。但是Cache-Aside並不能確保緩存和數據庫的一致性(AB線程在查詢數據庫時數據發生了改變,導致A線程拿到的是a數據,B線程拿到的是b數據,那麼很難保證AB線程最後put到緩存中的數據是最後更新的數據)。此外,通常會在應用啟動時或提供人工操作的功能進行緩存預熱,來防止緩存穿透。

二、臨時數據

這一類數據最大的特點是時效性很強,並且不需要進行持久化。我們常見的Session、Token、以及各種驗證碼等。

在緩存算法方面,沒有過多要求(緩存算法基本都是在空間恆定的情況下並且有優先順序才會討論的),但是需要考慮Redis分配內存的大小,必要時可以考慮持久化或者限流。

這類數據往往是由應用程序直接對緩存進行操作的。

三、熱點數據

緩存熱點數據的特徵是併發查詢非常多,例如商品信息,這類數據是動態變化的。

在緩存算法方面,通常會使用LFU/LRU或一些相關算法作為緩存算法,除了算法本身需要斟酌外,熱點數據的定義也是一個非常值得研究的問題。

在緩存策略方面,或許Read-Through是個不錯的選擇。此外,還需要結合具體情況來制定相應防止緩存異常(穿透、擊穿、雪崩)的策略,常見的有緩存預熱、分級緩存、限流等等。


以上就是我的一個看法,關於算法和策略的選擇上需要結合實際情況進行,但是緩存本身的意義是不變的:

1、減輕數據庫壓力(讀寫分離可以分擔一些讀的壓力,但是還是遠遠不夠);

2、臨時性存儲。

基於此,評估數據是否進行緩存的核心思想以及重要指標就是:在場景中對數據的查詢操作對數據庫的影響程度。

我是一名程序員,更多內容請關注:空心小窩頭

空心小窩頭


判斷數據是否放入Redis的方法,我說下自己的理解。

Redis的特點是內存存儲,所以它主要適合的是獨立、速度快、適合頻繁訪問/修改、常作為快速緩存替代SQL。

什麼樣的數據適合放入Redis中呢?這裡沒必要扯什麼數據類型、什麼業務等等虛的概念。從它的特點中能看出,所有不適合把數據放入SQL數據庫、同時又不方便本地緩衝的場景數據,都適合放入Redis中。

因此,如果目標數據既需要高速緩存,又需要獨立存在於程序之外:比如防止服務重啟(包括且不限於升級、錯誤、重啟)等造成數據丟失,或者多個服務共享此數據,這時就可以放入Redis中。因為Redis的穩定性是可期的,同時網絡接口又允許多個服務器同時訪問。

因此所有要求使用Redis的場景,都有重要的特徵,即高速和獨立存儲。基於這個需求,創造出來的業務概念即哪些所謂的 熱點業務數據、高速數據鏡像、共享緩存等等,也就好理解了。

下圖就是實際業務中的一種場景,即為了幫SQL抗流量。重複的查詢和快速的更新由Redis抗下,而SQL只做持久化。

希望能幫到有類似問題的朋友。朋友們,望不吝賜贊啊!


物聯網技術沙龍


高頻,原子數據不大,適合redis


分享到:


相關文章: