收集現有博文里都集中在描述memcache擴展的缺陷,簡單總結如下:
- 高并發下TS不好,不穩定
- 協議支持不完整: memcached擴展基于memcached項目的lib庫,能夠以極低的成本跟進memcache的更新;并且因為此特點,也支持了更多的mc協議。
- 將數字存儲為字符串: 對于強類型,或者是php中"==="這種比較會造成困擾,如set一個test:1, get test會返回"1",與1去做"==="會返回false,造成開發者困惑;
memcached擴展(比對memcache extension)功能上的優化點:
- 提供了setOption api 可以統一設置flag
- 支持二進制協議,提供了更高的性能,低內存、線程安全
- 功能更多:cas 檢查并設置
memcache擴展(比對memcached extension)更多的功能點(09年的2.2.0開始支持一致性hash):
- 
支持OO和過程兩組接口,而memcached擴展只支持OO
- 
支持獲取or設置key時的failover
其中功能點1不夠吸引人,PHP5版本之后,全線切OO編程,因此OO方法足夠實現用戶的直接使用,關鍵是功能點2。查閱資料可以得知,當網絡抖動or部分服務臨時不可用時,memcache擴展會主動的進行rehash,造成數據一致性問題,以一個簡單的計數器(限流用)舉例:
<?php                                                                                                                                                                     		error_reporting(-1);
	//$client = new memcached;
	$client = new memcache;
	$arr = array(
	    array("host"=>"127.0.0.1","port"=>11211),
	    array("host"=>"127.0.0.1","port"=>11212),
	);
	foreach ($arr as $ele)
	{
	    $client->addServer($ele["host"],$ele["port"],true);
	}
	$counter = $client->get('counter');
	var_dump($counter);
	if (empty($counter))
	    $client->set('counter', 100, 0);
	for ($i=0; $i < 100; $i++)
	{
	    try
	    {
	        printf("get counter...");
	        sleep(2);
	        $counter = $client->get('counter');
	        printf($counter);
	        if (false === $counter)
	        {
	            printf("connect error");
	            sleep(1);
	            continue;
	        }
	        if (0 >= $counter)
	        {
	            printf("loop end\n");
	            sleep(1);
	            exit(1);
	        }
	        printf("set counter...\n");
	        sleep(2);
	        $client->set('counter', $counter - 1);
	    }
	    catch (Exception $e)
	    {
	        echo "*";
	        var_dump($e->getMessage());
	        continue;
	    }
	}
	exit(0);模擬錯誤場景:
a. php連接11211和11212集群,counter作為key存在11211實例上; 
b. 循環繼續,eg:當計數器到90的循環內,在set counter階段,mcd進程11211失效(以kill來仿真),則將會把counter作為key寫入11212節點中(報一個notice) ; 
c. 計數器繼續遞減,eg:當counter為80時,在get counter階段 11211又啟動,所以從11211中拿數據,此時數據為false;在set counter階段,則將counter=>80寫到11211中; 
d. 計數器繼續遞減,eg:當counter為70時,在get counter階段 11211又失效,則獲取counter會拿到上一次切換的點80; 
e. 如果使用memcached擴展,則一旦對應的節點失效就會報錯,保證通知到運維方,對mc集群進行處理。
由于集群的網絡環境不可控,單次操作超時 or 單節點短時間不可用的場景會頻繁出現,因此不會使用隨機節點rehash的方式來保證系統可用,對數據一致性造成的負面影響過大,因此在memcached擴展中,選擇直接返回false,是取舍上收益更大的選擇。
針對此錯誤場景的通用解法應該是:
1. 本地緩存(臨時方案) 
2. 利用緩存代理(magent)
總結memcache擴展與memcached擴展對比如下表:
|  | PECL/MEMCACHE | PECL/MEMCACHED | 
|---|---|---|
| FIRST RELEASE DATE | 2004-06-08 | 2009-01-29 (beta) | 
| ACTIVELY DEVELOPED | Yes | Yes | 
| EXTERNAL DEPENDENCY | None | libmemcached | 
| Features |  |  | 
| AUTOMATIC KEY FIXUP | Yes | No | 
| APPEND/PREPEND | No | Yes | 
| AUTOMATIC SERIALZATION | Yes | Yes | 
| BINARY PROTOCOL | No | Optional | 
| CAS | No | Yes | 
| COMPRESSION | Yes | Yes | 
| COMMUNICATION TIMEOUT | Connect Only | Various Options | 
| CONSISTENT HASHING | Yes | Yes | 
| DELAYED GET | No | Yes | 
| MULTI-GET | Yes | Yes | 
| SESSION SUPPORT | Yes | Yes | 
| SET/GET TO A SPECIFIC SERVER | No | Yes | 
| STORES NUMERICS | Converted to Strings | Yes | 
因此從一個中間件擴展的簡單選型可以發現:在做開發框架技術選型時,設計者要保證對中間件擴展的掌握并進行充分測試。根據具體業務場景,進行合理選型。