基于python的web应用(二)
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应用(二)相关推荐
- w3af 基于Python的Web应用扫描器
全称"Web Application Attack and Audit Framework"--Web应用程序攻击审计框架.W3af是一个基于Python的Web应用扫描器.W3a ...
- 学习《Flask Web开发:基于Python的Web应用开发实战》分享
学习<Flask Web开发:基于Python的Web应用开发实战>分享一直在说学习Python,对同事,对朋友,都说我正在学习Python,这无形给自己一定的压力,促使自己要去学习,进步 ...
- 《FlaskWeb开发:基于Python的Web应用开发实战》笔记
开源库的cdn加速 可以在这里直接搜索复制script链接 https://www.bootcdn.cn/ requirements.txt文件的生成与使用 生成requirements文件:$ pi ...
- flask web开发:基于python的web应用开发实战_在知乎上学 Python Web 开发篇
通知: 1. 最近我们将进行2期学习小组,面向完全零基础的Python入门学习小组已经开始,第一次任务的讨论将于明晚(15号)进行,现在上车还来得及 2. 另有一期数据可视化小组将于年前启动,第一次讨 ...
- 《Flask Web开发:基于Python的Web应用开发实战》笔记(原创)
内容提要 在学习"狗书"<Flask Web开发:基于Python的Web应用开发实战>的过程中,一直遇到各种各样的坑.该书的第一部分是"Flask简介&qu ...
- 《Flask Web开发——基于Python的Web应用开发实践》一字一句上机实践(上)
目录 前言 第1章 安装 第2章 程序的基本结构 第3章 模板 第4章 Web表单 第5章 数据库 第6章 电子邮件 第7章 大型程序的结构 前言 学习Python也有一个半月时间了,学到现在感觉还是 ...
- 《Flask Web开发——基于Python的Web应用开发实践》一字一句上机实践(下)
目录 前言 第8章 用户认证 第9章 用户角色 第10章 用户资料 第11章 博客文章 第12章 关注者 第13章 用户评论 第14章 应用编程接口 前言 第1章-第7章学习实践记录请参见:< ...
- Flask Web开发:基于Python的Web应用开发实战
<Flask Web开发:基于Python的Web应用开发实战> 虽然简单的网站(Flask+Python+SAE)已经上线,但只是入门.开发大型网站,系统地学习一遍还是有必要的. 201 ...
- 基于python的数据分析毕业设计-基于python的Web大数据采集和数据分析
肖乐 丛天伟 严卫 摘要:该设计使用python语言作为开发语言,主要采用了两个框架:Scrapy和Django,用Scrapy来实现数据的采集技术,让数据采集效率更高,错误率低等:用Django来实 ...
- python web开发框架 支持windows_基于Python的Web开发框架研究_曾浩
INDUSTRY 计算 机 与 信息 技术 2011 年 8 月 第 8 期 ( 总第 153 期 ) 1 前言 Python 是 一 种开 发 效 率较 高的 语言 , 因此 比较 适 合需求 快 ...
最新文章
- 使用Python+OpenCV进行图像处理之入门教程
- java通过异常处理错误_java 通过异常处理错误
- [Abp 源码分析]权限验证
- 重启开源,分享无限--微软面试187题精选
- Mysql数据库设计规范之四数据库操作行为规范
- Java对象toString()方法
- 程序员眼中的统计学(3)】概率计算:把握机会
- 使用iOS AirPrint 让你的APP轻松实现打印功能
- 电脑网速慢怎么办?手把手教你提升网速
- cmos电路多余输入端能否悬空_CMOS电路多余输入端悬空会造成逻辑混乱,可以这样处理!...
- dell服务器双系统切换,戴尔笔记本双系统在不关机的状况下怎么转换另外一个系统?...
- oracle 错误 20001,LANG=c 引发的 ORA-20001 问题
- 【Codeforces613D】Kingdom and its Cities【虚树】【Tree DP】
- 安装pyqt5时报错Preparing metadata (pyproject.toml) ... error
- NB-IOT电信云北向开发,电信天翼物联网平台对接应用服务
- Python:利用高德API获取公交路线并可视化
- Android4.0 SDK新功能详解
- 计算机无线网卡,电脑如何无线上网 电脑无线网卡买什么好
- 在Word中引用参考文献
- Build Instructions (Windows) – The Chromium Projects
热门文章
- ueditor上传大容量视频报http请求错误的解决方法
- jquery原型方法map的使用和源码分析
- 使用 CodeIgniter 框架快速开发 PHP 应用(四)
- 就等android了
- IPv4地址何去何从 IPv6不向下兼容的尴尬
- 【EXLIBRIS】图洛克《收入再分配的经济学》中译本序 【ZZ】
- [Delphi]怎样访问Internet Explorer中的WebBrowser
- 3 描述android的组件,Android基础------Intent组件
- php网站用框架与不用的区别,做前端网页是不是必须要用网页框架
- OCP最新题库052考题解析及答案-第37题