您好,登錄后才能下訂單哦!
一、MemCache簡介
MemCache 是一個自由、源碼開放、高性能、分布式的分布式內存對象緩存系統,用于動態Web應用以減輕數據庫的負載。它通過在內存中緩存數據和對象來減少讀取數據庫的次數,從而提高了網站訪問的速度。 MemCaChe 是一個存儲鍵值對的 HashMap,在內存中對任意的數據(比如字符串、對象等)所使用的 key-value 存儲,數據可以來自數據庫調用、API調用,或者頁面渲染的結果。MemCache 設計理念就是小而強大,它簡單的設計促進了快速部署、易于開發并解決面對大規模的數據緩存的許多難題,而所開放的 API 使得 MemCache用于 Java、C/C++/C#、Perl、Python、PHP、Ruby 等大部分流行的程序語言。
另外,說一下為什么會有 Memcache 和 memcached 兩種名稱?其實 Memcache 是這個項目的名稱(也時它客戶端的名稱),而 memcached 是它服務器端的主程序文件名。
memcached是一個鍵/值系統,系統相對于MySQL簡單很多,雖然MySQL也有緩存,但是數據庫的SQL解析會耗費性能,查詢慢于memcached,另外MySQL的緩存設計得更加復雜,因為要考慮事務,日志,存儲引擎等模塊,它的性能也沒有memcached好。
memcached只做一件事情,簡單高效,在cache上比MySQL強,這應該容易理解。
1、協議
memcached的服務器客戶端通信并不使用復雜的XML等格式,而使用簡單的基于文本行的協議。
因此,通過telnet也能在memcached上保存數據、取得數據。
2、事件處理
libevent是個程序庫,它將Linux的epoll、BSD類操作系統的kqueue等事件處理功能封裝成統一的接口。即使對服務器的連接數增加,也能發揮O(1)的性能。memcached使用這個libevent庫,因此能在Linux、BSD、Solaris等操作系統上發揮其高性能。
3、存儲方式
為了提高性能,memcached中保存的數據都存儲在memcached內置的內存存儲空間中。由于數據僅存在于內存中,因此重啟memcached、重啟操作系統會導致全部數據消失。另外,內容容量達到指定值之后,就基于LRU(Least Recently Used)算法自動刪除不使用的緩存。memcached本身是為緩存而設計的服務器,因此并沒有過多考慮數據的永久性問題。
4、通信分布式
memcached盡管是“分布式”緩存服務器,但服務器端并沒有分布式功能。各個memcached不會互相通信以共享信息。那么,怎樣進行分布式呢?這完全取決于客戶端的實現。
5、memcached的應用場景
1)數據庫的前端緩存應用:讓它來分擔數據的并發壓力,當數據更新時,可以使程序通知緩存進行更新
2)session會話共享的共享存儲
6、memcached應用中的工作流程
它是一種內存緩存,可通過API的方式讀取內存中緩存的這些數據,當用戶需要讀取數據時,會首先訪問memcached緩存,如果緩存中有數據就直接返回給前端的應用程序,如果沒有,再轉發給后臺端的服務器,這時服務器除了返回數據給用戶,就會將數據更新給memcached緩存。
如果實際生產環境中,緩存服務器需要重啟(或者斷電),那么緩存中的數據將會丟失,那么這時替換的服務器并發壓力會擴大,可能會導致引入的服務器也跟著停機,無法提供服務,那么這時我們的處理流程是這樣的:
首先從負載均衡中將WEB應用停掉- - - >讓負載均衡不再轉發數據給WEB - - >接著啟動緩存服務器- - - - > 通過程序把數據庫的內容初始化到緩存服務器中- - - - >然后將網頁應用啟用- - - - >重啟數據庫服務器
7、memcached的一致性Hash算法
一致性 Hash 算法通過一個叫做一致性 Hash 環的數據結構實現 Key 到緩存服務器的 Hash 映射。簡單地說,一致性哈希將整個哈希值空間組織成一個虛擬的圓環(這個環被稱為一致性Hash 環),如假設某空間哈希函數 H 的值空間是 0~2^ 32 -1(即哈希值是一個 32 位無符號整型),整個哈希空間如下:
將各個服務器使用 H 進行一個哈希計算,具體可以使用服務器的 IP 地址或者主機名作為關鍵字,這樣每臺機器能確定其在上面的哈希環上的位置了,并且是按照順時針排列,這里我們假設三臺節點 memcache經計算后位置如下:
接下來使用相同算法計算出數據的哈希值 h,并由此確定數據在此哈希環上的位置。假如我們有數據 A、B、C、D、4 個對象,經過哈希計算后位置如下:
根據一致性哈希算法,數據 A 就被綁定到了 server01 上,D 被綁定到了 server02 上,B、C在 server03 上,是按照順時針找最近服務節點方法。
這樣得到的哈希環調度方法,有很高的容錯性和可擴展性:
假設 server03 宕機:
可以看到此時 C、B 會受到影響,將 B、C 節點被重定位到 Server01。一般的,在一致性哈希算法中,如果一臺服務器不可用,則受影響的數據僅僅是此服務器到其環空間中前一臺服務器(即順著逆時針方向行走遇到的第一臺服務器)之間數據,其它不會受到影響。
考慮另外一種情況,如果我們在系統中增加一臺服務器 Memcached Server 04:
此時 A、D、C 不受影響,只有 B 需要重定位到新的 Server04。一般的,在一致性哈希算法中,如果增加一臺服務器,則受影響的數據僅僅是新服務器到其環空間中前一臺服務器(即順著逆時針方向行走遇到的第一臺服務器)之間數據,其它不會受到影響。
綜上所述,一致性哈希算法對于節點的增減都只需重定位環空間中的一小部分數據,具有較好的容錯性和可擴展性。
一致性哈希的缺點:在服務節點太少時,容易因為節點分部不均勻而造成數據傾斜問題。我們可以采用增加虛擬節點的方式解決。
更重要的是,集群中緩存服務器節點越多,增加/減少節點帶來的影響越小,很好理解。換句話說,隨著集群規模的增大,繼續命中原有緩存數據的概率會越來越大,雖然仍然有小部分數據緩存在服務器中不能被讀到,但是這個比例足夠小,即使訪問數據庫,也不會對數據庫造成致命的負載壓力。
二、部署LNMP動靜分離&&memcache緩存服務器
環境如下:
所需源碼包可在此處下載并上傳至各服務器:https://pan.baidu.com/s/1-2pS702mz41e94nBXSgUnA
提取碼:rldk
1、部署Nginx服務
[root@nginx /]# yum -y install openssl-devel pcre-devel # 安裝所需依賴包
[root@nginx /]# mkdir nginx # 個人習慣而已
[root@nginx /]# cd nginx/
[root@nginx nginx]# rz # 使用的xshell連接的服務器,使用rz上傳所需的源碼包
[root@nginx nginx]# tar zxf nginx-1.14.0.tar.gz # 解壓到當前目錄
[root@nginx nginx]# cd nginx-1.14.0/
[root@nginx nginx-1.14.0]# useradd -M -s /sbin/nologin www # 創建Nginx運行用戶
[root@nginx nginx-1.14.0]# ./configure --prefix=/usr/local/nginx --user=www --group=www && make && make install # 編譯并安裝
[root@nginx nginx-1.14.0]# ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/ # 創建命令軟連接
[root@nginx nginx-1.14.0]# nginx # 啟動服務
[root@nginx nginx-1.14.0]# netstat -anput | grep 80 # 查看端口,確定服務已經啟動
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 6827/nginx: master
[root@nginx nginx-1.14.0]# cd /
[root@nginx /]# vim /usr/local/nginx/conf/nginx.conf
............................... // 省略部分內容
在server{} 字段中添加如下內容
location ~ \.php$ {
root /var/www/html; # 指定PHP的網頁存放路徑
fastcgi_pass 192.168.171.133:9000; # 指定PHP服務監聽端口及地址
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi.conf;
}
[root@nginx /]# nginx -s reload # 重啟服務使配置生效
2、部署PHP服務
#首先需要為PHP安裝依賴包
[root@php php]# yum -y install libxml2-devel openssl-devel bzip2-devel
[root@php php]# tar zxf libmcrypt-2.5.7
[root@php php]# cd libmcrypt-2.5.7/
[root@php libmcrypt-2.5.7]# ./configure --prefix=/usr/local/libmcrypt && make && make install
[root@php libmcrypt-2.5.7]# cd ..
[root@php php]# tar zxf php-5.6.27.tar.gz
[root@php php]# cd php-5.6.27/
[root@php php-5.6.27]# ./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的配置文件及控制服務的啟停
[root@php php-5.6.27]# cp php.ini-production /etc/php.ini #復制源碼中中提供的PHP配置文件
[root@php php-5.6.27]# cp sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
#復制其服務控制腳本文件
[root@php php-5.6.27]# chmod +x /etc/init.d/php-fpm #賦予執行權限
[root@php php-5.6.27]# chkconfig --add php-fpm #添加為系統服務,以便支持systemctl管理
[root@php php-5.6.27]# chkconfig php-fpm on #開啟
#復制php-fpm提供的默認配置文件并編輯它
[root@php php-5.6.27]# cp /usr/local/php5.6/etc/php-fpm.conf.default /usr/local/php5.6/etc/php-fpm.conf
[root@php php-5.6.27]# vim /usr/local/php5.6/etc/php-fpm.conf
listen = 192.168.171.133:9000 #監聽地址是本機的IP9000端口
pm.max_children = 50 #最大啟動的進程數
pm.start_servers = 5 #初始啟動進程數
pm.min_spare_servers = 5 #最小空閑進程
pm.max_spare_servers = 35 #最大空閑進程
#修改完成后,保存退出即可
[root@php /]# service php-fpm restart # 重啟PHP使配置生效
Gracefully shutting down php-fpm . done
Starting php-fpm done
[root@php /]# netstat -anput | grep 9000 # 查看是否運行
tcp 0 0 192.168.171.133:9000 0.0.0.0:* LISTEN 3054/php-fpm: maste
# 準備網頁測試文件
[root@php /]# mkdir -p /var/www/html
[root@php /]# cd /var/www/html/
[root@php html]# cat index.php
<?php
phpinfo();
?>
[root@php html]# cat index1.php
<?php
$link=mysqli_connect('192.168.171.135','zyz','pwd@123');
if($link) echo "恭喜你,數據庫連接成功!!!"; else echo "connect shibai";
mysqli_close($link);
?>
到這,即可訪問Nginx服務器的80端口來查看php服務器上定義的兩個網頁文件(在訪問連接數據庫的腳本文件時,需要先部署數據庫,并創建用來連接的用戶):
3、部署MySQL服務
# 這里部署一個簡單的數據庫即可
[root@mysql /]# mkdir -p mysql
[root@mysql /]# cd mysql/
[root@mysql mysql]# rz # 上傳所需
[root@mysql mysql]# sh mysql.sh # 直接sh執行腳本安裝即可,安裝完畢之后默認密碼是123
Starting MySQL.. SUCCESS!
mysql: [Warning] Using a password on the command line interface can be insecure.
[root@mysql mysql]# netstat -anput | grep 3306 # 確保服務已經啟動
tcp6 0 0 :::3306 :::* LISTEN 3290/mysqld
[root@mysql mysql]# mysql -u root -p # 登錄數據庫
Enter password:
mysql> create database bbs;
Query OK, 1 row affected (0.00 sec)
mysql> grant all on bbs.* to zyz@"192.168.171.%" identified by 'pwd@123';
Query OK, 0 rows affected, 1 warning (0.00 sec)
測試驗證:
4、部署Memcached服務
[root@memcached /]# mkdir memcached
[root@memcached /]# cd memcached/
[root@memcached memcached]# rz # 上傳所需源碼包
[root@memcached memcached]# tar zxf libevent-2.0.22-stable.tar.gz # 解包
[root@memcached memcached]# cd libevent-2.0.22-stable/
[root@memcached libevent-2.0.22-stable]# ./configure && make && make install # 編譯并安裝
[root@memcached libevent-2.0.22-stable]# cd ..
[root@memcached memcached]# tar zxf memcached-1.4.33.tar.gz
[root@memcached memcached]# cd memcached-1.4.33/
[root@memcached memcached-1.4.33]# ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local
/ && make && make install
[root@memcached memcached-1.4.33]# ln -s /usr/local/memcached/bin/memcached /usr/local/bin/ # 命令制作軟連接
[root@memcached memcached-1.4.33]# memcached -d -m 1024 -l 192.168.171.132 -p 11211 -c 10240 -P /usr/local/memcached/memcached.pid -u root
#啟動memcached服務,上述啟動參數說明如下:
# -d 選項是啟動一個守護進程。
# -m 分配給 Memcache 使用的內存數量,單位是 MB,默認 64MB。
# -l 監聽的 IP 地址。(默認:INADDR_ANY,所有地址)
# -p 設置 Memcache 的 TCP 監聽的端口,最好是 1024 以上的端口。
# -u 運行 Memcache 的用戶,如果當前為 root 的話,需要使用此參數指定用戶。
# -c 選項是最大運行的并發連接數,默認是 1024。
# -P 設置保存 Memcache 的 pid 文件路徑。
# -M 內存耗盡時返回錯誤,而不是刪除項
# -f 塊大小增長因子,默認是 1.25
# -n 最小分配空間,key+value+flags 默認是 48
# -h 顯示幫助
[root@memcached memcached-1.4.33]# netstat -anput | grep 11211 # 確定TCP及udp都在監聽
tcp 0 0 192.168.171.132:11211 0.0.0.0:* LISTEN 11666/memcached
udp 0 0 192.168.171.132:11211 0.0.0.0:* 11666/memcached
5、部署Memcache客戶端(返回PHP服務器操作)
[root@php /]# mkdir memcache
[root@php /]# cd memcache/
[root@php memcache]# rz # 上傳如下源碼包
[root@php memcache]# ls
memcache-3.0.8.tgz
[root@php memcache]# tar zxf memcache-3.0.8.tgz
[root@php memcache]# cd memcache-3.0.8/
[root@php memcache-3.0.8]# /usr/local/php5.6/bin/phpize # #執行該命令,以便生成configure文件
# 若在執行上述命令時報錯,則需要執行“yun -y install autoconf "安裝提示的autoconf包。
Configuring for: # 執行成功會顯示次此幾行
PHP Api Version: 20131106
Zend Module Api No: 20131226
Zend Extension Api No: 220131226
[root@php memcache-3.0.8]# ./configure --enable-memcache --with-php-config=/usr/local/php5.6/bin/php-config && make && make install # 編譯并安裝
# 執行完上述命令后,會顯示memcache.so存放的路徑
[root@php memcache-3.0.8]# vim /etc/php.ini # 編輯此文件
# 在最后一行添加如下內容,注意不要直接復制本人的路徑
extension = /usr/local/php5.6/lib/php/extensions/no-debug-non-zts-20131226/memcache.so
[root@php memcache-3.0.8]# service php-fpm restart # 重啟php使配置生效
Gracefully shutting down php-fpm . done
Starting php-fpm done
編寫測試文件:
[root@php memcache-3.0.8]# cd /var/www/html/
[root@php html]# vim test1.php
<?php
$memcache = new Memcache;
$memcache->connect('192.168.171.132', 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, 600) or die ("Failed to save data at the server");
echo "Store data in the cache (data will expire in 600 seconds)<br/>";
$get_result = $memcache->get('key');
echo "Data from the cache:<br/>";
var_dump($get_result);
?>
#編輯完成后,保存退出即可,此測試腳本是顯示memcached的版本
#并且向里面插入了一個緩存時間為600秒的鍵值對“test=123”,其ID為“key”
客戶端訪問編輯的test1.php文件,會看到以下內容:
在memcached服務器上安裝Telnet命令,并登陸緩存庫,查看是否可以得到其鍵值對
[root@memcached /]# yum -y install telnet # 安裝Telnet命令
[root@memcached /]# telnet 192.168.171.132 11211
Trying 192.168.171.132...
Connected to 192.168.171.132.
Escape character is '^]'.
get key # 查詢ID為“key”的鍵值對,可以看到我們測試腳本寫入的“test=123”
VALUE key 1 66
O:8:"stdClass":2:{s:8:"str_attr";s:4:"test";s:8:"int_attr";i:123;}
END
#在進行上面的get驗證時,需要將test1.php文件中插入的鍵值對的保存時間值改大一些
#或者重新訪問一下,以免緩存失效,查詢不到
至此,LNMP動靜分離&&memcache緩存服務器已經基本部署完成,接下來,配置PHP與memcached服務器溝通保存session會話
6、使用 memcache 實現 session 共享(在PHP服務器進行以下操作)
[root@php /]# vim /etc/php.ini
# 在末尾添加如下內容
session.save_handler = memcache
session.save_path = "tcp://192.168.171.132:11211?persistent=1&weight=1&timeout=1&retry_interval=15"
# 內容解釋如下:
# session.save_handler:設置 session 的儲存方式為 memcache 。
#默認以文件方式存取 session數據。
#session.save_path: 設置 session 儲存的位置
#使用多個 memcached server 時用逗號”,”隔開,
#可以帶額外的參數”persistent”、”weight”、”timeout”、”retry_interval”等等,
#類似這樣的:"tcp://host:port?persistent=1&weight=2,tcp://host2:port2"
[root@php /]# service php-fpm restart # 重啟服務使配置生效
Gracefully shutting down php-fpm . done
Starting php-fpm done
[root@php /]# vim /var/www/html/test2.php # 編寫配置文件
<?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 />";
?>
客戶端訪問編寫的test2.php測試文件,如下:
同樣,使用Telnet命令在memcached服務器上進行查詢其session_id的值,如下:
[root@memcached /]# telnet 192.168.171.132 11211
Trying 192.168.171.132...
Connected to 192.168.171.132.
Escape character is '^]'.
get d1n4umig3aq8okqrg7ep95t321
VALUE d1n4umig3aq8okqrg7ep95t321 0 26
session_time|i:1581082210;
END
#可以看到,查詢到的session_time和我們網頁訪問到的值是一樣的,說明其被緩存了
7、測試Memcached緩存數據庫
在MySQL數據庫上創建用于測試的表(所有操作都在MySQL數據庫上)如下:
[root@mysql mysql]# mysql -u root -p
Enter password:
mysql> create database testdb; # 創建數據庫
mysql> use testdb; # 進入庫中
Database changed
mysql> create table test1(id int not null auto_increment,name varchar(20) default null,primary key (id)) engine=innodb auto_increment=1 default charset=utf8; # 創建表
mysql> insert into test1(name) values ('aaa1'),('aaa2'),('aaa3'),('aaa4'),('aaa5'); # 向表中添加內容
mysql> select * from test1 # 查詢表中內容
-> ;
+----+------+
| id | name |
+----+------+
| 1 | aaa1 |
| 2 | aaa2 |
| 3 | aaa3 |
| 4 | aaa4 |
| 5 | aaa5 |
+----+------+
5 rows in set (0.00 sec)
mysql> desc test1; # 可查詢表結構
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> grant select on testdb.* to test@'%' identified by 'pwd@123';
# 創建用于測試的用戶
在PHP服務器上編寫以下測試文件,測試memcache 是否緩存數據成功:
[root@php html]# vim test3.php
<?php
$memcachehost = '192.168.171.132';
$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.171.135","test","pwd@123");
mysql_select_db(testdb);
$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><font color=#FF0000>$a[id]</font></b>";
echo "<br>";
echo "name is <b><font color=#FF0000>$a[name]</font></b>";
echo "<br>";
}
?>
客戶端訪問用于測試的腳本文件,第一次訪問的頁面如下:
客戶端刷新后,會看到以下頁面:
在查詢到的緩存過期前,可以在memcache上通過get 獲取到對應的緩存數據,如下(在memcache服務器上進行操作):
[root@memcached memcached]# telnet 192.168.171.132 11211
Trying 192.168.171.132...
Connected to 192.168.171.132.
Escape character is '^]'.
get d8c961e9895ba4b463841924dbcefc2b
VALUE d8c961e9895ba4b463841924dbcefc2b 0 251
a:5:{i:0;a:2:{s:2:"id";s:1:"1";s:4:"name";s:4:"aaa1";}i:1;a:2:{s:2:"id";s:1:"2";s:4:"name";s:4:"aaa2";}i:2;a:2:{s:2:"id";s:1:"3";s:4:"name";s:4:"aaa3";}i:3;a:2:{s:2:"id";s:1:"4";s:4:"name";s:4:"aaa4";}i:4;a:2:{s:2:"id";s:1:"5";s:4:"name";s:4:"aaa5";}}
END
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。