為什麼不能用memcached儲存Session
Memcached建立者Dormando很早就寫過兩篇文章[1][2],告誡開發人員不要用memcached儲存Session。他在第一篇文章中給出的理由大致是說,如果用memcached儲存Session,那麼當memcached叢集發生故障(比如記憶體溢位)或者維護(比如升級、增加或減少伺服器)時,使用者會無法登入,或者被踢掉線。而在第二篇文章中,他則指出,memcached的回收機制可能會導致使用者無緣無故地掉線。
Titas Norkūnas是DevOps諮詢服務提供商Bear Mountain的聯合創始人。由於看到Ruby/Rails社群忽略了Dormando那兩篇文章所指出的問題,所以他近日撰文對此進行了進一步的闡述。他認為問題的根本在於,memcached是一個設計用於快取資料而不是儲存資料的系統,因此不應該用於儲存Session
對於Dormando的那兩篇文章,他認為第一篇文章給出的原因很容易理解,而人們經常會對第二篇文章給出的原因認識不足。因此他對這個原因進行了詳細地闡述:
Memcached使用“最近最少使用(LRU)”演算法回收快取。但memcached的LRU演算法針對每個slab類執行,而不是針對整體。
這意味著,如果所有Session的大小大致相同,那麼它們會分成兩三個slab類。所有其它大小大致相同的資料也會放入同一些slab,與Session爭用儲存空間。一旦slab滿了,即使更大的slab中還有空間,資料也會被回收,而不是放入更大的slab中……在特定的slab中,Session最老的使用者將會掉線。使用者將會開始隨機掉線,而最糟糕的是,你很可能甚至都不會注意到它,直至使用者開始抱怨……
另外,Norkūnas提到,如果Session中增加了新資料,那麼Session變大也可能會導致掉線問題出現。
有人提出將Session和其它資料分別使用單獨的memcached快取。不過,由於memcached的LRU演算法是區域性的,那種方式不僅導致記憶體使用率不高,而且也無法消除使用者因為Session回收而出現隨機掉線的風險。
如果讀者非常希望藉助memcached提高Session讀取速度,那麼可以借鑑Norkūnas提出的memcached+RDBMS(在有些情況下,NoSQL也可以)的模式:
-
當用戶登入時,將Session “set”到memcached,並寫入資料庫;
-
在Session中增加一個欄位,標識Session最後寫入資料庫的時間;
-
每個頁面載入的時候,優先從memcached讀取Session,其次從資料庫讀取;
-
每載入N頁或者Y分鐘後,再次將Session寫入資料庫;
-
從資料庫中獲取過期Session,優先從memcached中獲取最新資料。