一、简介
1.1 CDN的简单了解:
内容分发网络(CDN)是一种新型网络构建方式,它是为能在传统的IP网发布宽带丰富媒体而特别优化的网络覆盖层;而从广义的角度,CDN代表了一种基于质量与秩序的网络服务模式。
CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。
CDN的基本原理是广泛采用各种缓存服务器,将这些缓存服务器分布到用户访问相对集中的地区或网络中,在用户访问网站时,利用全局负载技术将用户的访问指向距离最近的工作正常的缓存服务器上,由缓存服务器直接响应用户请求。
总的来说,内容服务基于缓存服务器,也称作代理缓存(Surrogate),它位于网络的边缘,距用户仅有”一跳”(Single Hop)之遥。同时,代理缓存是内容提供商源服务器(通常位于CDN服务提供商的数据中心)的一个透明镜像。这样的架构使得CDN服务提供商能够代表他们客户,即内容供应商,向最终用户提供尽可能好的体验,而这些用户是不能容忍请求响应时间有任何延迟的。
1.2 varnishi的基本介绍
- 处理流程图
- VCL出来流程图
处理过程大致分为如下几个步骤:
(1)Receive 状态,也就是请求处理的入口状态,根据 VCL 规则判断该请求应该是 Pass 或Pipe,或者进入 Lookup(本地查询)。
(2)Lookup 状态,进入此状态后,会在 hash 表中查找数据,若找到,则进入 Hit 状态,否则进入 miss 状态。
(3)Pass 状态,在此状态下,会进入后端请求,即进入 fetch 状态。
(4)Fetch 状态,在 Fetch 状态下,对请求进行后端的获取,发送请求,获得数据,并进行本地
的存储。
(5)Deliver 状态, 将获取到的数据发送给客户端,然后完成本次请求。
- 详细介绍
Varnish与一般服务器软件类似,分为master(management)进程和child(worker,主要做cache的工作)进程。master进程读入命令,进行一些初始化,然后fork并监控child进程。child进程分配若干线程进行工作,主要包括一些管理线程和很多woker线程。
针对文件缓存部分,master读入存储配置(-s file[,path[,size[,granularity]]] ),调用合适的存储类型,然后创建/读入相应大小的缓存大文件。接着,master初始化管理该存储空间的结构体。这些变量都是全局变量,在fork以后会被child进程所继承(包括文件描述符)。
在child进程主线程初始化过程中,将前面打开的存储大文件整个mmap到内存中(如果超出系统的虚拟内存,mmap失败,进程会减少原来的配置mmap大小,然后继续mmap),此时创建并初始化空闲存储结构体,挂到存储管理结构体,以待分配。
接着,真正的工作开始,Varnish的某个负责接受新HTTP连接的线程开始等待用户,如果有新的HTTP连接过来,它总负责接收,然后叫醒某个等待中的线程,并把具体的处理过程交给它。Worker线程读入HTTP请求的URI,查找已有的object,如果命中则直接返回并回复用户。如果没有命中,则需要将所请求的内容,从后端服务器中取过来,存到缓存中,然后再回复。
分配缓存的过程是这样的:它根据所读到object的大小,创建相应大小的缓存文件。为了读写方便,程序会把每个object的大小变为最接近其大小的内存页面倍数。然后从现有的空闲存储结构体中查找,找到最合适的大小的空闲存储块,分配给它。如果空闲块没有用完,就把多余的内存另外组成一个空闲存储块,挂到管理结构体上。如果缓存已满,就根据LRU机制,把最旧的object释放掉。
释放缓存的过程是这样的:有一个超时线程,检测缓存中所有object的生存期,如果超初设定的TTL(Time To Live)没有被访问,就删除之,并且释放相应的结构体及存储内存。注意释放时会检查该存储内存块前面或后面的空闲内存块,如果前面或后面的空闲内存和该释放内存是连续的,就将它们合并成更大一块内存。
整个文件缓存的管理,没有考虑文件与内存的关系,实际上是将所有的object都考虑是在内存中,如果系统内存不足,系统会自动将其换到swap空间,而不需要varnish程序去控制。
二、配置varnish
- 实验环境RedHat 6.5
2.1 安装varnish
[root@server1 ~]# ls
varnish-3.0.5-1.el6.x86_64.rpm varnish-libs-3.0.5-1.el6.x86_64.rpm
[root@server1 ~]# yum install -y *
2.2 配置varnish服务
[root@server1 ~]# vim /etc/sysconfig/varnish
NFILES=65535
MEMLOCK=64000
VARNISH_LISTEN_PORT=8 ##varnish服务端口为80,但要注意http端口80,不要开启httpd服务否则有矛盾
[root@server1 ~]# vim /etc/security/limits.conf
# End of file
varnish - nofile 65535
2.3 修改varnish配置文件
[root@server1 ~]# vim /etc/varnish/default.vcl
backend web1 {
.host = "172.25.67.2"; ##配置后端web1服务器
.port = "80";
}
[root@server1 ~]# /etc/init.d/varnish start
2.4配置web1服务器
[root@server2 ~]# yum install -y httpd
[root@server2 ~]# vim /var/www/html/index.html
[root@server2 ~]# cat /var/www/html/index.html
<h1>www.hello.org-server2</h1>
[root@server2 ~]# /etc/init.d/httpd start
client测试
- 需要做好域名解析
-bash-4.2# vim /etc/hosts
172.25.67.1 www.hello.org server1
2.5 查看缓存命中情况
- 修改varnish配置文件
[root@server1 ~]# vim /etc/varnish/default.vcl
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT from hello cache";
}
else {
set resp.http.X-Cache = "MISS from hello cache";
}
return (deliver);
}
- 测试:
- 第一次未命中MISS
- 第二次命中HIT
- 清除缓存
- 清除后Age为0
varnishadm ban.url .*$ ##清除所有缓存
varnishadm ban.url /index.html ##清除index.html页面缓存
varnishadm ban.url /admin/$ ##清除admin缓存
2.6定义多个不同域名站点的后端服务器
- 修改varnish配置文件
[root@server1 ~]# vim /etc/varnish/default.vcl
backend web1 {
.host = "172.25.67.2";
.port = "80";
}
backend web2 {
.host = "172.25.67.3";
.port = "80";
}
sub vcl_recv {
if (req.http.host ~ "^(www.)?hello.org") {
set req.http.host = "www.hello.org";
set req.backend = web1;
} elsif (req.http.host ~ "^bbs.hello.org") {
set req.backend = web2;
} else {error 404 "hello cache";
}
}
- .配置server3的http服务
[root@server3 ~]# cat /var/www/html/index.html
<h1>bbs.hello.org-server3</h1>
[root@server3 ~]# /etc/init.d/httpd restart
- client需要做域名解析
-bash-4.2# vim /etc/hosts
172.25.67.2 server2 www.hello.org
172.25.67.3 server3 bbs.hello.org
- 浏览器测试
2.7 负载均衡
- 修改配置文件
vim /etc/varnish/default.vcl
director lb round-robin { ##lb 轮询组
{.backend = web1;}
{.backend = web2;}
}
sub vcl_recv {
if (req.http.host ~ "^(www.)?hello.org") {
set req.http.host = "www.hello.org";
set req.backend = lb;
return (pass); ##为了测试方便,不进行缓存。
} elsif (req.http.host ~ "^bbs.hello.org") {
set req.backend = web2;
} else {
error 404 "hello cache";
}
}
- 域名解析
-bash-4.2# vim /etc/hosts
172.25.67.1 server1 www.hello.org
- 测试成功
三、varnish CDN 推送
- 配置CDN的环境
[root@server1 ~]# yum install -y unzip
[root@server1 ~]# unzip bansys.zip -d /var/www/html ##解压到httpd的默认发布目录下
[root@server1 ~]# cd bansys
[root@server1 bansys]# ls
class_socket.php config.php index.php purge_action.php static
[root@server1 bansys]# mv * .. ##将该目录下的文件移动到上层目录,即httpd的默认发布目录
[root@server1 bansys]# ls
[root@server1 bansys]# cd ..
[root@server1 html]# rm -fr bansys/
[root@server1 html]# ls
class_socket.php config.php index.php purge_action.php static
[root@server1 bansys]# yum install -y php ##需要安装php
[root@server1 bansys]# yum install -y httpd ##安装httpd
[root@server1 bansys]# vim /etc/httpd/conf/httpd.conf
#Listen 12.34.56.78:80
Listen 8080 ##将httpd的端口改为8080,避免与varnish冲突
- 配置php文件
[root@server1 ~]# vim /var/www/html/config.php ##只保留以下部分
<?php
$var_group1 = array(
'host' => array('172.25.67.1'),
'port' => '6802', ##CDN的端口
);
//varnish群组定义
//对主机列表进行绑定
$VAR_CLUSTER = array(
'www.hello.org' => $var_group1, ##域名解析需要和这里一致
);
//varnish版本
//2.x和3.x推送命令不一样
$VAR_VERSION = "3";
?>
- 修改varnish配置文件
bansys 有两种工作模式,分别是:telnet 和 http 模式。
telnet 模式需要关闭 varnish 服务管理端口的验证,注释掉/etc/sysconfig/varnish 文件中的 “ -S
${VARNISH_SECRET_FILE}”这行,重启 varnish 服务即可。
如果是 http 模式需要对 varnish 做以下设置:
[root@server1 ~]# vim /etc/varnish/default.vcl
acl hello { ##设置访问控制
"127.0.0.1";
"172.25.67.0"/24;
}
sub vcl_recv {
if (req.request == "BAN") {
if (!client.ip ~ hello) {
error 405 "Not allowed.";
}
ban("req.url ~ " + req.url);
error 200 "ban added";
}
if (req.http.host ~ "^(www.)?hello.org") {
set req.http.host = "www.hello.org";
set req.backend = lb;
} elsif (req.http.host ~ "^bbs.hello.org") {
set req.backend = web2;
} else {error 404 "hello cache";
}
}
[root@server1 ~]# /etc/init.d/varnish reload ##重新加载varnish配置
- 客户机测试
- 输入[172.25.67.18080]
- 进行推送
- 测试用群组+推送内容
- http://www.hello.org/index.html
- 测试成功