1、memcache的概念?
Memcache是一個高性能的分布式的內存對象緩存系統,通過在內存里維護一個統一的巨大的hash表,它能夠用來存儲各種格式的數據,包括圖像、視頻、文件以及數據庫檢索的結果等。簡單的說就是將數據調用到內存中,然后從內存中讀取,從而大大提高讀取速度。在動態系統中減少數據庫負載,提升性能。
memcache模塊是一個高效的守護進程,提供用于內存緩存的過程式程序和面向對象的方便的接口,特別是對于設計動態web程序時減少對數據庫的訪問
2:作用:它可以應對任意多個連接,使用非阻塞的網絡IO。由于它的工作機制是在內存中開辟一塊空間,然后建立一個HashTable,Memcached自管理這些HashTable。
3:Memcache官方網站:http://www.danga.com/memcached,更多詳細的信息可以來這里了解 :)
為什么會有Memcache和memcached兩種名稱?
其實Memcache是這個項目的名稱,而memcached是它服務器端的主程序文件名。一個是項目名稱,一個是主程序文件名,在網上看到了很多人不明白,于是混用了。
4:適用場合
1)分布式應用。由于memcached本身基于分布式的系統,所以尤其適合大型的分布式系統。
2)數據庫前段緩存。數據庫常常是網站系統的瓶頸。數據庫的大并發量訪問,常常造成網站內存溢出。當然我們也可以使用Hibernate的緩存機制。但memcached是基于分布式的,并可獨立于網站應用本身,所以更適合大型網站進行應用的拆分。
3)服務器間數據共享。舉例來講,我們將網站的登錄系統、查詢系統拆分為兩個應用,放在不同的服務器上,并進行集群,那這個時候用戶登錄后,登錄信息如何從登錄系統服務器同步到查詢系統服務器呢?這時候,我們便可以使用memcached,登錄系統將登錄信息緩存起來,查詢系統便可以獲得登錄信息,就像獲取本地信息一樣。
5:不適用場合
那些不需要“分布”的,不需要共享的,或者干脆規模小到只有一臺服務器的應用,memcached不會帶來任何好處,相反還會拖慢系統效率,因為網絡連接同樣需要資源
memcached安裝
【memcached 安裝使用windows 】
先把php版本從5.2.0升級到5.2.4(覆蓋原來的文件就行了)
http://jehiah.cz/projects/memcached-win32/ 上下載memcache的windows穩定版,解壓放某個盤下面,比如在c:\memcached
2.在終端(也即cmd命令界面)下輸入 'c:\memcached\memcached.exe -d install' 安裝
3.再輸入: 'c:\memcached\memcached.exe -d start' 啟動
NOTE: 以后memcached將作為windows的一個服務每次開機時自動啟動。默認端口:11211。在C:\winnt\php.ini 加入一行 'extension=php_memcache.dll'
[Memcache]
memcache.allow_failover = 1
memcache.max_failover_attempts=20
memcache.chunk_size =8192
memcache.default_port = 11211下載pecl的PECL 5.2.4 Win32 binaries模塊包,解壓縮后將其中的memcache.dll考到c:\php\ext 中,(也不一定是c盤的PHP文件夾下,主要是看你當初把PHP安裝到哪個盤符下面了)
NOTE: php和pecl的版本要一致。
6.重新啟動Apache,然后查看一下phpinfo,如果有memcache,那么就說明安裝成功!
注:memcache是danga.com的一個項目,最早是為 LiveJournal 服務的,目前全世界不少人使用這個緩存項目來構建自己大負載的網站,來分擔數據庫的壓力。
Memcache官方網站:http://www.danga.com/memcached
擴展下載: http://pecl4win.php.net/download.php/ext/5_1/5.1.2/php_memcache.dll
【安裝Memcache服務器端linux】
我目前的平臺,服務器是Fedora Core 1(內核:2.4.22),客戶端是Windows XP SP2,需要安裝的就是服務器的Memcached的守護進程和客戶端的PHP擴展php_memcache兩個東西。現在我分別來講。
服務器端主要是安裝memcache服務器端,目前的最新版本是 memcached-1.2.0 。
下載:http://www.danga.com/memcached/dist/memcached-1.2.0.tar.gz
另外,Memcache用到了libevent這個庫用于Socket的處理,所以還需要安裝libevent,libevent的最新版本是libevent-1.2。(如果你的系統已經安裝了libevent,可以不用安裝)
官網:http://www.monkey.org/~provos/libevent/
下載:http://www.monkey.org/~provos/libevent-1.2.tar.gz
我分別把兩個東東下載回來,放到 /tmp 目錄下:
cd /tmp
wget http://www.danga.com/memcached/dist/memcached-1.2.0.tar.gz
wget http://www.monkey.org/~provos/libevent-1.2.tar.gz
先安裝libevent:
tar zxvf libevent-1.2.tar.gz
cd libevent-1.2
./configure --prefix=/usr
make
make install
然后看看我們的libevent是否安裝成功:
ls -al /usr/lib | grep libevent
lrwxrwxrwx 1 root ??? root ?? ?? 21 11?? 12 17:38 libevent-1.2.so.1 -> libevent-1.2.so.1.0.3
-rwxr-xr-x ?? 1 root ??? root ?? ?? 263546 11?? 12 17:38 libevent-1.2.so.1.0.3
-rw-r--r-- ?? ??? 1 root ??? root ?? ?? 454156 11?? 12 17:38 libevent.a
-rwxr-xr-x ?? 1 root ??? root ?? ?? 811 11?? 12 17:38 libevent.la
lrwxrwxrwx 1 root ??? root ?? ?? 21 11?? 12 17:38 libevent.so -> libevent-1.2.so.1.0.3
還不錯,都安裝上了,再來安裝memcache,同時需要安裝中指定libevent的安裝位置:
cd /tmp
tar zxvf memcached-1.2.0.tar.gz
cd memcached-1.2.0
./configure --with-libevent=/usr
make
make install
如果中間出現報錯,請仔細檢查錯誤信息,按照錯誤信息來配置或者增加相應的庫或者路徑。
安裝完成后會把memcached放到 /usr/local/bin/memcached ,我們看以下是否安裝了:
ls -al /usr/local/bin/mem*
-rwxr-xr-x 1 root ??? root ?? 137986 11?? 12 17:39 /usr/local/bin/memcached
-rwxr-xr-x 1 root ??? root ?? 140179 11?? 12 17:39 /usr/local/bin/memcached-debug
恩,安裝完成了,現在我們看以下memcache的幫助:
/usr/local/bin/memecached -h
memcached 1.2.0
-p <num> 是設置Memcache監聽的端口,這里設置了12000,最好是1024以上的端口
-s <file> unix socket path to listen on (disables network support)
-l <ip_addr> 連接的IP地址, 默認是本機 是監聽的服務器IP地址,如果有多個地址的話,這里指定了服務器的IP地址192.168.0.122
-d 以守護程序(daemon)方式運行 memcached
-r maximize core file limit
-u 以的身份運行 (僅在以root運行的時候有效)<username> assume identity of <username> (only when run as root)
-m <num>最大內存使用,單位MB。默認64MB max memory to use for items in megabytes, default is 64 MB是分配給Memcache使用的內存數量,單位是MB,這里是10MB
-M內存耗盡時返回錯誤,而不是刪除項return error on memory exhausted (rather than removing items)
-c <num> 選項是最大運行的并發連接數,默認是1024,這里設置了256,按照你服務器的負載量來設定
-k lock down all paged memory
-v verbose (print errors/warnings while in event loop)
-vv very verbose (also print client commands/reponses)
-h 顯示幫助<-->print this help and exit
-i print memcached and libevent license
-b run a managed instanced (mnemonic: buckets)
-P <file> save PID in <file>, only used with -d option是設置保存Memcache的pid文件
-f <factor> 塊大小增長因子,默認是1.25chunk size growth factor, default 1.25
-n <bytes> ?? ?最小分配空間,key+value+flags默認是48minimum space allocated for key+value+flags, default 48
常用命令:
-d start 啟動memcached服務
-d restart 重起memcached服務
-d stop|shutdown 關閉正在運行的memcached服務
-d install 安裝memcached服務
-d uninstall 卸載memcached服務
netstat –an
參數不算多,我們來啟動一個Memcache的服務器端:
/usr/local/bin/memcached -d -m 10 -u root -l 192.168.0.200 -p 12000 -c 256 -P tmp/memcached.pid
-d選項是啟動一個守護進程,-m是分配給Memcache使用的內存數量,單位是MB,我這里是10MB,-u是運行Memcache的用戶,我這里是root,-l是監聽的服務器IP地址,如果有多個地址的話,我這里指定了服務器的IP地址192.168.0.200,-p是設置Memcache監聽的端口,我這里設置了12000,最好是1024以上的端口,-c選項是最大運行的并發連接數,默認是1024,我這里設置了256,按照你服務器的負載量來設定,-P是設置保存Memcache的pid文件,我這里是保存在/tmp/memcached.pid,如果要結束Memcache進程,執行:
kill cat /tmp/memcached.pid
【Memcache初試】
寫一個 example.php 文件(更多使用方法可以參看 PHP 手冊里的 Memcache Functions 使用說明),測試代碼如下:
<?php
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");
$version = $memcache->getVersion();
echo "Server's version: ".$version."
\n";
$tmp_object = new stdClass;
$tmp_object->str_attr = 'test';
$tmp_object->int_attr = 123;
$memcache->set('key', $tmp_object, false, 10) or die ("Failed to save data at the server");
echo "Store data in the cache (data will expire in 10 seconds)
\n";
$get_result = $memcache->get('key');
echo "Data from the cache:
\n";
var_dump($get_result);
?>
如果輸出如下,則測試成功:
Server's version: 1.4.5
Store data in the cache (data will expire in 10 seconds)
Data from the cache:
object(stdClass)#3 (2) { ["str_attr"]=> string(4) "test" ["int_attr"]=> int(123) }
[ 接口介紹 ]
服務器端和客戶端都安裝配置好了,現在我們就來測試以下我們的成果。Memcache客戶端包含兩組接口,一組是面向過程的接口,一組是面向對象的接口,具體可以參考PHP手冊 “LXXV. Memcache Functions”這章。我們為了簡單方便,就使用面向對象的方式,也便于維護和編寫代碼。Memcache面向對象的常用接口包括:
Memcache::connect -- 打開一個到Memcache的連接
Memcache::pconnect -- 打開一個到Memcache的長連接
Memcache::close -- 關閉一個Memcache的連接
Memcache::set -- 保存數據到Memcache服務器上
Memcache::get -- 提取一個保存在Memcache服務器上的數據
Memcache::replace -- 替換一個已經存在Memcache服務器上的項目(功能類似Memcache::set)
Memcache::delete -- 從Memcache服務器上刪除一個保存的項目
Memcache::flush -- 刷新所有Memcache服務器上保存的項目(類似于刪除所有的保存的項目)
Memcache::getStats -- 獲取當前Memcache服務器運行的狀態
[ 測試代碼 ]
現在我們開始一段測試代碼:
<?php
//連接
$mem=new Memcache;
$mem->connect("192.168.0.200",12000);
//保存數據
$mem->set('key1','This is first value',0,60);
$val=$mem->get('key1');
echo
"Get key1 value: "
.
$val
."
";
//替換數據
$mem->replace('key1','This is replace value',0,60);
$val=$mem->get('key1');
echo
"Get key1 value: "
.
$val
.
"
";
//保存數組
$arr
=
array('aaa','bbb','ccc','ddd');
$mem->set('key2',$arr,0,60);
$val2=$mem->get('key2');
echo
"Get key2 value: ";
print_r($val2);
echo
"
";
//刪除數據
$mem->delete('key1');
$val=$mem->get('key1');
echo
"Get key1 value: "
.
$val
.
"
";
//清除所有數據
$mem->flush();
$val2=$mem->get('key2');
echo
"Get key2 value: ";
print_r($val2);
echo
"
";
//關閉連接
$mem->close();
?>
如果正常的話,瀏覽器將輸出:
Get key1 value: This is first value
Get key1 value: This is replace value
Get key2 value: Array ( [0] => aaa [1] => bbb [2] => ccc [3] => ddd )
Get key1 value:
Get key2 value:
基本說明我們的Memcache安裝成功,我們再來分析以下上面的這段程序。
[ 程序分析 ]
初始化一個Memcache的對象:
$mem = new Memcache;
連接到我們的Memcache服務器端,第一個參數是服務器的IP地址,也可以是主機名,第二個參數是Memcache的開放的端口:
$mem->connect("192.168.0.200", 12000);
保存一個數據到Memcache服務器上,第一個參數是數據的key,用來定位一個數據,第二個參數是需要保存的數據內容,這里是一個字符串,第三個參數是一個標記,一般設置為0或者MEMCACHE_COMPRESSED就行了,第四個參數是數據的有效期,就是說數據在這個時間內是有效的,如果過去這個時間,那么會被Memcache服務器端清除掉這個數據,單位是秒,如果設置為0,則是永遠有效,我們這里設置了60,就是一分鐘有效時間:
$mem->set('key1', 'This is first value', 0, 60);
從Memcache服務器端獲取一條數據,它只有一個參數,就是需要獲取數據的key,我們這里是上一步設置的key1,現在獲取這個數據后輸出輸出:
$val = $mem->get('key1');
echo "Get key1 value: " . $val;
現在是使用replace方法來替換掉上面key1的值,replace方法的參數跟set是一樣的,不過第一個參數key1是必須是要替換數據內容的key,最后輸出了:
$mem->replace('key1', 'This is replace value', 0, 60);
$val = $mem->get('key1');
echo "Get key1 value: " . $val;
同樣的,Memcache也是可以保存數組的,下面是在Memcache上面保存了一個數組,然后獲取回來并輸出
$arr = array('aaa', 'bbb', 'ccc', 'ddd');
$mem->set('key2', $arr, 0, 60);
$val2 = $mem->get('key2');
print_r($val2);
現在刪除一個數據,使用delte接口,參數就是一個key,然后就能夠把Memcache服務器這個key的數據刪除,最后輸出的時候沒有結果
$mem->delete('key1');
$val = $mem->get('key1');
echo "Get key1 value: " . $val . "
";
最后我們把所有的保存在Memcache服務器上的數據都清除,會發現數據都沒有了,最后輸出key2的數據為空,最后關閉連接
$mem->flush();
$val2 = $mem->get('key2');
echo "Get key2 value: ";
print_r($val2);
echo "
";
【socket操作memcached】
下面是一段簡單的測試代碼,代碼中對標識符為 'mykey' 的對象數據進行存取操作:
<?php
// 包含 memcached 類文件
require_once('memcached-client.php');
// 選項設置
$options = array(
'servers' => array('192.168.1.1:11211'), //memcached 服務的地址、端口,可用多個數組元素表示多個 memcached 服務
'debug' => true, //是否打開 debug
'compress_threshold' => 10240, //超過多少字節的數據時進行壓縮
'persistant' => false //是否使用持久連接
);
// 創建 memcached 對象實例
$mc = new memcached($options);
// 設置此腳本使用的唯一標識符
$key = 'mykey';
// 往 memcached 中寫入對象
$mc->add($key, 'some random strings');
$val = $mc->get($key);
echo "n".str_pad('$mc->add() ', 60, '')."n";
var_dump($val);
// 替換已寫入的對象數據值
$mc->replace($key, array('some'=>'haha', 'array'=>'xxx'));
$val = $mc->get($key);
echo "n".str_pad('$mc->replace() ', 60, '')."n";
var_dump($val);
// 刪除 memcached 中的對象
$mc->delete($key);
$val = $mc->get($key);
echo "n".str_pad('$mc->delete() ', 60, '_')."n";
var_dump($val);
?>
[存儲數據庫查詢結果到memcache]
在實際應用中,通常會把數據庫查詢的結果集保存到 memcached 中,下次訪問時直接從 memcached 中獲取,而不再做數據庫查詢操作,這樣可以在很大程度上減輕數據庫的負擔。通常會將 SQL 語句 md5() 之后的值作為唯一標識符 key。下邊是一個利用 memcached 來緩存數據庫查詢結果集的示例(此代碼片段緊接上邊的示例代碼):
復制代碼 代碼如下:
<?php
$sql = 'SELECT * FROM users';
$key = md5($sql); //memcached 對象標識符
if ( !($datas = $mc->get($key)) ) {
// 在 memcached 中未獲取到緩存數據,則使用數據庫查詢獲取記錄集。
echo "n".str_pad('Read datas from MySQL.', 60, '')."n";
$conn = mysql_connect('localhost', 'test', 'test');
mysql_select_db('test');
$result = mysql_query($sql);
while ($row = mysql_fetch_object($result))
$datas[] = $row;
// 將數據庫中獲取到的結果集數據保存到 memcached 中,以供下次訪問時使用。
$mc->add($key, $datas);
} else {
echo "n".str_pad('Read datas from memcached.', 60, '')."n";
}
var_dump($datas);
?>
可以看出,使用 memcached 之后,可以減少數據庫連接、查詢操作,數據庫負載下來了,腳本的運行速度也提高了。
【Memcache協議分析】
如果你不喜歡 php_memcache.dll 擴展或者服務器器目前不支持這個擴展,那么就可以考慮自己構建,需要構建Memcahe的客戶端,要先了解Memcache協議的交互,這樣才能開發自己的客戶端,我這里就簡單的分析以下Memcache的協議。
(更詳細的協議內容請在Memcache服務器端的源碼的 doc/protocol.txt 文件中,本文基本來源于此)
Memcache既支持TCP協議,也支持UDP協議,不過我們這里是以TCP協議的協議作為主要考慮對象,想了解UDP協議的過程,請參考 doc/protocol.txt 文件。
[ 錯誤指令]
Memcache的協議的錯誤部分主要是三個錯誤提示之提示指令:
普通錯誤信息,比如指令錯誤之類的 ERROR\r\n
客戶端錯誤CLIENT_ERROR <錯誤信息>\r\n
服務器端錯誤SERVER_ERROR <錯誤信息>\r\n
[ 數據保存指令]
數據保存是基本的功能,就是客戶端通過命令把數據返回過來,服務器端接收后進行處理。
指令格式:
<命令> <鍵> <標記> <有效期> <數據長度>\r\n
<命令> - command name
主要是三個儲存數據的三個命令, set, add, replace
set 命令是保存一個叫做key的數據到服務器上
add 命令是添加一個數據到服務器,但是服務器必須這個key是不存在的,能夠保證數據不會被覆蓋
replace 命令是替換一個已經存在的數據,如果數據不存在,就是類似set功能
<鍵> - key
就是保存在服務器上唯一的一個表示符,必須是跟其他的key不沖突,否則會覆蓋掉原來的數據,這個key是為了能夠準確的存取一個數據項目
<標記> - flag
標記是一個16位的無符號整形數據,用來設置服務器端跟客戶端一些交互的操作
<有效期> - expiration time
是數據在服務器上的有效期限,如果是0,則數據永遠有效,單位是秒,Memcache服務器端會把一個數據的有效期設置為當前Unix時間+設置的有效時間
<數據長度> - bytes
數據的長度,block data 塊數據的長度,一般在這個個長度結束以后下一行跟著block data數據內容,發送完數據以后,客戶端一般等待服務器端的返回,服務器端的返回:
數據保存成功 STORED\r\n
數據保存失敗,一般是因為服務器端這個數據key已經存在了NOT_STORED\r\n
[ 數據提取命令]
從服務器端提取數據主要是使用get指令,格式是:
get <鍵>\r\n
<鍵> - key
key是是一個不為空的字符串組合,發送這個指令以后,等待服務器的返回。如果服務器端沒有任何數據,則是返回:
END\r\n
證明沒有不存在這個key,沒有任何數據,如果存在數據,則返回指定格式:
VALUE <鍵> <標記> <數據長度>\r\n
<數據塊>\r\n
返回的數據是以VALUE開始的,后面跟著key和flags,以及數據長度,第二行跟著數據塊。
<鍵> -key
是發送過來指令的key內容
<標記> - flags
是調用set指令保存數據時候的flags標記
<數據長度> - bytes
是保存數據時候定位的長度
<數據塊> - data block
數據長度下一行就是提取的數據塊內容
[ 數據刪除指令]
數據刪除指令也是比較簡單的,使用get指令,格式是:
delete <鍵> <超時時間>\r\n
<鍵> - key
key是你希望在服務器上刪除數據的key鍵
<超時時間> - timeout
按照秒為單位,這個是個可選項,如果你沒有指定這個值,那么服務器上key數據將馬上被刪除,如果設置了這個值,那么數據將在超時時間后把數據清除,該項缺省值是0,就是馬上被刪除
刪除數據后,服務器端會返回:
DELETED\r\n
刪除數據成功
NOT_FOUND\r\n
這個key沒有在服務器上找到
如果要刪除所有服務器上的數據,可以使用flash_all指令,格式:
flush_all\r\n
這個指令執行后,服務器上所有緩存的數據都被刪除,并且返回:
OK\r\n
這個指令一般不要輕易使,除非你卻是想把所有數據都干掉,刪除完以后可以無法恢復的。
[其他指令]
如果想了解當前Memcache服務器的狀態和版本等信息,可以使用狀態查詢指令和版本查詢指令。
如果想了解當前所有Memcache服務器運行的狀態信息,可以使用stats指令,格式
stats\r\n
服務器將返回每行按照 STAT 開始的狀態信息,包括20行,20項左右的信息,包括守護進程的pid、版本、保存的項目數量、內存占用、最大內存限制等等信息。
如果只是想獲取部分項目的信息,可以指定參數,格式:
stats <參數>\r\n
這個指令將只返回指定參數的項目狀態信息。
如果只是想單獨了解當前版本信息,可以使用version指令,格式:
version\r\n
將返回以 VERSION 開頭的版本信息
如果想結束當前連接,使用quit指令,格式:
quit\r\n
將斷開當前連接
另外還有其他指令,包括incr, decr 等,我也不太了解作用,就不做介紹了,如果感興趣,可以自己去研究。
【Memcache在中型網站的使用】
使用Memcache的網站一般流量都是比較大的,為了緩解數據庫的壓力,讓Memcache作為一個緩存區域,把部分信息保存在內存中,在前端能夠迅速的進行存取。那么一般的焦點就是集中在如何分擔數據庫壓力和進行分布式,畢竟單臺Memcache的內存容量的有限的。我這里簡單提出我的個人看法,未經實踐,權當參考。
[ 分布式應用]
Memcache本來支持分布式,我們客戶端稍加改造,更好的支持。我們的key可以適當進行有規律的封裝,比如以user為主的網站來說,每個用戶都有UserID,那么可以按照固定的ID來進行提取和存取,比如1開頭的用戶保存在第一臺Memcache服務器上,以2開頭的用戶的數據保存在第二胎Mecache服務器上,存取數據都先按照User ID來進行相應的轉換和存取。
但是這個有缺點,就是需要對User ID進行判斷,如果業務不一致,或者其他類型的應用,可能不是那么合適,那么可以根據自己的實際業務來進行考慮,或者去想更合適的方法。
[ 減少數據庫壓力]
這個算是比較重要的,所有的數據基本上都是保存在數據庫當中的,每次頻繁的存取數據庫,導致數據庫性能極具下降,無法同時服務更多的用戶,比如MySQL,特別頻繁的鎖表,那么讓Memcache來分擔數據庫的壓力吧。我們需要一種改動比較小,并且能夠不會大規模改變前端的方式來進行改變目前的架構。
我考慮的一種簡單方法:
后端的數據庫操作模塊,把所有的Select操作提取出來(update/delete/insert不管),然后把對應的SQL進行相應的hash算法計算得出一個hash數據key(比如MD5或者SHA),然后把這個key去Memcache中查找數據,如果這個數據不存在,說明還沒寫入到緩存中,那么從數據庫把數據提取出來,一個是數組類格式,然后把數據在set到Memcache中,key就是這個SQL的hash值,然后相應的設置一個失效時間,比如一個小時,那么一個小時中的數據都是從緩存中提取的,有效減少數據庫的壓力。
缺點是數據不實時,當數據做了修改以后,無法實時到前端顯示,并且還有可能對內存占用比較大,畢竟每次select出來的數據數量可能比較巨大,這個是需要考慮的因素。
上面只是我兩點沒有經過深思熟慮的簡單想法,也許有用,那就最好了。
【Memcache的安全】
我們上面的Memcache服務器端都是直接通過客戶端連接后直接操作,沒有任何的驗證過程,這樣如果服務器是直接暴露在互聯網上的話是比較危險,輕則數據泄露被其他無關人員查看,重則服務器被入侵,因為Mecache是以root權限運行的,況且里面可能存在一些我們未知的bug或者是緩沖區溢出的情況,這些都是我們未知的,所以危險性是可以預見的。
為了安全起見,我做兩點建議,能夠稍微的防止黑客的入侵或者數據的泄露。
[ 內網訪問]
最好把兩臺服務器之間的訪問是內網形態的,一般是Web服務器跟Memcache服務器之間。普遍的服務器都是有兩塊網卡,一塊指向互聯網,一塊指向內網,那么就讓Web服務器通過內網的網卡來訪問Memcache服務器,我們Memcache的服務器上啟動的時候就監聽內網的IP地址和端口,內網間的訪問能夠有效阻止其他非法的訪問。
memcached -d -m 1024?? -u root -l 192.168.0.200 -p 11211 -c 1024 -P /tmp/memcached.pid
Memcache服務器端設置監聽通過內網的192.168.0.200的ip的11211端口,占用1024MB內存,并且允許最大1024個并發連接
[ 設置防火墻]
防火墻是簡單有效的方式,如果卻是兩臺服務器都是掛在網的,并且需要通過外網IP來訪問Memcache的話,那么可以考慮使用防火墻或者代理程序來過濾非法訪問。
一般我們在Linux下可以使用iptables或者FreeBSD下的ipfw來指定一些規則防止一些非法的訪問,比如我們可以設置只允許我們的Web服務器來訪問我們Memcache服務器,同時阻止其他的訪問。
iptables -F
iptables -P INPUT DROP
iptables -A INPUT -p tcp -s 192.168.0.2 --dport 11211 -j ACCEPT
iptables -A INPUT -p udp -s 192.168.0.2 --dport 11211 -j ACCEPT
上面的iptables規則就是只允許192.168.0.2這臺Web服務器對Memcache服務器的訪問,能夠有效的阻止一些非法訪問,相應的也可以增加一些其他的規則來加強安全性,這個可以根據自己的需要來做。
【Memcache的擴展性】
Memcache算是比較簡潔高效的程序,Memcache 1.2.0 的源代碼大小才139K,在Windows平臺上是不可想象的,但是在開源世界來說,這是比較正常合理的。
Memcache目前都只是比較簡單的功能,簡單的數據存取功能,我個人希望如果有識之士,能夠在下面兩方面進行擴展。
- 日志功能
目前Memcache沒有日志功能,只有一些命令在服務器端進行回顯,這樣是很不利于對一個服務器的穩定性和負載等等進行監控的,最好能夠相應的加上日志的等功能,便于監控。 - 存儲結構
目前的數據形式就是: key => data 的形式,特別單一,只能夠存儲單一的一維數據,如果能夠擴展的話,變成類似數據庫的格式,能夠存儲二維數據,那樣會讓可以用性更強,使用面更廣,當然相應的可能代碼效率和存取效率更差一些。 - 同步功能
數據同步是個比較重要的技術,因為誰都不能保證一臺服務器是持久正常的運行的,如果能夠具有類似MySQL的 Master/Slave的功能,那么將使得Memcache的數據更加穩定,那么相應的就可以考慮存儲持久一點的數據,并且不用害怕Memcache的down掉,因為有同步的備份服務器,這個問題就不是問題了。
以上三點只是個人拙見,有識之士和技術高手可以考慮。
【結束語】
我上面的內容都只是自己安裝和使用的一些想法,不能保證絕對正確,只是給需要的人一個參考,一個推廣Memcache的文章,希望更多的人能夠認識和了解這個技術,并且為自己所用。
我花費了整整一個晚上的時間洋洋灑灑的寫了這么長,無非是對于這項開源技術的熱愛,我想開源世界能夠繁榮起來,就是源于大家的熱愛并且愿意做出貢獻,開源世界才這么精彩。
希望本文能夠給需要的人一些幫助,希望不會誤導他們,呵呵。
附加:(我操作Memcache相應對應上面文章內容的圖片)
[ 啟動Memcache]
[ Memcache的PHP測試代碼]
[測試代碼執行效果]
[ 通過Telnet連接到Memcache ]
[ 基本的Memcache的數據存取協議交互]
[ Memcache狀態信息協議交互]
【MemAdmin】
MemAdmin是一款可視化的Memcached管理與監控工具,使用PHP開發,體積小,操作簡單。
主要功能:
服務器參數監控:STATS、SETTINGS、ITEMS、SLABS、SIZES實時刷新
服務器性能監控:GET、DELETE、INCR、DECR、CAS等常用操作命中率實時監控支持數據遍歷,方便對存儲內容進行監視支持條件查詢,篩選出滿足條件的KEY或VALUE
數組、JSON等序列化字符反序列顯示
兼容memcache協議的其他服務,如Tokyo Tyrant (遍歷功能除外)
支持服務器連接池,多服務器管理切換方便簡潔
高級 memcached 客戶機命令
可以在 memcached 中使用的兩個高級命令是 gets 和 cas。gets 和 cas 命令需要結合使用。您將使用這兩個命令來確保不會將現有的名稱/值對設置為新值(如果該值已經更新過)。我們來分別看看這些命令。
gets
gets 命令的功能類似于基本的 get 命令。兩個命令之間的差異在于,gets 返回的信息稍微多一些:64 位的整型值非常像名稱/值對的 “版本” 標識符。
下面是使用 gets 命令的客戶機服務器交互:
set userId 0 0 5
12345
STORED
get userId
VALUE userId 0 5
12345
END
gets userId
VALUE userId 0 5 4
12345
END
考慮 get 和 gets 命令之間的差異。gets 命令將返回一個額外的值 — 在本例中是整型值 4,用于標識名稱/值對。如果對此名稱/值對執行另一個 set 命令,則 gets 返回的額外值將會發生更改,以表明名稱/值對已經被更新。清單 6 顯示了一個例子:
清單 6. set 更新版本指示符
set userId 0 0 5
33333
STORED
gets userId
VALUE userId 0 5 5
33333
END
您看到 gets 返回的值了嗎?它已經更新為 5。您每次修改名稱/值對時,該值都會發生更改。
cas
cas(check 和 set)是一個非常便捷的 memcached 命令,用于設置名稱/值對的值(如果該名稱/值對在您上次執行 gets 后沒有更新過)。它使用與 set 命令相類似的語法,但包括一個額外的值:gets 返回的額外值。
注意以下使用 cas 命令的交互:
set userId 0 0 5
55555
STORED
gets userId
VALUE userId 0 5 6
55555
END
cas userId 0 0 5 6
33333
STORED
如您所見,我使用額外的整型值 6 來調用 gets 命令,并且操作運行非常順序。現在,我們來看看清單 7 中的一系列命令:
清單 7. 使用舊版本指示符的 cas 命令
set userId 0 0 5
55555
STORED
gets userId
VALUE userId 0 5 8
55555
END
cas userId 0 0 5 6
33333
EXISTS
注意,我并未使用 gets 最近返回的整型值,并且 cas 命令返回 EXISTS 值以示失敗。從本質上說,同時使用 gets 和 cas 命令可以防止您使用自上次讀取后經過更新的名稱/值對。
緩存管理命令
最后兩個 memcached 命令用于監控和清理 memcached 實例。它們是 stats 和 flush_all 命令。
stats
stats 命令的功能正如其名:轉儲所連接的 memcached 實例的當前統計數據。在下例中,執行 stats 命令顯示了關于當前 memcached 實例的信息:
stats
STAT pid 63
STAT uptime 101758
STAT time 1248643186
STAT version 1.4.11
STAT pointer_size 32
STAT rusage_user 1.177192
STAT rusage_system 2.365370
STAT curr_items 2
STAT total_items 8
STAT bytes 119
STAT curr_connections 6
STAT total_connections 7
STAT connection_structures 7
STAT cmd_get 12
STAT cmd_set 12
STAT get_hits 12
STAT get_misses 0
STAT evictions 0
STAT bytes_read 471
STAT bytes_written 535
STAT limit_maxbytes 67108864
STAT threads 4
END
此處的大多數輸出都非常容易理解。稍后在討論緩存性能時,我還將詳細解釋這些值的含義。至于目前,我們先來看看輸出,然后再使用新的鍵來運行一些 set 命令,并再次運行 stats 命令,注意發生了哪些變化。
flush_all
flush_all 是最后一個要介紹的命令。這個最簡單的命令僅用于清理緩存中的所有名稱/值對。如果您需要將緩存重置到干凈的狀態,則 flush_all 能提供很大的用處。下面是一個使用 flush_all 的例子:
set userId 0 0 5
55555
STORED
get userId
VALUE userId 0 5
55555
END
flush_all
OK
get userId
END
緩存性能
在本文的最后,我將討論如何使用高級 memcached 命令來確定緩存的性能。stats 命令用于調優緩存的使用。需要注意的兩個最重要的統計數據是 et_hits 和 get_misses。這兩個值分別指示找到名稱/值對的次數(get_hits)和未找到名稱/值對的次數(get_misses)。
結合這些值,我們可以確定緩存的利用率如何。初次啟動緩存時,可以看到 get_misses 會自然地增加,但在經過一定的使用量之后,這些 get_misses 值應該會逐漸趨于平穩 — 這表示緩存主要用于常見的讀取操作。如果您看到 get_misses 繼續快速增加,而 get_hits 逐漸趨于平穩,則需要確定一下所緩存的內容是什么。您可能緩存了錯誤的內容。
確定緩存效率的另一種方法是查看緩存的命中率(hit ratio)。緩存命中率表示執行 get 的次數與錯過 get 的次數的百分比。要確定這個百分比,需要再次運行 stats 命令,如清單 8 所示:
清單 8. 計算緩存命中率
stats
STAT pid 6825
STAT uptime 540692
STAT time 1249252262
STAT version 1.2.6
STAT pointer_size 32
STAT rusage_user 0.056003
STAT rusage_system 0.180011
STAT curr_items 595
STAT total_items 961
STAT bytes 4587415
STAT curr_connections 3
STAT total_connections 22
STAT connection_structures 4
STAT cmd_get 2688
STAT cmd_set 961
STAT get_hits 1908
STAT get_misses 780
STAT evictions 0
STAT bytes_read 5770762
STAT bytes_written 7421373
STAT limit_maxbytes 536870912
STAT threads 1
END
現在,用 get_hits 的數值除以 cmd_gets。在本例中,您的命中率大約是 71%。在理想情況下,您可能希望得到更高的百分比 — 比率越高越好。查看統計數據并不時測量它們可以很好地判定緩存策略的效率。
[常有命令如下:]
啟動/結束
memcached -d -m 10 -u root -l 192.168.0.122 -p 11200 -c 256 -P /tmp/memcached.pid
-d 選項是啟動一個守護進程,
-m 是分配給Memcache使用的內存數量,單位是MB,這里是10MB
-u 是運行Memcache的用戶,這里是root
-l 是監聽的服務器IP地址,如果有多個地址的話,這里指定了服務器的IP地址192.168.0.122
-p 是設置Memcache監聽的端口,這里設置了12000,最好是1024以上的端口
-c 選項是最大運行的并發連接數,默認是1024,這里設置了256,按照你服務器的負載量來設定
-P 是設置保存Memcache的pid文件
kill cat /tmp/memcached.pid
獲取運行狀態
echo stats | nc 192.168.1.123 11200
watch "echo stats | nc 192.168.1.123 11200" (實時狀態)
1。memcached的連接函數(connect, pconnect)
2。memcahced的操作函數(set, get, delete, replace, flush)
3。多服務器配置函數(addServer)
4。狀態監控函數(getStats.....)
[安裝多個memcached]
sc create "Memcached Server1" start= auto binPath= "C:\memcached\memcached.exe -d runservice -m 32 -p 11220 -l 127.0.0.1" DisplayName= "Memcached Server1"
下面是啟動、停止、卸載該服務的命令:
sc start "Memcached Server1" //啟動
sc stop "Memcached Server1" //停止
sc delete "Memcached Server1" //卸載該服務
分布式memcached測試:
<?php
//我的電腦上有兩個memcahced服務.
$mem=new Memcache;
$mem->addServer('127.0.0.1',11211);
$mem->addServer('127.0.0.1',11221);
$mem->addServer('127.0.0.1',11220);
//這里注意,把key1,放入到 11211端口的mem還是
//9999 端口的mem就不要我們操心,有$mem對象本身維護.
if($mem->set('key1','hello',MEMCACHE_COMPRESSED,300)){
echo 'add ok!';
}
if($mem->set('key2','hello2',MEMCACHE_COMPRESSED,300)){
echo 'add ok!';
}
if($mem->set('key3','hello3',MEMCACHE_COMPRESSED,300)){
echo 'add ok!';
}
?>
總結:
- mem服務的數據不是同步的, 數據是分布的
- 把什么數據放入到哪個memcached是由客戶端的mem對象決定
- 當執行addServer的時候,并不是立即去連接mem服務,而是通過計算,hash后才去決定連接哪個mem服務,因此當你大量加入服務器到連接池,沒有多余開銷
【memcache的細節討論】
① 生命周期
從數據放入mem開始計時,直到時間到了,就銷毀, 如果時間為0, 則表示不過期.
memcache的數據被銷毀的情況如下:
- 時間到
- 重啟memcached服務
- 重啟memcached服務所在的機器
- delete / flush 銷毀數據
② 如何把session數據放入到memcached服務中.
步驟:
- 修改php.ini的配置文件
如下:
;[sesson.save_handler有user|files|memcache]
session.save_handler= memcache
session.save_path= "tcp://127.0.0.1:11211"
③ 測試一把,重啟apache
測試ok
<?php
//傳統的代碼
session_start();
$_SESSION['name']='天龍八部300';
$_SESSION['city']='beijing';
class Dog{
public $name;
}
$dog1=new Dog;
$dog1->name='abcde';
$_SESSION['dog']=$dog1;
//如果session數據入mem,那他一定是以session_id為
//key值進行添加
//取出
$name=$_SESSION['name'];
echo "name=$name";
echo "sessionid=".session_id();
思考,如果管理員,不讓我們修改php.ini 文件,我們如何處理session入memcached這個功能, 我們通過一個函數可以去修改 php.ini 的配置.
代碼:
<?php
ini_set("session.save_handler","memcache");
ini_set("session.save_path","tcp://127.0.0.1:9999");
同時你也可以通過 ini_set 去動態的修改對php.ini 的其它設置 。但是他不影響其它php頁面,也不會去修改php.ini 文件本身, 只對本頁面生效.
memcached vs session比較
memcached 主要的目的是提速 ,因此它是一種無狀態的數據.即,數據不和用戶綁定.
session數據是和用戶綁定的,因此是一種有狀態數據.
Memcached一些特性和限制
? 在 Memcached 中可以保存的item數據量是沒有限制的,只有內存足夠
? Memcached單進程最大使用內存為2G,要使用更多內存,可以分多個端口開啟多個Memcached進程
? 最大30天的數據過期時間, 設置為永久的也會在這個時間過期,常量REALTIME_MAXDELTA
606024*30 控制
? 最大鍵長為250字節,大于該長度無法存儲,常量KEY_MAX_LENGTH 250 控制
? 單個item最大數據是1MB,超過1MB數據不予存儲,常量POWER_BLOCK 1048576 進行控制,
它是默認的slab大小
? 最大同時連接數是200,通過 conn_init()中的freetotal 進行控制,最大軟連接數是1024,通過
settings.maxconns=1024 進行控制
? 跟空間占用相關的參數:settings.factor=1.25, settings.chunk_size=48, 影響slab的數據占用和步進方式
什么樣的數據適合放入memcached中?
1)變化頻繁,具有不穩定性的數據,不需要實時入庫,如在線用戶,session信息
2)和memcached技術類似是redis (key/value數據庫),也是把數據放在內存中,并定時向磁盤同步
memcached的基本命令(安裝、卸載、啟動、配置相關):
-p 監聽的端口
-l 連接的IP地址, 默認是本機
-d start 啟動memcached服務
-d restart 重起memcached服務
-d stop|shutdown 關閉正在運行的memcached服務
-d install 安裝memcached服務
-d uninstall 卸載memcached服務
-u 以的身份運行 (僅在以root運行的時候有效)
-m 最大內存使用,單位MB。默認64MB
-M 內存耗盡時返回錯誤,而不是刪除項
-c 最大同時連接數,默認是1024
-f 塊大小增長因子,默認是1.25
-n 最小分配空間,key+value+flags默認是48
-h 顯示幫助
memcached的基本命令(當memcached 啟動后 用于對memcached管理的數據和本身運行狀態相關的命令):
Command
Description
Example
get
Reads a value
get mykey
set
Set a key unconditionally
set mykey 0 60 5
add
Add a new key
add newkey 0 60 5
replace
Overwrite existing key
replace key 0 60 5
append
Append data to existing key
append key 0 60 15
prepend
Prepend data to existing key
prepend key 0 60 15
incr
Increments numerical key value by given number
incr mykey 2
decr
Decrements numerical key value by given number
decr mykey 5
delete
Deletes an existing key
delete mykey
flush_all
Invalidate specific items immediately
flush_all
Invalidate all items in n seconds
flush_all 900
stats
Prints general statistics
stats
Prints memory statistics
stats slabs
Prints memory statistics
stats malloc
Print higher level allocation statistics
stats items
stats detail
stats sizes
Resets statistics
stats reset
version
Prints server version.
version
verbosity
Increases log level
verbosity
quit
Terminate telnet session
quit
對查看的信息的關鍵字中英文對照表
pid
memcache服務器的進程ID
uptime
服務器已經運行的秒數
time
服務器當前的unix時間戳
version
memcache版本
pointer_size
當前操作系統的指針大小(32位系統一般是32bit)
rusage_user
進程的累計用戶時間
rusage_system
進程的累計系統時間
curr_items
服務器當前存儲的items數量
total_items
從服務器啟動以后存儲的items總數量
bytes
當前服務器存儲items占用的字節數
curr_connections
當前打開著的連接數
total_connections
從服務器啟動以后曾經打開過的連接數
connection_structures
服務器分配的連接構造數
cmd_get
get命令(獲取)總請求次數
cmd_set
set命令(保存)總請求次數
get_hits
總命中次數
get_misses
總未命中次數
evictions
為獲取空閑內存而刪除的items數(分配給memcache的空間用滿后需要刪除舊的items來得到空間分配給新的items)
bytes_read
總讀取字節數(請求字節數)
bytes_written
總發送字節數(結果字節數)
limit_maxbytes
分配給memcache的內存大小(字節)
threads
當前線程數