2011-04-18 68 views
3

我正在爲Sql Server中的C#Asp.Net MVC3網站實現內容數據庫。從SQL Server 2008 R2優化內存中的分層結構緩存

表結構基本上是鄰接表,但是我的文件和文件夾分成FileSystem:這樣我就可以分離單個用戶/帳戶內容:

FileSystem: 
    [ID] 

Folder: 
    [ID] 
    [FileSystemID] 
    [ParentFolderID] (null) 
    [Name] 

File: 
    [ID] 
    [FileSystemID] 
    [ParentFolderID] 
    [Name] 
    [Content] 

允許這裏的低效正常化,這是很基本的東西。

我也有專欄[Created][Modified]在適用情況下。

這些文件將用於在Asp.Net MVC 3站點中執行頁面的動態標記,其中每個請求都將根據原始Asp查找更具體的css/image文件的品牌版本。網絡MVC內容網址 - 例如"~/Content/Site.css"可能會變成"~/[dynamic content root]/[accountid]/[theme]/Site.css"

這個基本機制已經可以工作了,我主要關心的是緩存和版本控制。

顯而易見,不是一直在爲相同的文件和文件夾探測數據庫,而是建立內容文件系統的內存緩存以加速內容查找和傳送。但是,我需要一種有效的方法來確保Web場中的所有Web服務器都檢測到帳戶虛擬文件系統(更改/刪除/創建的任何文件或文件夾)的更改,以確保主題更改立即反映在所有服務器上,下一個請求。

由於分層查詢可能很昂貴,因此我每次都打折運行所有在文件系統中創建的/上次修改的日期的健全性檢查。然而,我所考慮的是整個文件系統上的一個級聯版本號。

因此,任何文件系統中的更改會導致文件系統本身上的版本號增加,並且可能會從更改的項上增加所有父文件夾。因此,讀者可以簡單地附加到整個文件系統或其特定部分,並且每次運行一個便宜的查詢以根據緩存版本檢查當前版本。

這確實會減慢更新速度,但我期望文件系統很少發生變化,而且它會被頻繁讀取。我唯一關心的就是更新的併發性,以及如何管理它。

這會是一個好方法嗎?有什麼更好的,我可以考慮?

任何想法歡迎!

回答

3

由於您使用的是SQL Server,我建議在SQL Server中使用類似於SqlCacheDependency對象或SqlDependency對象的東西作爲Query Notifications服務的一部分。

我已經在各種項目中成功地使用了它,導致通知的負擔在數據庫上,而不是我自己寫的一些輪詢機制。下面是我如何使用它的緩存角色信息的示例:

public CacheDependency GetRoleActionCacheDependency() 
    { 
     using (var connection = new SqlConnection(Database.Database.Connection.ConnectionString)) 
     { 
      connection.Open(); 
      using (SqlCommand sc = new SqlCommand("select roleid, actionid from dbo.RoleAction", connection)) 
      { 
       var dependency = new SqlCacheDependency(sc); 
       sc.ExecuteNonQuery(); 
       connection.Close(); 
       return dependency; 
      } 
     } 
    } 

該緩存依賴無效緩存一旦有事情在roleaction表的變化。我可以通過在查詢中添加參數來獲取行級別的通知。

這是我如何稱此代碼。你可以讓你的實際依賴對象存儲在緩存中,但在我的特殊情況下,對象實例本身駐留在應用程序(靜態),所以我不需要緩存它本身,我只需要使其無效。我將它設置爲null(getter管理其重新填充)。

CacheDependency rolePathAccessCacheDependency = GetRoleActionRepository().GetRoleActionCacheDependency(); 
    HttpContext.Current.Cache.Add("anything will do", new object(), rolePathAccessCacheDependency, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, 
        (key, value, reason) => 
        { 
         _rolePathAccess = null; 
        }); 

也完成你需要這在Global.asax應用程序啓動的例子:

SqlDependency.Start(ConfigurationManager.ConnectionStrings["DatabaseConnection"].ConnectionString); 

和應用端:

SqlDependency.Stop(ConfigurationManager.ConnectionStrings["DatabaseConnection"].ConnectionString); 

我忘了一件事是,這取決於啓用S​​QL Server中的代理服務。這是啓用它的一種方式,但請注意,第一條語句魔法地授予您對數據庫的獨佔訪問權限並回滾其他任何內容,因此只有在知道自己在做什麼的情況下才能在生產環境中使用它。第二個陳述是你真正需要的,如果你已經擁有獨家使用權。從我

ALTER DATABASE MYDatabase SET SINGLE_USER WITH ROLLBACK IMMEDIATE 
ALTER DATABASE MYDatabase SET ENABLE_BROKER 
ALTER DATABASE MYDatabase SET MULTI_USER 
GO   
+0

嗯,是的,我確實懷疑這種使用是否會成爲答案。我已經看過它,並在db修改中被阻止,儘管這是一個全新的數據庫,所以我可以逃避它。我會有一個戲,看看我如何繼續,謝謝。 – 2011-04-18 20:11:58

+0

@Andras Zoltan我用這些功能取得了相當大的成功。我從來沒有遇到過啓用經紀人服務的麻煩,或者當然我不需要親自接觸任何DBA的圈子,因爲我在一家小公司。 – Quesi 2011-04-18 20:53:54

+0

我需要更多地考慮這一點:我正在使用Repository模式;所以我很有興趣看看我是如何將這一特定功能納入其中的 - 存儲庫接口將不得不公開緩存依賴端點;但這是特定於ASP.net的。啊多層設計的詛咒。 – 2011-04-19 20:42:06

0

只是一些隨機的想法:

你確實有性能問題,你可以跟蹤他們回到這個具體問題?你需要一個快速解決方案,或者你正在潛入更廣泛的問題。您尋找的吞吐量是多少?有些數字?

瀏覽器和你的服務器之間有幾層,'網絡'可以在瀏覽器代理等緩存,如果你讓它。然後是IIS本身,旨在處理緩存。 mvc使用那些(相對)靜態網址的方式,這兩個來自「開箱即用」。

下一層將是你的MVC對象模型,你可以保留整個樹到內存中嗎?這樣你就不需要進行流程調用。這可以節省很多次,更不用說去磁盤了。如果我理解正確,你仍然會分享很多文件,所以你可以分享這些(flyweight模式)的實例。在需要時懶惰加載它們,並有一種機制在需要時釋放它們。記憶比你的時間便宜。

rgds GJ

+0

那麼,沒有性能問題,但它還沒有生活!潛在的過早優化,是的,但是經驗和流量水平的估計,只是說盡可能少地擊中分貝是最好的路徑。我也會利用瀏覽器緩存;但只是想確保當我實現服務器緩存時,我的數據庫結構適用於此。奎斯的答案很好,因爲我不需要做太多的工作來確保這一點,但你在這裏提出了有效的觀點。 – 2011-04-18 21:45:02