2011-03-18 78 views
3

我有大約50個網站,跨5個網絡服務器負載平衡。他們都使用企業庫緩存,並訪問相同的緩存數據庫。高速緩存數據庫中的項目每隔幾個小時刷新一次,使用ICacheItemRefreshAction實現。網絡農場中的分佈式臨界區域

我想通過將刷新代碼放在critical section中來保證只有一個網站刷新緩存。

  • 如果Web站點是在一臺服務器上的單個應用程序池運行時,我可以用一個lock()

  • 如果Web站點是在單獨的應用程序,池在單個運行服務器,我可以使用Mutex

但是,這些將不能確保跨多個Web服務器的關鍵部分。

目前,我在緩存數據庫中創建一個新密鑰以充當互斥體。這將一般工作,但我可以看到2進程可能進入臨界區的渺茫機會。

public class TakeLongTimeToRefresh : ICacheItemRefreshAction 
{ 
    #region ICacheItemRefreshAction Members 

    public void Refresh(string removedKey, object expiredValue, CacheItemRemovedReason removalReason) 
    { 
     string lockKey = "lockKey"; 
     ICacheManager cm = CacheFactory.GetCacheManager(); 

     if (!cm.Contains(lockKey)) 
     { 
      Debug.WriteLine("Entering critical section"); 
      // Add a lock-key which will never expire for synchronisation. 
      // I can see a small window of opportunity for another process to enter 
      // the critical section here... 
      cm.Add(lockKey, lockKey, 
        CacheItemPriority.NotRemovable, null, 
        new NeverExpired()); 

      object newValue = SomeLengthyWebserviceCall(); 
      cm.Remove(removedKey); 
      Utilities.AddToCache(removedKey, newValue); 

      cm.Remove("lockkey"); 
     } 
    } 
} 

是否有具有保證關鍵部分,以確保我不調用Web服務兩次的一種方式?

編輯我應該補充一點,我不能使用共享文件,因爲部署策略會阻止它。

StackOverflow的引用:

+0

也許某種令牌環系統? – jp2code 2011-03-18 15:53:32

回答

4

你必須涉及共同所有的一些外部鎖定習得。例如,表t在SQL與一行和一個鎖字段,您將獲得一個鎖:影響

set transaction isolation serializable; 
update t set lock = 1 where lock = 0; 

檢查行,如果1你有鎖,通過更新鎖0釋放。這實際上是捎帶在SQLServer的行鎖上,如果兩個同時啓動,只有一個會在S鎖定後獲得U鎖,另一個會阻塞並隨後返回0行(因爲第一個事務將其翻轉爲1)。

+0

我認爲這是正確的做法。如果EL緩存在添加現有密鑰時拋出異常,則會產生相同的效果。但是,如果沒有,我需要在SQL中自己實現它。謝謝:) – 2011-03-18 15:57:42

+6

只要記住,這種鎖定是不持久的,如果你的進程在獲取之後但在釋放鎖之前發生故障,它將永久鎖定。擺脫這種方式的一個好方法是強制執行超時,這意味着如果在設定時間內鎖沒有被釋放,即使鎖= 1,請求者也可以獲得它,例如 'set lock = 1,locktime = getdate()where lock = 0或datediff(m,locktime,getdate())> 15' 15分鐘 – mmix 2011-03-18 22:57:58

+0

@mmix感謝您的建議。我正在使用它。唯一的問題是我認爲datepart「m」是幾個月而不是幾分鐘。分鐘將是「mi」。參考:https://msdn.microsoft.com/en-us/library/ms189794.aspx – 2015-07-30 00:39:54

1

我建議你將創建/返回鎖定句柄的邏輯移動到數據庫,並且將它們組合,這將保證它始終是一個具有鎖定的進程。

因此,數據庫可能有一個存儲過程,您要求一個鎖,並且它會返回空結果(不成功)或將創建一個記錄並將其返回。