咱們在開發中,常常會用到各類緩存,好比Session、Application、HttpRuntime.Cache、Redis、Memcached、MongoDB、Riak等。而通常項目中使用緩存時,都是比較初級的,大多都是常見的Key-Value方式,經過依賴、時間、同步更新或直接刪除方法來管理緩存的過時。固然網上對於緩存的介紹絕大部分都是這方面的,而對於多級緩存、緩存與緩存相互關聯、表記錄與多緩存關聯、後端緩存與前端頁面緩存關聯、緩存名稱動態生成的緩存與其餘緩存聯動處理、頻繁更新的緩存與其餘緩存聯動問題......等等不一樣狀況下該若是去管理這些緩存的知識點,我在園子裏找了半天也沒有看到......而最近本身開發的項目中就碰到了緩存管理上的問題,因此發這篇貼子同你們討論一下有什麼更好的解決方案。前端
隨着項目參與人員數量的增長,你們經驗的不一樣和對緩存的認知不同,而項目爲了達到在生產環境上能處理更大的併發和良好的性能,緩存的使用也愈來愈普遍了。項目在老闆、運營部門和項目經理的推進下,新功能、新需求不斷的推陳出新,代碼與複雜度也幾何級的爆增起來,緩存的使用幾乎充斥在全部代碼的調用當中,因爲沒有專門寫一個處理插件對它進行統一管理,形成緩存管理開始有些混亂。算法
好比對運行中的系統在某些狀況下執行了清空所有緩存時,偶爾會發生一些小異常(有些數據讀取不正常);對同一結果重複使用緩存(A同事建立了一個緩存來存儲H任務執行結果的,而B同事不知道A同事建立過,也建立了一個),浪費內存空間;多個緩存依賴同一個緩存值的變更,某些人因爲一些須要修改了所依賴緩存的名稱以及所影響的一些緩存時,個別非本身編寫的緩存沒有處理到或忘記處理了;某些緩存存儲內容依賴臨時表來建立的,緩存名稱有規律但不固定,而另一些緩存的內容是根據這些緩存來計算的,當這些緩存更新時如何能自動同步所依賴它的緩存......後端
固然上面這些狀況或還有其餘的狀況單獨編寫代碼來處理確定能夠實現,只須要花多一些時間而已,問題是若是系統很龐大後,充斥差各類交叉關聯的緩存時,它們已像蜘蛛網同樣,動一發而牽動全身,寫這些處理代碼一個沒考慮好就會影響到其餘內容。何況有不少時候更新臨時表記錄時,有些緩存名稱是不固定的(根據某些規則關聯到其餘表記錄或日期等方式生成的緩存名稱),代碼並不可能智能識別要同步更新那些緩存。因此編寫一個強大的自動化緩存處理插件也勢在必行了。緩存
相信博客園團隊和其餘一些大型的網站都有着本身一套完善的緩存管理辦法,因爲本身知識廣度還不足夠,暫時沒有在網上發現有一套完善、高效的解決方案能夠借鑑,只好本身來想辦法解決,因此先拋出一塊磚頭,看可否引來一堆美玉了,嘿嘿...服務器
下面咱們先來了解一下緩存中的一些分類與名詞說明併發
按名稱的命名可分爲:框架
固定名稱:一般以表名、字段名、功能名稱、前幾項的組合......等按各人的喜愛來進行命名,調用時也直接方便函數
有固定前綴(單個或多個可變後綴或可變後綴+固定後綴組合等):表名+記錄Id、臨時表名(表名按必定規則進行變更,好比後綴爲年月、關聯表的Id等)、功能名稱+編碼......調用時須要動態傳入指定的參數,在不知道參數的狀況下沒法對該緩存進行操做性能
按緩存依賴內容可分爲:學習
依賴指定表:指定表記錄增長、修改、刪除、更新時,須要同步更新該緩存內容
依賴指定表中的某些或某條記錄:同上
依賴多個表數據:同上
依賴指定字段值:默字段值改變時,同步修改(主要用於更新頻率比較高的字段,好比頁面點擊計數等,若是須要用到緩存的,須要獨立出來存儲,以避免更新時執行同步清除功能)
依賴其餘緩存:指定緩存值改動時,須要同步修改所依賴它的其餘緩存值(好比依賴某些計算結果或狀態值;存儲某些臨時記錄等)
......
按影響緩存值的操做可分爲:
數據表記錄的添加、修改、刪除;其餘緩存值的更新變化;某些計算結果的變化等
對於所依賴的內容變化後,相關緩存就須要同步更新,這樣又可分爲實時同步和延時同步等方式
緩存更新策略經過有:實時更新(主要針對記錄級別緩存,直接同步更新指定記錄;固然也能夠整表更新,但這樣對程序執行性能有較大的影響)、超時檢測(好比緩存依賴其餘緩存時,設置一個最後更新時間與獲取時間,經過比較兩個時間來肯定緩存是否過時)、絕對時間過時(爲緩存設定過時時間)、動態時間過時(緩存被訪問後過時時間順延)等。
按緩存數據集合大小分:
單值、單條記錄、小型數據集合、中型數據集合、大型數據集合、超大型數據集合
對於緩存管理,數據集越小則存取與轉換速度越快,因此當數據集合過大時,就必須進行分割,將集合儘可能分紅小塊,提高緩存使用性能
按緩存更新頻率分:
固定值(指的是某些配置信息,存儲進緩存後它的值就再也不變化)、偶爾更新、常常更新、頻繁更新
按緩存級別分:
無分級緩存、二級緩存
其餘:
數據緩存、頁面緩存......
通常來講,大部分人使用緩存都是直接key-value,這樣種操做簡單方便,無需太多的算法去處理。而這樣操做對於記錄集合比較大的數據(固然不能直接緩存大型或超大型數據)來講,頻繁的進行數據存取轉換也會消耗很多資源,因此有時須要在這個基礎上再加個二級緩存,將NOSQL緩存中讀取出來的數據載入IIS緩存中,程序直接編寫代碼調用,只有相關值更改時再從新加載一次,這樣就減小了對大數據轉換的性能損耗,固然程序的複雜度就大大提高了不少。
對於使用二級緩存或依賴其餘緩存的緩存來講,常常更新或頻繁更新影響是最大的,程序寫的很差直接會形成性能幾何級的降低(由於每一次更新都須要同步更新相關的全部緩存)。
目前系統使用緩存情況
目前個人框架使用的是二級緩存,首先是使用Redis緩存存儲各類表記錄和值,而後對於某些數據量不小,修改很少但使用相對比較頻繁的數據,爲了減小從Redis緩存中不停的讀取出來後進行反序列化操做,會從Redis緩存中讀取出來後將它存儲到IIS緩存中,當這些數據有更新時會實時同步更新IIS緩存中的數據,這些代碼都封裝在邏輯層中,統一使用模板生成,方便快捷。
將業務數據量大的模塊進行了分割,天天按不一樣屬性生成N個臨時表,次日凌晨會執行定時任務將對這些臨時表進行分析處理,去除無效數據後統一更新到歷史表中(歷史表按月生成)。業務數據分割後,每一個表的記錄量都不多,它們都會存儲到相應的緩存中給先後端、服務、Socket等接口進行共同調用處理,目前是不一樣服務器全部功能共用一個緩存服務。各類系統服務會將經常使用的數據或記錄存儲到指定的緩存中,減小跨臨時表查詢操做或全表數據查詢操做。有些功能只使用當天要用到的一些最新數據,舊數據再也不使用不須要參與查詢,也會使用單獨的緩存來進行存儲,緩存存儲按固定前綴+有規則的後綴進行管理。
前端頁面則直接緩存在Redis中。
......
緩存處理存在問題
除了前面所講的緩存問題外,咱們後端更新某些數據時(好比商品資料),就必須清除前端全部頁面緩存,全面從新生成(由於不少頁面都會展現商品相關信息),因爲沒有一個綜合管理緩存的框架,在更新時就會將一些沒必要刪除的緩存也同步清除了。而在某些時候緩存被不少其餘緩存所依賴時,清除該緩存也會清除一些多餘的緩存,而不是精肯定位。對於動態生成的可變後綴的緩存,在某些時候沒法傳遞後綴參數時,將很難同步更新這些緩存內容。
緩存處理解決思路
對於出現上面的一些問題,在綜合考慮後,想寫個獨立的緩存處理插件來處理這些問題。主要經過配置來將緩存直接綁定數據表、字段、記錄Id、關聯緩存、頁面緩存等關聯內容,在這些緩存更新時同步清除對應的緩存模塊,以便其餘緩存重啓緩存載入程序來加載相應數據到緩存中。在清除時有針對性,而不會跨界清空多餘的緩存。不知你們有什麼好的建議?
下面是個人一些解決思路:
一、首先緩存插件必須是一個獨立的程序
二、調用必須經過統一的接口來進行處理
三、緩存關聯必須經過配置來實現綁定
四、緩存命名必須符合必定的規範
具體實現辦法:
獲取緩存:Get Cache => Check null => Load => Save(保存時會執行存儲數據的檢查,這裏開發時要當心,避免出現死循環) => Return Cache (即取緩存時必須檢查指定緩存是否爲空,爲空時調用Load接口載入數據到緩存——Load函數功能由操做方實現,使用配置+IoC來調用,IoC配置文件和接口文件能夠用T4模板直接生成——,而後將數據存儲到緩存中,最後返回所要的緩存;固然若是緩存不爲空時直接返回緩存)
存儲數據:Save Cache => Save => Check Relevance => Delete Relevance Cache (即存儲數據時,首先將數據保存到緩存中,而後讀取配置信息檢查該緩存與那些緩存關聯,若是存在關聯關係的緩存,則同步清除這些緩存,以便下次獲取這些緩存時能從新加載)
刪除緩存:Delete Cache => Delete => Check Relevance => Delete Relevance Cache(刪除時執行遞歸調用,按正常來講,這種關聯應該不會太深)
設置緩存參數:Set (修改緩存插件的一些全局配置)
給外部直接調用的只有Get/Save/Delete,須要外部程序實現的接口暫定爲Load這一個,裏面實現數據加載的代碼
在配置時,緩存依賴必須單向,避免出現死循環(可寫程序檢查配置)
要處理好動態後綴緩存的處理,能經過參數控制智能判斷緩存的關聯。好比名稱爲tablename_id的緩存,在執行Load時會將id截取出來傳遞給操做函數,那麼載入時就只加載該id的記錄;
對於更新頻繁的數據,好比頁面點擊計數等,若是須要用到緩存的,須要獨立出來存取和更新,以避免更新時執行同步清除功能
能夠經過Set來開啓或關閉Load、Delete Relevance Cache功能等
因爲工做時間繁忙,本隨筆斷斷續續寫了好長時間,有些想法和思路沒有及時記下來都忘了,暫時想到這麼多,思路也不是很成熟,不知你們有什麼好的建議?這種處理模式是否存在什麼問題?歡迎你們出來拍磚
版權聲明:
本文由AllEmpty原創併發佈於博客園,歡迎轉載,未經本人贊成必須保留此段聲明,且在文章頁面明顯位置給出原文連接,不然保留追究法律責任的權利。若有問題,能夠經過1654937@qq.com 聯繫我,很是感謝。
發表本編內容,主要是爲了和你們共同窗習共同進步,有興趣的朋友能夠加加Q羣:327360708 ,你們一塊兒探討。
更多內容,敬請觀注博客:http://www.cnblogs.com/EmptyFS/