您好,登錄后才能下訂單哦!
博主QQ:819594300
博客地址:http://zpf666.blog.51cto.com/
有什么疑問的朋友可以聯(lián)系博主,博主會(huì)幫你們解答,謝謝支持!
一、MemCache簡(jiǎn)述
session
MemCache是一個(gè)自由、源碼開放、高性能、分布式的分布式內(nèi)存對(duì)象緩存系統(tǒng),用于動(dòng)態(tài)Web應(yīng)用以減輕數(shù)據(jù)庫(kù)的負(fù)載。它通過在內(nèi)存中緩存數(shù)據(jù)和對(duì)象來減少讀取數(shù)據(jù)庫(kù)的次數(shù),從而提高了網(wǎng)站訪問的速度。 MemCaChe是一個(gè)存儲(chǔ)鍵值對(duì)的HashMap,在內(nèi)存中對(duì)任意的數(shù)據(jù)(比如字符串、對(duì)象等)所使用的key-value存儲(chǔ),數(shù)據(jù)可以來自數(shù)據(jù)庫(kù)調(diào)用、API調(diào)用,或者頁(yè)面渲染的結(jié)果。MemCache設(shè)計(jì)理念就是小而強(qiáng)大,它簡(jiǎn)單的設(shè)計(jì)促進(jìn)了快速部署、易于開發(fā)并解決面對(duì)大規(guī)模的數(shù)據(jù)緩存的許多難題,而所開放的API使得MemCache能用于Java、C/C++/C#、Perl、Python、PHP、Ruby等大部分流行的程序語(yǔ)言。
另外,說一下為什么會(huì)有Memcache和memcached兩種名稱?其實(shí)Memcache是這個(gè)項(xiàng)目的名稱,而memcached是它服務(wù)器端的主程序文件名
MemCache的官方網(wǎng)站為http://memcached.org/
MemCache訪問模型
為了加深對(duì)memcache的理解,以memcache為代表的分布式緩存,訪問模型如下:
特別澄清一個(gè)問題,MemCache雖然被稱為”分布式緩存”,但是MemCache本身完全不具備分布式的功能,MemCache集群之間不會(huì)相互通信(與之形成對(duì)比的,比如JBoss Cache,某臺(tái)服務(wù)器有緩存數(shù)據(jù)更新時(shí),會(huì)通知集群中其他機(jī)器更新緩存或清除緩存數(shù)據(jù)),所謂的”分布式”,完全依賴于客戶端程序的實(shí)現(xiàn),就像上面這張圖的流程一樣。
同時(shí)基于這張圖,理一下MemCache一次寫緩存的流程:
1、應(yīng)用程序輸入需要寫緩存的數(shù)據(jù)
2、API將Key輸入路由算法模塊,路由算法根據(jù)Key和MemCache集群服務(wù)器列表得到一臺(tái)服務(wù)器編號(hào)
3、由服務(wù)器編號(hào)得到MemCache及其的ip地址和端口號(hào)
4、API調(diào)用通信模塊和指定編號(hào)的服務(wù)器通信,將數(shù)據(jù)寫入該服務(wù)器,完成一次分布式緩存的寫操作
讀緩存和寫緩存一樣,只要使用相同的路由算法和服務(wù)器列表,只要應(yīng)用程序查詢的是相同的Key,MemCache客戶端總是訪問相同的客戶端去讀取數(shù)據(jù),只要服務(wù)器中還緩存著該數(shù)據(jù),就能保證緩存命中。
這種MemCache集群的方式也是從分區(qū)容錯(cuò)性的方面考慮的,假如Node2宕機(jī)了,那么Node2上面存儲(chǔ)的數(shù)據(jù)都不可用了,此時(shí)由于集群中Node0和Node1還存在,下一次請(qǐng)求Node2中存儲(chǔ)的Key值的時(shí)候,肯定是沒有命中的,這時(shí)先從數(shù)據(jù)庫(kù)中拿到要緩存的數(shù)據(jù),然后路由算法模塊根據(jù)Key值在Node0和Node1中選取一個(gè)節(jié)點(diǎn),把對(duì)應(yīng)的數(shù)據(jù)放進(jìn)去,這樣下一次就又可以走緩存了,這種集群的做法很好,但是缺點(diǎn)是成本比較大。
一致性Hash算法
從上面的圖中,可以看出一個(gè)很重要的問題,就是對(duì)服務(wù)器集群的管理,路由算法至關(guān)重要,就和負(fù)載均衡算法一樣,路由算法決定著究竟該訪問集群中的哪臺(tái)服務(wù)器,先看一個(gè)簡(jiǎn)單的路由算法。
1、余數(shù)Hash
簡(jiǎn)單的路由算法可以使用余數(shù)Hash:用服務(wù)器數(shù)目和緩存數(shù)據(jù)KEY的hash值相除,余數(shù)為服務(wù)器列表下標(biāo)編號(hào),假如某個(gè)str對(duì)應(yīng)的HashCode是52、服務(wù)器的數(shù)目是3,取余數(shù)得到1,str對(duì)應(yīng)節(jié)點(diǎn)Node1,所以路由算法把str路由到Node1服務(wù)器上。由于HashCode隨機(jī)性比較強(qiáng),所以使用余數(shù)Hash路由算法就可以保證緩存數(shù)據(jù)在整個(gè)MemCache服務(wù)器集群中有比較均衡的分布。
如果不考慮服務(wù)器集群的伸縮性,那么余數(shù)Hash算法幾乎可以滿足絕大多數(shù)的緩存路由需求,但是當(dāng)分布式緩存集群需要擴(kuò)容的時(shí)候,就難辦了。
就假設(shè)MemCache服務(wù)器集群由3臺(tái)變?yōu)?臺(tái)吧,更改服務(wù)器列表,仍然使用余數(shù)Hash,52對(duì)4的余數(shù)是0,對(duì)應(yīng)Node0,但是str原來是存在Node1上的,這就導(dǎo)致了緩存沒有命中。再舉個(gè)例子,原來有HashCode為0~19的20個(gè)數(shù)據(jù),那么:
那么不妨舉個(gè)例子,原來有HashCode為0~19的20個(gè)數(shù)據(jù),那么:
現(xiàn)在擴(kuò)容到4臺(tái),加粗標(biāo)紅的表示命中:
如果擴(kuò)容到20+的臺(tái)數(shù),只有前三個(gè)HashCode對(duì)應(yīng)的Key是命中的,也就是15%。當(dāng)然現(xiàn)實(shí)情況肯定比這個(gè)復(fù)雜得多,不過足以說明,使用余數(shù)Hash的路由算法,在擴(kuò)容的時(shí)候會(huì)造成大量的數(shù)據(jù)無法正確命中(其實(shí)不僅僅是無法命中,那些大量的無法命中的數(shù)據(jù)還在原緩存中在被移除前占據(jù)著內(nèi)存)。在網(wǎng)站業(yè)務(wù)中,大部分的業(yè)務(wù)數(shù)據(jù)度操作請(qǐng)求上事實(shí)上是通過緩存獲取的,只有少量讀操作會(huì)訪問數(shù)據(jù)庫(kù),因此數(shù)據(jù)庫(kù)的負(fù)載能力是以有緩存為前提而設(shè)計(jì)的。當(dāng)大部分被緩存了的數(shù)據(jù)因?yàn)榉?wù)器擴(kuò)容而不能正確讀取時(shí),這些數(shù)據(jù)訪問的壓力就落在了數(shù)據(jù)庫(kù)的身上,這將大大超過數(shù)據(jù)庫(kù)的負(fù)載能力,嚴(yán)重的可能會(huì)導(dǎo)致數(shù)據(jù)庫(kù)宕機(jī)。
這個(gè)問題有解決方案,解決步驟為:
(1)在網(wǎng)站訪問量低谷,通常是深夜,技術(shù)團(tuán)隊(duì)加班,擴(kuò)容、重啟服務(wù)器
(2)通過模擬請(qǐng)求的方式逐漸預(yù)熱緩存,使緩存服務(wù)器中的數(shù)據(jù)重新分布
2、一致性Hash算法
一致性Hash算法通過一個(gè)叫做一致性Hash環(huán)的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)Key到緩存服務(wù)器的Hash映射。簡(jiǎn)單地說,一致性哈希將整個(gè)哈希值空間組織成一個(gè)虛擬的圓環(huán)(這個(gè)環(huán)被稱為一致性Hash環(huán)),如假設(shè)某空間哈希函數(shù)H的值空間是0~2^32-1(即哈希值是一個(gè)32位無符號(hào)×××),整個(gè)哈??臻g如下:
下一步將各個(gè)服務(wù)器使用H進(jìn)行一個(gè)哈希計(jì)算,具體可以使用服務(wù)器的IP地址或者主機(jī)名作為關(guān)鍵字,這樣每臺(tái)機(jī)器能確定其在上面的哈希環(huán)上的位置了,并且是按照順時(shí)針排列,這里我們假設(shè)三臺(tái)節(jié)點(diǎn)memcache經(jīng)計(jì)算后位置如下:
接下來使用相同算法計(jì)算出數(shù)據(jù)的哈希值h,并由此確定數(shù)據(jù)在此哈希環(huán)上的位置
假如我們有數(shù)據(jù)A、B、C、D、4個(gè)對(duì)象,經(jīng)過哈希計(jì)算后位置如下:
根據(jù)一致性哈希算法,數(shù)據(jù)A就被綁定到了server01上,D被綁定到了server02上,B、C在server03上,是按照順時(shí)針找最近服務(wù)節(jié)點(diǎn)方法
這樣得到的哈希環(huán)調(diào)度方法,有很高的容錯(cuò)性和可擴(kuò)展性:
假設(shè)server03宕機(jī):
可以看到此時(shí)C、B會(huì)受到影響,將B、C被重定位到Server01。一般的,在一致性哈希算法中,如果一臺(tái)服務(wù)器不可用,則受影響的數(shù)據(jù)僅僅是此服務(wù)器到其環(huán)空間中前一臺(tái)服務(wù)器(即順著逆時(shí)針方向行走遇到的第一臺(tái)服務(wù)器)之間數(shù)據(jù),其它不會(huì)受到影響。
考慮另外一種情況,如果我們?cè)谙到y(tǒng)中增加一臺(tái)服務(wù)器Memcached Server 04:
此時(shí)A、D、C不受影響,只有B需要重定位到新的Server04。一般的,在一致性哈希算法中,如果增加一臺(tái)服務(wù)器,則受影響的數(shù)據(jù)僅僅是新服務(wù)器到其環(huán)空間中前一臺(tái)服務(wù)器(即順著逆時(shí)針方向行走遇到的第一臺(tái)服務(wù)器)之間數(shù)據(jù),其它不會(huì)受到影響。
綜上所述,一致性哈希算法對(duì)于節(jié)點(diǎn)的增減都只需重定位環(huán)空間中的一小部分?jǐn)?shù)據(jù),具有較好的容錯(cuò)性和可擴(kuò)展性。
一致性哈希的缺點(diǎn):在服務(wù)節(jié)點(diǎn)太少時(shí),容易因?yàn)楣?jié)點(diǎn)分部不均勻而造成數(shù)據(jù)傾斜問題。我們可以采用增加虛擬節(jié)點(diǎn)的方式解決。
更重要的是,集群中緩存服務(wù)器節(jié)點(diǎn)越多,增加/減少節(jié)點(diǎn)帶來的影響越小,很好理解。換句話說,隨著集群規(guī)模的增大,繼續(xù)命中原有緩存數(shù)據(jù)的概率會(huì)越來越大,雖然仍然有小部分?jǐn)?shù)據(jù)緩存在服務(wù)器中不能被讀到,但是這個(gè)比例足夠小,即使訪問數(shù)據(jù)庫(kù),也不會(huì)對(duì)數(shù)據(jù)庫(kù)造成致命的負(fù)載壓力。
MemCache實(shí)現(xiàn)原理
首先要說明一點(diǎn),MemCache的數(shù)據(jù)存放在內(nèi)存中
1、訪問數(shù)據(jù)的速度比傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)要快,因?yàn)镺racle、MySQL這些傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)為了保持?jǐn)?shù)據(jù)的持久性,數(shù)據(jù)存放在硬盤中,IO操作速度慢
2、MemCache的數(shù)據(jù)存放在內(nèi)存中同時(shí)意味著只要MemCache重啟了,數(shù)據(jù)就會(huì)消失
3、既然MemCache的數(shù)據(jù)存放在內(nèi)存中,那么勢(shì)必受到機(jī)器位數(shù)的限制,32位機(jī)器最多只能使用2GB的內(nèi)存空間,64位機(jī)器可以認(rèn)為沒有上限
然后我們來看一下MemCache的原理,MemCache最重要的是內(nèi)存如何分配的,MemCache采用的內(nèi)存分配方式是固定空間分配,如下圖所示:
這張圖片里面涉及了slab_class、slab、page、chunk四個(gè)概念,它們之間的關(guān)系是:
1、MemCache將內(nèi)存空間分為一組slab
2、每個(gè)slab下又有若干個(gè)page,每個(gè)page默認(rèn)是1M,如果一個(gè)slab占用100M內(nèi)存的話,那么這個(gè)slab下應(yīng)該有100個(gè)page
3、每個(gè)page里面包含一組chunk,chunk是真正存放數(shù)據(jù)的地方,同一個(gè)slab里面的chunk的大小是固定的
4、有相同大小chunk的slab被組織在一起,稱為slab_class
MemCache內(nèi)存分配的方式稱為allocator(分配運(yùn)算),slab的數(shù)量是有限的,幾個(gè)、十幾個(gè)或者幾十個(gè),這個(gè)和啟動(dòng)參數(shù)的配置相關(guān)。
MemCache中的value存放的地方是由value的大小決定的,value總是會(huì)被存放到與chunk大小最接近的一個(gè)slab中,比如slab[1]的chunk大小為80字節(jié)、slab[2]的chunk大小為100字節(jié)、slab[3]的chunk大小為125字節(jié)(相鄰slab內(nèi)的chunk基本以1.25為比例進(jìn)行增長(zhǎng),MemCache啟動(dòng)時(shí)可以用-f指定這個(gè)比例),那么過來一個(gè)88字節(jié)的value,這個(gè)value將被放到2號(hào)slab中。放slab的時(shí)候,首先slab要申請(qǐng)內(nèi)存,申請(qǐng)內(nèi)存是以page為單位的,所以在放入第一個(gè)數(shù)據(jù)的時(shí)候,無論大小為多少,都會(huì)有1M大小的page被分配給該slab。申請(qǐng)到page后,slab會(huì)將這個(gè)page的內(nèi)存按chunk的大小進(jìn)行切分,這樣就變成了一個(gè)chunk數(shù)組,最后從這個(gè)chunk數(shù)組中選擇一個(gè)用于存儲(chǔ)數(shù)據(jù)。
如果這個(gè)slab中沒有chunk可以分配了怎么辦,如果MemCache啟動(dòng)沒有追加-M(禁止LRU,這種情況下內(nèi)存不夠會(huì)報(bào)Out Of Memory錯(cuò)誤),那么MemCache會(huì)把這個(gè)slab中最近最少使用的chunk中的數(shù)據(jù)清理掉,然后放上最新的數(shù)據(jù)。
Memcache的工作流程:
1、檢查客戶端的請(qǐng)求數(shù)據(jù)是否在memcached中,如果有,直接把請(qǐng)求數(shù)據(jù)返回,不再對(duì)數(shù)據(jù)庫(kù)進(jìn)行任何操作,路徑操作為①②③⑦。
2、如果請(qǐng)求的數(shù)據(jù)不在memcached中,就去查數(shù)據(jù)庫(kù),把從數(shù)據(jù)庫(kù)中獲取的數(shù)據(jù)返回給客戶端,同時(shí)把數(shù)據(jù)緩存一份到memcached中(memcached客戶端不負(fù)責(zé),需要程序明確實(shí)現(xiàn)),路徑操作為①②④⑤⑦⑥。
3、每次更新數(shù)據(jù)庫(kù)的同時(shí)更新memcached中的數(shù)據(jù),保證一致性。
4、當(dāng)分配給memcached內(nèi)存空間用完之后,會(huì)使用LRU(Least Recently Used,最近最少使用)策略加上到期失效策略,失效數(shù)據(jù)首先被替換,然后再替換掉最近未使用的數(shù)據(jù)。
Memcached特征:
協(xié)議簡(jiǎn)單:
它是基于文本行的協(xié)議,直接通過telnet在memcached服務(wù)器上可進(jìn)行存取數(shù)據(jù)操作
注:文本行的協(xié)議:指的是信息以文本傳送,一個(gè)信息單元傳遞完畢后要傳送換行。比如對(duì)于HTTP的GET請(qǐng)求來說,GET/index.html HTTP/1.1是一行,接下去每個(gè)頭部信息各占一行。一個(gè)空行表示整個(gè)請(qǐng)求結(jié)束
基于libevent事件處理:
Libevent是一套利用C開發(fā)的程序庫(kù),它將BSD系統(tǒng)的kqueue,Linux系統(tǒng)的epoll等事件處理功能封裝成一個(gè)接口,與傳統(tǒng)的select相比,提高了性能。
內(nèi)置的內(nèi)存管理方式:
所有數(shù)據(jù)都保存在內(nèi)存中,存取數(shù)據(jù)比硬盤快,當(dāng)內(nèi)存滿后,通過LRU算法自動(dòng)刪除不使用的緩存,但沒有考慮數(shù)據(jù)的容災(zāi)問題,重啟服務(wù),所有數(shù)據(jù)會(huì)丟失。
分布式
各個(gè)memcached服務(wù)器之間互不通信,各自獨(dú)立存取數(shù)據(jù),不共享任何信息。服務(wù)器并不具有分布式功能,分布式部署取決于memcache客戶端。
Memcache的安裝
分為兩個(gè)過程:memcache服務(wù)器端的安裝和memcached客戶端的安裝。
所謂服務(wù)器端的安裝就是在服務(wù)器(一般都是linux系統(tǒng))上安裝Memcache實(shí)現(xiàn)數(shù)據(jù)的存儲(chǔ)。
所謂客戶端的安裝就是指php(或者其他程序,Memcache還有其他不錯(cuò)的api接口提供)去使用服務(wù)器端的Memcache提供的數(shù)據(jù),需要php添加擴(kuò)展。
PHP的Memcache
二、centos7.2+nginx+php+memcache+mysql
環(huán)境描述:
nginx和php:
所需軟件:nginx-1.10.2.tar.gz
php-5.6.27.tar.gz
ip地址:192.168.1.8
mysql:
所需軟件:mysql-5.7.13.tar.gz
ip地址:192.168.1.9
memcache:
所需軟件:memcached-1.4.33.tar.gz
ip地址:192.168.1.10
虛擬機(jī)環(huán)境如下:
下面開始正式的實(shí)驗(yàn)操作:
1)安裝nginx
①解壓縮zlib
注意:不需要編譯,只需要解壓就行。
②解壓縮pcre
注意:不需要編譯,只需要解壓就行。
③yum安裝nginx依賴包
④下載安裝nginx源碼包
下載nginx的源碼包:http://nginx.org/download
解壓縮、編譯及安裝nginx源碼包:
圖中配置、編譯安裝部分如下所示:
./configure--prefix=/usr/local/nginx1.10 --with-http_dav_module--with-http_stub_status_module --with-http_addition_module--with-http_sub_module --with-http_flv_module --with-http_mp4_module--with-pcre=/root/pcre-8.39 --with-zlib=/root/zlib-1.2.8 --with-http_ssl_module--with-http_gzip_static_module --user=www --group=www && make&& make install
說明:--with-pcre:用來設(shè)置pcre的源碼目錄。
--with-zlib:用來設(shè)置zlib的源碼目錄。
因?yàn)榫幾gnginx需要用到這兩個(gè)庫(kù)的源碼。
⑤做軟鏈接
⑥nginx配置文件語(yǔ)法檢測(cè)
⑦啟動(dòng)nginx
⑧防火墻開啟80端口例外
⑨在一臺(tái)客戶機(jī)瀏覽器上瀏覽nginx網(wǎng)頁(yè),測(cè)試一下nginx
2)安裝php
①安裝libmcrypt
②yum安裝php依賴包
③解壓縮、編譯及安裝php源碼包
圖中配置、編譯安裝部分如下所示:
./configure--prefix=/usr/local/php5.6 --with-mysql=mysqlnd --with-pdo-mysql=mysqlnd--with-mysqli=mysqlnd --with-openssl --enable-fpm --enable-sockets--enable-sysvshm --enable-mbstring --with-freetype-dir --with-jpeg-dir--with-png-dir --with-zlib --with-libxml-dir=/usr --enable-xml --with-mhash--with-mcrypt=/usr/local/libmcrypt --with-config-file-path=/etc--with-config-file-scan-dir=/etc/php.d --with-bz2 --enable-maintainer-zts&& make && make install
④拷貝php.ini樣例文件
修改/etc/php.ini文件,將short_open_tag修改為on,修改后的內(nèi)容如下:
//支持php短標(biāo)簽
⑤創(chuàng)建php-fpm服務(wù)啟動(dòng)腳本并啟動(dòng)服務(wù)
提供php-fpm配置文件并編輯:
說明:如果是nginx和php分離部署,這里需要改成php真實(shí)的ip,然后php服務(wù)器還要開始9000端口例外。除此之外都和本博文一樣即可。
啟動(dòng)php-fpm服務(wù):
3)安裝mysql
(在192.168.1.9主機(jī)上操作)
因?yàn)閏entos7.2默認(rèn)安裝了mariadb-libs,所以先要卸載掉
查看是否安裝mariadb
#rpm-qa | grep mariadb
卸載mariadb
rpm-e --nodeps mariadb-libs
然后具體的mysql安裝請(qǐng)參考我的mysql5.7.13的安裝,博文地址:
http://zpf666.blog.51cto.com/11248677/1908988
這里我的mysql是安裝好的,我們看一下服務(wù)是否啟動(dòng):
防火墻開啟3306端口例外:
4、安裝memcached服務(wù)端
(在192.168.1.10主機(jī)操作)
memcached是基于libevent的事件處理。libevent是個(gè)程序庫(kù),它將Linux的epoll、BSD類操作系統(tǒng)的kqueue等事件處理功能封裝成統(tǒng)一的接口。即使對(duì)服務(wù)器的連接數(shù)增加,也能發(fā)揮I/O的性能。 memcached使用這個(gè)libevent庫(kù),因此能在Linux、BSD、Solaris等操作系統(tǒng)上發(fā)揮其高性能。
①安裝memcached依賴庫(kù)libevent
②安裝memcached
③檢測(cè)memcache是否安裝成功
通過以上操作就很簡(jiǎn)單的把memcached服務(wù)端編譯好了。這時(shí)候就可以打開服務(wù)端進(jìn)行工作了。
④配置環(huán)境變量
進(jìn)入用戶宿主目錄,編輯.bash_profile,為系統(tǒng)環(huán)境變量LD_LIBRARY_PATH增加新的目錄,需要增加的內(nèi)容如下:
圖片中具體內(nèi)容如下:
MEMCACHED_HOME=/usr/local/memcached
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MEMCACHED_HOME/lib
⑤啟動(dòng)memcache服務(wù)
注意:-m后面跟的是分配給memcache的內(nèi)存,不能大于等于本主機(jī)內(nèi)存。我的主機(jī)是2048M內(nèi)存,我給了1024M。
啟動(dòng)參數(shù)說明:
-d 選項(xiàng)是啟動(dòng)一個(gè)守護(hù)進(jìn)程。
-m 分配給Memcache使用的內(nèi)存數(shù)量,單位是MB,默認(rèn)64MB。
-l 監(jiān)聽的IP地址。(默認(rèn):INADDR_ANY,所有地址)
-p 設(shè)置Memcache的TCP監(jiān)聽的端口,最好是1024以上的端口。
-u 運(yùn)行Memcache的用戶,如果當(dāng)前為root的話,需要使用此參數(shù)指定用戶。
-c 選項(xiàng)是最大運(yùn)行的并發(fā)連接數(shù),默認(rèn)是1024。
-P 設(shè)置保存Memcache的pid文件。
-M 內(nèi)存耗盡時(shí)返回錯(cuò)誤,而不是刪除項(xiàng)
-f 塊大小增長(zhǎng)因子,默認(rèn)是1.25
-n 最小分配空間,key+value+flags默認(rèn)是48
-h 顯示幫助
⑥防火墻開啟11211端口例外
⑦刷新用戶環(huán)境變量
刷新環(huán)境變量的時(shí)候報(bào)了一個(gè)錯(cuò)誤,讓執(zhí)行那條命令,你就執(zhí)行以下即可。
然后再次刷新環(huán)境變量:
⑧編寫memcached服務(wù)啟停腳本
腳本內(nèi)容如下:
#!/bin/sh
#
# pidfile:/usr/local/memcached/memcached.pid
# memcached_home: /usr/local/memcached
# chkconfig: 35 21 79
# description: Start and stop memcachedService
# Source function library
. /etc/rc.d/init.d/functions
RETVAL=0
prog="memcached"
basedir=/usr/local/memcached
cmd=${basedir}/bin/memcached
pidfile="$basedir/${prog}.pid"
#interface to listen on (default:INADDR_ANY, all addresses)
ipaddr="192.168.1.10"
#listen port
port=11211
#username for memcached
username="root"
#max memory for memcached,default is 64M
max_memory=1024
#max connections for memcached
max_simul_conn=10240
start() {
echo -n $"Starting service:$prog"
$cmd -d -m $max_memory -u $username -l$ipaddr -p $port -c $max_simul_conn -P $pidfile
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch/var/lock/subsys/$prog
}
stop() {
echo -n $"Stopping service:$prog "
run_user=$(whoami)
pidlist=$(ps -ef | grep $run_user | grepmemcached | grep -v grep | awk '{print($2)}')
for pid in $pidlist
do
kill -9 $pid
if [ $? -ne 0 ]; then
return 1
fi
done
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f/var/lock/subsys/$prog
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage: $0{start|stop|restart|status}"
exit 1
esac
exit $RETVAL
設(shè)置腳本可被執(zhí)行:
說明:
shell腳本中return的作用
1)終止一個(gè)函數(shù).
2)return命令允許帶一個(gè)整型參數(shù), 這個(gè)整數(shù)將作為函數(shù)的"退出狀態(tài)
碼"返回給調(diào)用這個(gè)函數(shù)的腳本, 并且這個(gè)整數(shù)也被賦值給變量$?.
3)命令格式:returnvalue
先別急著閃,memcache服務(wù)腳本是配置好了,但是有個(gè)問題:
從上圖可以看出,重啟不了memcache,這是因?yàn)楫?dāng)前memcache服務(wù)是運(yùn)行著的,這個(gè)服務(wù)是開始的時(shí)候第⑤步啟動(dòng)的,所以咱們現(xiàn)在用服務(wù)腳本是重啟不了的,解決辦法如下:
就是殺死正在運(yùn)行的memcache服務(wù)的進(jìn)程。
然后開始再重啟服務(wù):
至此就可以用服務(wù)腳本控制memcache服務(wù)了。
5、配置nginx.conf文件(在nginx&&php主機(jī)上操作)
①配置成如下的nginx.conf文件
把原有的東西全部刪除,配置成如下內(nèi)容:
說明一下:我這里nginx&&php主機(jī)用的是4核,如果你的不是4核,請(qǐng)修改worker_cpu_affinity,如果是4核,請(qǐng)忽略該問題,全部復(fù)制我寫好的內(nèi)容即可。
user www www;
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
pid logs/nginx.pid;
events {
use epoll;
worker_connections 65535;
multi_accept on;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local]"$request" '
# '$status$body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
tcp_nodelay on;
client_header_buffer_size 4k;
open_file_cache max=102400 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 1;
client_header_timeout 15;
client_body_timeout 15;
reset_timedout_connection on;
send_timeout 15;
server_tokens off;
client_max_body_size 10m;
fastcgi_connect_timeout 600;
fastcgi_send_timeout 600;
fastcgi_read_timeout 600;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;
fastcgi_temp_path /usr/local/nginx1.10/nginx_tmp;
fastcgi_intercept_errors on;
fastcgi_cache_path /usr/local/nginx1.10/fastcgi_cache levels=1:2keys_zone=cache_fastcgi:128m inactive=1d max_size=10g;
gzip on;
gzip_min_length 2k;
gzip_buffers 4 32k;
gzip_http_version 1.1;
gzip_comp_level 6;
gzip_types text/plain text/csstext/javascript application/json application/javascriptapplication/x-javascript application/xml;
gzip_vary on;
gzip_proxied any;
server {
listen 80;
server_name www.benet.com;
#charset koi8-r;
#access_log logs/host.access.log main;
location ~*^.+\.(jpg|gif|png|swf|flv|wma|wmv|asf|mp3|mmf|zip|rar)$ {
valid_referers none blocked www.benet.com benet.com;
if ($invalid_referer) {
#return 302 http://www.benet.com/img/nolink.jpg;
return 404;
break;
}
access_log off;
}
location / {
root html;
index index.php index.html index.htm;
}
location ~*\.(ico|jpe?g|gif|png|bmp|swf|flv)$ {
expires 30d;
#log_not_found off;
access_log off;
}
location ~* \.(js|css)$ {
expires 7d;
log_not_found off;
access_log off;
}
location = /(favicon.ico|roboots.txt) {
access_log off;
log_not_found off;
}
location /status {
stub_status on;
}
location ~ .*\.(php|php5)?$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_cache cache_fastcgi;
fastcgi_cache_valid 200 302 1h;
fastcgi_cache_valid 301 1d;
fastcgi_cache_valid any 1m;
fastcgi_cache_min_uses 1;
fastcgi_cache_use_stale error timeoutinvalid_header http_500;
fastcgi_cache_keyhttp://$host$request_uri;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
②重啟nginx服務(wù)
③編寫一個(gè)php測(cè)試頁(yè)
④在客戶端使用瀏覽器訪問test1.php測(cè)試頁(yè)
6、memcache客戶端(在nginx&&php主機(jī)上操作)
說明:memcache分為服務(wù)端和客戶端。服務(wù)端用來存放緩存,客戶端用來操作緩存。
安裝php擴(kuò)展庫(kù)(phpmemcache)
說明:安裝PHP Memcache擴(kuò)展:
可以使用php自帶的pecl安裝程序
#/usr/local/php5.6/bin/pecl install memcache
也可以從源碼安裝,他是生成php的擴(kuò)展庫(kù)文件memcache.so。
①安裝memcache擴(kuò)展庫(kù)
圖片中內(nèi)容如下:
./configure--enable-memcache --with-php-config=/usr/local/php5.6/bin/php-config &&make && make install
記住安裝完畢后,最后一行你的這個(gè)路徑。
/usr/local/php5.6/lib/php/extensions/no-debug-zts-20131226/
②修改php.ini
添加如下一行內(nèi)容:
圖片中內(nèi)容如下:
extension=/usr/local/php5.6/lib/php/extensions/no-debug-zts-20131226/memcache.so
③重啟php-fpm服務(wù)
④測(cè)試
說明:檢查php擴(kuò)展是否正確安裝。
主要是看查詢結(jié)果中是否有memcache項(xiàng)。
⑤在客戶機(jī)瀏覽器上再次訪問test1.php
則看到不到memcache和在session會(huì)話里面看不到memcache。
這是因?yàn)?,nginx配置文件里配置了fast-cgi緩存,如果不注釋點(diǎn)這一行,客戶端訪問的test1.php的數(shù)據(jù),是fast-cgi緩存的,因?yàn)橛芯彺妫琺emcache就起不到作用了。
解決辦法如下:
再次刷新test1.php頁(yè)面,就可以看見如下的兩個(gè)截圖:
⑥編寫test2.php測(cè)試頁(yè)
說明:這個(gè)測(cè)試頁(yè)測(cè)試的是往memcache服務(wù)器寫/讀數(shù)據(jù)測(cè)試
具體內(nèi)容如下:
<?php
$memcache = new Memcache;
$memcache->connect('192.168.1.10',11211) or die ("Could not connect");
$version = $memcache->getVersion();
echo "Server's version:".$version."<br/>";
$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 (datawill expire in 10 seconds)<br/>";
$get_result = $memcache->get('key');
echo "Data from thecache:<br/>";
var_dump($get_result);
?>
在客戶機(jī)上訪問test2.php
⑦使用memcache實(shí)現(xiàn)session共享
配置php.ini中的Session為memcache方式。
說明:1394行是修改
1424行是添加
兩行的文字內(nèi)容如下:
session.save_handler = memcache
session.save_path = "tcp://192.168.1.10:11211?persistent=1&weight=1&timeout=1&retry_interval=15"
注:
ession.save_handler:設(shè)置session的儲(chǔ)存方式為memcache 。默認(rèn)以文件方式存取session數(shù)據(jù),如果想要使用自定義的處理來存取session數(shù)據(jù),比如memcache方式則修為session.save_handler = memcache
session.save_path:設(shè)置session儲(chǔ)存的位置,多臺(tái)memcache用逗號(hào)隔開
使用多個(gè) memcached server 時(shí)用逗號(hào)”,”隔開,可以帶額外的參數(shù)”persistent”、”weight”、”timeout”、”retry_interval”等等,
類似這樣的:
"tcp://host:port?persistent=1&weight=2,tcp://host2:port2"。
memcache實(shí)現(xiàn)session共享也可以在某個(gè)一個(gè)應(yīng)用中設(shè)置:
ini_set("session.save_handler","memcache");
ini_set("session.save_path","tcp://192.168.0.9:11211");
ini_set()只對(duì)當(dāng)前php頁(yè)面有效,并且不會(huì)去修改php.ini文件本身,也不會(huì)影響其他php頁(yè)面。
⑧測(cè)試memcache可用性
重啟php-fpm:
在nginx&&php
服務(wù)器上新建//usr/local/nginx1.10/html/memcache.php文件。內(nèi)容如下:
<?php
session_start();
if (!isset($_SESSION['session_time']))
{
$_SESSION['session_time'] = time();
}
echo "session_time:".$_SESSION['session_time']."<br/>";
echo"now_time:".time()."<br />";
echo"session_id:".session_id()."<br />";
?>
這個(gè)memcache.php的測(cè)試頁(yè)面主要測(cè)試的是:
當(dāng)客戶機(jī)訪問時(shí),給客戶機(jī)生成一個(gè)session信息,這個(gè)session就是記錄在什么時(shí)間點(diǎn)緩存到memcache的數(shù)據(jù)。
刷新一下頁(yè)面,再看:
每刷一次頁(yè)面,now_time的值就一直在漲,而session_time一直不會(huì)變的,因?yàn)槭莝ession會(huì)話保持嘛。
訪問網(wǎng)址http://192.168.1.8/memcache.php可以查看session_time是否都是為memcache中的Session,同時(shí)可以在不同的服務(wù)器上修改不同的標(biāo)識(shí)查看是否為不同的服務(wù)器上的。
可以直接用sessionid 去 memcached 里查詢一下:
說明:得到session_time|i:1493893966;這樣的結(jié)果,說明session 正常工作。
默認(rèn)memcache會(huì)監(jiān)聽11221端口,如果想清空服務(wù)器上memecache的緩存,一般使用的是:
或者
說明:使用flush_all 后并不是刪除memcache上的key,而是置為過期。
memcache安全配置:
因?yàn)閙emcache不進(jìn)行權(quán)限控制,因此需要通過iptables將memcache僅開放個(gè)web服務(wù)器。
7、測(cè)試memcache緩存數(shù)據(jù)庫(kù)數(shù)據(jù)
①先在Mysql服務(wù)器上創(chuàng)建測(cè)試表
②編寫測(cè)試腳本
作用:用于測(cè)試memcache是否緩存數(shù)據(jù)成功。
先需要為這個(gè)腳本添加一個(gè)只讀的數(shù)據(jù)庫(kù)用戶,命令格式:
在web服務(wù)器上創(chuàng)建測(cè)試腳本內(nèi)容如下:
<?php
$memcachehost = '192.168.1.10';
$memcacheport =11211;
$memcachelife = 60;
$memcache = new Memcache;
$memcache->connect($memcachehost,$memcacheport)or die ("Could not connect");
$query="select * from test1 limit 10";
$key=md5($query);
if(!$memcache->get($key))
{
$conn=mysql_connect("192.168.1.9","user","123456");
mysql_select_db(testdb1);
$result=mysql_query($query);
while ($row=mysql_fetch_assoc($result))
{
$arr[]=$row;
}
$f = 'mysql';
$memcache->add($key,serialize($arr),0,30);
$data = $arr ;
}
else{
$f = 'memcache';
$data_mem=$memcache->get($key);
$data = unserialize($data_mem);
}
echo $f;
echo "<br>";
echo "$key";
echo "<br>";
//print_r($data);
foreach($data as $a)
{
echo "number is <b><fontcolor=#FF0000>$a[id]</font></b>";
echo "<br>";
echo "name is <b><font color=#FF0000>$a[name]</font></b>";
echo "<br>";
}
?>
③訪問頁(yè)面測(cè)試
說明:如果出現(xiàn)mysql表示memcached中沒有內(nèi)容,需要memcached從數(shù)據(jù)庫(kù)中取得
再刷新頁(yè)面,如果有memcache標(biāo)志表示這次的數(shù)據(jù)是從memcached中取得的。
memcached有個(gè)緩存時(shí)間默認(rèn)是1分鐘,過了一分鐘后,memcached需要重新從數(shù)據(jù)庫(kù)中取得數(shù)據(jù)。
④查看 Memcached 緩存情況
我們需要使用 telnet 命令查看。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。