memcached是一個(gè)高性能的分布式的內(nèi)存對(duì)象緩存系統(tǒng),通過(guò)在內(nèi)存里維護(hù)一個(gè)統(tǒng)一的巨大的hash表,它能夠用來(lái)存儲(chǔ)各種格式的數(shù)據(jù),包括圖像、視
頻、文件以及數(shù)據(jù)庫(kù)檢索的結(jié)果等。最初為了加速 LiveJournal
訪問(wèn)速度而開(kāi)發(fā)的,后來(lái)被很多大型的網(wǎng)站采用。起初作者編寫(xiě)它可能是為了提高動(dòng)態(tài)網(wǎng)頁(yè)應(yīng)用,為了減輕數(shù)據(jù)庫(kù)檢索的壓力,來(lái)做的這個(gè)緩存系統(tǒng)。它的緩存是一
種分布式的,也就是可以允許不同主機(jī)上的多個(gè)用戶同時(shí)訪問(wèn)這個(gè)緩存系統(tǒng), 這種方法不僅解決了共享內(nèi)存只能是單機(jī)的弊端,
同時(shí)也解決了數(shù)據(jù)庫(kù)檢索的壓力,最大的優(yōu)點(diǎn)是提高了訪問(wèn)獲取數(shù)據(jù)的速度!基于memcached作者對(duì)分布式cache的理解和解決方案。
memcached完全可以用到其他地方 比如分布式數(shù)據(jù)庫(kù), 分布式計(jì)算等領(lǐng)域。
1、 memcached 協(xié)議理解
memcache是為了加快http://www.livejournal.com/訪問(wèn)速度而誕生的一個(gè)項(xiàng)目。
它的官方主頁(yè)是:http://www.danga.com/memcached/
目前在網(wǎng)站開(kāi)發(fā)中應(yīng)用較少,主要的應(yīng)用有:
http://www.danga.com/memcached/users.bml
在國(guó)內(nèi)的網(wǎng)站開(kāi)發(fā)中,還很少?zèng)]見(jiàn)到有應(yīng)用的,中文資料十分匱乏。
工作機(jī)制:通過(guò)在內(nèi)存中開(kāi)辟一塊區(qū)域來(lái)維持一個(gè)大的hash表來(lái)加快頁(yè)面訪問(wèn)速度,和數(shù)據(jù)庫(kù)是獨(dú)立的。但是目前主要用來(lái)緩存數(shù)據(jù)庫(kù)的數(shù)據(jù)。允許多 個(gè)server通過(guò)網(wǎng)絡(luò)形成一個(gè)大的hash,用戶不必關(guān)心數(shù)據(jù)存放在哪,只調(diào)用相關(guān)接口就可。存放在內(nèi)存的數(shù)據(jù)通過(guò)LRU算法進(jìn)行淘汰出內(nèi)存。同時(shí)可以 通過(guò)刪除和設(shè)置失效時(shí)間來(lái)淘汰存放在內(nèi)存的數(shù)據(jù)。
2、 memcached 使用入門
2.1 memcached的安裝
?<1>memcached服務(wù)的安裝
先檢查linux內(nèi)核版本,建議將memcached 安裝在2.6以上。
因?yàn)閙emcached 需要用到libevent和 epoll 。
memcached安裝前首先確定你的服務(wù)器上面安裝了libevent庫(kù),
libevent下載地址( http://www.monkey.org/~provos/libevent/)。
下載memcached的源碼( http://www.danga.com/memcached/download.bml)。
Memcached最初是用perl寫(xiě)的,現(xiàn)在的版本是用c寫(xiě)的。
下載后拷貝到一個(gè)目錄,安裝需要root用戶來(lái)執(zhí)行
tar -zxvf memcached-1.1.12.tar.gz
cd memcached-1.1.12
./configure
這里必須先要configure, 它會(huì)檢測(cè)你的系統(tǒng)情況,然后生成一個(gè)config.h文件和其它的幾個(gè)文件,另外和其它的configure一樣,你可以配置它的安裝路徑等等。默認(rèn)應(yīng)用程序安裝在/usr/local/bin目錄下。
make //編譯
make install //安裝
<2>memcached客戶端的安裝
根據(jù)memcached協(xié)議,用戶可以自己寫(xiě)出符合自己要求的客戶端程序。目前http://www.danga.com/memcached/download.bml
提供perl,c,java,python,php等客戶端程序供下載和參考。下面我就以perl客戶端程序?yàn)槔f(shuō)明客戶端的安裝:
下載后拷貝到一個(gè)目錄,安裝需要root用戶來(lái)執(zhí)行
這樣就安裝好了memcahced, 啟動(dòng)memcached就可使用分布式緩存系統(tǒng)了!
2.2 快速入門
<1> memcached服務(wù)的啟動(dòng)
memcached的啟動(dòng)非常簡(jiǎn)單,它沒(méi)有配置文件,只要配置好幾個(gè)參數(shù)就可以使用了。下面我以一個(gè)實(shí)際應(yīng)用的例子,具體說(shuō)明一下:
memcached ?d ?m 500 -l 64.128.191.151 -p 11211 -vv >>/var/www/kelly/test/logs/memcached_$$.log
啟動(dòng)的這個(gè)memcached為一個(gè)后臺(tái)守護(hù)進(jìn)程模式(-d), 然后緩存的空間為500M(-m), 監(jiān)聽(tīng)(-l)服務(wù)器64.128.191.15的11211號(hào)端口(-p).,將日志寫(xiě)道/var/www/kelly/test/logs /memcached_$$.log(-vv)。
其實(shí)memcached的參數(shù)也非常的有限,就下面這幾個(gè):
我們也可以將這個(gè)啟動(dòng)腳本寫(xiě)道/etc/rc.d或者/erc/rc.local,這樣可以在服務(wù)器啟動(dòng)時(shí)候執(zhí)行。
<2> memcached客戶端的連接
下面我就以perl客戶端程序?yàn)槔f(shuō)明客戶端的連接:
啟動(dòng)兩個(gè)memcached server
perl客戶端程序
?運(yùn)行測(cè)試
$ perl test-memcache.pl
$ perl test-memcache.pl
Value is '123'
可以看到,第一次沒(méi)有取得my_key,第二次從memcached中得到my_key的值。
同時(shí)通過(guò)查看日志,可以發(fā)現(xiàn)的確存儲(chǔ)在兩個(gè)memcache server中。
這個(gè)簡(jiǎn)單的例子,解釋了如何在memcached中存取數(shù)據(jù),以及memcache是真正的分布式緩存系統(tǒng)。
當(dāng)然,這還只是很簡(jiǎn)單的例子,體現(xiàn)不出memcache的優(yōu)勢(shì),下面將通過(guò)一個(gè)很具體的例子,給出詳細(xì)的應(yīng)用。
3、 memcached在Zorpia的應(yīng)用
http://www.zorpia.com 是一個(gè)網(wǎng)頁(yè)相冊(cè),博客,交友,論壇的大型網(wǎng)站公司?,F(xiàn)在已有超過(guò)140萬(wàn)活躍使用者遍布美國(guó),香港,東南亞,歐洲,澳洲,亞洲等其它地區(qū)。每天的訪問(wèn)量都在增長(zhǎng),已成為全世界排名第五的社會(huì)生活關(guān)系網(wǎng)。
Memcached也采用了memcached來(lái)提高網(wǎng)站的訪問(wèn)速度,并且取得了很好的效果,我在負(fù)責(zé)zorpia的memcached項(xiàng)目時(shí)候積累了一些經(jīng)驗(yàn),主要的做法如下:
1) 通過(guò)對(duì)memcache的perl客戶端進(jìn)行包裝,定制自己的客戶端。
2) 通過(guò)制定符合zorpia規(guī)范的hash key命名規(guī)范
? ? memcache中需要存儲(chǔ)的內(nèi)容的key均由string組成。
這個(gè)string統(tǒng)一由一個(gè)memcache.pm的subroutine來(lái)實(shí)現(xiàn)。(假設(shè)這個(gè)subroutine是 get_key() )
? ? memcache中存放兩種形式的數(shù)據(jù)
(1) result of SQL query :
(2) 普通變量(variable)
這兩種數(shù)據(jù)的key的組合方式是不相同的,由get_key進(jìn)行判斷和完成
? ? 關(guān)于get_key 和 naming rule
get_key subroutine完成所有memcache key的命名,naming rule也是在它里邊體現(xiàn):
(1)輸入?yún)?shù) -- hash結(jié)構(gòu),里邊定義了當(dāng)前需要存放的數(shù)據(jù)的信息
結(jié)構(gòu)
(2)返回值 -- string,返回?cái)?shù)據(jù)的key_name
?必須確定 get_key 的傳入hash的結(jié)構(gòu),
hash中主要有兩個(gè)元素
type --- 定義當(dāng)前數(shù)據(jù)結(jié)構(gòu)的類型 ,有 'var' , 'sql'兩種值
object --- 存放當(dāng)前數(shù)據(jù)結(jié)構(gòu)的詳細(xì)信息,
當(dāng) type eq 'var'時(shí),object表示變量的名字,該名字由程序員指定
當(dāng) type eq 'sql'時(shí),object包含所存放sql的主要基本信息,hash結(jié)構(gòu),也由程序員按照規(guī)則制定
## 當(dāng)variable 數(shù)據(jù)類型,比較簡(jiǎn)單
$var_hash = {
type => 'var', ## var表示當(dāng)前類型是 variable
object => 'language', ## language代表variable的名字
};
生成的key是Zorpia::var| language
## sql 數(shù)據(jù)
比如select first_name from user where user_id =2那么hash為
$sql_hash = {
type => 'sql',
object => {
table => {table2=>"user",}, ## sql 查詢的表
column => {column1=>"first_name",}, ## sql所要查詢的column
condition => { user_id =>"2",}, ## sql條件
},
};
生成的key是Zorpia::sql|user|first_name| user_id =2
get_key subroutine必須對(duì)傳入hash進(jìn)行判斷,對(duì)不同類型的數(shù)據(jù)按照不同的方式組合,形成key,返回給使用者。這個(gè)key,必須保證其唯一性:
比如:所有字母小寫(xiě),一些數(shù)組在組合成key之前必須首先排序
? ? get_key函數(shù)
3) 制定需要應(yīng)用memcached的規(guī)則
?經(jīng)常訪問(wèn)的表user,user_details
?合理設(shè)定變量在memcached的生存周期
?將活躍用戶的信息預(yù)先導(dǎo)入到memcached
?分別在多臺(tái)機(jī)器上啟動(dòng)多個(gè)memcached服務(wù)
?編寫(xiě)腳本監(jiān)控memcached服務(wù)是否活動(dòng)
4) User表的具體應(yīng)用舉例
? 在 select時(shí)候
先查詢memcahce里有沒(méi)有,有的話,返回;否則從數(shù)據(jù)庫(kù)select,在memcache里設(shè)置,返回。
?在 update,insert,delete時(shí)候
先在數(shù)據(jù)庫(kù)update,insert,delete,在memcache里設(shè)置,返回。
4、 memcached的應(yīng)用展望
使用了memcached以后, 我發(fā)現(xiàn)以前做過(guò)的很多的項(xiàng)目都可以應(yīng)用它提高效率,包括最近做的“大單追蹤”, “數(shù)碼搜索”等等。當(dāng)然既然memcahced是分布式的緩存系統(tǒng),那么它就是建立了一個(gè)分布式的平臺(tái), 我們可以用它來(lái)進(jìn)行分布式的記數(shù), 因?yàn)閷?duì)于一個(gè)鍵值key我們可以設(shè)置它的數(shù)值以及有效期在參數(shù)中,另外還可以重新設(shè)置這個(gè)鍵值的數(shù)值。 所以我總結(jié)了一下目前可以應(yīng)用到的地方:
<1>.數(shù)據(jù)庫(kù)檢索結(jié)果的緩存,也就是說(shuō)可以有機(jī)的和數(shù)據(jù)庫(kù)結(jié)合起來(lái)應(yīng)用,提高效率。
這也是目前memcached用到的最多的地方,比如用于大型網(wǎng)站等。
可以這樣來(lái)實(shí)現(xiàn):
打開(kāi)memcached服務(wù)器連接
編寫(xiě)sql語(yǔ)句, 同時(shí)算出它的一個(gè)hash key值
獲取這個(gè)hash值的memcached保存數(shù)據(jù)(get)
如果獲取的這個(gè)hash值的數(shù)據(jù)存在。返回
否則連接數(shù)據(jù)庫(kù)查找
把這個(gè)查找結(jié)果保存在memcached中(set),可以設(shè)置有效期
返回查找結(jié)果
<2>.分布式計(jì)算
<3>.分布式共享數(shù)據(jù)
總之,memcached的機(jī)制比較靈活,可以適用于一切需要分布式緩存數(shù)據(jù)的地方,隨著memcached逐漸為人所知,必將在更多的分布式應(yīng)用領(lǐng)域大放異彩。
http://nio.infor96.com/php-memcached/
一、memcached 簡(jiǎn)介
在很多場(chǎng)合,我們都會(huì)聽(tīng)到 memcached 這個(gè)名字,但很多同學(xué)只是聽(tīng)過(guò),并沒(méi)有用過(guò)或?qū)嶋H了解過(guò),只知道它是一個(gè)很不錯(cuò)的東東。這里簡(jiǎn)單介紹一下,memcached 是高效、快速的分布式內(nèi)存對(duì)象緩存系統(tǒng),主要用于加速 WEB 動(dòng)態(tài)應(yīng)用程序。
二、memcached 安裝
首先是下載 memcached 了,目前最新版本是 1.1.12,直接從官方網(wǎng)站即可下載到 memcached-1.1.12.tar.gz。除此之外,memcached 用到了 libevent,我下載的是 libevent-1.1a.tar.gz。
接下來(lái)是分別將 libevent-1.1a.tar.gz 和 memcached-1.1.12.tar.gz 解開(kāi)包、編譯、安裝:
make install安裝完成之后,memcached 應(yīng)該在 /usr/bin/memcached。
三、運(yùn)行 memcached 守護(hù)程序
運(yùn)行 memcached 守護(hù)程序很簡(jiǎn)單,只需一個(gè)命令行即可,不需要修改任何配置文件(也沒(méi)有配置文件給你修改 ):
參數(shù)解釋:
-d 以守護(hù)程序(daemon)方式運(yùn)行 memcached;-m 設(shè)置 memcached 可以使用的內(nèi)存大小,單位為 M;-l 設(shè)置監(jiān)聽(tīng)的 IP 地址,如果是本機(jī)的話,通常可以不設(shè)置此參數(shù);-p 設(shè)置監(jiān)聽(tīng)的端口,默認(rèn)為 11211,所以也可以不設(shè)置此參數(shù);-u 指定用戶,如果當(dāng)前為 root 的話,需要使用此參數(shù)指定用戶。當(dāng)然,還有其它參數(shù)可以用,man memcached 一下就可以看到了。
四、memcached 的工作原理
首先 memcached 是以守護(hù)程序方式運(yùn)行于一個(gè)或多個(gè)服務(wù)器中,隨時(shí)接受客戶端的連接操作,客戶端可以由各種語(yǔ)言編寫(xiě),目前已知的客戶端 API 包括 Perl/PHP/Python/Ruby/Java/C#/C 等等。PHP 等客戶端在與 memcached 服務(wù)建立連接之后,接下來(lái)的事情就是存取對(duì)象了,每個(gè)被存取的對(duì)象都有一個(gè)唯一的標(biāo)識(shí)符 key,存取操作均通過(guò)這個(gè) key 進(jìn)行,保存到 memcached 中的對(duì)象實(shí)際上是放置內(nèi)存中的,并不是保存在 cache 文件中的,這也是為什么 memcached 能夠如此高效快速的原因。注意,這些對(duì)象并不是持久的,服務(wù)停止之后,里邊的數(shù)據(jù)就會(huì)丟失。
三、PHP 如何作為 memcached 客戶端
有兩種方法可以使 PHP 作為 memcached 客戶端,調(diào)用 memcached 的服務(wù)進(jìn)行對(duì)象存取操作。
第一種,PHP 有一個(gè)叫做 memcache 的擴(kuò)展,Linux 下編譯時(shí)需要帶上 ?enable-memcache[=DIR] 選項(xiàng),Window 下則在 php.ini 中去掉 php_memcache.dll 前邊的注釋符,使其可用。
除此之外,還有一種方法,可以避開(kāi)擴(kuò)展、重新編譯所帶來(lái)的麻煩,那就是直接使用 php-memcached-client。
本文選用第二種方式,雖然效率會(huì)比擴(kuò)展庫(kù)稍差一些,但問(wèn)題不大。
四、PHP memcached 應(yīng)用示例
首先 下載 memcached-client.php,在下載了 memcached-client.php 之后,就可以通過(guò)這個(gè)文件中的類“memcached”對(duì) memcached 服務(wù)進(jìn)行操作了。其實(shí)代碼調(diào)用非常簡(jiǎn)單,主要會(huì)用到的方法有 add()、get()、replace() 和 delete(),方法說(shuō)明如下:
add ($key, $val, $exp = 0)
往 memcached 中寫(xiě)入對(duì)象,$key 是對(duì)象的唯一標(biāo)識(shí)符,$val 是寫(xiě)入的對(duì)象數(shù)據(jù),$exp 為過(guò)期時(shí)間,單位為秒,默認(rèn)為不限時(shí)間;
get ($key)
從 memcached 中獲取對(duì)象數(shù)據(jù),通過(guò)對(duì)象的唯一標(biāo)識(shí)符 $key 獲??;
replace ($key, $value, $exp=0)
使用 $value 替換 memcached 中標(biāo)識(shí)符為 $key 的對(duì)象內(nèi)容,參數(shù)與 add() 方法一樣,只有 $key 對(duì)象存在的情況下才會(huì)起作用;
delete ($key, $time = 0)
刪除 memcached 中標(biāo)識(shí)符為 $key 的對(duì)象,$time 為可選參數(shù),表示刪除之前需要等待多長(zhǎng)時(shí)間。
下面是一段簡(jiǎn)單的測(cè)試代碼,代碼中對(duì)標(biāo)識(shí)符為 ‘mykey’ 的對(duì)象數(shù)據(jù)進(jìn)行存取操作:
// 包含 memcached 類文件require_once(‘memcached-client.php’);// 選項(xiàng)設(shè)置$options = array( ’servers’ => array(‘192.168.1.1:11211′), //memcached 服務(wù)的地址、端口,可用多個(gè)數(shù)組元素表示多個(gè) memcached 服務(wù) ‘debug’ => true, //是否打開(kāi) debug ‘compress_threshold’ => 10240, //超過(guò)多少字節(jié)的數(shù)據(jù)時(shí)進(jìn)行壓縮 ‘persistant’ => false //是否使用持久連接 );// 創(chuàng)建 memcached 對(duì)象實(shí)例$mc = new memcached($options);// 設(shè)置此腳本使用的唯一標(biāo)識(shí)符$key = ‘mykey’;// 往 memcached 中寫(xiě)入對(duì)象$mc->add($key, ’some random strings’);$val = $mc->get($key);echo “n”.str_pad(‘$mc->add() ’, 60, ‘_’).“n”;var_dump($val);// 替換已寫(xiě)入的對(duì)象數(shù)據(jù)值$mc->replace($key, array(’some’=>‘haha’, ‘array’=>‘xxx’));$val = $mc->get($key);echo “n”.str_pad(‘$mc->replace() ’, 60, ‘_’).“n”;var_dump($val);// 刪除 memcached 中的對(duì)象$mc->delete($key);$val = $mc->get($key);echo “n”.str_pad(‘$mc->delete() ’, 60, ‘_’).“n”;var_dump($val);?>
是不是很簡(jiǎn)單,在實(shí)際應(yīng)用中,通常會(huì)把數(shù)據(jù)庫(kù)查詢的結(jié)果集保存到 memcached 中,下次訪問(wèn)時(shí)直接從 memcached 中獲取,而不再做數(shù)據(jù)庫(kù)查詢操作,這樣可以在很大程度上減輕數(shù)據(jù)庫(kù)的負(fù)擔(dān)。通常會(huì)將 SQL 語(yǔ)句 md5() 之后的值作為唯一標(biāo)識(shí)符 key。下邊是一個(gè)利用 memcached 來(lái)緩存數(shù)據(jù)庫(kù)查詢結(jié)果集的示例(此代碼片段緊接上邊的示例代碼):
= ‘SELECT * FROM users’;$key = md5($sql); //memcached 對(duì)象標(biāo)識(shí)符if ( !($datas = $mc->get($key)) ) { // 在 memcached 中未獲取到緩存數(shù)據(jù),則使用數(shù)據(jù)庫(kù)查詢獲取記錄集。 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; // 將數(shù)據(jù)庫(kù)中獲取到的結(jié)果集數(shù)據(jù)保存到 memcached 中,以供下次訪問(wèn)時(shí)使用。 $mc->add($key, $datas);} else { echo “n”.str_pad(‘Read datas from memcached.’, 60, ‘_’).“n”;}var_dump($datas);?>可以看出,使用 memcached 之后,可以減少數(shù)據(jù)庫(kù)連接、查詢操作,數(shù)據(jù)庫(kù)負(fù)載下來(lái)了,腳本的運(yùn)行速度也提高了。
之前我曾經(jīng)寫(xiě)過(guò)一篇名為《PHP 實(shí)現(xiàn)多服務(wù)器共享 SESSION 數(shù)據(jù)》文章,文中的 SESSION 是使用數(shù)據(jù)庫(kù)保存的,在并發(fā)訪問(wèn)量大的時(shí)候,服務(wù)器的負(fù)載會(huì)很大,經(jīng)常會(huì)超出 MySQL 最大連接數(shù),利用 memcached,我們可以很好地解決這個(gè)問(wèn)題,工作原理如下:
用戶訪問(wèn)網(wǎng)頁(yè)時(shí),查看 memcached 中是否有當(dāng)前用戶的 SESSION 數(shù)據(jù),使用 session_id() 作為唯一標(biāo)識(shí)符;如果數(shù)據(jù)存在,則直接返回,如果不存在,再進(jìn)行數(shù)據(jù)庫(kù)連接,獲取 SESSION 數(shù)據(jù),并將此數(shù)據(jù)保存到 memcached 中,供下次使用;
當(dāng)前的 PHP 運(yùn)行結(jié)束(或使用了 session_write_close())時(shí),會(huì)調(diào)用 My_Sess::write() 方法,將數(shù)據(jù)寫(xiě)入數(shù)據(jù)庫(kù),這樣的話,每次仍然會(huì)有數(shù)據(jù)庫(kù)操作,對(duì)于這個(gè)方法,也需要進(jìn)行優(yōu)化。使用一個(gè)全局變量,記錄用戶進(jìn)入頁(yè)面時(shí)的 SESSION 數(shù)據(jù),然后在 write() 方法內(nèi)比較此數(shù)據(jù)與想要寫(xiě)入的 SESSION 數(shù)據(jù)是否相同,不同才進(jìn)行數(shù)據(jù)庫(kù)連接、寫(xiě)入數(shù)據(jù)庫(kù),同時(shí)將 memcached 中對(duì)應(yīng)的對(duì)象刪除,如果相同的話,則表示 SESSION 數(shù)據(jù)未改變,那么就可以不做任何操作,直接返回了;
那么用戶 SESSION 過(guò)期時(shí)間怎么解決呢?記得 memcached 的 add() 方法有個(gè)過(guò)期時(shí)間參數(shù) $exp 嗎?把這個(gè)參數(shù)值設(shè)置成小于 SESSION 最大存活時(shí)間即可。另外別忘了給那些一直在線的用戶延續(xù) SESSION 時(shí)長(zhǎng),這個(gè)可以在 write() 方法中解決,通過(guò)判斷時(shí)間,符合條件則更新數(shù)據(jù)庫(kù)數(shù)據(jù)。
五、相關(guān)資源
memcached 官方網(wǎng)站
PHP memcached client
下載 memcached-client.php
http://www.dirk.sh/diary/216
Memcached 是一個(gè)非常優(yōu)秀的緩存加速系統(tǒng),和 Squid 的前端緩存加速不同,它是通過(guò)基于內(nèi)存緩存對(duì)象來(lái)減少數(shù)據(jù)庫(kù)查詢的方式改善網(wǎng)站系統(tǒng)的反應(yīng),而其中最吸引人的一個(gè)特性就是支持分布式部署;也就是說(shuō)可以在 一群機(jī)器上建立一堆 Memcached 服務(wù),每個(gè)服務(wù)可以根據(jù)具體服務(wù)器的硬件配置使用不同大小的內(nèi)存塊,這樣一來(lái),理論上可以建立一個(gè)無(wú)限巨大的基于內(nèi)存的 cache storage 系統(tǒng)。
Php 下的 Memcached 官方 API 是 memcache 這個(gè)包,前不久發(fā)布 2.0.0 stable 版本,關(guān)鍵的更新是增加了 addServer() 函數(shù)用于支持 Multiple servers with loadbalancing and failover,在 FreeBSD 下安裝:
[root@trinity ~]# cd /usr/ports/databases/memcached/[root@trinity ~]# make install clean[root@trinity ~]# cd /usr/ports/databases/pecl-memcache[root@trinity ~]# make install clean另外一個(gè)號(hào)稱更快的 API 包是 mcache,看作者的說(shuō)明,是直接使用了 libmemcache,但在 FreeBSD 下目前還沒(méi)有 Ports,需要源代碼方式安裝,具體可以參考 mcache 的說(shuō)明。
一個(gè)簡(jiǎn)單的 PHP 腳本示例:
addServer('localhost', 11211);$memcache->addServer('localhost', 11212);if ($memcache) { $count = intval($memcache->get('static_count')); $count ++; $memcache->set('static_count', $count, 0, 30); var_dump($memcache->get('static_count'));} else { echo "Connection to memcached failed";}?>但不管 Memcached 是一個(gè)多么優(yōu)秀的東西,在沒(méi)有合理的緩存策略(緩存什么東西?如何緩存?緩存時(shí)機(jī)?過(guò)期策略?)的情況下,只會(huì)被濫用,發(fā)揮不了真正的作用。構(gòu)思 中…...
1、 memcached 協(xié)議理解
memcache是為了加快http://www.livejournal.com/訪問(wèn)速度而誕生的一個(gè)項(xiàng)目。
它的官方主頁(yè)是:http://www.danga.com/memcached/
目前在網(wǎng)站開(kāi)發(fā)中應(yīng)用較少,主要的應(yīng)用有:
http://www.danga.com/memcached/users.bml
在國(guó)內(nèi)的網(wǎng)站開(kāi)發(fā)中,還很少?zèng)]見(jiàn)到有應(yīng)用的,中文資料十分匱乏。
工作機(jī)制:通過(guò)在內(nèi)存中開(kāi)辟一塊區(qū)域來(lái)維持一個(gè)大的hash表來(lái)加快頁(yè)面訪問(wèn)速度,和數(shù)據(jù)庫(kù)是獨(dú)立的。但是目前主要用來(lái)緩存數(shù)據(jù)庫(kù)的數(shù)據(jù)。允許多 個(gè)server通過(guò)網(wǎng)絡(luò)形成一個(gè)大的hash,用戶不必關(guān)心數(shù)據(jù)存放在哪,只調(diào)用相關(guān)接口就可。存放在內(nèi)存的數(shù)據(jù)通過(guò)LRU算法進(jìn)行淘汰出內(nèi)存。同時(shí)可以 通過(guò)刪除和設(shè)置失效時(shí)間來(lái)淘汰存放在內(nèi)存的數(shù)據(jù)。
2、 memcached 使用入門
2.1 memcached的安裝
?<1>memcached服務(wù)的安裝
先檢查linux內(nèi)核版本,建議將memcached 安裝在2.6以上。
因?yàn)閙emcached 需要用到libevent和 epoll 。
memcached安裝前首先確定你的服務(wù)器上面安裝了libevent庫(kù),
libevent下載地址( http://www.monkey.org/~provos/libevent/)。
下載memcached的源碼( http://www.danga.com/memcached/download.bml)。
Memcached最初是用perl寫(xiě)的,現(xiàn)在的版本是用c寫(xiě)的。
下載后拷貝到一個(gè)目錄,安裝需要root用戶來(lái)執(zhí)行
tar -zxvf memcached-1.1.12.tar.gz
cd memcached-1.1.12
./configure
這里必須先要configure, 它會(huì)檢測(cè)你的系統(tǒng)情況,然后生成一個(gè)config.h文件和其它的幾個(gè)文件,另外和其它的configure一樣,你可以配置它的安裝路徑等等。默認(rèn)應(yīng)用程序安裝在/usr/local/bin目錄下。
make //編譯
make install //安裝
<2>memcached客戶端的安裝
根據(jù)memcached協(xié)議,用戶可以自己寫(xiě)出符合自己要求的客戶端程序。目前http://www.danga.com/memcached/download.bml
提供perl,c,java,python,php等客戶端程序供下載和參考。下面我就以perl客戶端程序?yàn)槔f(shuō)明客戶端的安裝:
下載后拷貝到一個(gè)目錄,安裝需要root用戶來(lái)執(zhí)行
- tar -zxvf Cache-Memcached-1.14.tar.gz
- cd Cache-Memcached-1.14
- perl makefile.pl
- make
- make install
- make test
2.2 快速入門
<1> memcached服務(wù)的啟動(dòng)
memcached的啟動(dòng)非常簡(jiǎn)單,它沒(méi)有配置文件,只要配置好幾個(gè)參數(shù)就可以使用了。下面我以一個(gè)實(shí)際應(yīng)用的例子,具體說(shuō)明一下:
memcached ?d ?m 500 -l 64.128.191.151 -p 11211 -vv >>/var/www/kelly/test/logs/memcached_$$.log
啟動(dòng)的這個(gè)memcached為一個(gè)后臺(tái)守護(hù)進(jìn)程模式(-d), 然后緩存的空間為500M(-m), 監(jiān)聽(tīng)(-l)服務(wù)器64.128.191.15的11211號(hào)端口(-p).,將日志寫(xiě)道/var/www/kelly/test/logs /memcached_$$.log(-vv)。
其實(shí)memcached的參數(shù)也非常的有限,就下面這幾個(gè):
- ? -p port number to listen on
- ? -l interface to listen on, default is INDRR_ANY
- ? -d run as a daemon
- ? -r maximize core file limit
- ? -u assume identity of (only when run as root)
- ? -m max memory to use for items in megabytes, default is 64 MB
- ? -M return error on memory exhausted (rather than removing items)
- ? -c max simultaneous connections, default is 1024
- ? -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
我們也可以將這個(gè)啟動(dòng)腳本寫(xiě)道/etc/rc.d或者/erc/rc.local,這樣可以在服務(wù)器啟動(dòng)時(shí)候執(zhí)行。
<2> memcached客戶端的連接
下面我就以perl客戶端程序?yàn)槔f(shuō)明客戶端的連接:
啟動(dòng)兩個(gè)memcached server
- memcached ?d ?m 500 -l 64.128.191.151 -p 11211 -vv >>/var/www/kelly/test/logs/memcached_$$.log
- memcached ?d ?m 500 -l 64.128.191.151 -p 11212 -vv >>/var/www/kelly/test/logs/memcached_$$.log
perl客戶端程序
- #!/usr/bin/perl
- use Cache::Memcached;
- my $memd = new Cache::Memcached {
- 'servers' => [ "64.128.191.15:11211" , "64.128.191.15:11212"],
- };
- my $val = $memd->get( "my_key" );
- if ( $val )
- {
- print "Value is '$val'\n";
- }
- # Set a value
- $memd->set("my_key", "123");
- $memd->disconnect_all();
$ perl test-memcache.pl
$ perl test-memcache.pl
Value is '123'
可以看到,第一次沒(méi)有取得my_key,第二次從memcached中得到my_key的值。
同時(shí)通過(guò)查看日志,可以發(fā)現(xiàn)的確存儲(chǔ)在兩個(gè)memcache server中。
這個(gè)簡(jiǎn)單的例子,解釋了如何在memcached中存取數(shù)據(jù),以及memcache是真正的分布式緩存系統(tǒng)。
當(dāng)然,這還只是很簡(jiǎn)單的例子,體現(xiàn)不出memcache的優(yōu)勢(shì),下面將通過(guò)一個(gè)很具體的例子,給出詳細(xì)的應(yīng)用。
3、 memcached在Zorpia的應(yīng)用
http://www.zorpia.com 是一個(gè)網(wǎng)頁(yè)相冊(cè),博客,交友,論壇的大型網(wǎng)站公司?,F(xiàn)在已有超過(guò)140萬(wàn)活躍使用者遍布美國(guó),香港,東南亞,歐洲,澳洲,亞洲等其它地區(qū)。每天的訪問(wèn)量都在增長(zhǎng),已成為全世界排名第五的社會(huì)生活關(guān)系網(wǎng)。
Memcached也采用了memcached來(lái)提高網(wǎng)站的訪問(wèn)速度,并且取得了很好的效果,我在負(fù)責(zé)zorpia的memcached項(xiàng)目時(shí)候積累了一些經(jīng)驗(yàn),主要的做法如下:
1) 通過(guò)對(duì)memcache的perl客戶端進(jìn)行包裝,定制自己的客戶端。
2) 通過(guò)制定符合zorpia規(guī)范的hash key命名規(guī)范
? ? memcache中需要存儲(chǔ)的內(nèi)容的key均由string組成。
這個(gè)string統(tǒng)一由一個(gè)memcache.pm的subroutine來(lái)實(shí)現(xiàn)。(假設(shè)這個(gè)subroutine是 get_key() )
? ? memcache中存放兩種形式的數(shù)據(jù)
(1) result of SQL query :
(2) 普通變量(variable)
這兩種數(shù)據(jù)的key的組合方式是不相同的,由get_key進(jìn)行判斷和完成
? ? 關(guān)于get_key 和 naming rule
get_key subroutine完成所有memcache key的命名,naming rule也是在它里邊體現(xiàn):
(1)輸入?yún)?shù) -- hash結(jié)構(gòu),里邊定義了當(dāng)前需要存放的數(shù)據(jù)的信息
結(jié)構(gòu)
(2)返回值 -- string,返回?cái)?shù)據(jù)的key_name
?必須確定 get_key 的傳入hash的結(jié)構(gòu),
hash中主要有兩個(gè)元素
type --- 定義當(dāng)前數(shù)據(jù)結(jié)構(gòu)的類型 ,有 'var' , 'sql'兩種值
object --- 存放當(dāng)前數(shù)據(jù)結(jié)構(gòu)的詳細(xì)信息,
當(dāng) type eq 'var'時(shí),object表示變量的名字,該名字由程序員指定
當(dāng) type eq 'sql'時(shí),object包含所存放sql的主要基本信息,hash結(jié)構(gòu),也由程序員按照規(guī)則制定
## 當(dāng)variable 數(shù)據(jù)類型,比較簡(jiǎn)單
$var_hash = {
type => 'var', ## var表示當(dāng)前類型是 variable
object => 'language', ## language代表variable的名字
};
生成的key是Zorpia::var| language
## sql 數(shù)據(jù)
比如select first_name from user where user_id =2那么hash為
$sql_hash = {
type => 'sql',
object => {
table => {table2=>"user",}, ## sql 查詢的表
column => {column1=>"first_name",}, ## sql所要查詢的column
condition => { user_id =>"2",}, ## sql條件
},
};
生成的key是Zorpia::sql|user|first_name| user_id =2
get_key subroutine必須對(duì)傳入hash進(jìn)行判斷,對(duì)不同類型的數(shù)據(jù)按照不同的方式組合,形成key,返回給使用者。這個(gè)key,必須保證其唯一性:
比如:所有字母小寫(xiě),一些數(shù)組在組合成key之前必須首先排序
? ? get_key函數(shù)
- sub get_key{
- my $hash = shift;
- return undef unless $hash && ref $hash eq "HASH";
- my $type = $hash->{type};
- my $key_name;
- if ($type eq 'sql') {
- my ($table_key,$column_key,$condition_key);
- $table_key=_get_key($hash->{object}->{table});
- $column_key=_get_key($hash->{object}->{column});
- $condition_key=_get_key($hash->{object}->{condition});
- $key_name = join('|',$type,$table_key,$column_key,$condition_key);
- #Currently the length limit of a key is set at 250 characters
- if (length($key_name)>250)
- {
- $key_name=substr(0,250,$key_name);
- }
- }
- elsif($type eq 'var')
- {
- $key_name = join('|',$type,$hash->{object});
- }
- return $key_name;
- }
- sub _get_key
- {
- my $hash=shift;
- return undef unless $hash && ref $hash eq "HASH";
- my ($t,$ret,$i);
- foreach $i (sort keys %$hash)
- {
- $i=~s/^\s+|\s+$//g;
- $hash->{$i}=~s/^\s+|\s+$//g;
- push(@$t,lc("$i=$hash->{$i}"));
- }
- $ret=join(':',sort { $a cmp $b } @$t);
- return $ret;
- }
?經(jīng)常訪問(wèn)的表user,user_details
?合理設(shè)定變量在memcached的生存周期
?將活躍用戶的信息預(yù)先導(dǎo)入到memcached
?分別在多臺(tái)機(jī)器上啟動(dòng)多個(gè)memcached服務(wù)
?編寫(xiě)腳本監(jiān)控memcached服務(wù)是否活動(dòng)
4) User表的具體應(yīng)用舉例
? 在 select時(shí)候
先查詢memcahce里有沒(méi)有,有的話,返回;否則從數(shù)據(jù)庫(kù)select,在memcache里設(shè)置,返回。
- my $sql_hash = {
- type => 'sql',
- object => {
- table => {table1=>"user",},
- column => {column1=>"user_id",},
- condition => {email=>$user_id,},
- },
- };
- my $key=Zorpia::MemCache::get_key($sql_hash);
- my $user_id_by_email=Zorpia::MemCache::get($key);
- if(!$user_id_by_email)
- {
- my $sth;
- my $query ="select user_id from user where email=?";
- $sth = $dbh->prepare($query);
- $sth->execute($user_id);
- my $user1 = $sth->fetchrow_hashref();
- $user_id_by_email=$user1->{'user_id'};
- Zorpia::MemCache::set($key,$user_id_by_email,1800);
- }
先在數(shù)據(jù)庫(kù)update,insert,delete,在memcache里設(shè)置,返回。
- &Zorpia::DB::data_entry_no_return($dbh,"user","COUNT(*)","$account_information_insert_statement user_id=$current_user_id", "user_id=$current_user_id");
- #add by kelly
- my $sql_hash = {
- type => 'sql',
- object => {
- table => {table1=>"user",},
- column => {column1=>"user_id",},
- condition => {user_id=>$current_user_id,},
- },
- };
- my $key=Zorpia::MemCache::get_key($sql_hash);
- my $query = "SELECT *, user_id AS id FROM user WHERE user_id=?";
- my $sth_memc = $dbh->prepare($query);
- $sth_memc->execute($current_user_id);
- my $user_memc = $sth_memc->fetchrow_hashref();
- &Zorpia::MemCache::set($key,$user_memc,21600);
使用了memcached以后, 我發(fā)現(xiàn)以前做過(guò)的很多的項(xiàng)目都可以應(yīng)用它提高效率,包括最近做的“大單追蹤”, “數(shù)碼搜索”等等。當(dāng)然既然memcahced是分布式的緩存系統(tǒng),那么它就是建立了一個(gè)分布式的平臺(tái), 我們可以用它來(lái)進(jìn)行分布式的記數(shù), 因?yàn)閷?duì)于一個(gè)鍵值key我們可以設(shè)置它的數(shù)值以及有效期在參數(shù)中,另外還可以重新設(shè)置這個(gè)鍵值的數(shù)值。 所以我總結(jié)了一下目前可以應(yīng)用到的地方:
<1>.數(shù)據(jù)庫(kù)檢索結(jié)果的緩存,也就是說(shuō)可以有機(jī)的和數(shù)據(jù)庫(kù)結(jié)合起來(lái)應(yīng)用,提高效率。
這也是目前memcached用到的最多的地方,比如用于大型網(wǎng)站等。
可以這樣來(lái)實(shí)現(xiàn):
打開(kāi)memcached服務(wù)器連接
編寫(xiě)sql語(yǔ)句, 同時(shí)算出它的一個(gè)hash key值
獲取這個(gè)hash值的memcached保存數(shù)據(jù)(get)
如果獲取的這個(gè)hash值的數(shù)據(jù)存在。返回
否則連接數(shù)據(jù)庫(kù)查找
把這個(gè)查找結(jié)果保存在memcached中(set),可以設(shè)置有效期
返回查找結(jié)果
<2>.分布式計(jì)算
<3>.分布式共享數(shù)據(jù)
總之,memcached的機(jī)制比較靈活,可以適用于一切需要分布式緩存數(shù)據(jù)的地方,隨著memcached逐漸為人所知,必將在更多的分布式應(yīng)用領(lǐng)域大放異彩。
http://nio.infor96.com/php-memcached/
一、memcached 簡(jiǎn)介
在很多場(chǎng)合,我們都會(huì)聽(tīng)到 memcached 這個(gè)名字,但很多同學(xué)只是聽(tīng)過(guò),并沒(méi)有用過(guò)或?qū)嶋H了解過(guò),只知道它是一個(gè)很不錯(cuò)的東東。這里簡(jiǎn)單介紹一下,memcached 是高效、快速的分布式內(nèi)存對(duì)象緩存系統(tǒng),主要用于加速 WEB 動(dòng)態(tài)應(yīng)用程序。
二、memcached 安裝
首先是下載 memcached 了,目前最新版本是 1.1.12,直接從官方網(wǎng)站即可下載到 memcached-1.1.12.tar.gz。除此之外,memcached 用到了 libevent,我下載的是 libevent-1.1a.tar.gz。
接下來(lái)是分別將 libevent-1.1a.tar.gz 和 memcached-1.1.12.tar.gz 解開(kāi)包、編譯、安裝:
- # tar -xzf libevent-1.1a.tar.gz# cd libevent-1.1a# ./configure --prefix=/usr# make# make install# cd ..# tar -xzf memcached-1.1.12.tar.gz# cd memcached-1.1.12# ./configure --prefix=/usr# make#
三、運(yùn)行 memcached 守護(hù)程序
運(yùn)行 memcached 守護(hù)程序很簡(jiǎn)單,只需一個(gè)命令行即可,不需要修改任何配置文件(也沒(méi)有配置文件給你修改 ):
- /usr/bin/memcached -d -m 128 -l 192.168.1.1 -p 11211 -u httpd
-d 以守護(hù)程序(daemon)方式運(yùn)行 memcached;-m 設(shè)置 memcached 可以使用的內(nèi)存大小,單位為 M;-l 設(shè)置監(jiān)聽(tīng)的 IP 地址,如果是本機(jī)的話,通常可以不設(shè)置此參數(shù);-p 設(shè)置監(jiān)聽(tīng)的端口,默認(rèn)為 11211,所以也可以不設(shè)置此參數(shù);-u 指定用戶,如果當(dāng)前為 root 的話,需要使用此參數(shù)指定用戶。當(dāng)然,還有其它參數(shù)可以用,man memcached 一下就可以看到了。
四、memcached 的工作原理
首先 memcached 是以守護(hù)程序方式運(yùn)行于一個(gè)或多個(gè)服務(wù)器中,隨時(shí)接受客戶端的連接操作,客戶端可以由各種語(yǔ)言編寫(xiě),目前已知的客戶端 API 包括 Perl/PHP/Python/Ruby/Java/C#/C 等等。PHP 等客戶端在與 memcached 服務(wù)建立連接之后,接下來(lái)的事情就是存取對(duì)象了,每個(gè)被存取的對(duì)象都有一個(gè)唯一的標(biāo)識(shí)符 key,存取操作均通過(guò)這個(gè) key 進(jìn)行,保存到 memcached 中的對(duì)象實(shí)際上是放置內(nèi)存中的,并不是保存在 cache 文件中的,這也是為什么 memcached 能夠如此高效快速的原因。注意,這些對(duì)象并不是持久的,服務(wù)停止之后,里邊的數(shù)據(jù)就會(huì)丟失。
三、PHP 如何作為 memcached 客戶端
有兩種方法可以使 PHP 作為 memcached 客戶端,調(diào)用 memcached 的服務(wù)進(jìn)行對(duì)象存取操作。
第一種,PHP 有一個(gè)叫做 memcache 的擴(kuò)展,Linux 下編譯時(shí)需要帶上 ?enable-memcache[=DIR] 選項(xiàng),Window 下則在 php.ini 中去掉 php_memcache.dll 前邊的注釋符,使其可用。
除此之外,還有一種方法,可以避開(kāi)擴(kuò)展、重新編譯所帶來(lái)的麻煩,那就是直接使用 php-memcached-client。
本文選用第二種方式,雖然效率會(huì)比擴(kuò)展庫(kù)稍差一些,但問(wèn)題不大。
四、PHP memcached 應(yīng)用示例
首先 下載 memcached-client.php,在下載了 memcached-client.php 之后,就可以通過(guò)這個(gè)文件中的類“memcached”對(duì) memcached 服務(wù)進(jìn)行操作了。其實(shí)代碼調(diào)用非常簡(jiǎn)單,主要會(huì)用到的方法有 add()、get()、replace() 和 delete(),方法說(shuō)明如下:
add ($key, $val, $exp = 0)
往 memcached 中寫(xiě)入對(duì)象,$key 是對(duì)象的唯一標(biāo)識(shí)符,$val 是寫(xiě)入的對(duì)象數(shù)據(jù),$exp 為過(guò)期時(shí)間,單位為秒,默認(rèn)為不限時(shí)間;
get ($key)
從 memcached 中獲取對(duì)象數(shù)據(jù),通過(guò)對(duì)象的唯一標(biāo)識(shí)符 $key 獲??;
replace ($key, $value, $exp=0)
使用 $value 替換 memcached 中標(biāo)識(shí)符為 $key 的對(duì)象內(nèi)容,參數(shù)與 add() 方法一樣,只有 $key 對(duì)象存在的情況下才會(huì)起作用;
delete ($key, $time = 0)
刪除 memcached 中標(biāo)識(shí)符為 $key 的對(duì)象,$time 為可選參數(shù),表示刪除之前需要等待多長(zhǎng)時(shí)間。
下面是一段簡(jiǎn)單的測(cè)試代碼,代碼中對(duì)標(biāo)識(shí)符為 ‘mykey’ 的對(duì)象數(shù)據(jù)進(jìn)行存取操作:
// 包含 memcached 類文件require_once(‘memcached-client.php’);// 選項(xiàng)設(shè)置$options = array( ’servers’ => array(‘192.168.1.1:11211′), //memcached 服務(wù)的地址、端口,可用多個(gè)數(shù)組元素表示多個(gè) memcached 服務(wù) ‘debug’ => true, //是否打開(kāi) debug ‘compress_threshold’ => 10240, //超過(guò)多少字節(jié)的數(shù)據(jù)時(shí)進(jìn)行壓縮 ‘persistant’ => false //是否使用持久連接 );// 創(chuàng)建 memcached 對(duì)象實(shí)例$mc = new memcached($options);// 設(shè)置此腳本使用的唯一標(biāo)識(shí)符$key = ‘mykey’;// 往 memcached 中寫(xiě)入對(duì)象$mc->add($key, ’some random strings’);$val = $mc->get($key);echo “n”.str_pad(‘$mc->add() ’, 60, ‘_’).“n”;var_dump($val);// 替換已寫(xiě)入的對(duì)象數(shù)據(jù)值$mc->replace($key, array(’some’=>‘haha’, ‘array’=>‘xxx’));$val = $mc->get($key);echo “n”.str_pad(‘$mc->replace() ’, 60, ‘_’).“n”;var_dump($val);// 刪除 memcached 中的對(duì)象$mc->delete($key);$val = $mc->get($key);echo “n”.str_pad(‘$mc->delete() ’, 60, ‘_’).“n”;var_dump($val);?>
是不是很簡(jiǎn)單,在實(shí)際應(yīng)用中,通常會(huì)把數(shù)據(jù)庫(kù)查詢的結(jié)果集保存到 memcached 中,下次訪問(wèn)時(shí)直接從 memcached 中獲取,而不再做數(shù)據(jù)庫(kù)查詢操作,這樣可以在很大程度上減輕數(shù)據(jù)庫(kù)的負(fù)擔(dān)。通常會(huì)將 SQL 語(yǔ)句 md5() 之后的值作為唯一標(biāo)識(shí)符 key。下邊是一個(gè)利用 memcached 來(lái)緩存數(shù)據(jù)庫(kù)查詢結(jié)果集的示例(此代碼片段緊接上邊的示例代碼):
= ‘SELECT * FROM users’;$key = md5($sql); //memcached 對(duì)象標(biāo)識(shí)符if ( !($datas = $mc->get($key)) ) { // 在 memcached 中未獲取到緩存數(shù)據(jù),則使用數(shù)據(jù)庫(kù)查詢獲取記錄集。 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; // 將數(shù)據(jù)庫(kù)中獲取到的結(jié)果集數(shù)據(jù)保存到 memcached 中,以供下次訪問(wèn)時(shí)使用。 $mc->add($key, $datas);} else { echo “n”.str_pad(‘Read datas from memcached.’, 60, ‘_’).“n”;}var_dump($datas);?>可以看出,使用 memcached 之后,可以減少數(shù)據(jù)庫(kù)連接、查詢操作,數(shù)據(jù)庫(kù)負(fù)載下來(lái)了,腳本的運(yùn)行速度也提高了。
之前我曾經(jīng)寫(xiě)過(guò)一篇名為《PHP 實(shí)現(xiàn)多服務(wù)器共享 SESSION 數(shù)據(jù)》文章,文中的 SESSION 是使用數(shù)據(jù)庫(kù)保存的,在并發(fā)訪問(wèn)量大的時(shí)候,服務(wù)器的負(fù)載會(huì)很大,經(jīng)常會(huì)超出 MySQL 最大連接數(shù),利用 memcached,我們可以很好地解決這個(gè)問(wèn)題,工作原理如下:
用戶訪問(wèn)網(wǎng)頁(yè)時(shí),查看 memcached 中是否有當(dāng)前用戶的 SESSION 數(shù)據(jù),使用 session_id() 作為唯一標(biāo)識(shí)符;如果數(shù)據(jù)存在,則直接返回,如果不存在,再進(jìn)行數(shù)據(jù)庫(kù)連接,獲取 SESSION 數(shù)據(jù),并將此數(shù)據(jù)保存到 memcached 中,供下次使用;
當(dāng)前的 PHP 運(yùn)行結(jié)束(或使用了 session_write_close())時(shí),會(huì)調(diào)用 My_Sess::write() 方法,將數(shù)據(jù)寫(xiě)入數(shù)據(jù)庫(kù),這樣的話,每次仍然會(huì)有數(shù)據(jù)庫(kù)操作,對(duì)于這個(gè)方法,也需要進(jìn)行優(yōu)化。使用一個(gè)全局變量,記錄用戶進(jìn)入頁(yè)面時(shí)的 SESSION 數(shù)據(jù),然后在 write() 方法內(nèi)比較此數(shù)據(jù)與想要寫(xiě)入的 SESSION 數(shù)據(jù)是否相同,不同才進(jìn)行數(shù)據(jù)庫(kù)連接、寫(xiě)入數(shù)據(jù)庫(kù),同時(shí)將 memcached 中對(duì)應(yīng)的對(duì)象刪除,如果相同的話,則表示 SESSION 數(shù)據(jù)未改變,那么就可以不做任何操作,直接返回了;
那么用戶 SESSION 過(guò)期時(shí)間怎么解決呢?記得 memcached 的 add() 方法有個(gè)過(guò)期時(shí)間參數(shù) $exp 嗎?把這個(gè)參數(shù)值設(shè)置成小于 SESSION 最大存活時(shí)間即可。另外別忘了給那些一直在線的用戶延續(xù) SESSION 時(shí)長(zhǎng),這個(gè)可以在 write() 方法中解決,通過(guò)判斷時(shí)間,符合條件則更新數(shù)據(jù)庫(kù)數(shù)據(jù)。
五、相關(guān)資源
memcached 官方網(wǎng)站
PHP memcached client
下載 memcached-client.php
http://www.dirk.sh/diary/216
Memcached 是一個(gè)非常優(yōu)秀的緩存加速系統(tǒng),和 Squid 的前端緩存加速不同,它是通過(guò)基于內(nèi)存緩存對(duì)象來(lái)減少數(shù)據(jù)庫(kù)查詢的方式改善網(wǎng)站系統(tǒng)的反應(yīng),而其中最吸引人的一個(gè)特性就是支持分布式部署;也就是說(shuō)可以在 一群機(jī)器上建立一堆 Memcached 服務(wù),每個(gè)服務(wù)可以根據(jù)具體服務(wù)器的硬件配置使用不同大小的內(nèi)存塊,這樣一來(lái),理論上可以建立一個(gè)無(wú)限巨大的基于內(nèi)存的 cache storage 系統(tǒng)。
Php 下的 Memcached 官方 API 是 memcache 這個(gè)包,前不久發(fā)布 2.0.0 stable 版本,關(guān)鍵的更新是增加了 addServer() 函數(shù)用于支持 Multiple servers with loadbalancing and failover,在 FreeBSD 下安裝:
[root@trinity ~]# cd /usr/ports/databases/memcached/[root@trinity ~]# make install clean[root@trinity ~]# cd /usr/ports/databases/pecl-memcache[root@trinity ~]# make install clean另外一個(gè)號(hào)稱更快的 API 包是 mcache,看作者的說(shuō)明,是直接使用了 libmemcache,但在 FreeBSD 下目前還沒(méi)有 Ports,需要源代碼方式安裝,具體可以參考 mcache 的說(shuō)明。
一個(gè)簡(jiǎn)單的 PHP 腳本示例:
addServer('localhost', 11211);$memcache->addServer('localhost', 11212);if ($memcache) { $count = intval($memcache->get('static_count')); $count ++; $memcache->set('static_count', $count, 0, 30); var_dump($memcache->get('static_count'));} else { echo "Connection to memcached failed";}?>但不管 Memcached 是一個(gè)多么優(yōu)秀的東西,在沒(méi)有合理的緩存策略(緩存什么東西?如何緩存?緩存時(shí)機(jī)?過(guò)期策略?)的情況下,只會(huì)被濫用,發(fā)揮不了真正的作用。構(gòu)思 中…...