一、簡介
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
- 測試成功