3.1 Caching模式
Caching(緩衝)模式描述了如何通過用完資源後不立刻釋放資源來避免對資源的昂貴的重新擷取。資源會維持它們的標識,並保留在某種可以快速存取的儲存空間中。它們可以被重用,從而避免了重新擷取。
1.問題
對相同資源的重複的擷取、初始化以及釋放造成了不必要的開銷。在系統的同一個組件或者多個組件訪問相同資源的情形下,重複的擷取和初始化帶來了CPU周期和系統整體效能的開銷。應該減少擷取、訪問和釋放頻繁使用的資源的開銷,以提高效能。為瞭解決這個問題,需要關注以下幾點:
1)效能(Performance)。重複擷取、初始化和釋放資源的開銷必須最小化。
2)複雜性(Complexity)。解決方案不應當使得擷取和釋放資源的操作變得更複雜,更麻煩。此外,解決方案也不應對資源訪問增加不必要的間接層。
3)可用性(Availability)。解決方案應當在資源提供者暫時停用情況下也使得資源可以被訪問。
4)延展性(Scalability)。解決方案應該對於資源的數目而言是可伸縮的。
2.解決方案
暫時把資源儲存在稱做“緩衝”的快速存取緩衝區中。當資源後來被訪問時,用緩衝來擷取和返回資源,而不需要從資源提供者(比如管理資源的作業系統)重新擷取它。緩衝通過資源標識(比如指標、引用、主鍵)來識別資源。
保持頻繁訪問的資源,不釋放它們,這避免了重新擷取和釋放資源的開銷。使用緩衝簡化了對訪問資源的組件的管理。
當緩衝中的資源不再需要時,它們就被釋放了。緩衝的實現決定了如何去除不再需要的資源。這一行為受策略控制。
3.結構
資源使用者使用資源。
資源是一個實體(比如串連)。
資源緩衝(Resource Cache)緩衝了資源使用者釋放的資源。
資源提供者擁有並管理多種資源。
4.實現
1)選擇資源。選擇可以從緩衝獲益的資源。這些通常是擷取代價高昂,使用頻繁的資源。緩衝經常在發現效能瓶頸之後作為最佳化手段被引入。
在分布式系統中,存在兩種緩衝,用戶端緩衝和伺服器端緩衝。用戶端的緩衝對於節省頻寬以及節省用於重複地從服務端傳送資料到用戶端的時間很有效。而服務端緩衝則有助於解決多個客戶請求導致重複擷取和釋放服務端的相同資源的問題。
2)決定緩衝介面。資源若要被釋放,並被資源使用者直接從緩衝中重新擷取,就必須設計一個合適的介面。這個介面需要提供release()和acquire()方法。
public interface Cache{
public void release(Resource resource);
public Resource acquire(Identity id);
}
上面的介面依賴於獨立的資源標識。但不是所有的資源都有獨立的標識。在某些情況下,資源標識可能需要從資源的屬性計算得出。
資源使用者把資源釋放到緩衝(而不是釋放給資源提供者)時會調用release()方法。
3)實現緩衝。Cache介面中acquire()和release()方法的實現提供了緩衝的主要功能。
public class CacheImpl implements Cache {
public void release(Resource resource) {
String id = resource.getId();
map.put(id, resource);
}
//....
HashMap map;
}
release()方法把資源添加到map中,這樣稍後對acquire()的調用就可以通過它的標識找到資源。為了達到最佳化的目的,建議使用雜湊表,因為雜湊表可以執行幾乎是常數時間複雜度的尋找。
緩衝實現中的acquire()方法應當負責基於標識從表中尋找資源。另一種變體是,當資源從緩衝中擷取失敗時,那就意味著沒有找到所需標識的資源,那麼緩衝本身可以從資源提供者擷取資源。public class CacheImpl implements Cache {
public Resource acquire(Identity id) {
Resource resource = map.get(id);
if (resource == null)
throw new ResourceNotFound();
return resource;
}
} 4)決定如何整合緩衝(可選)。如果必須透明地整合緩衝,就可以使用Interceptor(截取器)模式或者Cache Proxy模式。引入Interceptor或者Cache Proxy把操作變得透明,從而降低了顯式地釋放資源到緩衝以及從緩衝重新擷取資源的複雜性。5)決定清除策略。儲存在緩衝中的資源會佔用儲存空間。若許久未用,那麼保留這些資源就變得低效了。因此,應該使用Evictor模式來刪除不再需要使用的資源。6)確保一致性。很多資源都有相關聯的狀態,必須在資源建立時正確地初始化這些狀態。此外,當資源被寫操作所訪問時,需要在原來的資源和鏡像原來資源的緩衝中的資源之間保持一致性。 5.結論優點:1)效能。對頻繁使用的資源的快速存取是緩衝的一個明顯好處。和Pooling模式不同,緩衝確保資源維持它們的標識。因此,當相同的資源需要被再次訪問時,資源就不需要從別的地方擷取,它已經在那裡了。2)延展性。避免資源擷取和釋放是緩衝的一個“隱藏”的好處。本質上緩衝的實現方式是儲存頻繁訪問的資源。因此,和Pooling模式一樣,Caching模式有助於避免擷取和釋放資源的開銷。這對於頻繁的使用尤其有好處,從而提升了延展性。3)使用複雜性。緩衝確保了從使用者的角度擷取和釋放資源的複雜性不會增加,雖然需要有額外的步驟來檢查資源是否在緩衝中可獲得。4)可用性。緩衝資源在資源提供者暫時停用時候增加了資源的可用性,因為被緩衝的資源還是可用的。5)穩定性。因為Caching模式減少了釋放和重新擷取資源的操作量,所以降低了記憶體片段的可能性,從而會帶來更好的系統的穩定性,這和Pooling模式類似。 缺點:1)同步複雜性。取決於資源的類型,複雜性會增加,因為需要保證被緩衝的資源和緩衝資源所代表的未經處理資料的狀態的一致性。這一複雜性在叢集環境中變得更加顯著,在某些極端的情況下會使得這個模式毫無用處。2)持久性。對被緩衝的資源的改變在系統崩潰時可能會丟失。但是,如果使用了同步緩衝,那麼這個問題可以被避免。3)空間開銷。系統的運行時空間開銷會增加,因為很可能沒被使用的資源也被緩衝了。但是,如果使用Evictor模式,那麼可以把這種未使用的被緩衝的資源的數目最小化。