那些年我們一起擼過的快取寫法
上次主要討論快取讀寫這塊各種程式碼實現,本篇就上次的問題繼續來,看看那些年折騰過的各種快取做法。
閱讀目錄:
快取預熱
上次有同學問過,在第一次載入時快取都為空,怎麼進行預熱。
單機Web情況下一般使用RunTimeCache,這種情況下:
可以在啟動事件裡面重新整理
void Application_Start(object sender, EventArgs e) { //重新整理 }
另外可以單寫個重新整理快取頁面,上線後手動重新整理下或釋出時自動呼叫重新整理,再或者由使用者自行觸發。
分散式快取(Redis、Memcached)情況下:
比如在幾十臺伺服器快取時,單刷滿快取都需要不少一段時間。
這種預熱就複雜一些,有的會單寫個應用程式去跑,也有的會單寫套框架機制去處理(更智慧化)。
其目的是在系統上線之前,所有的快取都預先載入完畢。
多級快取
計算機結構中CPU和記憶體之間一般都配有一級快取、二級快取來增加交換速度。
這樣當CPU呼叫大量資料時,就可避開記憶體直接從CPU快取中呼叫,加快讀取速度。
根據CPU快取得出多級快取的特點:
1:每一級快取中儲存的是下一級快取的一部分。
2:讀取速度按級別依次遞減,成本也依次遞減,容量依次遞增。
3:當前級別未命中時,才會去下一級尋找。
而在企業應用級開發中,使用多級快取是同樣的目的及設計,只是粒度更粗,更靈活。
根據速度依次排列lv1-lv6的快取型別圖:
3級快取的命中流程圖例子:
執行緒快取
Web應用是天生的多執行緒開發,對於一些公共資源必須考慮執行緒安全,為止不得不通過鎖來保證資料的完整性和正確性。
在實際當中一臺web伺服器至少也得處理成百上千的請求,想一想在業務複雜的處理流程,函式每呼叫一次都得鎖一下,對伺服器也是個不小的浪費。
而通過執行緒快取,可以讓當前處理使用者請求的執行緒只拿自己需要的資料。
public static ThreadLocal<UserScore> localUserInfo = new ThreadLocal<UserScore>();
藉助Net提供的執行緒本地變數,可以在請求入口去拉取當前用戶的資料。
在之後執行緒整個生命週期裡面,業務邏輯可以毫無顧慮的使用這些資料,而不需要考慮執行緒安全。
因為不用重新拿新快取資料,所以也不用擔心資料撕裂的問題。
其當前執行緒週期裡面的資料是完整無誤的,只有使用者第二次發起請求才會重新去拿新資料。
這樣就能提高不少伺服器吞吐量,注意要線上程的出口處銷燬資料。
記憶體快取
無論是遠端資料庫讀取,還是快取伺服器讀取。避免不了要跨程式,跨網路通訊,有的還跨機房。
而應用程式頻繁讀寫,對Web、DB伺服器都是個不小的消耗,速度相較記憶體也慢的多。
程式碼上加鎖、非同步,甚至加伺服器在內,都不是一個很好的辦法。因為載入速度,對使用者體驗非常重要。
所以在有要求的專案中使用本地記憶體做二級快取,是非常有必要的。目的就是1:抗併發,2:加快讀取速度。
有個著名的快取五分鐘法則法則,就是說如果一個資料頻繁被訪問,那麼就應該放記憶體中。
舉個例子: 有100併發過來,加鎖會導致前端99執行緒等候,這個99執行緒等候著,其實是一直在消耗Web伺服器資源。不加就是快取雪崩。
如果每分鐘拉取一份快取,快取到記憶體,這樣99線程等候時間極大縮短。
檔案快取
相對於記憶體,硬碟容量大,速度相較於走網路還更快。
所以我們完全可以把一些不經常變更,放在記憶體又比較浪費的資料快取到本地硬碟。
比如使用sqlite一些檔案資料庫,我們很容易做到。
分散式快取
基於記憶體快取的redis、memcached等。
基於檔案nosql的Casssandra、mongodb等。
redis、memcached是主流的分散式記憶體快取,也是應用和DB中間最大的快取層。
nosql這類的其實不單單只是做快取用了,完全用在一些非核心業務的DB層了。
DB快取
這一層DB主要是快取由原始資料計算出的結果,從而避免由Web程式通過SQL或在使用中直接計算。
當然也可以把計算好的資料,儲存到redis中當快取。
多層快取
多層快取概念在很多地方都用到過:
1:上面介紹的多級快取就是一種,把內容根據讀取頻率,分不同的等級、不同的層次進行儲存,頻率越高離查詢越近。
2:還一種多層是快取索引的做法,類似B樹查詢,這樣能提高檢索效率。
3:從架構上來說瀏覽器快取、CDN快取、反向代理快取、服務端快取、也是多層快取。
總結
在使用上大家根據實際場景,進行各種組合搭配。本篇談的比較理論些,有些內容細節沒展開。
比如分散式快取的使用,快取置換策略及演算法,快取過期機制等。
系列目錄:
那些年我們一起追過的快取寫法(二)
相關文章
- 那些年我們一起追過的快取寫法(一)快取
- 那些年,我們一起追過的APPAPP
- 那些年我們一起踩過的Dubbo坑
- 那些年,我們一起誤解過的RESTREST
- 那些年,我們一起追過的化學元素
- 那些年,我們一起走過的iOS推送的坑iOS
- SQL Server DBA:那些年,我們一起用過的工具FASQLServer
- 那些年,我們一起做過的 Java 課後練習題(71 - 75)Java
- 那些年,我們一起做過的 Java 課後練習題(1 - 5)Java
- 那些年,我們解析過的前端異常前端
- 純技術團隊創業,那些年我們一起走過的彎路創業
- 那些年,我們處理過的SQL問題SQL
- 那些年,我們一起追尋的非同步程式設計非同步程式設計
- 那些年,我們用過的伺服器軟體伺服器
- 致畢業生:那些年我們錯過的“BAT”BAT
- 聊聊我們那些年用過的表示式引擎元件元件
- 《我們一起進大廠》系列-快取雪崩、擊穿、穿透快取穿透
- 那些年,我們見過的 Java 服務端“問題”Java服務端
- IT人,那些年,一起踩過的坑
- Python:那些年我們遇到的坑Python
- 我們們一起來談談,redis為什麼快?Redis
- 淺談快取寫法(一):快取的雪崩和穿透快取穿透
- 那些年我們賺過的外快(POS(移動支付)介面開發)
- 那些年 IT大佬們吹過的牛逼
- 小程式開發,那些我們跳過的坑
- 那些年 我追過的語言
- 那些年我看過的前端書前端
- 十年前那些我們曾迷戀過的網頁網頁
- 高速輸出-我們戲說快取快取
- 【高德地圖API】那些年我們一起開發的APP—即LBS應用模式分享地圖APIAPP模式
- 寫給那些IT的新人們
- 那些年我們用過的元件-結構化日誌元件 Serilog元件
- 那些年,我們看不懂的那些Kotlin標準函式Kotlin函式
- 手寫那些年用過的React路由React路由
- 我們有線上社群啦!快來加入一起玩兒~
- 那些年讓我們頭疼的CSS3動畫CSSS3動畫
- 當我們在談論HTTP快取時我們在談論什麼HTTP快取
- 那些年我玩過的程式語言(二)