(一):基礎(chǔ)概念
- memcache是什么?
Memcache 是一個高性能的分布式內(nèi)存對象緩存系統(tǒng),用于動態(tài)Web應用以減輕數(shù)據(jù)庫負載。它通過在內(nèi)存中緩存數(shù)據(jù)和對象來減少讀取數(shù)據(jù)庫的次數(shù),從而提高動態(tài)、數(shù)據(jù)庫驅(qū)動網(wǎng)站的速度。Memcached基于一個存儲鍵/值對的hashmap。其守護進程(daemon )是用C寫的,但是客戶端可以用任何語言來編寫,并通過memcached協(xié)議與守護進程通信。
- memcache的工作原理?

RDBMS :關(guān)系數(shù)據(jù)庫管理系統(tǒng)(Relational Database Management System)。
memcached:
php有兩個memcache客戶端,一個是php memcached, 一個是php memcache??蛻舳说膍emcached
相當于memcache的Plus版,實際在操作上和memcache幾乎類似,當然作為memcache的升級版,memcached在穩(wěn)定性和速度上更好,php操作memcached提供了更多的方法。在php官方的手冊中分別搜索memcached和memcache 能發(fā)現(xiàn)他們的異同點。
- memcache的主要特點?
- 協(xié)議簡單 基于C/S架構(gòu)(Client/Server)
2.基于libevent的事件處理
3.內(nèi)置內(nèi)存存儲方式
4.互不通信的分布式內(nèi)純緩存服務器
- memcache的使用場景?
1.因為memcache是不能持久化數(shù)據(jù)的,一旦memcache宕機或者重啟之類的,原來存入的數(shù)據(jù)都會丟失,所以對一些數(shù)據(jù)的安全性要求不高的可以考慮使用memcache
2.因為memcache存儲的單個對象的最大是1M所以,當有一些體積相對較小,但是頻繁被訪問的數(shù)據(jù)時,可以是考慮memcache
3.當一個系統(tǒng)有大量的動態(tài)內(nèi)容時,存在大量的讀取數(shù)據(jù)庫的操作,造成數(shù)據(jù)庫負載過高時,可以考慮使用memcache做緩存來緩解數(shù)據(jù)庫壓力
4.多臺服務器需要共享某些數(shù)據(jù)的時候,可以考慮使用memcache,例如:session共享
5.小結(jié):memcache基本就是做緩存用的,為的是緩解服務器的壓力,提高系統(tǒng)悉能
(二) 安裝memcache
1.準備工具
1.1 : Xshell
1.2 :一個可用的LAMP/LNMP環(huán)境
1.3:我測試的是LAMP CentOS7+Apache(2.4.6)+MySql(5.6.35)+PHP(5.416)
2.安裝基本流程
2.1 安裝memcached的服務器端
一般在服務器端安裝memcached得首先安裝libevent庫才行,但是在CentSO上使用yum方式安裝可以解決這種依賴
yum install memcached
2.2 安裝php的memcache擴展
yum install php-memcache2.3 重啟一下服務器
3.memcache安裝后測試
3.1 開啟memcache服務器端
2017-03.png3.1.1memcached指令參數(shù)基礎(chǔ)解釋
//在memcache的服務器端,我們可以通過memcached -help查該指令有那些參數(shù),我們只解釋下他的基礎(chǔ)參數(shù)的意思 //例如 指令 /usr/bin/memcached -d -l 127.0.0.1 -p 11211 -m 150 -u root -d 表示是守護進程 -l 連接的ip地址 -p memcached服務器監(jiān)聽的端口 -m 分配給memcached服務的最大的內(nèi)存,單位是MB,默認是64M -u 以誰的身份運行,示例中的是root用戶運行,實際中少這么用,權(quán)限太高了 -c 同時最大的連接數(shù) 默認是1024 -n 最小分配空間 key+value+flags 默認是483.2 查看php的memcache安裝是否成功
3.2.1 進入你應用的根目錄 例如:/var/www/html/ 下
3.2.2. 新建一個文件 vim phpinfo.php<?php phpinfo(); ?>3.2.3 使用瀏覽器訪問該文件 如果出現(xiàn)如下信息
2017-03.png
3.2.4 表示php的memcache擴展開啟成功了
3.2.5 注意: 當你的memcache都安裝好了,在服務器上寫的php腳本,通過客戶端瀏覽器訪問卻沒有什么內(nèi)容返回的情況,我們首先查看一下Linux上的訪問日志和錯誤日志,我是的LAMP環(huán)境,訪問日志和錯誤日志都是放在了默認的位置 /var/log/httpd 目錄下.打開access_log
access_log.png
狀態(tài)碼是200 表示訪問是ok的
我們再看錯誤日志error_log
error.png
我們看到最近的一次錯誤是許可被拒絕了
基本分析是可能和權(quán)限,安全保護有關(guān)(SELinux,防火墻等)
此處我臨時關(guān)閉SElinux即可 指令如下setenforce 0
(三):PHP操作memcache
- 簡單的講memcache是php對內(nèi)存操作的一種媒介
- 既然是對內(nèi)存的操作,不能免俗的就要從增刪改查四部曲開始
- php操作memcache,就和操作一個普通的類是一樣的
php連接memcache服務器
- 我們進入項目的根目錄(例如:/var/www/html/)新建一個文件con.php
<?php
//新建一個memcache對象$mem
$mem = new Memcache;
//連接memcache服務器
//connect("memcache服務器地址","memcache服務器使用的端口號")
$mem->connect("127.0.0.1",11211);
//查看memcache服務器的統(tǒng)計狀態(tài)
print_r($mem->getStats());
```php <?php
//新建一個memcache對象$mem
$mem = new Memcache;
//向連接池中添加一個memcache服務器
/*
*使用addServer方法也可以連接memcache服務器上,引用php手冊上的說法是:
*"使用這個方法的時候網(wǎng)絡(luò)連接并不會立刻建立,而是直到真正使用的時候才建立。 因此在加
*入大量服務器到連接池中時也是沒有開銷的,因為它們可能并不會被使用"
*/
$mem->addServer("127.0.0.1",11211);
//查看memcache服務器的統(tǒng)計狀態(tài)
print_r($mem->getStats());
-
通過瀏覽器訪問該文件
2017-03.png
2.1 返回的統(tǒng)計信息是一個數(shù)組,我們大概了解一下返回的統(tǒng)計信息的意思
[pid] => 37344 服務器的進程id
[uptime] => 21672 服務從啟動到當前所經(jīng)過的時間,單位是秒
[time] => 1489951190 服務器所在主機當前系統(tǒng)的時間,單位是秒
[version] => 1.4.15 memcached的版本號
[libevent] => 2.0.21-stable
[pointer_size] => 64 服務器所在主機操作系統(tǒng)的指針大小
[rusage_user] => 1.174806
[rusage_system] => 0.931503
[curr_connections] => 8 表示當前系統(tǒng)打開的連接數(shù)
[total_connections] => 33 表示從memcached服務啟動到當前時間,系統(tǒng)打開過的連接的總數(shù)
[connection_structures] => 9
[reserved_fds] => 20
[cmd_get] => 14 累積獲取數(shù)據(jù)的數(shù)量
[cmd_set] => 1 累積保存數(shù)據(jù)的數(shù)量
[cmd_flush] => 0
[cmd_touch] => 0
[get_hits] => 12 表示獲取數(shù)據(jù)成功的次數(shù)
[get_misses] => 2 表示獲取數(shù)據(jù)失敗的次數(shù)
[delete_misses] => 0 表示刪除數(shù)據(jù)失敗的次數(shù)
[delete_hits] => 0 表示刪除數(shù)據(jù)命中的次數(shù)
[incr_misses] => 0 表示增加一個元素失敗的次數(shù)
[incr_hits] => 0 表示增加一個元素命中的次數(shù)
[decr_misses] => 0 表示減少一個元素失敗的次數(shù)
[decr_hits] => 0 表示減少一個元素命中的次數(shù)
[cas_misses] => 0
[cas_hits] => 0
[cas_badval] => 0
[touch_hits] => 0
[touch_misses] => 0
[auth_cmds] => 0
[auth_errors] => 0
[bytes_read] => 270 memcached服務器從網(wǎng)絡(luò)讀取的總的字節(jié)數(shù)
[bytes_written] => 12788 memcached服務器發(fā)送到網(wǎng)絡(luò)的總的字節(jié)數(shù)。
[limit_maxbytes] => 157286400 memcached服務緩存允許使用的最大字節(jié)數(shù)
[accepting_conns] => 1
[listen_disabled_num] => 0
[threads] => 4 被請求的工作線程的總數(shù)量
[conn_yields] => 0
[hash_power_level] => 16
[hash_bytes] => 524288
[hash_is_expanding] => 0
[bytes] => 0
[curr_items] => 0
[total_items] => 1
[expired_unfetched] => 0
[evicted_unfetched] => 0
[evictions] => 0
[reclaimed] => 0
2.2 我們看到使用php操作memcache,首先是實例化一個memcache的對象,然后建立一個memcache服務端的連接.
php操作memcache
添加數(shù)據(jù)###
1.1 例如文件位置 : /var/www/html/con.php
<?php $mem = Memcache; $mem->connect('127.0.0.1',11211); //memcache緩存數(shù)據(jù)的結(jié)構(gòu)是基于 key -> value (鍵值)的 //add('鍵名','值','是否壓縮','多少秒后失效') $mem->add('one','故人西辭黃鶴樓',0,60);1.2 我們再用一個文件驗證是否存入 文件位置:/var/www/html/test.php
<?php $mem = Memcache; $mem->connect('127.0.0.1',11211); echo date("Y-m-d H:i:s"); echo $mem->get('one');1.3 通過瀏覽器訪問執(zhí)行,結(jié)果如下

超過設(shè)定的時間后就失效了
2017-03-25.png
1.4 我們也可以使用set('鍵名','值',是否壓縮,失效時間)來添加數(shù)據(jù)
<?php $mem = Memcache; $mem->connect('127.0.0.1',11211); //set('鍵名','值','是否壓縮','多少秒后失效') $mem->add('one','故人西辭黃鶴樓',0,60); $mem->set('one','煙花三月下?lián)P州',0,60);1.5 我們再獲取一下這個值

1.6 add()和set()方法的區(qū)別: add()添加一個值,如果這個值存在,則添加失敗
set()添加一個值,如果這個值存在,則替換掉原有的刪除數(shù)據(jù)###
2.1 修改 /var/www/html/test.php 文件
<?php $mem = new Memcache; $mem->connect("127.0.0.1",11211); echo date("Y-m-d H:i:s"); echo $mem->get('one')."<br />"; $mem->delete('one'); $one = $mem->get('one'); if(empty($one)) { echo "數(shù)據(jù)已經(jīng)刪除"; }2.2 執(zhí)行該文件后的效果


2.3 使用flush()方法清除已經(jīng)存儲的所有數(shù)據(jù)
2.3.1 修改 /var/www/html/con.php 文件并執(zhí)行<?php $mem = new Memcache; $mem->addServer("127.0.0.1",11211); $mem->add('one','故人西辭黃鶴樓',false,0); $mem->set('two','煙花三月下?lián)P州',0,0); $mem->set('three','孤帆遠影碧空盡',0,0); $mem->set('four','唯見長江天際流',0,0);
2.3.2 修改 /var/www/html/test.php 文件并執(zhí)行
<?php $mem = new Memcache; $mem->connect("127.0.0.1",11211); $result = $mem->get(array('one','two','three','four')); echo "<pre>"; var_dump($result);
2.3.3 結(jié)果如下

2.3.4 再修改 /var/www/html/test.php 文件并執(zhí)行
<?php $mem = new Memcache; $mem->connect("127.0.0.1",11211); $mem->flush(); $result = $mem->get(array('one','two','three','four')); echo "<pre>"; var_dump($result);2.3.5 結(jié)果如下

修改數(shù)據(jù)###
3.1 php修改memcache的數(shù)據(jù)一般有兩個方法set() 和replace()
3.1.1再修改 /var/www/html/test.php 文件并執(zhí)行<?php $mem = new Memcache; $mem->connect("127.0.0.1",11211); //replace('被更新的鍵','新值','是否壓縮','過期時間') $flag = $mem->replace('four','歡迎來到揚州',0,0); if($flag === FALSE) { echo "更新數(shù)據(jù)失敗"; }else{ echo "更新數(shù)據(jù)成功"; } $result = $mem->get(array('one','two','three','four')); echo "<pre>"; var_dump($result);3.1.2 通過瀏覽器訪問test.php文件后的結(jié)果如下:

3.1.3 我們再次修改 /var/www/html/test.php 文件并執(zhí)行
<?php $mem = new Memcache; $mem->connect("127.0.0.1",11211); //更新一個不存在的鍵 例如:five $flag = $mem->replace('five','火星歡迎您',0,0); if($flag === FALSE) { echo "更新數(shù)據(jù)失敗"; }else{ echo "更新數(shù)據(jù)成功"; } $result = $mem->get(array('one','two','three','four')); echo "<pre>"; var_dump($result);3.1.4 執(zhí)行后結(jié)果如下:

3.2 set()和replace是區(qū)別是:
當數(shù)據(jù)存在的時候,set()方法和replace()方法都能更新(修改),作用相同 當數(shù)據(jù)不存在的時候,set()方法會添加這樣一條數(shù)據(jù),replace()方法會返回FALSE查詢數(shù)據(jù)###
//memcache有關(guān)查詢的幾個方法 get()獲取memcache上key的值,前面有示例,既能是單一的key值也可以是一組key的數(shù)組 getStatus()獲取當前memcache服務器的統(tǒng)計信息 getServerStatus('服務器地址','端口號')用于獲取一個服務器的在線/離線狀態(tài),返回一個服務器的狀態(tài),0表示服務器離線,非0表示在線。 getExtendedStats()緩存服務器池中所有服務器統(tǒng)計信息,如果緩存池中有多臺memcache服務器,就將這些服務器的信息以二維數(shù)組的形式都返回 //例如,我向連接池中添加兩臺memcache服務器: $mem->addServer("127.0.0.1",11211); $mem->addServer("127.0.0.1",11212); $stats = $mem->getExtendedStats(); print_r($stats); //返回的信息格式將會是: Array ( [127.0.0.1:11211]=>Array ( ......... ) [127.0.0.1:11212]=>Array ( ......... ) )增加或者減少一個元素的值###
increment('要增加值的元素的鍵','增加的量'); decrement('要減少值的元素的鍵','減少的量');我們修改 /var/www/html/con.php 文件并執(zhí)行
<?php $mem = new Memcache; $mem->connect("127.0.0.1",11211); $mem->set('num',4,0,0);我們修改 /var/www/html/test.php 文件并執(zhí)行
<?php $mem = new Memcache; $mem->connect("127.0.0.1",11211); $mem->increment('num',3); echo $mem->get('num');結(jié)果如下:

鍵 , 壓縮 ,過期時間,緩存過期,分配內(nèi)存耗盡
- 鍵(key) : 因為memcache是基于鍵和值的存儲方式,memcache中鍵的命名很可以很隨意,但是我們還是推薦比較有意義鍵名,key的最大長度是250個字節(jié)
- 壓縮 :因為memcache存儲單個item最大數(shù)據(jù)是在1MB內(nèi).所以當我們進行存儲,會考慮是否開啟壓縮
//e.g: bool memcache::set(key,value,是否壓縮[0/1],失效時間);2.1 壓縮會節(jié)省更多的內(nèi)存空間,但是也會帶來額外的CPU開銷,運行速度相對會慢
2.2 未壓縮,占用的內(nèi)存空間小,但是運行速度快
2.3memcache 支持的最大存儲對象是1M,所以在將單個大于1M的內(nèi)容存儲到memcache的時候需要開壓縮
- 有效時間:
memcache::set("key","value",是否壓縮,有效時間); memcache::add("key","value",是否要鎖,有效時間);memcache的有效時間單位是秒(s),手冊的解釋是"當前寫入緩存的數(shù)據(jù)的失效時間",設(shè)置有效時間有兩種寫法,并且有區(qū)別
//這種設(shè)置的有效時間的最大值是2592000秒既30天,但是要是有效時間大于30天怎么辦? memcache::set("home","love",0,2592000); //這樣這種時間戳的方式可以設(shè)置大于30天的有效時間 memcache::set("hope","love",0,time()+2592001);
- 當我們設(shè)置的一個緩存超過的有效期,那么這個緩存就"過期"了,不能再使用了,那么些過期的緩存數(shù)據(jù)會被memcache清除掉嗎?會的,memcache清除過期的數(shù)據(jù)是采用的一種"懶惰"的機制,過期后不會立刻清除掉,而是當再次通過get()方式獲取緩存時刪除過期的數(shù)據(jù)
- 我們再開啟memcache的時候曾經(jīng)通過-m這個參數(shù)給開啟的這個memcache分配一定內(nèi)存大小,可是當這個分配的內(nèi)存被使用殆盡的時候會怎么樣呢?當分配的內(nèi)存用盡,此時再向memcache中存入數(shù)據(jù),那么memcache就會將最近不常用的數(shù)據(jù)刪除掉,這種機制就是LRU(least recently used )
php操作memcache 基礎(chǔ)示例
我們模擬一個場景,我現(xiàn)在的user表(僅三個字段)中存在52W條數(shù)據(jù),我要取出最新的2萬條數(shù)據(jù).
分析:第一次訪問,memcache中沒有這些數(shù)據(jù),我們就從DB中取得這些數(shù)據(jù),并且將這些數(shù)據(jù)存入memcache中,當需要訪問相同的數(shù)據(jù)的時候,直接從memcache中提供這些數(shù)據(jù)
準備數(shù)據(jù)
mysql.png- 編寫基本腳本(php)文件
我們在根目錄下新建一個文件 vim /var/www/html/test2.php<?php $starttime = microtime(true); echo $starttime; echo "<hr />"; function getmemcache($sql,Memcache $memacche) { $key = md5($sql); $data = $memcache->get($key); if(!$data) { try{
$pdo = new PDO("mysql:host=localhost;dbname=test",'root','123456');
}catch(PDOException $e){
die($e->getMessage());
}
$stmt = $pdo->prepare($sql);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$memcache->set($key,$data,MEMCACHE_COMPRESSED, 0);
}return $data;
}
$mem = new Memcache();
$mem->connect('127.0.0.1',11211);
$sql = "select * from user order by id desc limit 0,20000";
$data = getmemcache($sql,$mem);
echo "<pre>";
print_r($data);
$mem->close();
$endtime = microtime(true);
echo "<hr />";
echo $endtime.'<br />';
echo '執(zhí)行時間'.round($endtime-$starttime,3).'秒';
3.通過客戶端瀏覽器第一次訪問test2.php文件

4.再次訪問test2.php文件

5.我們可以看到第二訪問是從memcache中獲取測數(shù)據(jù),應為我在test2.php文件中有2W條數(shù)據(jù)輸出,感覺還是耗時很多,我們將數(shù)據(jù)輸出那段代碼注釋掉,再次并且清空一下memcache緩存,再次訪問test2.php文件


學習本是一個自我修正的過程,總結(jié)中有許多的不足,萬望不吝賜教
[參考資料]:
1.http://php.net/manual/zh/class.memcache.php php手冊memcache部分
2.http://www.w3cschool.cn/memcached/ W3Cschool memcached部分
3.http://blog.csdn.net/heiyeshuwu/article/details/3950532 Memcached原理和使用詳情
[拓展資料]:
- 《大型網(wǎng)站技術(shù)架構(gòu)》李智慧著
- http://www.songyawei.cn/content/5008?utm_source=tuicool&utm_medium=referral memcache和memcached的區(qū)別
- http://www.cnblogs.com/caoxiaojian/p/5715568.html Memcache介紹與應用場景
- http://yw666.blog.51cto.com/11977292/1910163?utm_source=tuicool&utm_medium=referral memcache緩存服務器
- http://www.cnblogs.com/crazyacking/p/5793239.html 走進緩存的世界
- http://www.imooc.com/learn/527 近距離探索memcache緩存






