2010-10-28 76 views
2

我想問你的專家建議在C#中可行的架構。C#架構建議:緩存結構中的數據的方法?

我有一個C#服務,它響應來自局域網上的本地用戶的請求,從互聯網獲取數據包,並將這些數據加工成結構中的數據陣列。每個數據請求大約需要2秒鐘,並返回4000個字節。每天可能有數以萬計的請求。我需要緩存數據處理的結果,以便第二次和隨後的訪問可以立即提供給LAN上的任何其他用戶(可能有50個以上的用戶)。

約束:

  1. 底層的數據不會改變,即我不擔心「髒」數據(太棒了!)。
  2. 我想要緩存的數據是一個相當複雜的結構,包含嵌套的DateTime,double等數組。數據是從互聯網提供的數據中使用大量數學計算的。
  3. 無論有多少數據被緩存(即緩存必須是大小限制的),我都不能使用超過100MB的內存。
  4. 我無法通過數字索引爲緩存中的數據建立索引,我不得不使用date(「YYYY-MM-DD」)和唯一ID字符串(「XXXXXXXX」)的組合對其進行索引。
  5. 它必須快速,即它必須服務於RAM的大部分響應。
  6. 緩存中的數據必須每隔24小時保存到磁盤。

這裏是我此刻的選擇:

  1. 緩存在服務器類的數據,使用私有變量(即私人列表或字典),然後將其序列化到磁盤偶爾;
  2. 使用數據庫;

我對你的專家意見很感興趣。

回答

2

到目前爲止,最簡單的解決方案是使用Dictionary<string, ComplexDataStructure>

關於您的要求:

  1. 緩存的壽命是最容易被具有後臺線程,做緩存曾經10分鐘或小時左右的掃描來管理。在ComplexDataStructure中,創建緩存時存儲DateTime,並且在其生命週期過期後從字典中刪除密鑰;

  2. 因爲您正在存儲實際的數據結構,所以複雜性不是問題;

  3. 限制尺寸可能很困難。 sizeof() equivalent for reference types?可幫助您計算對象結構的大小。這個操作不是微不足道的,但你可以用ComplexDataStructure來存儲結果。然後,與用於1的線程相同的線程可以在空間不足時刪除條目。更簡單的解決方案可能是使用GC.GetTotalMemory()並確定您的進程的總內存使用量是否超出特定限制。然後,只需刪除一個緩存項目,並在第二次運行時,當您看到您仍然使用太多內存時,請刪除第二個;

  4. 只要使用一個字符串;

  5. 使用Dictionary<,>可能是因爲禁食的方式;

  6. 再次使用1中的線程並實現這樣的邏輯。

確保您正確處理您的鎖定策略。這裏最大的問題將是,當另一個線程正在處理數據時,您不希望收斂。對此的解決方案可以是以下策略:

  1. 鎖定字典;

  2. 驗證緩存項是否存在;

  3. 當緩存項不存在:

    1. 創建一個空的緩存項;

    2. 將其添加到詞典;

    3. 鎖定緩存項目;

    4. 釋放字典上的鎖;

    5. 做數據處理;

    6. 將crunched數據添加到緩存項目;

    7. 釋放緩存項目上的鎖定;

  4. 當緩存項目已經存在時;

    1. 當緩存項目實際上確實有收斂的數據時,返回該值;

    2. 當緩存項沒有收集到的數據時,對緩存項進行鎖定;

    3. 在鎖內部,出現了嘎吱嘎吱的數據(因爲鎖迫使你在另一個線程上等待)。

有跡象表明,將要解決的其他問題,但我認爲基本都在這裏描述。

+0

很好的答案,謝謝。我不是自己實現這個功能,而是最終使用Kellerman提供的現成解決方案.NET緩存庫。 – Contango 2010-10-31 20:47:07

+0

不客氣。 – 2010-10-31 21:22:09

0

怎麼樣:使用IIS提供的內部方法?

+0

對不起,我的問題還不夠清楚:我必須緩存本地數據,它包含在用C#編寫的服務類中的結構中。我已經使問題變得更清楚。 – Contango 2010-10-28 09:36:25

0

我想我已經找到了完美的解決方案:PostSharp + Kellerman .NET日誌庫。 PostSharp需要一個輕微的學習曲線(大約15分鐘),但是一旦你開始運行,你可以用屬性[Cachable]註釋你的方法,系統會自動爲你緩存這個方法的結果。它儘可能清潔您的解決方案。