2011-08-23 25 views
2

我們有一種情況,我們正在調用一個相當昂貴的API函數。讓我們叫它API.ExpensiveCall()通過每10秒查詢一次錯誤的想法來緩存結果?

這個ExpensiveCall()在Web應用程序中被頻繁調用。雖然對於一個用戶來說並不明顯,但當你有5個左右同時在線的用戶時,它會變得很明顯。

我們想要緩存這些結果。但由於API.ExpensiveCall()對我們來說基本上是一個黑匣子,我們無法使我們的緩存無效,知道何時刷新。

所以我們提出的解決方案是創建一個windows服務,它將每隔10秒簡單地調用這個API.ExpensiveCall(),然後將結果保存到Web應用程序已經使用的本地數據庫中。

這樣,如果網站上有1個用戶或20多個用戶,則只需每10秒調用一次ExpensiveCall()即可。這是API.ExpensiveCall()連接到的外部系統上的受控負載。

問題

我們的項目經理不同意這種說法。出於某種原因,他認爲每10秒鐘進行一次定時刷新是一個壞主意,因爲他認爲這會給外部系統帶來太多的負擔。

但是,如果我們沒有做任何事情,並且沒有任何緩存的方式,它不僅會降低Web應用程序的性能,但它肯定會導致不止一個ExpensiveCall第二在外部系統。而且這個數字會根據Web應用程序上的用戶數量而倍增。

我想問問你這種緩存方式真的這麼糟糕嗎?你有沒有聽說過使用這種方法進行緩存的其他系統?如果這是一個糟糕的主意,當系統對你來說是一個黑盒子時,有沒有其他更好的緩存系統結果的方法?

編輯:

您的回答似乎表明我應該使用的ASP.Net的內存緩存機制超時功能。

我喜歡超時的想法。我現在看到的唯一(小)問題是,當超時到期並且是時候調用ExpensiveCall()時,它將是阻塞調用。與查詢本地表格不同,本地表格通過不斷刷新的單獨過程保持最新狀態。這是我發現投票想法有吸引力的事情。儘管我必須承認,每10秒輪詢一次就會感到奇怪,這就是爲什麼我要圍繞它進行輪詢。

回答

1

看看my response to this question - 它描述了一種確保標準緩存中新數據的方法。似乎它也可能直接解決您的情況。足夠

+0

是的,這正好描述了我需要做的事情。我想我在描述中錯過了「異步」這個詞。我會調查這一點。謝謝。 – 7wp

3

如果「它對一個用戶不明顯」,那麼也許你應該讓第一次調用方法緩存結果,然後每X秒過期緩存。這種方式每X秒只有一次呼叫會影響性能。

我同意每10秒鐘打一次外部服務聽起來至多不冷,最壞的情況是拒絕服務攻擊(取決於呼叫的權重和提供商的容量)。

+0

博覽會。但是你能否詳細說明爲什麼它不會很酷?此外,外部系統仍在組織內部。它不會通過網絡或類似的東西。 – 7wp

+0

@ 7wp:至少讓負責該服務的團隊知道你是低效打電話給他們,因爲他們不公開的機制,以幫助您智能緩存失效,並要求他們在未來的版本中添加適當的功能。 –

+0

如果它是一個內部系統,那麼它只要負責維護其他系統的跡象,說明他們能夠處理負載不酷。我同意埃裏克,你應該先去看看他們是否能提供更好的解決方案。 –

4

您的項目經理可能是對的:當沒有連續五分鐘的請求時,您仍然會進行輪詢,從而導致30次不必要的昂貴函數調用。

這些東西通常被解決的方式是這樣的:無論何時您需要昂貴調用的數據,您都需要檢查緩存。如果它不在那裏,那麼你調用昂貴的函數並將數據存儲在緩存中,並添加一個時間戳。如果是,則檢查數據的年齡(因此是時間戳)。如果時間超過10秒,則請調用昂貴的功能,然後更新緩存。否則,請使用緩存的數據。 ASP.NET的內置緩存API可以讓您以最小的努力完成所有這些工作 - 只需將緩存過期設置爲10秒,並且您應該很好。

通過這種方式,您將獲得兩全其美 - 您的數據永遠不會超過10秒,但您仍然可以避免不斷的輪詢。

+0

是ASP.Net的內置緩存全局到所有會話? – 7wp

+1

我喜歡超時的想法。我現在看到的唯一(小)問題是,當超時到期並且是時候調用ExpensiveCall()時,它將是阻塞調用。而不是尋找一個當地的餐桌,通過不斷刷新,在一個單獨的過程中保持最新。這是我發現投票想法有吸引力的事情。儘管我必須承認,每10秒輪詢一次就會感到奇怪,這就是爲什麼我要圍繞它進行投票。 – 7wp

+0

如果呼叫不是noticable給用戶,那麼它是阻止可能沒有太大的關注。 – tdammers

2

使用時間範圍(例如10秒)來使緩存失效沒有任何根本性的錯誤。

如果用戶看到過時10秒的數據的後果從業務角度來看是可以接受的,那麼這是一個完全合理的解決方案。你可能不希望實際到期緩存,直到你得到你的第一個請求後的10秒已經過去(因爲單個用戶的影響並不十分顯著......如果延遲處理該用戶的請求是明顯的,預先將緩存過期可以)。

1

聽起來這可能是一個單例操作(例如,所有請求都會使用相同的操作結果)。如果是這樣的話,這聽起來像是可以緩存在HttpRuntime.Cache中的東西。

var mutex = new Mutex(); 

public IEnumerable<MyData> GetMyData() 
{ 
    mutex.WaitOne(); 
    var cache = HttpRuntime.Cache; 
    var data = cache["MyData"] as IEnumerable<MyData>; 
    if (data == null) 
    { 
    data = API.ExpensiveCall(); 
    cache.Add("MyData", data, null, 
     DateTime.Now.AddSeconds(60), Cache.NoSlidingExpiration, CacheItemPriority.High, null); 
    } 

    mutex.ReleaseMutex(); 
    return data; 
} 

在這個意義上說,你叫GetMyData它確實對應用程序緩存的檢查,如果數據不存在(或者已經過期,這被刪除),我們使我們的昂貴的調用,緩存結果並返回數據。

+1

我喜歡超時的想法。我現在看到的唯一(小)問題是,當超時到期並且是時候調用ExpensiveCall()時,它將是阻塞調用。而不是尋找一個當地餐桌,這是一個不斷更新的獨立過程。這是我發現投票想法有吸引力的事情。儘管我必須承認,每10秒輪詢一次就會感到奇怪,這就是爲什麼我要圍繞它進行投票。 – 7wp

+0

請使用'lock'或'try {...} finally {...}'來避免在特殊情況下鎖定互斥鎖。 – binki

+0

此外,請注意'互斥'應該是一個靜態類成員或什麼...使用'var'暗示它可能存在於某些本地範圍內。 – binki