session_set_save_handler無關的memcached儲存session的方法
在memcached伺服器上
1)下載memcached
#wget http://memcached.googlecode.com/files/memcached-1.4.15.tar.gz
2)由於memcached依賴libevent所以需要先安裝libevent庫,這裡直接yum安裝
#yum install *libevent*
3)安裝memcached
#./configure --prefix=/usr/local/memcached
#make
#make install
4)啟動memcached
#/usr/local/memcached/bin/memcached -d -m 4096 -p 11211 -u root
-d daemon ?-p port -u ?user -m memory
在web server伺服器上
5)在web server上安裝php的memcache模組
#/usr/local/php/bin/pecl install memcache
Enable memcache session handler support? [yes] : yes(這裡選擇yes)
6)在php.ini中加入如下內容:
extension=/usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/memcache.so
7)修改php.ini中的session.save_handler及session.save_path為如下內容:
session.save_handler = memcache
session.save_path = "tcp://memcached伺服器ip:11211"
亦可在PHP程式中
ini_set('session.save_handler', 'memcache');
ini_set('session.save_path', 'tcp://memcached伺服器ip:11211');
注意:這種使用memcached儲存session的方式與session_set_save_handler無關
安裝完memcached之後
在php.ini中
將session.save_handler 修改為memcache,並修改save_path指向memcached的地址和連接埠即可
session.save_handler = memcache
session.save_path = tcp://127.0.0.1:11211
memcache的PECL這個擴充非常強大,可以支援failover以及分布儲存。
使用方法很簡單,只需要在session.save_path的參數列表中,使用逗號分隔各個memcached伺服器,如:
session.save_path = "tcp://172.16.8.81:11211,tcp://172.16.8.82:11211,tcp://172.16.8.83:11211"
則儲存的session會經過hash之後儲存到各個memcached伺服器中,而hash的演算法memcache支援兩種,crc32以及fnv:
memcache.hash_function= {crc32,fnv}
文檔中很少有提到fnv演算法的,據說其散列要比crc32更好,但是我通過以下小小的程式實驗之後,發現仍舊是crc32的散列演算法分布的更加平均。
<?phpini_set("memcache.hash_function", "crc32");$memcache = new Memcache;$memcache1 = new Memcache;$memcache2 = new Memcache;$memcache->addServer('localhost', 11211);$memcache->addServer('localhost', 11212);$memcache->flush();$memcache1->connect('localhost', 11211);$memcache2->connect('localhost', 11212);$fp1 = fopen("mem1.txt", "w");$fp2 = fopen("mem2.txt", "w");for ($i = 0; $i < 1000; $i++){$memcache->set($i, $i, 0, 1000);fwrite($fp1, $memcache1->get($i) . " ");fwrite($fp2, $memcache2->get($i) . " ");}fclose($fp1);fclose($fp2);
接著我就session的儲存進行了測試
我開了3個memcached進程進行測試
<?phpini_set("memcache.hash_function", "fnv");ini_set("error_reporting", "E_CORE_ERROR");$memcache1 = new Memcache;$memcache1->connect('localhost', 11211);$memcache1->flush();$memcache2 = new Memcache;$memcache2->connect('localhost', 11212);$memcache2->flush();$memcache3 = new Memcache;$memcache3->connect('localhost', 11213);$memcache3->flush();$fp1 = fopen('mem1.txt', 'w');$fp2 = fopen('mem2.txt', 'w');$fp3 = fopen('mem3.txt', 'w');for ($i = 0; $i < 1000; $i++){session_start();$ssid = session_id();echo $ssid;session_register("id");$_SESSION["id"] = $ssid;session_write_close();fwrite($fp1, $memcache1->get($ssid) . ' ');fwrite($fp2, $memcache2->get($ssid) . ' ');fwrite($fp3, $memcache3->get($ssid) . ' ');//session_destroy();}fclose($fp1);fclose($fp2);fclose($fp3);
比較奇怪的是 memcached2一般都會不被選中,
而1,3的內容是一致的。可能是為了failover,
而當我把1,3關閉後,2中將會出現內容,說明memcached2是正常工作的。
而不論我的散列演算法使用crc32還是fnv,這種現象都存在,
最後我發現:這個測試程式存在問題。
因為在session_write_close之後,整個程式的session都是唯一的了。
也就是雖然迴圈了這麼多次,裡麵包含了session_destroy調用,但是返回的session id都是同樣的。
這就導致了兩個檔案中的內容一致而另一個檔案中沒有內容,
基於此點,
我只能分次呼叫指令碼,指令碼修改如下:
<?phpini_set("memcache.hash_strategy", "consistent");ini_set("memcache.hash_function", "crc32");ini_set("error_reporting", "E_CORE_ERROR");ini_set("memcache.allow_failover", "0");$memcache1 = new Memcache;$memcache1->connect('localhost', 10001);$memcache1->flush();$memcache2 = new Memcache;$memcache2->connect('localhost', 10002);$memcache2->flush();$memcache3 = new Memcache;$memcache3->connect('localhost', 10003);$memcache3->flush();$fp1 = fopen("mem1.txt", "a+");$fp2 = fopen("mem2.txt", "a+");$fp3 = fopen("mem3.txt", "a+");session_start();$ssid = session_id();echo $ssid . "\n";session_register("id");$_SESSION["id"] = $ssid;//session_destroy();session_write_close();fwrite($fp1, $memcache1->get($ssid) . " ");fwrite($fp2, $memcache2->get($ssid) . " ");fwrite($fp3, $memcache3->get($ssid) . " ");session_destroy();fclose($fp1);fclose($fp2);fclose($fp3);
然後再shell中重複運行多次,返回的ID不同了。
再開啟mem*.txt檔案查看,
發現3個檔案中,每個session會儲存在其中兩個檔案,然後分布不同。
這證明了使用memcache來儲存session,一個是做到了failover,第二會按照session id來做hash分布儲存。