圖 1. 一個典型的博客頁面內的可緩存元素
將這種結構放在 blog 站點的其他元素,poster 信息、注釋 — 設置 blog post 本身 — 進行推斷,可以看出為了顯示主頁的內容很可能需要發生 10-20 次數據庫查詢和格式化。 每天對數百甚至數千的的頁面查看重復此過程,那麼您的服務器和應用程序執行的查詢要遠遠多於為了顯示頁面內容所需執行的查詢。
通過使用 memcached,可以將加載自數據庫的格式化信息存儲為一種可直接用在 Web 頁面上的格式。並且由於信息是從 RAM 而不是通過數據庫和其他處理從磁盤加載的,所以對信息的訪問幾乎是瞬時的。
再強調一下,memcached 是一個用來存儲常用信息的緩存,有了它,您便無需從緩慢的資源,比如磁盤或數據庫,加載並處理信息了。
對 memcached 的接口是通過網絡連接提供的。這意味著您可以在多個客戶機間共享單個的 memcached 服務器(或多個服務器,如本文稍後所示的)。這個網絡接口非常迅速,並且為了改善性能,服務器會故意不支持身份驗證或安全性通信。但這不應限制部署選項。memcached 服務器應該存在於您網絡的內部。網絡接口的實用性以及可以部署多個 memcached 實例的簡便性讓您可以使用多個機器上的多余 RAM 來提高您緩存的整體大小。
memcached 的存儲方法是一個簡單的鍵/值對,類似於很多語言內的散列或關聯數組。通過提供鍵和值來將信息存儲到 memcached 內,通過按特定的鍵請求信息來恢復信息。
信息會無限期地保留在緩存內,除非發生如下的情況:
上述這些情況可以與您應用程序的邏輯綜合使用以便確保緩存內的信息是最新的。有了這些基礎知識後,讓我們來看看在應用程序內如何能最好地利用 memcached。
在使用 memcached 改進應用程序性能時,可以對一些關鍵的過程和步驟進行修改。
在加載信息時,典型的場景如圖 2 所示。
圖 2. 加載要顯示的信息的典型順序
一般而言,這些步驟是:
在使用 memcached 時,為配合這個緩存,可對應用程序的邏輯進行稍許修改:
圖 3 是對這些步驟的總結。
圖 3. 在使用 memcached 時加載適合於顯示的信息
數據加載成為了至多三個步驟的一個過程,從緩存加載數據或從數據庫(視情況而定)加載數據並存儲在緩存內。
當這個過程首次發生時,數據將正常地從數據庫或其他數據源加載,然後再存儲到 memcached 內。當下一次訪問此信息時,它就會從 memcached 拉出,而不是從數據庫加載,節省了時間和 CPU 循環。
問題的另一個方面是要確保如果更改了要存儲在 memcached 內的信息,在更新後端信息的同時還要更新 memcached 的版本。這會讓圖 4 內所示的這個典型順序發生稍許變化,如 圖 5 所示。
圖 4. 在一個典型的應用程序內更新或存儲數據
圖 5.顯示了使用 memcached 後發生了變化的流程
比如,仍以博客站點為例,在博客系統更新數據庫內的類別列表時,更新應該遵循如下順序:
memcached 內的存儲操作是原子的,所以信息的更新不會讓客戶機只獲得部分數據;它們獲得的或者是老版本,或者是新版本。
對於大多數應用程序,這兩個操作是您惟一需要注意的。在訪問他人使用的數據時,它會自動被添加到這個緩存內,而且如果對該數據進行了更改,此緩存內也會自動進行更新。
memcached 另一個需要重點考慮的因素是如何組織和命名存儲在緩存內的這些數據。從之前博客站點的例子中,不難看出需要使用一種一致的命名結構以便您能加載博客類別、歷史和其他信息,然後再在加載信息(並更新緩存)時或者在更新數據(同樣也要更新緩存)時使用。
使用的何種具體的命名系統特定於應用程序,但通常可以使用一種與現有應用程序類似的結構,並且這種結構很可能基於某種惟一識別符。當從數據庫拉出信息或在整理信息集時,就會發生這種情況。
以 blog post 為例,可以在一個具有鍵 category-list 的項中存儲類別列表。與此 post ID 對應的單個 post,比如 blogpost-29 相關的值都可以使用,而該項的注釋則可以存儲在 blogcomments-29 內,其中 29 就是這個 blog post 的 ID。這樣一來, 您就可以將各種各樣的信息存儲在緩存內,使用不同的前綴來標識這些信息。
memcached 鍵/值存儲的簡便性(以及安全性的缺乏)意味著如果您想要在使用同一個 memcached 服務器的同時支持多個應用程序,那麼就可以考慮使用其他格式的量詞來標識數據屬於某種特定的應用程序。比如,可以添加像 blogapp:blogpost-29 這樣的應用程序前綴。這些鍵是沒有格式的,所以可以使用任何字符串作為鍵的名稱。
在存儲值的方面,應該確保存儲在緩存內的信息適合於您的應用程序。比如,對於這個博客系統,您可能想要存儲被博客應用程序使用的對象以便格式化博客信息,而不是原始的 HTML。如果同一個基礎結構用在應用程序內的多個地方,這一點更具實用性。
大多數語言的接口,包括 Java?、Perl、PHP 等,都能串行化語言對象以便存儲在 memcached 內。這就讓您可以存儲並隨後從內存存儲恢復全部對象,而不是在您的應用程序內手動重構它們。 很多對象,或它們使用的結構,都基於某種散列或數組結構。對於跨語言的環境,比如在 JSP 環境和 JavaScript 環境間共享相同信息,可以使用一種架構中立的格式,比如 JavaScript Object Notation (JSON) 甚或 XML。
作為一種開源產品以及一種最初開發用來工作於現有開源環境內的產品,memcached 受大量環境和平台支持。與 memcached 服務器通信的接口有很多,並常常具有針對所有語言的多個實現。參見 參考資料 以獲得常用的庫和工具箱。
要列出所有受支持的接口和環境不太可能,但它們均支持 memcached 協議提供的基礎 API。這些描述已經被簡化並應用在不同語言的上下文內,在這些語言中,使用不同的值可指示錯誤。主要的函數有:
比如,在 Perl 內,基本 set 操作可以如清單 1 所示的那樣處理。
use Cache::Memcached;
my $cache = new Cache::Memcached {
'servers' => [
'localhost:11211',
],
};
$cache->set('mykey', 'myvalue');
Ruby 內的相同的基本操作如清單 2 所示。
require 'memcache'
memc = MemCache::new '192.168.0.100:11211'
memc["mykey"] = "myvalue"
在兩個例子中可以看到相同的基本結構:設置 memcached 服務器,然後分配或設置值。其他的接口也可用,包括適合於 Java 技術的那些接口,讓您可以在 WebSphere 應用程序內使用 memcached。memcached 接口類允許將 Java 對象直接序列化到 memcached 以便於存儲和加載復雜的結構。當在像 WebSphere 這樣的環境內進行部署時,有兩個事情非常重要:服務的彈性(在 memcached 不可用時如何做)以及如何提高緩存存儲量來改進在使用多個應用程序服務器或在使用像 WebSphere eXtreme Scale 這樣的環境時的性能。我們接下來就來看看這兩個問題。
有關 memcached 最常見的一個問題是:“若緩存不可用了,會發生什麼情況呢?”正如之前章節中明示的,緩存內的信息不應該成為信息的的惟一資源。必須要能夠從其他位置加載存儲在緩存內的數據。
雖然,無法從緩存訪問信息將會減緩應用程序的性能,但它不應該阻止應用程序的運轉。可能會發生這樣幾個場景:
如果 memcached 服務宕掉,應用程序應該回退到從原始數據源加載信息並對信息進行顯示所需的格式化。此應用程序還應繼續嘗試在 memcached 內加載和存儲信息。
一旦 memcached 服務器恢復可用,應用程序就應該自動嘗試存儲數據。沒有必要強制重載已緩存了的數據,可以使用標准的訪問來用信息加載和填充緩存。最終,緩存將會被最常用的數據重新填充。
再次重申,memcached 是信息的緩存但並非惟一的數據源。memcached 服務器不可用不應該是應用程序的終結,雖然這意味著在 memcached 服務器恢復正常之前性能會有所降低。實際上,memcached 服務器相對簡單,並且雖然不是絕對無故障的,但它的簡單性的結果就是它很少會出錯。
memcached 服務器只是網絡上針對一些鍵存儲值的一個緩存。如果有多台機器,那麼很自然地會想要在所有多余機器上設置一個 memcached 的實例來提供一個超大的聯網 RAM 緩存存儲。
有了這個想法後,還有一種想當然是需要使用某種分配或復制機制來在機器之間復制鍵/值對。這種方式的問題是如果這麼做反而會減少可用的 RAM 緩存,而不是增加。如圖 6 所示,可以看出這裡有三個應用程序服務器,每個服務器都可以訪問一個 memcached 實例。
圖 6. 多重 memcached 實例的不正確使用
盡管每個 memcached 實例都是 1 GB 的大小(產生 3 GB 的 RAM 緩存),但如果每個應用程序服務器只有其自己的緩存(或者在 memcached 之間存在著數據的復制),那麼整個安裝也仍只能有 1 GB 的緩存在每個實例間復制。
由於 memcached 通過一個網絡接口提供信息,因此單個的客戶機可以從它所能訪問的任何一個 memcached 實例訪問數據。如果數據沒有跨每個實例被復制,那麼最終在每個應用程序服務器上,就可以有 3 GB 的 RAM 緩存可用,如圖 7 所示。
圖 7. 多重 memcached 實例的正確使用
這個方法的問題是選擇哪個服務器來儲存鍵/值對,以及當想要重新獲得一個值時,如何決定要與哪個 memcached 服務器對話。問題的解決方案就是忽略復雜的東西,比如查找表,或是寄望 memcached 服務器來為您處理這個過程。而 memcached 客戶機則必須要力求簡單。
memcached 客戶機不必決定此信息,它只需對在存儲信息時指定的鍵使用一個簡單的散列算法。當想要從一列 memcached 服務器存儲或獲取信息時,memcached 客戶機就會用一個一致的散列算法從這個鍵獲取一個數值。舉個例子,鍵 mykey 被轉換成數值 23875 。是保存還是獲取信息無關緊要,這個鍵將總是被用作惟一標識符來從 memcached 服務器加載,因此在本例中,“mykey” 散列轉化後對應的值總是 23875。
如果有兩個服務器,那麼 memcached 客戶機將對這個數值進行一個簡單的運算(例如,系數)來決定它應將此值存儲在第一個還是第二個配置了的 memcached 實例上。
當存儲一個值時,客戶機會從這個鍵確定出散列值以及它原來存儲在哪個服務器上。當獲取一個值時,客戶機會從這個鍵確定出相同的散列值並會選擇相同的服務器來獲取信息。
如果在每個應用程序服務器上使用的是相同的服務器列表(並且順序相同),那麼當需要保存或檢索同一個鍵時,每個應用程序服務器都將選擇同一個服務器。現在,在這個例子中,有 3GB 的 memcached 空間可以共享,而不是同一個 1 GB 的空間的復制,這就帶來了更多的可用緩存,並很有可能會提高有多個用戶情況下的應用程序的性能。
這個過程也有其復雜性(比如當一個服務器不可用時會怎樣),更多信息,請參見相關文檔(參見 參考資料)。
盡管 memcached 很簡單,但 memcached 實例有時候還是會被不正確地使用。
最常見的 memcached 誤用就是把它用作一個數據存儲,而不是一個緩存。memcached 的首要目的就是加快數據的響應時間,否則數據從其他數據源構建或恢復需要很長時間。一個典型的例子就是從一個數據庫中恢復信息,特別是在信息顯示給用戶前需要對信息進行格式化或處理的時候。Memcached 被設計用來將信息存儲在內存中以避免每次在數據需要恢復時重復執行相同的任務。
切不可將 memcached 用作運行應用程序所需信息的惟一信息源;數據應總是可以從其他信息源獲取。此外,要記住 memcached 只是一個鍵/值的存儲。不能在數據上執行查詢,或者對內容進行迭代來提取信息。應該使用它來存儲數據塊或對象以備批量使用。
雖然可以使用 memcached 存儲加載自數據庫的數據行,但這實際上是查詢緩存,並且大多數數據庫都提供各自的查詢緩存的機制。其他的對象,比如文件系統的圖像或文件的情況與此相同。很多應用程序和 web 服務器針對此類工作已經有了一些很好的解決方案。
如果在加載和格式化後,使用它來存儲全部信息塊,就可以從 memcached 獲得更多的實用工具和性能上的改善。仍以我們的博客站點為例,存儲信息的最佳點是在將博客類別格式化為對象,甚至是在格式化成 HTML 後。博客頁面的構造可通過從 memcached 加載各個組件(比如 blog post、category list、post history 等)並將完成的 HTML 寫回至客戶機實現。
為了確保最佳性能,memcached 並未提供任何形式的安全性,沒有身份驗證,也沒有加密。這意味著對 memcached 服務器的訪問應該這麼處理:一是通過將它們放到應用程序部署環境相同的私有側,二是如果安全性是必須的,那麼就使用 UNIX? socket 並只允許當前主機上的應用程序訪問此 memcached 服務器。
這多少犧牲了一些靈活性和彈性,以及跨網絡上的多台機器共享 RAM 緩存的能力,但這是在目前的情況下確保 memcached 數據安全性的惟一一種解決方案。
除了不應該使用 memcached 實例的情況外,memcached 的靈活性不應忽視。由於 memcached 與應用程序處於相同的架構水平,所以很容易集成並連接到它。並且更改應用程序以便利用 memcached 也並不復雜。此外,由於 memcached 只是一個緩存,所以在出現問題時它不會停止應用程序的執行。如果使用正確的話,它所做的是減輕其余服務器基礎設施的負載(減少對數據庫和數據源的讀操作),這意味著無需更多的硬件就可以支持更多的客戶機。
但請記住,它僅僅是個緩存!
在本文中,我們了解了 memcached 以及如何最佳地使用它。我們看到了信息如何存儲、如何選擇合理的鍵以及如何選擇要存儲的信息。我們還討論了所有 memcached 用戶都要遇到的一些關鍵的部署問題,包括多服務器的使用、當 memcached 實例消亡時該怎麼做,以及(也許最為重要的)在哪些情況下不能使用 memcached。
作為一種開源的應用程序並且是目的簡單而直白的應用程序,memcached 的功能和實用性均來自於這種簡單性。通過為信息提供巨大的 RAM 存儲空間、讓它在網絡上可用,然後再讓它可通過各種不同的接口和語言訪問到,memcached 可被集成到多種多樣的安裝和環境中。