Memcached介绍
1.Memcached是什么?
Memcached是一个开源的、支持高性能、高并发的分布式内存缓存系统,由C语言编写。总共2000多行代码。从软件的名称上来看,前三个字符Mem就是内存的意思。而接下来的后面5个字符cache就是缓存的意思。最后一个字符d,是daemon的意思,代表是服务器端守护进程模式。
Memcached服务分为服务器端和客户端两部分,其中服务端软件名字形如memcached-1.4.24.tar.gz,客户端的软件名字如:mamcache-2.25.tar.gz
Memcached软件诞生于2003年,最初由LiveJouranl和Brad Fitzpatrick开发完成。Memcache是整个项目的名称,而memcached是服务端的软件名称,因其协议简单,应用部署方便,且支持高并发,因此被互联网企业广泛使用,直到现在仍然如此。其官方网站地址:http://memcached.org
Memcached的作用
在传统的场景中,多数的web应用都将数据保存在关系型数据库中(例如:MySQL),Web服务器从中读取数据并在浏览器中显示,但是随着数据量的增大,访问的集中,关系型数据库的负担就会出现加重,影响缓慢,导致网站打开延迟的问题,影响用户体验。
在这个时候就需要Memcached出马了,使用·Memcached的主要目的是,通过在自身内存中缓存关系型数据库的查询结果,减少了数据库被访问的次数,从而提高了动态web应用的速度,提高网站架构的并发访问能力。
Memcached服务的运行原理是通过在事先规划好的系统内存空间中临时缓存数据库中的各类数据,以达到减少前端业务服务对数据库的直接高并发访问,从而提高了大规模网站集群中动态服务的并发访问能力。
网站读取Memcached数据时的工作流程
从逻辑上来说,当程序访问后端数据库获取数据时会优先访问Memcached缓存,如果缓存中有数据就直接返回给客户端用户,如果没有合适的数据(没有命中),再去后端的数据库读取数据,读取到需要的数据后,就会把数据返回给客户端,同时还会把读取到的数据缓存到Memcached中,这样客户端再次请求相同的数据时就会直接读取到Memcached缓存数据中,这样就大大的减少了数据库的压力。并提高了整个网站的访问速度,提高了用户的体验。
具体的流程图如下:
1)检查客户端的请求是否在memcached中,如果memcached中有数据,那么直接把请求数据返回,不再对后端的数据库进行任何的操作。路径为1-2-3-7
2)如果请求的数据不在memcached中,就会去查询数据库,把数据库中获取的数据返回给客户端,同时把数据缓存一份到memcached中。路径为1-2-4-5-7-6
3)每次更新数据库的同时更新memcached中的数据,保证一致性。
4)当分配给memcached内存空间用完之后,会使用LRU(Least Recently Used)最近最少使用策略加上到期失效策略,失效数据首先被替换,然后在替换掉最近未使用的数据。
测试环境: Centos7.2+Nginx+PHP+Memcached+MySQL
环境描述:OS:Centos7.2x86_64
Nginx:nginx-1.10.2.tar.gz IP地址:192.168.146.100/24
PHP:php-5.6.27.tar.gz IP地址:192.168.146.100/24
Memcached:memcached-1.4.33.tar.gz IP地址:192.168.146.110/24
MySQL:mysql-5.7.13.tar.gz IP地址:192.168.146.120/24
1、安装Nginx(192.168.146.100主机操作)
1)解压zlib以及pcre只需要解压就行,在后面编译安装nginx的时候同时安装
[root@nginx-app src]# tar zxf pcre-8.39.tar.gz [root@nginx-app src]# tar zxf zlib-1.2.8.tar.gz
安装需要的包
[root@nginx-app src]# yum install -y gcc gcc-c++ make libtool openssl openssl-devel
2)解压Nginx源码包,并且创建Nginx运行用户
[root@nginx-app src]# tar zxf nginx-1.10.2.tar.gz [root@nginx-app src]# groupadd www [root@nginx-app src]# useradd -g www www -s /sbin/nologin [root@nginx-app src]# cd nginx-1.10.2/
./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=/usr/local/src/pcre-8.39 --with-zlib=/usr/local/src/zlib-1.2.8 --with-http_ssl_module --with-http_gzip_static_module --user=www --group=www make && make install
./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=/usr/local/src/pcre-8.39 –with-zlib=/usr/local/src/zlib-1.2.8 –with-http_ssl_module –with-http_gzip_static_module –user=www –group=www
make && make install
以上红色字段是指定pcre以及zlib的解压路径
3)创建软连接并启动Nginx
[root@nginx-app nginx-1.10.2]# ln -s /usr/local/nginx1.10/sbin/nginx /usr/local/sbin/ [root@nginx-app nginx-1.10.2]# nginx -t nginx: the configuration file /usr/local/nginx1.10/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx1.10/conf/nginx.conf test is successful [root@nginx-app nginx-1.10.2]# nginx [root@nginx-app nginx-1.10.2]# netstat -anput | grep nginx tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 36607/nginx: master
关闭防火墙,客户端打开浏览器访问http://NginxIP/如下出现NGinx页面表示成功:
2、安装PHP(192.168.146.100主机操作)
安装libmcrypt
[root@nginx-app src]# tar zxf libmcrypt-2.5.7.tar.gz [root@nginx-app src]# cd libmcrypt-2.5.7/ [root@nginx-app libmcrypt-2.5.7]# ./configure --prefix=/usr/local/libmcrypt && make && make install
安装相关的依赖包
[root@nginx-app ~]# yum install -y libxml2-devel libcurl-devel openssl-devel bzip2-devel
编译安装PHP
[root@nginx-app src]# tar zxf php-5.6.27.tar.gz [root@nginx-app src]# cd 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.ini文件并修改如下:
[root@nginx-app php-5.6.27]# cp php.ini-production /etc/php.ini
修改short_open_tag = On //支持PHP短标签
创建php-fpm服务启动脚本:
[root@nginx-app php-5.6.27]# cp sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm [root@nginx-app php-5.6.27]# chmod +x /etc/init.d/php-fpm [root@nginx-app php-5.6.27]# chkconfig --add php-fpm [root@nginx-app php-5.6.27]# chkconfig php-fpm on
提供php配置文件并编辑
[root@nginx-app php-5.6.27]# cp /usr/local/php5.6/etc/php-fpm.conf.default /usr/local/php5.6/etc/php-fpm.conf
修改如下:
pid = run/php-fpm.pid
listen = 127.0.0.1:9000
pm.max_children = 300
pm.start_servers = 10
pm.min_spare_servers = 10
pm.max_spare_servers = 50
修改完成后启动php-fpm服务
[root@nginx-app php-5.6.27]# service php-fpm start Starting php-fpm done [root@nginx-app php-5.6.27]# netstat -anput | grep php tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 57246/php-fpm: mast
3、安装MySQL(二进制安装-192.168.146.120主机操作)
1)在centos7中默认安装了mariadb需要卸载
[root@mysql ~]# rpm -qa | grep mariadb mariadb-libs-5.5.44-2.el7.centos.x86_64 [root@mysql ~]# rpm -e mariadb-libs-5.5.44-2.el7.centos.x86_64 --nodeps
2)下载MySQL二进制安装包
[root@mysql ~]# wget http://mirrors.sohu.com/mysql/MySQL-5.7/mysql-5.7.18-linux-glibc2.5-x86_64.tar.gz
3)解压mysql二进制包并且拷贝到/usr/local/mysql下
[root@mysql ~]# tar zxf mysql-5.7.18-linux-glibc2.5-x86_64.tar.gz && mv mysql-5.7.18-linux-glibc2.5-x86_64 /usr/local/mysql
4)进入/usr/local/mysql 创建data以及log目录
[root@mysql ~]# cd /usr/local/mysql/ && mkdir data && mkdir log && chmod +755 data/
5)优化执行路径
[root@mysql mysql]# echo "export PATH=$PATH:/usr/local/mysql/bin" >> /etc/profile && source /etc/profile
6)创建mysql组并且创建mysql用户
[root@mysql mysql]# groupadd mysql && useradd -r -g mysql -s /bin/false mysql
7)编写Mysql主配置如下:
vim /etc/my.cnf
[client] socket=/usr/local/mysql/mysql.sock [mysqld] basedir=/usr/local/mysql datadir=/usr/local/mysql/data pid-file=/usr/local/mysql/data/mysqld.pid socket=/usr/local/mysql/mysql.sock log_error=/usr/local/mysql/log/mysql.err
8)给予data目录750权限以及初始化mysql
[root@mysql mysql]# chmod 750 data/ && chown -R mysql . && chgrp -R mysql . && bin/mysqld --initialize --user=mysql
9)添加mysql服务并启动
[root@mysql mysql]# cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld && service mysqld start Starting MySQL. SUCCESS!
修改MySQL密码并登陆Mysql数据库
[root@mysql mysql]# cat /usr/local/mysql/log/mysql.err | grep password
4、安装Memcached服务端(192.168.146.110主机上操作)
1)首先需要安装memcached依赖库libevent
[root@memcached src]# tar zxf libevent-2.0.22-stable.tar.gz [root@memcached src]# cd libevent-2.0.22-stable/ [root@memcached libevent-2.0.22-stable]# ./configure && make && make install
安装memcached
[root@memcached src]# tar zxf memcached-1.4.33.tar.gz [root@memcached src]# 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 src]# ls /usr/local/memcached/bin/memcached
通过以上操作就很简单的把memcached服务端编译好了。这时候就可以打开服务端进行工作了。
配置环境变量:
进入用户宿主目录,编辑.bash_profile,为系统环境变量LD_LIBRARY_PATH增加新的目录,增加内容如下:
[root@memcached src]# vim ~/.bash_profile
MEMCACHED_HOME=/usr/local/memcached
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MEMCACHED_HOME/lib
启动Memcached
-d 选项是启动一个守护进程。
-m 分配给Memcache使用的内存数量,单位是MB,默认64MB。
-l 监听的IP地址。(默认:INADDR_ANY,所有地址)
-p 设置Memcache的TCP监听的端口,最好是1024以上的端口。
-u 运行Memcache的用户,如果当前为root的话,需要使用此参数指定用户。
-c 选项是最大运行的并发连接数,默认是1024。
-P 设置保存Memcache的pid文件。
刷新用户环境变量
[root@memcached src]# source ~/.bash_profile
编写memcached服务启动脚本
vim /etc/init.d/memcached
#!/bin/sh # # pidfile: /usr/local/memcached/memcached.pid # memcached_home: /usr/local/memcached # chkconfig: 35 21 79 # description: Start and stop memcached Service # 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.146.120" #listen port port=11211 #username for memcached username="root" #max memory for memcached,default is 64M max_memory=2048 #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 | grep memcached | 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
设置脚本可被执行:
[root@memcached src]# chmod +x /etc/init.d/memcached [root@memcached src]# chkconfig --add memcached [root@memcached src]# chkconfig memcached on
5、配置Nginx.conf文件和php通信(在Nginx主机上操作)
vim /usr/local/nginx/conf/nginx.conf
配置内容如下:
user www www; worker_processes 1; 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:2 keys_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/css text/javascript application/json application/javascript application/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 timeout invalid_header http_500; fastcgi_cache_key http://$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.conf
写入PHP测试页面访问如下:
6、memcache客户端(在php服务器操作):
安装memcached扩展库:
[root@nginx-app src]# tar zxf memcache-3.0.8.tgz [root@nginx-app src]# cd memcache-3.0.8/ [root@nginx-app memcache-3.0.8]# /usr/local/php5.6/bin/phpize Configuring for: PHP Api Version: 20131106 Zend Module Api No: 20131226 Zend Extension Api No: 220131226
安装完后会出下面提示一定要把下面框内的记住后面会用的到
打开php.ini添加如下:(如果不知道添加到哪,可以添加到最后一行)
检查php扩展是否正确的安装
[root@nginx-app memcache-3.0.8]# /usr/local/php5.6/bin/php -m | grep memcache
在次打开浏览器测试:
测试代码:
vim /usr/local/nginx/html/test.php
<?php $memcache = new Memcache; $memcache->connect('192.168.146.110',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 (data will expire in 10 seconds)<br/>"; $get_result = $memcache->get('key'); echo "Data from the cache:<br/>"; var_dump($get_result); ?>
去连接memcached服务端端口号为11211 如果成功那么久打印出版本号以及test&123(大概意思)如下:
使用memcached实现session共享
配置php.ini中的Session为memcached方式
session.save_handler = memcache
session.save_path = “tcp://192.168.146.110:11211?persistent=1&weight=1&timeout=1&retry_interval=15”
测试memcached可用性
vim /usr/local/nginx/html/memcached.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 />""; ?>
以上代码中大概意思获取session-id
访问网址:http://192.168.146.100/memcached.php可以查看session_time是否为memcache中的session,同时可以在不同的服务器上修改不同的标识查看是否为不同的服务器上的。
可以直接使用sessionid去memcached中查询如下:(memcached主机操作)
提示:如果get不到,那么请重启php以及重新加载nginx,清除浏览器再次访问192.168.146.100/memcached.php
获取的session_id 重新在memcached主机上get即可
得到session_time|i:1514396084;这样的结果,说明session可以正常的工作
7、测试memcache缓存数据库数据(MySQL服务器操作)
在MySQL服务器上创建测试表
mysql> create database testdb1; Query OK, 1 row affected (0.00 sec) mysql> use testdb1; 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 -> ; Query OK, 0 rows affected (0.13 sec) mysql> insert into test1(name) values('tom1'),('tom2'),('tom3'),('tom4'),('tom5'); Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> select * from test1; +----+------+ | id | name | +----+------+ | 1 | tom1 | | 2 | tom2 | | 3 | tom3 | | 4 | tom4 | | 5 | tom5 | +----+------+ 5 rows in set (0.00 sec)
测试:这里有一个php脚本,用于测试memcache是否缓存数据成功,需要为这个脚本添加一个只读的数据库用户
mysql> grant select on testdb1.* to user@'%' identified by '123456';
在web服务器上创建php脚本(192.168.146.100操作)
vim /usr/local/nginx/html/test6.php
<?php $memcachehost = '192.168.146.110'; $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.146.120","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><font color=#FF0000>$a[id]</font></b>"; echo "<br>"; echo "name is <b><font color=#FF0000>$a[name]</font></b>"; echo "<br>"; } ?>
在访问页面之前先来看看这张图
此时我们的memcached等环境已经全部搭建完成,那么按照这个图来说,第一次用户访问会先去寻找memcached服务器,如果memcached服务器没有数据,那么就会去Mysql数据库中调用数据,当在回给用户的时候同时memcached已经做了缓存,那么在第二次用户访问数据时,就可以直接去找memcached,不会在mysql数据库上做任何操作,从而减轻了mysql数据库的负担。
访问测试如下:
第一次访问:
第二次访问memcached已经做了缓存,那么就不会调用数据库 f5刷新即可