第十六周微职位:Memcached,haproxy,varnish

1、为LNMP架构添加memcached支持,并完成对缓存效果的测试报告;

一、Memcached的简介:

    Memcached是一个自由开源的,高性能,分布式内存对象缓存系统。它是一种基于内存的key-value存储,用来存储小块的任意数据(字符串、对象)。这些数据可以是数据库调用、API调用或者是页面渲染的结果。

    Memcached简洁而强大。它的简洁设计便于快速开发,减轻开发难度,解决了大数据量缓存的很多问题。它的API兼容大部分流行的开发语言。本质上,它是一个简洁的key-value存储系统。

一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性。

特征:

    1)协议简单;

    2)基于libevent的事件处理;

    3)内置内存存储方式;

    4)memcached不互相通信的分布式。

Memcached常用选项:

    -l <ip_addr>:监听的地址
    -m <num>:缓存空间大小,单位为MB, 默认为64
    -c <num>:最大并发连接数,默认为1024
    -M:缓存空间耗尽时,向请求者返回错误信息,而不是基于LRU算法进行缓存清理
    -f <factor>:growth factor, 增长因子
    -t <threads>:处理用于请求的线程数

二 基于LNMP架构添加Memcached支持并验证其结果

1、结构示意图:

wKiom1nViCHCDhz6AABco8LB8fY196.png

2. 实验环境

IP    功用    

192.168.237.129    nginx    

192.168.237.131    php-fpm+mariadb+memcached    

3. 实验步骤

Nginx, PHP-FPM和MariaDB安装在此忽略。

(1) Memcached安装

#安装Memcached
yum -y install memcached
#启动Memcached
memcached -d -m 1024 -u memcached

连接测试

telnet 192.168.237.131 11211

wKioL1nViDzhlqGXAAANSYQrp2Q196.png


查看Memcached信息

wKiom1nViJbQYDKLAAA5ueWCWX8084.png

(2) 安装PHP的Memcached的扩展

    php连接memcached服务的模块有两个,php-pecl-memcache和php-pecl-memcached.若要安装php-pecl-memcached需要依赖libmemcached程序包,可以提供相应操作查看memcached的工具。在这里为方便演示就直接使用php-pecl-memcache扩展模块。

    #安装PHP的Memcached扩展模块
    yum -y install php-pecl-memcache

    测试PHP是否已支持Memcached, 浏览器中输入http://192.168.237.129/index.php

(3) 测试Memcached缓存

#在nginx根目录下写入php测试脚本
vim /usr/share/nginx/html/test.php
<?php
$mem = new Memcache;
$mem->connect("192.168.237.131", 11211);   #连接Memcached

$version = $mem->getVersion();
echo "Server's version: ".$version."<br/>\n";   #输出Memcached版本信息

$mem->set('testkey', 'Hello World', 0, 600);   #向Memcached存储数据'Hello World',时间为600s
echo "Store data in the cache (data will expire in 600 seconds)<br/>\n";   

$get_result = $mem->get('testkey');   #获取testkey的值
echo "$get_result is from memcached server.";
?>

测试Memcached缓存结果,在浏览器中输入192.168.237.129/test.php

wKioL1nViTfDvySaAAAt3WfwbeA835.png

可以看出缓存已生效,再查看Memcached相应信息

wKioL1nViUegpLtZAAA9XWunRYw327.png


2、部署配置haproxy,能够实现将来自用户的80端口的http请求转发至后端8000上的server服务,写出其配置过程。

Haproxy的安装:(也可通过源码安装)

yum -y install haproxy

修改基本的配置文件如下:

配置文件所在地址: /etc/haproxy/haproxy.cfg   

 global   
    maxconn 5120      
    chroot /usr/share/haproxy      
    daemon      
    quiet      
    nbproc 2      
    pidfile /usr/share/haproxy/haproxy.pid      
defaults      
    option  httplog      
    option  dontlognull      
    timeout connect 5s      
    timeout client 50s      
    timeout server 20s      
listen http      
    bind :80      
    timeout client 1h      
    tcp-request inspect-delay 2s       
    tcp-request content accept if is_http      
    server server-http :8080      
backend servers     
    server server1 127.0.0.1:8080 maxconn 32

 

3、阐述varnish的功能及其应用场景,并通过实际的应用案例来描述配置、测试、调试过程。


先安装varnish

#yum -y install varnish
配置文件的简单介绍

  

NFILES=131072                
MEMLOCK=82000    
NPROCS="unlimited"    
# DAEMON_COREFILE_LIMIT="unlimited"        #内核最大打开的文件数    
RELOAD_VCL=1                               #是否自动加载VCL    
VARNISH_VCL_CONF=/etc/varnish/default.vcl  #默认加载的VCL文件    
VARNISH_LISTEN_PORT=80                     #监听端口,默认为6081    
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1     #管理的IP地址    
VARNISH_ADMIN_LISTEN_PORT=6082             #管理端口    
VARNISH_SECRET_FILE=/etc/varnish/secret    #密钥文件    
VARNISH_MIN_THREADS=50                     #最小线程数量    
VARNISH_MAX_THREADS=1000                   #最大线程数量  
VARNISH_THREAD_TIMEOUT=120                 #线程超时时间    
VARNISH_STORAGE_FILE=/var/lib/varnish/varnish_storage.bin #缓存文件位置    
VARNISH_STORAGE_SIZE=1G                    #设置文件缓存大小变量    
VARNISH_MEMORY_SIZE=64M                    #设置内存缓存大小变量    
#VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}" #默认存储到文件中,这里可以修改存储位置    
VARNISH_STORAGE="malloc,${VARNISH_MEMORY_SIZE}" #设置缓存位置为内存    
VARNISH_TTL=120                    
DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \    
             -f ${VARNISH_VCL_CONF} \    
             -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \    
             -t ${VARNISH_TTL} \    
             -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \    
             -u varnish -g varnish \    
             -S ${VARNISH_SECRET_FILE} \    
             -s ${VARNISH_STORAGE}"    #所有启动加载选项

启动服务如下:

# service varnish start

Varnish命令介绍

# varnishd -h    
-a address:port        #表示varnish对httpd的监听地址及其端口    
-b address:port        #表示后端服务器地址及其端口    
-d                     #表示使用debug调试模式    
-f file                #指定varnish服务器的配置文件    
-p param=value         #指定服务器参数,用来优化varnish性能    
-P file                #Varnish进程PID文件存放路径    
-n dir                 #指定varnish的工作目录    
-s kind[,storageoptions] #指定varnish缓存内容的存放方式,常用的方式有:“-s file,<dir_or_file>,<size>”;其中“<dir_or_file>”    
                          指定缓存文件的存放路径,“<size>”指定缓存文件的大小    
-t                     #指定默认的TTL值    
-T address:port        #设定varnish的telnet管理地址及其端口    
-V                     #显示varnish版本号和版权信息    
-w int[,int[,int]]     #设定varnish的工作线程数,常用的方式有:  -w min,max    
 -w min,max,timeout    
如:-w3,25600,50       #这里最小启动的线程数不能设定过大,设置过大,会导致varnish运行异常缓慢
环境如下:

wKiom1nVjILhmtJuAAA7tBXR0Ko681.png

在lamp1、lamp2上分别都安装服务并启动
######在Lamp1服务器上安装Httpd、Php、Mysql,启动服务    
# yum -y install httpd php mysql-server php-mysql    
# service httpd start    
# service mysqld start    
------------------------------------------------------------------------    
######在Lamp2服务器上安装Httpd、Php,启动服务    
# yum -y install httpd php php-mysql    
# service httpd start


lamp上都测试php界面

安装论坛程序:

# mysql    
mysql> create database bbs;    
mysql> grant all on bbs.* to 'bbsuser'@'172.16.%.%' identified by 'bbspass';    
mysql> flush privileges;    
注释:为论坛创建一个数据库并授权用户访问    
------------------------------------------------------------------------    
######安装论坛程序    
# unzip Discuz_X3.0_SC_UTF8.zip    
# cp -rf upload/* /var/www/html/    
# chmod -R +w /var/www/html/{config,data,uc_server,uc_client}    #添加可写权限    
# chown -R apache /var/www/html/*      #修改属主权限

wKioL1nVjQaR5HNAAADtJ1Gyvuk230.png

将论坛程序拷贝到lamp2服务器上一份并访问测试

# scp -rp /var/www/html/* 172.16.14.3:/var/www/html/    

# service httpd restart    #重启lamp2服务器的WEB服务    

安装web服务器并测试页面:

# yum -y install httpd    

# service httpd start    

# echo "<h1>WEB</h1>" > /var/www/html/index.html #创建测试页    

wKioL1nVjVHgmLu0AABd5OXCCDQ507.png

将Lamp1服务器上的论坛程序拷贝到WEB服务器一份,因为需要论坛中的一些静态文件如:(.jpg|.html)结尾的文件等

# scp -rp /var/www/html/* 172.16.14.3:/var/www/html/    


Varnish安装及配置

在第一部分中我们已经修改过默认监听端口为"80",接下来为Varnish提供一个VCL配置文件,建议基于默认的配置文件基础上修改,修改前    

备份一下文件。    

[root@varnish ~]# cd /etc/varnish/    

[root@varnish varnish]# cp default.vcl default.vcl.bak    

[root@varnish varnish]# vim default.vcl    

######定义ACL    

acl purgers {                    #定义acl,实现IP地址过滤    

    "127.0.0.1";    

    "172.16.0.0"/16;    

}    

######定义健康状态检测    

probe dynamic {                  #设置动态网站服务器健康状态检测    

    .url = "/index.html";    

    .interval = 5s;    

    .timeout = 1s;    

    .expected_response = 200;    

}            #这里设置了两个健康状态检测主要是为了区分动、静网站    

probe static {                   #设置动态网站服务器健康状态检测    

    .url = "/index.html";        #定义检测的页面    

    .interval = 5s;              #探测请求的发送周期,默认为5秒    

    .timeout = 1s;               #每次探测请求的过期时间    

    .expected_response = 200;    

}    

######定义后端服务器    

backend app1 {                  #定义一个后端服务器    

    .host = "172.16.14.2";      #服务器地址    

    .port = "80";               #服务器监听端口    

    .probe = dynamic;           #健康状态检测    

}    

backend app2 {    

    .host = "172.16.14.3";    

    .port = "80";    

    .probe = dynamic;    

}    

backend web {              

    .host = "172.16.14.4";    

    .port = "80";    

    .probe = static;    

}    

######定义后端服务器组,实现负载均衡效果    

director apps random {          #定义一个后端服务器组,实现负载均衡效果    

    {    

         .backend = app1;       #调用前面已定义过的后端主机    

     .weight = 2;           #设置权重    

    }    

    {    

     .backend = app2;    

     .weight = 2;    

    }    

}    

######定义vcl_recv函数,实现请求到达并成功接收后调用此函数中定义的规则    

sub vcl_recv {    

######定义动、静分离,以".php"或".php?后面跟所有文件"结尾的请求都发送到动态服务器,其他请求都发送到静态服务器    

    if (req.url ~ "\.php(\?\.*|$)") {    

    set req.backend = apps;    

    } else {    

    set req.backend = web;    

    }    

    return(lookup);    

######定义允许清除缓存的IP地址,调用的是前面定义的ACL    

    if (req.request == "PURGE") {    

        if (!client.ip ~ purgers) {    

        error 405 "Method not allowed";    

    }    

        return(lookup);    

    }    

######重新定义http请求首部,让后端服务器可以记录请求客户端的真实IP地址    

        if (req.restarts == 0) {    

            if (req.http.x-forwarded-for) {    

               set req.http.X-Forwarded-For =    

               req.http.X-Forwarded-For + ", " + client.ip;    

            } else {    

                 set req.http.X-Forwarded-For = client.ip;    

            }    

         }    

######除了定义的请求方法外,其他请求都到后端服务器    

    if (req.request != "GET" &&    

        req.request != "HEAD" &&    

        req.request != "PUT" &&    

        req.request != "POST" &&    

        req.request != "TRACE" &&    

        req.request != "OPTIONS" &&    

        req.request != "DELETE") {    

        return (pipe);    

    }    

    if (req.request != "GET" && req.request != "HEAD") {    

        return (pass);    

    }    

######定义不缓存认证与Cookie信息    

    if (req.http.Authorization || req.http.Cookie) {    

        return (pass);    

    }    

######定义压缩功能    

    if (req.http.Accept-Enconding) {    

       if (req.url ~ "\.(jpg|jpeg|gif|bmp|png|flv|gz|tgz|tbz|mp3)$") {    

           remove req.http.Accept-Encoding;    

       remove req.http.Cookie;    

       } else if (req.http.Accept-Encoding ~ "gzip") {    

       set req.http.Accept-Encoding = "gzip";    

       } else if (req.http.Accept-Encoding ~ "deflate") {    

       set req.http.Accept-Encoding = "deflate";    

       } else { remove req.http.Accept-Encoding;    

       }    

    }    

######定义指定格式结尾的文件去除Cookie信息    

    if (req.request == "GET" && req.url ~ "\.(jpeg|jpg|gif|png|bmp|swf)$") {    

    unset req.http.cookie;    

    }    

######定义防盗链设置    

    if (req.http.referer ~ "http://.*") {    

        if (!(req.http.referer ~ "http://.*\.baidu\.com" || req.http.referer ~"http://.*\.google\.com.*")) {    

              set req.http.host = "www.allen.com";    

          set req.url = "http://172.16.14.4/error.html";    

    }    

    }    

}    

######定义vcl_hash函数    

sub vcl_hash {    

    hash_data(req.url);    

    if (req.http.host) {    

        hash_data(req.http.host);    

    } else {    

        hash_data(server.ip);    

    }    

    return(hash);    

}    

######定义vcl_hit函数    

sub vcl_hit {    

    if (req.request == "PURGE") { #语法方法为"PURGE"    

       purge;                     #清除缓存    

       error 200 "Purged.";       #返回错误状态码为"200"    

    }    

    return(deliver);    

}    

######定义vcl_miss函数    

sub vcl_miss {    

    if (req.request == "PURGE") {    

    purge;    

    error 404 "Not In Cache.";    

    }    

    return(fetch);    

}    

######定义vcl_psss函数    

sub vcl_pass {    

    if (req.request == "PURGE") {    

       error 502 "Purged On A Passed Object.";    

    }    

    return(pass);    

}    

######定义vcl_fetch函数    

sub vcl_fetch {    

######定义缓存,如果匹配到已定义文件结尾的缓存1天,其他则缓存1小时    

    if (req.request == "GET" && req.url ~ "\.(html|jpg|png|bmp|jpeg|gif|js|ico|swf|css)$") {    

       set beresp.ttl = 1d;    

       set beresp.http.expires = beresp.ttl;    

    } else {    

       set beresp.ttl = 1h;    

    }    

    return(deliver);    

}    

######定义在http首部中,如果请求命中显示"HIT",未命中则显示"MISS"    

sub vcl_deliver {    

    if (obj.hits > 0) {    

       set resp.http.X-Cache = "HIT";    

    } else {    

       set resp.http.X-Cache = "MISS";    

    }    

}    

----------------------------------------------------------------------    

[root@varnish ~]# service varnish restart    #重启服务生效,重启服务器后所有缓存将被清除,当然也可以不用重启服务使其生效,如下:    

----------------------------------------------------------------------    

[root@varnish ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082    

varnish> help                        #获取帮助    

varnish> vcl.load acl_1 default.vcl  #加载acl文件,acl_1为配置名称    

200       

VCL compiled.    

varnish> vcl.list                    #查看加载的acl文件列表    

200       

active          7 boot    

available       0 acl_1    

varnish> vcl.use acl_1               #应用acl文件    

200    

varnish> quit                        #退出    

------------------------------------------------------------------------    

注释:  -S:指定varnish的密钥文件  -T:指定varnish服务器地址及管理端口,默认端口为"6082"    

服务验证:

压力测试,如下:    

######后端服务器不经过缓存测试    

[root@localhost ~]# ab -c 100 -n 1000 http://172.16.14.2/index.php    

Concurrency Level:      1000    

Time taken for tests:   6.812 seconds    

Complete requests:      10000    

Failed requests:        0    

Write errors:           0    

Non-2xx responses:      10051    

Total transferred:      2281577 bytes    

HTML transferred:       0 bytes    

Requests per second:    1468.04 [#/sec] (mean)  #每秒请求并发    

Time per request:       681.179 [ms] (mean)    

Time per request:       0.681 [ms] (mean, across all concurrent requests)    

Transfer rate:          327.10 [Kbytes/sec] received    

----------------------------------------------------------------------    

######经过缓存测试    

[root@localhost ~]# ab -c 1000 -n 10000 http://172.16.14.1/index.php    

Concurrency Level:      1000    

Time taken for tests:   2.594 seconds    

Complete requests:      10000    

Failed requests:        0    

Write errors:           0    

Non-2xx responses:      10056    

Total transferred:      3117360 bytes    

HTML transferred:       0 bytes    

Requests per second:    3855.05 [#/sec] (mean)    

Time per request:       259.400 [ms] (mean)    

Time per request:       0.259 [ms] (mean, across all concurrent requests)    

Transfer rate:          1173.59 [Kbytes/sec] received    

----------------------------------------------------------------------    

注释:从上面数据中可以看出,经过缓存做压力测试并发量高    

测试缓存是否能命中    

[root@lamp2 ~]# curl -I http://172.16.14.1/index.php    

HTTP/1.1 301 Moved Permanently    

Server: Apache/2.2.15 (CentOS)    

X-Powered-By: PHP/5.3.3    

location: forum.php    

Content-Type: text/html; charset=UTF-8    

Content-Length: 0    

Accept-Ranges: bytes    

Date: Thu, 05 Oct 2017 09:48:01 GMT    

X-Varnish: 2142028839    

Age: 0    

Via: 1.1 varnish    

Connection: keep-alive    

X-Cache: MISS    #第一次请求,未命中显示"MISS"    

------------------------------------------------------------------------    

[root@lamp2 ~]# curl -I http://172.16.14.1/index.php    

HTTP/1.1 301 Moved Permanently    

Server: Apache/2.2.15 (CentOS)    

X-Powered-By: PHP/5.3.3    

location: forum.php    

Content-Type: text/html; charset=UTF-8    

Content-Length: 0    

Accept-Ranges: bytes    

Date: Thu, 05 Oct 2017 09:48:15 GMT     

X-Varnish: 2142028841 2142028839    

Age: 7    

Via: 1.1 varnish    

Connection: keep-alive    

X-Cache: HIT    #第二次请求,命中则显示"HIT"    


验证动、静分离的效果:

wKiom1nVj0yg8i-TAACR8i2Ueyw707.png

    从上图中可以看出,提供静态页面的服务停止后,所有图片都不能显示,当然把服务再启动起来就可以访问正常了,这里就不在测试了…

    验证健康状态检测

wKiom1nVj9aB7-8XAABEbzkS6MY161.png


查看缓存命中率状态;命中率的高低

wKiom1nVj-riotgEAACGvu45KDo948.png

相关文章

相关标签/搜索