快取誤區(下)

2021-07-10 02:47:58 字數 3095 閱讀 8282

在很多時候,我們往往會快取乙個物件的集合,但是,我們在讀取的時候,只是每次讀取其中一部分。 我們舉個例子來說明這個問題(例子可能不是很恰當,但是足以說明問題)。

在購物站點中,常見的操作就是查詢一些產品的資訊,這個時候,如果使用者輸入了「25寸電視機」,然後查詢相關的產品。這個時候,在後台,我們可以查詢資料庫,找到幾百條這樣的資料,然後,我們將這幾百條資料作為乙個快取項快取起來,**的**如下:

同時,我們對找出的產品進行分頁的顯示,每次展示10條。其實在每次分頁的時候,我們都是根據快取的鍵去獲取資料,然後選擇下乙個10條資料,然後顯示。

如果是使用本地記憶體快取,那麼這可能不是什麼問題,如果是採用分布式快取,問題就來了。下圖可以清楚的說明這個過程,如圖所示:

相信大家看完這個圖,然後結合之前的講述應該很清楚了問題所在了:每次都按照快取鍵獲取全部資料,然後在應用伺服器那裡反序列化全部資料,但是只是取其中10條。

這裡可以將資料集合再次拆分,分為例如25-0-10-products,25-11-20-products等的快取項,如下圖所示:

當然,查詢和快取的方式有很多,拆分的方式也有很多,這裡這是給出一些常見的問題!

為了更好的說明這個問題,我們首先看到下面的乙個類結構圖,如圖:

如果我們要把一些customer資料快取起來,這裡就可以可能出現兩個問題:

由於使用.net的預設序列化機制,或者沒有適當的加入相應attribute(屬性),使得快取了一些原本不需要快取的資料。

將customer快取的時候,同時,為了更快的獲取customer的order資訊,將order資訊快取在了另外乙個快取項中,導致同乙份資料被快取兩次。

下面,我們就分別來看看這兩個問題。

首先看到第乙個。如果我們使用分布式快取來快取一些customer的資訊的時候,如果我們沒有自己重新customer的序列化機制,而是採用的預設的,那麼序列化機制在序列化customer的時候,會將customer所引用的物件也序列化,然後在序列化被序列化物件中的其他引用物件,最後的結果就是:customer被序列化,customer的order資訊被序列化,order引用的orderitem被序列化,最後orderitem引用的product也會序列化。

整個物件圖全部被序列化了,如果這種情況是我們想要的,那麼沒有問題;如果不是的,那麼,我們就浪費了很多的資源了,解決的方法有兩個:第一,自己實現序列化,自己完全控制哪些物件需要序列化,我們前面已經講過了;第二,如果使用預設的序列化機制,那麼在不要需要序列化的物件上面加上[nonserialized]標記。

下面,我們看到第二個問題。這個問題主要是由於第乙個問題引起的:原本在快取customer的時候,已經將customer的其他資訊,例如order,product已經快取了。但是很多的技術人員不清楚這一點,然後又把customer的order資訊去快取在其他的快取項,使用的使用就根據customer的標識,例如id去快取中獲取order資訊,如下**所示:

解決這個問題的方法也比較明顯,參看第乙個問題的解決方案就可以了!

因為快取是有一套資料失效檢測週期的(之前說過,要麼是固定時間失效,要麼是相對時間失效),所以,很多的技術人員喜歡把一些動態變化的資訊儲存在快取中,以充分利用快取機制的這種特性,其中,快取程式的配置資訊就是其中乙個例子。

因為在應用的中的一些配置,可能會發生變化,最簡單的就是資料庫連線字串了,如下**:

當這樣設定之後,每隔一段時間快取失效之後,就去重新讀取配置檔案,這時候,可能此時的配置就和之前不一樣了,並且其他的地方都可以讀取快取從而進行更新,特別是在多台伺服器上面部署同乙個站點的時候,有時候,我們沒有及時的去修改每個伺服器上面的站點的配置檔案裡面的資訊,這個時候如何使用分布式快取快取配置資訊,只要更新乙個站點的配置檔案,其他站點就全部修改了,技術人員皆大歡喜。ok,這確實看起來是個不錯的方法(在必要的時候可以採用一下),但是,不是所有的配置資訊都要保持一樣的,而且還要考慮怎樣乙個情況:如果快取伺服器出了問題,宕機了,那麼我們所有使用這個配置資訊的站點可能都會出問題。

我們有時候會遇到這樣的乙個情況:我們把乙個物件快取起來,用乙個鍵作為快取鍵來獲取這個資料,之後,我們又通過乙個索引作為快取鍵來獲取這個資料,如下**所示:

我們之所以這樣寫,主要因為我們會以多種方式來從快取中讀取資料,例如在進行迴圈遍歷的時候,需要通過索引來獲取資料,例如index++等,而有些情況,我們可能需要通過其他的方式,例如,產品名來獲取產品的資訊。

如果遇到這樣的情況,那麼就建議將這些多個鍵組合起來,形成如下的形式:

另外乙個常見的問題就是:相同的資料被快取在不同的快取項中,例如,如果使用者查詢尺寸為36寸的彩電,那麼可能有可能乙個編號為100的電視產品就在結果中,此時,我們將結果快取。另外,使用者在查詢乙個生產廠家為tcl的電視,如果編號為100的電視產品又出現在結果中,我們把結果又快取在另外乙個快取項中。這個時候,很顯然,出現了記憶體的浪費。

對於這樣的情況,之前筆者採用的方法就是,在快取中建立了乙個索引列表,如圖所示:

這種情況應該是使用快取最常見的問題,例如,如果我們現在獲取了乙個customer的所有沒有處理的訂單的資訊,然後快取起來,類似的**如下:

之後,使用者的乙個訂單被處理了,但是快取還沒有更新,那麼這個時候,快取中的資料就已經有問題!當然,我這裡只是列舉的最簡單的場景,大家可以聯想自己應用中的其他產品,很有可能會出現快取中的資料和實際資料庫中的不一樣。

現在很多的時候,我們已經容忍了這種短時間的不一致的情況。其實對於這種情況,沒有非常完美的解決方案,如果要做,倒是可以實現,例如每次修改或者刪除乙個資料,就去遍歷快取中的所有資料,然後進行操作,但是這樣往往得不償失。另外乙個折中的方法就是,判斷資料的變化週期,然後盡可能的將快取的時間變短一點。

使用快取的9大誤區(下)

在很多時候,我們往往會快取乙個物件的集合,但是,我們在讀取的時候,只是每次讀取其中一部分。我們舉個例子來說明這個問題 例子可能不是很恰當,但是足以說明問題 在購物站點中,常見的操作就是查詢一些產品的資訊,這個時候,如果使用者輸入了 25寸電視機 然後查詢相關的產品。這個時候,在後台,我們可以查詢資料...

使用快取的9大誤區(下)轉

在很多時候,我們往往會快取乙個物件的集合,但是,我們在讀取的時候,只是每次讀取其中一部分。我們舉個例子來說明這個問題 例子可能不是很恰當,但是足以說明問題 在購物站點中,常見的操作就是查詢一些產品的資訊,這個時候,如果使用者輸入了 25寸電視機 然後查詢相關的產品。這個時候,在後台,我們可以查詢資料...

VxWorks下程式設計的幾個誤區

vxworks下程式設計的幾個誤區 tornado使用標準c語言嗎?為什麼沒有提供inb outb 等函式?tornado預設使用gnu編譯器,支援ansiiso c,c 以及at t語法彙編 非intel 由於c 很龐大,而且在不斷發展,所以有些標準c 的特徵 可能gnu不支援 基本沒有編譯器支援...