正確理解 memcached,才能更好的使用
基於memcached官方wiki,寫了幾篇 memcached 內部機制的文章,比如記憶體分配、LRU的工作原理。接下來從應用的角度說說memcached,只有從正確的角度理解,才能更好的應用,否則就會出現很多誤解,比如有時候比較memcached和redis是毫無意義的。
1:記憶體、記憶體、記憶體
memcached是完全基於記憶體操作的,是一個快取系統,從本質它不是一個數據庫系統,也不支援持久化。
既然是記憶體,在使用之前問自己,memcached快取的資料如果丟失,會影響你的業務嗎?
2:分散式系統
memcached本身是一個非常輕量級的服務,不支援主輔同步,也沒有叢集的概念。但為了可擴充套件性,memcached 伺服器端和 memcached 客戶端結合起來可以構成一個分散式系統。
在memcached分散式系統中,各個 memcached 節點之間無須通訊,所以擴充套件性非常好。
3:不支援複雜的操作
和 redis 不一樣的是,memcached 沒有複雜的資料結構(比如佇列、集合),它只能儲存字串型別,也不關心具體儲存什麼,這是它的一個優勢:簡單。但很多人用的時候可能就不爽了,說它比 redis 弱爆了,其實雙方的應用場景不一樣。
當然也可以基於基本命令模擬一些資料結構,這是允許的,但這和memcached無關。
4:原子操作
memcached 所有操作都是 O(1) ,都是原子操作,同一時間操作多個 set 不會有任何的影響。
5:效能
memcached 效能高的原因主要在於 libevent 事件機制、多執行緒、全記憶體操作、模型簡單(比如 O(1),儘量避免鎖機制)。
配置相對較高的伺服器,每秒可以處理 200,000+ 的請求,即使在很慢的機器上,每秒處理幾百次也毫無壓力。
memcached 所有的操作都是 O(1),set/get 操作不應該出現滯後,一個請求正常情況下不到 1ms 就能返回,如果遇到 Hang,那可能是連線數過多、產生了 swap、遇到了網路問題。
6:不推薦儲存 session 資料
現在很多業務都用 memcached 儲存 session 資料,在使用之前一定要評估風險,因為 memcached 是基於記憶體的,如果儲存的 session 丟失了,會話使用者就掉線了。
7:不支援名稱空間
memcached 一般針對某個key進行操作,不支援 namespace 功能,原因在於為了實現namespace,會讓系統實現複雜化(比如為了實現過期設定功能)。
但名稱空間的作用卻非常大,比如以下需求:
-
希望批量刪除某些 key。
-
如果獲取相關聯資料(比如有多個key),但 memcached 節點非常多,如果這些key根據 Hash 演算法分散儲存到多個節點,那麼獲取的時候效能就會下降。
但很多客戶端模擬實現了namespace功能 ,比如 PHP memcached 擴充套件就有相應的函式,比如 addByKey(),getAllKeys() 等函式,這些後續我再說。
8:Failure or Failover
如果你的應用沒有使用一致性hash演算法或其他的hash演算法,連線某一個memcache節點的時候,如果網路連線超時,或某個節點不能通訊(比如網線被拔了),那麼客戶端呼叫只能選擇 Failure,遇到這樣的情況,可能就要去後端讀取資料了。
如果你的應用使用一致性hash演算法,那麼應該選擇 Failure or Failover?
這裡有一個誤區,一致性 hash 演算法是減少上線或下線伺服器帶來的快取失效問題,本質上不是為了讓客戶端隨時隨地都能獲取到資料。
如果網路連線超時,或某個節點不能通訊(比如網線被拔了),儘量不要選擇自動 Failover ,比如三個節點,本來某個 key 對應第一個節點,如果客戶端發現第一個節點不可用,就自動儲存到第二個節點,原因就在於如果第一個節點恢復了,可能獲取到舊的資料(在 Failover 的時候新資料更新到第二個節點)。
根據這一原則,PHP memcached 擴充套件預設是不做 Failover 的,這也是正確的應用方式,如果你實在要 Failover,可以使用下面的程式碼。
$memcache = new Memcached; $memcache->setOption(Memcached::OPT_DISTRIBUTION,Memcached::DISTRIBUTION_CONSISTENT); $memcache->setOption(Memcached::OPT_SERVER_FAILURE_LIMIT, 1); $memcache->setOption(Memcached::OPT_AUTO_EJECT_HOSTS,true); $memcache->addServer('localhost', 11212); $memcache->addServer('localhost', 11213); $memcache->set("abc",1); echo $memcache->get("abc"); print_r($memcache->getResultMessage());
9:能不能list所有的keys
不能,memcached 本身不支援,它就是一個 key-value 系統,但如果實在想實現list,可以通過兩個辦法:
-
推薦在啟動的時候配置 -vvv,這樣能夠將所有set的key打印出來,而且是排查問題非常好的方法。
-
執行 stats cachedump 命令,不過不推薦使用,因為操作比較慢,而且只能拿到區域性的資料。
10:memcached 應用場景?
-
能快取任何資料,有效減少後端的壓力並提升響應能力。
-
計算器,比如利用 incr 命令。
-
Rate limiting,非常有用,比如登陸系統可以使用它限制非法登陸。
-
雖然 memcached 不支援佇列和堆疊,但 append/prepend 命令還是有一定作用的,比如可以實現排行榜。
11:一些小技巧
(1)Zero byte values
如果你只是要使用 memcached 的key ,其對應的value沒有任何價值,那麼為了減少記憶體的使用,可以設定0位元組長的值。
(2)儘量減少 key 長度,有效利用記憶體。
(3)有效利用鎖機制,比如 add 命令,專門寫過一篇文章介紹過《使用Memcached實現抽獎活動 》。