5 缓存加速器varnish安装

5.1 安装

这里采用的是apt-get安装

#apt-get install varnish

5.2 修改主配置

修改配置文件 /etc/varnish/default.vcl

# This is a basic VCL configuration file for varnish.  See the vcl(7)

# man page for details on VCL syntax and semantics.

#

# Default backend definition.  Set this to point to your content

# server.

#

backend tornado8001 {

.host = "127.0.0.1";

.port = "8001";

.probe = {

.timeout = 5s;

.interval = 2s;

.window = 10;

.threshold = 8;

}

}

backend tornado8002 {

.host = "127.0.0.1";

.port = "8002";

.probe = {

.timeout = 5s;

.interval = 2s;

.window = 10;

.threshold = 8;

}

}

backend tornado8003 {

.host = "127.0.0.1";

.port = "8003";

.probe = {

.timeout = 5s;

.interval = 2s;

.window = 10;

.threshold = 8;

}

}

backend tornado8004 {

.host = "127.0.0.1";

.port = "8004";

.probe = {

.timeout = 5s;

.interval = 2s;

.window = 10;

.threshold = 8;

}

}

director yxm random

{ .retries = 4;

{ .backend = tornado8001;

.weight = 4;

}

{ .backend = tornado8002;

.weight = 4;

}

{ .backend = tornado8003;

.weight = 4;

}

{ .backend = tornado8004;

.weight = 4;

}

}

acl purge {

"localhost";

"127.0.0.1";

}

#

# Below is a commented-out copy of the default VCL logic.  If you

# redefine any of these subroutines, the built-in logic will be

# appended to your code.

sub vcl_recv {

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

if (!client.ip ~ purge) {

error 405 "Not allowed.";

return(lookup);

}

}

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") {

/* Non-RFC2616 or CONNECT which is weird. */

return (pipe);

}

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

/* We only deal with GET and HEAD by default */

return (pass);

}

if (req.request == "GET" && req.url ~ "\.(py)($|\?)") {

set req.backend = yxm;

}

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

/* Not cacheable by default */

return (pass);

}

return (lookup);

}

#

sub vcl_pipe {

#     # Note that only the first request to the backend will have

#     # X-Forwarded-For set.  If you use X-Forwarded-For and want to

#     # have it set for all requests, make sure to have:

#     # set bereq.http.connection = "close";

#     # here.  It is not set by default as it might break some broken web

#     # applications, like IIS with NTLM authentication.

return (pipe);

}

#

sub vcl_pass {

return (pass);

}

#

sub vcl_hash {

hash_data(req.url);

if (req.http.host) {

hash_data(req.http.host);

} else {

hash_data(server.ip);

}

return (hash);

}

#

sub vcl_hit {

return (deliver);

}

sub vcl_miss {

return (fetch);

}

sub vcl_fetch {

if (beresp.ttl <= 0s ||

beresp.http.Set-Cookie ||

beresp.http.Vary == "*") {

/*

* Mark as "Hit-For-Pass" for the next 2 minutes

*/

set beresp.ttl = 120 s;

return (hit_for_pass);

}

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

{ set beresp.ttl = 7d; }

return (deliver);

}

#

sub vcl_deliver {

set resp.http.x-hits = obj.hits ;

if (obj.hits > 0)

{ set resp.http.X-Cache = "HIT cqtel-bbs"; }

else { set resp.http.X-Cache = "MISS cqtel-bbs"; }

}

#

# sub vcl_error {

#     set obj.http.Content-Type = "text/html; charset=utf-8";

#     set obj.http.Retry-After = "5";

#     synthetic {"

# <?xml version="1.0" encoding="utf-8"?>

# <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"

#  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

# <html>

#   <head>

#     <title>"} + obj.status + " " + obj.response + {"</title>

#   </head>

#   <body>

#     <h1>Error "} + obj.status + " " + obj.response + {"</h1>

#     <p>"} + obj.response + {"</p>

#     <h3>Guru Meditation:</h3>

#     <p>XID: "} + req.xid + {"</p>

#     <hr>

#     <p>Varnish cache server</p>

#   </body>

# </html>

# "};

#     return (deliver);

# }

#

sub vcl_init {

return (ok);

}

sub vcl_fini {

return (ok);

}

说明:根据官方文档得知,在转发后端请求时,如果配置服务器组,会线将请求转发到dirctor,然后根据director的规则来就行选中后端的具体服务器:

5.3 原理:

(1) Receive状态,也就是请求处理的入口状态,根据VCL规则判断该请求应该是Pass或Pipe,或者进入Lookup(本地查询)。

(2) Lookup状态,进入此状态后,会在hash表中查找数据,若找到,则进入Hit状态,否则进入miss状态。

(3) Pass状态,在此状态下,会进入后端请求,即进入fetch状态。

(4) Fetch状态,在Fetch状态下,对请求进行后端的获取,发送请求,获得数据,并进行本地的存储。

(5) Deliver状态, 将获取到的数据发送给客户端,然后完成本次请求。

5.4 VCL内置函数:

(1)vcl_recv函数

用于接收和处理请求,当请求到达并成功接收后被调用,通过判断请求的数据来决定如何处理请求。

此函数一般以如下几个关键字结束:

q pass:表示进入pass模式,把请求控制权交给vcl_pass函数。

q pipe:表示进入pipe模式,把请求控制权交给vcl_pipe函数。

q error code [reason]:表示返回“code”给客户端,并放弃处理该请求,“code”是错误标识,例如200、405等,“reason”是错误提示信息。

(2)vcl_pipe函数

此函数在进入pipe模式时被调用,用于将请求直接传递至后端主机,在请求和返回的内容没有改变的情况下,将不变的内容返回给客户端,直到这个链接关闭。

此函数一般以如下几个关键字结束:

q error code [reason]

q pipe

(3)vcl_pass函数

此函数在进入pass模式时被调用,用于将请求直接传递至后端主机,后端主机应答数据后送给客户端,但不进行任何缓存,在当前连接下每次都返回最新的内容。

此函数一般以如下几个关键字结束:

q error code [reason]

q pass

(4)lookup

表示在缓存里查找被请求的对象,并且根据查找的结果把控制权交给函数vcl_hit或者函数vcl_miss。

(5)vcl_hit函数

在执行lookup指令后,如果在缓存中找到请求的内容,将自动调用该函数。

此函数一般以如下几个关键字结束:

q deliver:表示将找到的内容发送给客户端,并把控制权交给函数vcl_deliver。

q error code [reason]

q pass

(6)vcl_miss函数

在执行lookup指令后,如果没有在缓存中找到请求的内容时自动调用该方法,此函数可以用于判断是否需要从后端服务器取内容。

此函数一般以如下几个关键字结束:

q fetch:表示从后端获取请求的内容,并把控制权交给vcl_fetch函数。

q error code [reason]

q pass

(7)vcl_fetch函数

在从后端主机更新缓存并且获取内容后调用该方法,接着,通过判断获取的内容来决定是否将内容放入缓存,还是直接返回给客户端。

此函数一般以如下几个关键字结束:

q error code [reason]

q pass

q deliver

(8)vcl_deliver函数

在缓存中找到请求的内容后,发送给客户端前调用此方法。此函数一般以如下几个关键字结束:

q error code [reason]

q deliver

(9)vcl_timeout 函数

此函数在缓存内容到期前调用。一般以如下几个关键字结束:

q discard:表示从缓存中清除该内容。

q fetch

(10)vcl_discard函数

在缓存内容到期后或缓存空间不够时,自动调用该方法,一般以如下几个关键字结束:

q keep:表示将内容继续保留在缓存中。

q discard

5.5 VCL内置全局变量:

公用变量名称    含义

req.backend        指定对应的后端主机

server.ip              表示服务器端IP

client.ip               表示客户端IP

req.request          指定请求的类型,例如GET、HEAD、POST等

req.url                 指定请求的地址

req.proto            表示客户端发起请求的HTTP协议版本

req.http.header   表示对应请求中的http头部信息

req. restarts         表示请求重启的次数,默认最大值为4

Varnish               在向后端主机请求时,可以使用的公用变量如下所示:

公用变量名称 含义

beresp.request 指定请求的类型,例如GET、HEAD等

beresp.url 指定请求的地址

beresp .proto 表示客户端发起请求的HTTP协议版本

beresp .http.header 表示对应请求中的http头部信息

beresp .ttl 表示缓存的生存周期,也就是cache保留多长时间,单位是秒

从cache或者后端主机获取内容后,可以使用的公用变量如下所示:

公用变量名称 含义

obj.status 表示返回内容的请求状态代码,例如200、302、504等

obj.cacheable 表示返回的内容是否可以缓存,也就是说,如果HTTP返回是200、203、300、301、302、404、410等,并且有非0的生存期,则可以缓存

obj.valid 表示是否是有效的HTTP应答

obj.response 表示返回内容的请求状态信息

obj.proto 表示返回内容的HTTP协议版本

obj.ttl 表示返回内容的生存周期,也就是缓存时间,单位是秒

obj.lastuse 表示返回上一次请求到现在的间隔时间,单位是秒

对客户端应答时,可以使用的公用变量如下所示:

公用变量名称 含义

resp.status 表示返回给客户端的HTTP状态代码

resp.proto 表示返回给客户端的HTTP协议版本

resp.http.header 表示返回给客户端的HTTP头部信息

resp.response 表示返回给客户端的HTTP状态信息

5.6 副配置文件调整

通过启动脚本可以看到,varnish在启动的时候会调用启动参数文件 /etc/default/varnish,调整如下:

DAEMON_OPTS="-a :6081 \

-T localhost:6082 \

-n /var/varnish_dir \

-f /etc/varnish/default.vcl \

-S /etc/varnish/secret \

-s file,/var/varnish_dir/varnish_cache.data,5120m \

-u root \

-g root"

-a 程序监听端口

-T 程序管理端口

-f 程序启动定义的VCL规则文件

-S 加密文件

-s file(将缓存在swap上)|malloc(缓存在内存上),缓存文件名,缓存大小

-u 启动用户名

-g 启动用户组

5.7 启动程序:

#service varnish start

由于使用了varnish缓存做代理,所以nginx的反向代理也需要相应调整,只需调整upstream即可:如下:

upstream tornado {

server 127.0.0.1:6081;

}

5.8访问测试:

多点击刷新几次可以,看到已经缓存命中:

5.9 Varnish 状态分析:

几个重要指标:

q “Client connections accepted”表示客户端向反向代理服务器成功发送HTTP请求的总数量。

q "Client requests received"表示到现在为止,浏览器向反向代理服务器发送HTTP请求的累积次数,由于可能会使用长连接,所以这个值一般会大于“Client connections accepted”。

q “Cache hits”表示反向代理服务器在缓存区中查找并且命中缓存的次数。

q “Cache misses”表示直接访问后端主机的请求数量,也就是非命中数。

q “N struct object”表示当前被缓存的数量。

q “N expired objects”表示过期的缓存内容数量。

q “N LRU moved objects”表示被淘汰的缓存内容个数。

从上面的结果可以看到缓存命中率:31/38*100%=81%

5.10 管理varnish日志:

1 通过自带的varnishlog指令可以获得varnish详细的系统运行日志。

2 通过自带的varnishncsa指令得到类似apache的combined输出格式的日志。

root@debian:/etc/logrotate.d# varnishncsa -n /var/varnish_dir/ -w /var/log/varnish/varnish.log

^C

root@debian:/etc/logrotate.d# cat /var/log/varnish/varnish.log

127.0.0.1 - - [12/Sep/2013:13:51:05 +0800] "GET http://10.15.62.202/ HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"

127.0.0.1 - - [12/Sep/2013:13:51:06 +0800] "GET http://10.15.62.202/ HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"

127.0.0.1 - - [12/Sep/2013:13:51:07 +0800] "GET http://10.15.62.202/ HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"

127.0.0.1 - - [12/Sep/2013:13:51:07 +0800] "GET http://10.15.62.202/ HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"

root@debian:/etc/logrotate.d#

下面编写一个名为varnishncsa的shell脚本,每小时生成,

#!/bin/sh

if [ "$1" = "start" ];then

/usr/local/varnish/bin/varnishncsa -n /data/varnish/cache  -f |/usr/sbin/rotatelogs /data/varnish/log/varnish.%Y.%m.%d.%H.log 3600 480 &

elif [ "$1" = "stop" ];then

killall varnishncsa

else

echo $0 "{start|stop}"

fi

由于时间关系,对于日志管理先写到这(有时间可以加强这一块)

5.11 管理varnish缓存

清除所有缓存:

#/usr/bin/varnishadm -T 127.0.0.1:6082ban.url  ^.*$

直观查看varnish的命中率,这里在网上找到了一个php的页面:

<?php

// This is just a code snippet written by Jason "Foxdie" Gaunt, its not meant to be executed, it may work as-is, it may not.

// I freely acknowledge this code is unoptimised but it has worked in practice for 6 months :)

// Lets define our connection details

$adminHost = "127.0.0.1"; // varnish服务器的IP地址

$adminPort = "3500"; // varnish服务器管理端口

// pollServer(str) - this function connects to the management port, sends the command and returns the results, or an error on failure

function pollServer($command) {

global $adminHost, $adminPort;

$socket = socket_create(AF_INET, SOCK_STREAM, getprotobyname("tcp"));

if ((!socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, Array("sec" => "5", "usec" => "0"))) OR (!socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, Array("sec" => "5", "usec" => "0"))))  {

die("Unable to set socket timeout");

}

if (@socket_connect($socket, $adminHost, $adminPort)) {

$data = "";

if (!$socket) {

die("Unable to open socket to " . $server . ":" . $port . "\n");

}

socket_write($socket, $command . "\n");

socket_recv($socket, $buffer, 65536, 0);

$data .= $buffer;

socket_close($socket);

return $data;

}

else {

return "Unable to connect: " . socket_strerror(socket_last_error()) . "\n";

}

}

// byteReduce(str) - this function converts a numeric value of bytes to a human readable format and returns the result

function byteReduce($bytes) {

// Terabytes

if ($bytes > 1099511627776) {

return round($bytes / 1099511627776) . "TB";

}

else if ($bytes > 1073741824) {

return round($bytes / 1073741824) . "GB";

}

else if ($bytes > 1048576) {

return round($bytes / 1048576) . "MB";

}

else if ($bytes > 1024) {

return round($bytes / 1024) . "KB";

}

else {

return $bytes . "B";

}

}

// This is where our main code starts

echo "<div class=\"inner\"><br />Statistics since last reset:<ul>";

$stats = pollServer("stats");

if (substr($stats, 0, 3) == "200") { // If request was legitimate

// Clear all excessive white space and split by lines

$stats = preg_replace("/ {2,}/", "|", $stats);

$stats = preg_replace("/\n\|/", "\n", $stats);

$statsArray = explode("\n", $stats);

// Removes the first call return value and splits by pipe

array_shift($statsArray);

$statistics = array();

foreach ($statsArray as $stat) {

@$statVal = explode("|", $stat);

@$statistics[$statVal[1]] = $statVal[0];

}

unset($stats, $statsArray, $stat, $statVal);

// Start outputting statistics

echo "<li>" . $statistics["Client connections accepted"] . " clients served over " . $statistics["Client requests received"] . " requests";

echo "<li>" . round(($statistics["Cache hits"] / $statistics["Client requests received"]) * 100) . "% of requests served from cache";

echo "<li>" . byteReduce($statistics["Total header bytes"] + $statistics["Total body bytes"]) . " served (" . byteReduce($statistics["Total header bytes"]) . " headers, " . byteReduce($statistics["Total body bytes"]) . " content)";

// The following line is commented out because it only works when using file storage, I switched to malloc and this broke

// echo "<li>" . byteReduce($statistics["bytes allocated"]) . " out of " . byteReduce($statistics["bytes allocated"] + $statistics["bytes free"]) . " used (" . round(($statistics["bytes allocated"] / ($statistics["bytes allocated"] + $statistics["bytes free"])) * 100) . "% usage)";

}

else {

echo "Unable to get stats, error was: \"" . $stats;

}

echo "</ul></div>";

?>

转载于:https://blog.51cto.com/yxmsama/1378550

基于python的web应用(二)相关推荐

  1. w3af 基于Python的Web应用扫描器

    全称"Web Application Attack and Audit Framework"--Web应用程序攻击审计框架.W3af是一个基于Python的Web应用扫描器.W3a ...

  2. 学习《Flask Web开发:基于Python的Web应用开发实战》分享

    学习<Flask Web开发:基于Python的Web应用开发实战>分享一直在说学习Python,对同事,对朋友,都说我正在学习Python,这无形给自己一定的压力,促使自己要去学习,进步 ...

  3. 《FlaskWeb开发:基于Python的Web应用开发实战》笔记

    开源库的cdn加速 可以在这里直接搜索复制script链接 https://www.bootcdn.cn/ requirements.txt文件的生成与使用 生成requirements文件:$ pi ...

  4. flask web开发:基于python的web应用开发实战_在知乎上学 Python Web 开发篇

    通知: 1. 最近我们将进行2期学习小组,面向完全零基础的Python入门学习小组已经开始,第一次任务的讨论将于明晚(15号)进行,现在上车还来得及 2. 另有一期数据可视化小组将于年前启动,第一次讨 ...

  5. 《Flask Web开发:基于Python的Web应用开发实战》笔记(原创)

    内容提要 在学习"狗书"<Flask Web开发:基于Python的Web应用开发实战>的过程中,一直遇到各种各样的坑.该书的第一部分是"Flask简介&qu ...

  6. 《Flask Web开发——基于Python的Web应用开发实践》一字一句上机实践(上)

    目录 前言 第1章 安装 第2章 程序的基本结构 第3章 模板 第4章 Web表单 第5章 数据库 第6章 电子邮件 第7章 大型程序的结构 前言 学习Python也有一个半月时间了,学到现在感觉还是 ...

  7. 《Flask Web开发——基于Python的Web应用开发实践》一字一句上机实践(下)

    目录 前言 第8章 用户认证 第9章 用户角色 第10章 用户资料 第11章 博客文章 第12章 关注者 第13章 用户评论 第14章 应用编程接口   前言 第1章-第7章学习实践记录请参见:< ...

  8. Flask Web开发:基于Python的Web应用开发实战

    <Flask Web开发:基于Python的Web应用开发实战> 虽然简单的网站(Flask+Python+SAE)已经上线,但只是入门.开发大型网站,系统地学习一遍还是有必要的. 201 ...

  9. 基于python的数据分析毕业设计-基于python的Web大数据采集和数据分析

    肖乐 丛天伟 严卫 摘要:该设计使用python语言作为开发语言,主要采用了两个框架:Scrapy和Django,用Scrapy来实现数据的采集技术,让数据采集效率更高,错误率低等:用Django来实 ...

  10. python web开发框架 支持windows_基于Python的Web开发框架研究_曾浩

    INDUSTRY 计算 机 与 信息 技术 2011 年 8 月 第 8 期 ( 总第 153 期 ) 1 前言 Python 是 一 种开 发 效 率较 高的 语言 , 因此 比较 适 合需求 快 ...

最新文章

  1. 使用Python+OpenCV进行图像处理之入门教程
  2. java通过异常处理错误_java 通过异常处理错误
  3. [Abp 源码分析]权限验证
  4. 重启开源,分享无限--微软面试187题精选
  5. Mysql数据库设计规范之四数据库操作行为规范
  6. Java对象toString()方法
  7. 程序员眼中的统计学(3)】概率计算:把握机会
  8. 使用iOS AirPrint 让你的APP轻松实现打印功能
  9. 电脑网速慢怎么办?手把手教你提升网速
  10. cmos电路多余输入端能否悬空_CMOS电路多余输入端悬空会造成逻辑混乱,可以这样处理!...
  11. dell服务器双系统切换,戴尔笔记本双系统在不关机的状况下怎么转换另外一个系统?...
  12. oracle 错误 20001,LANG=c 引发的 ORA-20001 问题
  13. 【Codeforces613D】Kingdom and its Cities【虚树】【Tree DP】
  14. 安装pyqt5时报错Preparing metadata (pyproject.toml) ... error
  15. NB-IOT电信云北向开发,电信天翼物联网平台对接应用服务
  16. Python:利用高德API获取公交路线并可视化
  17. Android4.0 SDK新功能详解
  18. 计算机无线网卡,电脑如何无线上网 电脑无线网卡买什么好
  19. 在Word中引用参考文献
  20. Build Instructions (Windows) – The Chromium Projects

热门文章

  1. ueditor上传大容量视频报http请求错误的解决方法
  2. jquery原型方法map的使用和源码分析
  3. 使用 CodeIgniter 框架快速开发 PHP 应用(四)
  4. 就等android了
  5. IPv4地址何去何从 IPv6不向下兼容的尴尬
  6. 【EXLIBRIS】图洛克《收入再分配的经济学》中译本序 【ZZ】
  7. [Delphi]怎样访问Internet Explorer中的WebBrowser
  8. 3 描述android的组件,Android基础------Intent组件
  9. php网站用框架与不用的区别,做前端网页是不是必须要用网页框架
  10. OCP最新题库052考题解析及答案-第37题