当前位置: 首页 > 编程日记 > 正文

awstats CGI模式下动态生成页面缓慢的改进

本文可以看做是 多server多站点情况下awstats日志分析 这篇文章的下篇,在使用过程中发现awstats在cgi模式下动态生成分析报告慢的问题 (尤其是有些站点每天两个多G的日志,查看起来简直是在考验人的耐性),本文分享一种改造这个缺点的思路。

首先再来总结下awstats的处理过程以及查看分析结果的两种方式,来看官方版说明:

Process logs: Building/updating statistics database,建立/更新统计数据库(包含统计结果的文本文件)命令如下
  perl awstats.pl -config=mysite -update
Run reports: Building and reading reports(生成并阅读报告)
1.The first option is to build the main reports, in a static HTML page, from the command line, using the following syntax
  第一种方式,通过命令行生成html文件,然后浏览器展示。命令如下
  perl awstats.pl -config=mysite -output -staticlinks > awstats.mysite.html
2.The second option is to dynamically view your statistics from a browser.  To do this, use the URL:
  第二种方式,通过如下的url“动态”的生成该站点的分析报告
  http://www.myserver.mydomain/awstats/awstats.pl?config=mysite

总体思路就是,既然“动态生成”这个过程耗时,那就在服务器上定时通过curl 请求每个站点对应的url将生成的html页面存储到特定位置,然后浏览器访问时直接读取html文件即可(可能有同学要问了,这么费事,那为啥不直接用上面的第一种方式,用awstats.pl提供的参数直接生成html文件呢?这也就回归到上篇文章中讨论过的两种方式的差别了,awstats.pl生成的静态html页面从易用性和美观性都不如通过CGI动态生成的html页面)

思路有了,接下来就是“尝试”和“分析特征”。我们直接以

curl  -o /tmp/mysite.html http://www.myserver.mydomain/awstats/awstats.pl?config=mysite

得到的页面源代码如下

<html >
<head>
<meta name="generator" content="AWStats 7.4 (build 20150714) from config file awstats./usr/local/awstats/etc/www.conf.conf (http://www.awstats.org)">
<meta name="robots" content="noindex,nofollow">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta http-equiv="expires" content="Wed Apr 27 11:09:58 2016">
<meta http-equiv="description" content="Awstats - Advanced Web Statistics for www.dddd.com (2015-08) - main">
<title>Statistics for www.mysite.com (2015-08) - main</title>
</head><frameset cols="240,*">
<frame name="mainleft" src="awstats.pl?config=mysite&amp;framename=mainleft" noresize="noresize" frameborder="0" />
<frame name="mainright" src="awstats.pl?config=mysite&amp;framename=mainright" noresize="noresize" scrolling="yes" frameborder="0" />
<noframes><body>Your browser does not support frames.<br />
You must set AWStats UseFramesWhenCGI parameter to 0
to see your reports.<br />
</body></noframes>
</frameset></html>

可以看到动态生成的页面实际上是一个包含了两个frame(mainleft和mainright)的html文件,也就是说,如果我们想还原一个动态生成的报告页面,需要通过如下三条命令来生成对应的三个文件

curl -s -o main.html "http://www.myserver.mydomain/awstats/awstats.pl?config=mysite"    #取得主页面
curl -s -o left.html "http://www.myserver.mydomain/awstats/awstats.pl?config=mysite&framename=mainleft"    #取得左frame
curl -s -o right.html "http://www.myserver.mydomain/awstats/awstats.pl?config=mysite&framename=mainright"    #取得右frame

然后,需要在 main.html中修改mainleft和mainright两个frame的src属性,将其指定到我们生成的left.html和right.html。如此我们就实现了将动态页面静态化(实际上是把动态生这个等待时间放到脚本里定时执行了)。

接下来,就是具体的实现过程了,涉及到对上篇文章中“cron_awstats_update.sh”脚本的改进,修改后的脚本内容如下(注释还算丰富,也能帮助理解思路)

#!/bin/sh#awstats日志分析
basedir=/usr/local/awstats-7.4
date_y_m=$(date +%Y%m -d '1 day ago')    #因为该脚本是第二天凌晨分析前一天的日志
year=`echo ${date_y_m:0:4}`
month=`echo ${date_y_m:4:5}`cd $basedir
#循环更新所有站点日志统计信息
echo -e "\e[1;31m-------`date "+%F %T"`    开始处理---------\n\e[0m" >>logs/cron.log
for i in `ls result/`
doecho -e "\e[1;32m -----`date "+%F %T"`  处理 $i 日志-----\e[0m" >>logs/cron.logperl wwwroot/cgi-bin/awstats.pl -config=etc/$i.conf -lang=cn -update &>>logs/cron.log#将动态页面静态化,查看展示页面结构可得:主页面基本没内容,主要靠左右两个frame来生成内容#所以可以将每一个站点的展示页分为三部分来缓存echo -e "\e[1;32m -----`date "+%F %T"` 分析 $i 生成静态页面-----\n\e[0m" >>logs/cron.logcd wwwrootif [ ! -d $i/$date_y_m ];then mkdir -p $i/$date_y_m;ficd $i/$date_y_mcurl -s -o main.html\    #主页面"http://127.0.0.1/cgi-bin/awstats.pl?month=$month&year=$year&output=main&config=/usr/local/services/awstats-7.4/etc/$site.conf&framename=index"curl -s -o left.html\    #左页面"http://127.0.0.1/cgi-bin/awstats.pl?month=$month&year=$year&output=main&config=/usr/local/services/awstats-7.4/etc/$site.conf&framename=mainleft"curl -s -o right.html\    #右页面"http://127.0.0.1/cgi-bin/awstats.pl?month=$month&year=$year&output=main&config=/usr/local/services/awstats-7.4/etc/$site.conf&framename=mainright"#修改main.html里关于左右两个frame的引用sed -i -e 's/awstats.pl.*left/left.html/g' -e 's/awstats.pl.*right/right.html/g' main.html#接下来修改上面三个文件中的超链接部分sed -i -e 's#awstats.pl#http://123.123.123.123/cgi-bin/awstats.pl#g'\    #123.123.123.123为公网ip-e 's/charset=.*/charset=utf-8">/g'\-e 's/lang="cn"//g'\main.html left.html right.html#剩下的事就是去修改nginx index.html页面的超链接指向cd $basedir
done
echo -e "\e[1;33m-------`date "+%F %T"`  处理完成---------\n\e[0m" >>logs/cron.log#####
#原始请求样式,
#http://127.0.0.1/cgi-bin/awstats.pl?config=/usr/local/awstats-7.4/etc/heibai.conf 这个url访问该站点最新数据,会产生下面三个请求
#http://127.0.0.1/cgi-bin/awstats.pl?config=/usr/local/awstats-7.4/etc/heibai.conf
#http://127.0.0.1/cgi-bin/awstats.pl?config=/usr/local/awstats-7.4/etc/heibai.conf&framename=mainleft
#http://127.0.0.1/cgi-bin/awstats.pl?config=/usr/local/awstats-7.4/etc/heibai.conf&framename=mainright
#####
#选择年月之后,会产生如下三个请求
#http://127.0.0.1/cgi-bin/awstats.pl?month=05&year=2016&output=main&config=%2Fusr%2Flocal%2Fawstats-7.4%2Fetc%2Fheibai.conf&framename=index 经过编码的
#http://127.0.0.1/cgi-bin/awstats.pl?month=05&year=2016&output=main&config=/usr/local/awstats-7.4/etc/heibai.conf&framename=mainleft
#http://127.0.0.1/cgi-bin/awstats.pl?month=05&year=2016&output=main&config=/usr/local/awstats-7.4/etc/heibai.conf&framename=mainright
#####

经过脚本处理之后,在wwwroot目录下,站点目录与html文件会是这个样子

wKioL1cqEOqRhvxzAAAV65JUv4I766.png

到此,我们对上篇文章中的nginx配置部分做相应修改后就可以通过如下url来访问了

http://www.myserver.mydomain/www/201605    #表示www站2016年5月的统计页面

但是,改造到这里并不算完,在动态生成的页面里,有选择年和月的下拉框,可以查看指定年月的统计页面,如下图

wKioL1cp_hmxFR28AAAMlr8RRXg686.png

这个功能会产生一个如下的请求
http://www.myserver.mydomain/cgi-bin/awstats.pl?month=04&year=2016&output=main&config=www.conf&framename=index

仍然是动态请求(即仍然会慢),但按照我们的设计,每个月应该都已经生成了静态文件,所以是不需要动态生成的。如何将这个功能点修改为也按照上面静态url的格式呢,这里作者首先想到了两个方案:
  一个是通过js获取年和月的值,然后在表单的action处拼出所需的url
  另一个是通过nginx的rewrite来实现
经过尝试和对比,第二种方案更适合这里的场景,因为第一种涉及到对生成的html文件内容进行修改,且不止一处,实现起来啰嗦一些;而第二种方案只需要在nginx里做配置即可(这里如何从nginx获取到参数值并且引用该值算是一个小技巧吧)。

最终,修改之后的nginx配置文件如下

server {listen   800;root /usr/local/awstats/wwwroot;access_log /tmp/awstats_access_log access;error_log /tmp/awstats_nginx.error_log notice;location / {index index.html main.html;}# Static awstats files: HTML files stored in DOCUMENT_ROOT/awstats/location /awstats/classes/ {alias classes/;}location /awstats/css/ {alias css/;}location /awstats/icon/ {alias icon/;}location /awstats-icon/ {alias icon/;}location /awstats/js/ {alias js/;}# Dynamic stats.location ~ ^/cgi-bin/(awredir|awstats)\.pl.* {gzip off;fastcgi_pass 127.0.0.1:9000;fastcgi_param SCRIPT_FILENAME $document_root/cgi-bin/fcgi.php;fastcgi_param X_SCRIPT_FILENAME $document_root$fastcgi_script_name;fastcgi_param X_SCRIPT_NAME $fastcgi_script_name;include fastcgi_params;fastcgi_send_timeout 300;#为了让顶部根据时间筛选功能也能用上之前生成的静态页面, 其中%2F部分为url编码后的/,为了取得站点名if ($query_string ~* "^month=(\d+)&year=(\d+)&output=main&config=.+etc%2F(.+)\.conf&framename=index$") {set $month $1;set $year $2;set $site $3;rewrite  ^/cgi-bin/awstats\.pl  /$site/$year$month? permanent;}}expires 12h;
}


最后一点,不要忘了修改“入口文件”`index.html`哦,js自动生成的超链接要修改,增加及修改下面内容

/*... 省略 ...*/
//一个能计算昨天明天等日期的函数function GetDateStr(AddDayCount) {var dd = new Date();dd.setDate(dd.getDate()+AddDayCount);//获取AddDayCount天后的日期var y = dd.getFullYear();var m = dd.getMonth()+1;//获取当前月份的日期var d = dd.getDate();if (m<10) {return y+"0"+m;    //格式自定义} else {return y+''+m;}}var yesterday=GetDateStr(-1);   //计算昨天日期  格式  201604//向表格填充内容for (var tdid=0;tdid<num;tdid++) {//依顺序获取各td元素var tdnode=document.getElementById(tdid+1);//取出每个域名里的主机名,服务器端配置文件命名方式为 “主机名.conf”var hostname=vhost[tdid].split(".abc",1);//向表格插入域名并且设置超链接tdnode.innerHTML="<a href=\""+hostname+"/"+yesterday+"\">" +vhost[tdid] +"</a>";}/*... 省略 ...*/


主要修改如下图

wKiom1gHghmgIYaYAAEeOgYQVZ8009.png

ok,到这里整个改进过程完毕。每个月份的统计结果的主页面都已经实现了静态化,查看时再也不用经历漫长的等待了!
  PS: 工具再好,也不见得完全适合或者满足自己的需求,大部分情况下作为“软件使用者”的运维同胞,应该有这个意识:不只会用,必要时还能改。共勉!

相关文章:

计算机水平flash试题,计算机flash考试试题

《Flash动画设计》课程考核方案一、考试班级及科目216班 《Flash动画设计》二、考试时间1、考核时间&#xff1a;90分钟2、考试地点&#xff1a;学校计算机3机房3、考核时期&#xff1a;十七、十八周内各课任教师自主选定三、考核形式上机独立完成所有操作。在规定时间内按考核…

CDH大数据集群安全风险汇总

一&#xff0c;风险分为内部和外部 首先内部&#xff1a; CDH大数据集群部署过程中会自动创建以服务命名的用户&#xff0c;如图所示 用户名(login_name)&#xff1a;口令位置(passwd)&#xff1a;用户标识号(UID)&#xff1a;用户组标识号(GID)&#xff1a;注释性描述(users)&…

有界阻塞队列ArrayBlockingQueue和无界阻塞队列LinkedBlockingQueue

ArrayBlockingQueue和LinkedBlockingQueue最大的区别是一个是有界无界&#xff0c;各有优劣。 先看实例代码&#xff1a; main函数起2个线程模拟生成消费者 import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.…

zabbix监控windows 服务器各项性能

Zabbix agent 在windows上安装部署1、 下载与解压地址: http://www.zabbix.com/downloads/2.4.0/zabbix_agents_2.4.0.win.zip解压zabbix_agents_2.4.0.win.zipconf目录存放是agent配置文件 bin文件存放windows下32位和64位安装程序2、 配置与安装2.1 配置zabbix agent相关配…

计算机设备板块超跌,半导体全线拉升,沪指强势突破3600点,午后A股会再次冲高回落吗...

周四开盘沪指开于3585点&#xff0c;和周三收盘价低开了8个点。上午开盘后沪指呈现低开高走的趋势&#xff0c;10点以后沪指持续拉升上涨不但顺利地突破了3600点而且还创了反弹新高。除了沪指以外深市三大股指也是全线翻红&#xff0c;上午A股的三大股指再次全线拉升并且均创了…

docker之基础

一、Docker简介 容器&#xff1a;运行在同一类用户空间上的程序打包在一起&#xff0c;相当于一个集装箱 Docker:码头装运工&#xff1b;把集装箱搬运到该有的位置。 Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器&#xff08;LXC&…

Java一个线程能否结束另一个永不停止的线程

在Java中停止一个线程有三种办法 &#xff1a; 1.正常结束执行&#xff1b; 2.发生异常; 3.被其他线程stop(Java官方不建议) 参考&#xff1a;https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html 为什么Thread.stop弃用…

pxe cobbler ipmi bmc

http://blog.csdn.net/xuensong520/article/details/8922926 http://blog.csdn.net/xuensong520/article/details/8915945 http://www.wenzizone.cn/?p408 #执行外部脚本(后置脚本)vi /var/www/cobbler/ks_mirror/config/autoip.sh #创建脚本&#xff0c;自动设置Linux系统静…

广东电大计算机绘图试题,电大计算机绘图期末复习试题及答案参考小抄.doc

电大计算机绘图期末复习试题及答案参考小抄一、填空题(每小题1.5分&#xff0c;共30分)1&#xff0e;CAD的常用图形输入设备有???鼠标??、数字化仪、图形输入板、光笔、??键盘 等。2&#xff0e;CAD的软件可分为系统软件、支撑软件和???应用软件??? 软件三个层次。…

django07 字符串替换

1. 模板语言&#xff08;字符串替换&#xff09; 1. 母版和继承 1. 什么时候用母版&#xff1f; html页面有重复的代码&#xff0c;把它们提取出来放到一个单独的html文件。 &#xff08;比如&#xff1a;导航条和左侧菜单&#xff09; 2. 子页面如何使用母版&#xff1f; {% e…

【云和恩墨】一次 truncate 核心表衍生的安全管理思考

第一章 一次 truncate 核心表衍生的安全管理思考 云和恩墨 | 2016-05-06 17:56 本文编辑整理来自上周四晚云和恩墨大讲堂 黄嵩 关于数据安全问题的分享。安全问题涉及到信息系统的方方面面&#xff0c;尤其是其核心资产——数据的安全。无论是数据访问控制的裸露&#xff0…

合理估算线程池线程数量

参考《Java并发编程实战》 线程数量计算公式 公式&#xff1a;Nthread Ncpu * Ucpu * &#xff08;1 W/C&#xff09;&#xff0c;各字段含义&#xff1a; Nthreads&#xff1a;线程数量 Ncpu&#xff1a;CPU的数量&#xff0c;Runtime.getRuntime().availableProcessors()…

通过regedt查看计算机密码,win10系统通过注册表设置定时更换密码提醒的处理步骤...

有关win10系统通过注册表设置定时更换密码提醒的操作方法想必大家有所耳闻。但是能够对win10系统通过注册表设置定时更换密码提醒进行实际操作的人却不多。其实解决win10系统通过注册表设置定时更换密码提醒的问题也不是难事&#xff0c;小编这里提示两点&#xff1a; 1、首先在…

苏宁零售云 App 稳定保障实践

1. 背景 苏宁零售云目标T4-T6级市场的业务&#xff0c;定位更靠谱的智慧零售解决方案和零售服务集成商&#xff0c;实战式跨界赋能。苏宁易购TO C的经验丰富&#xff0c;相关的方案很完善&#xff0c;但是零售云TO B相关业务启动后&#xff0c;业务增长迅速&#xff0c;App相关…

小酌重构系列[8]——提取接口

前言 世间唯一“不变”的是“变化”本身&#xff0c;这句话同样适用于软件设计和开发。在软件系统中&#xff0c;模块&#xff08;类、方法&#xff09;应该依赖于抽象&#xff0c;而不应该依赖于实现。 当需求发生“变化”时&#xff0c;如果模块&#xff08;类、方法&#xf…

多线程并发编程需要注意虚假唤醒Spurious wakeup

虚假唤醒 Spurious wakeup 如果等待线程在没有通知被调用的情况下唤醒&#xff0c;则称为Spurious wakeup。 解决方案就是: 使用while条件判断&#xff0c;更好的方案是避免使用wait这种低级的API&#xff0c;而是使用高级的并发工具。 因为这些高级的并发工具都是经过无数…

高中计算机个人总结怎么写,毕业生自我总结范文

毕业生自我总结范文1时光飞逝&#xff0c;三年忙碌而充实的大学生活在一片有序的繁忙中将要过去了&#xff0c;回首过去三年&#xff0c;内心感慨万千。我是20xx年春参加电大机械班的学习&#xff0c;回顾这三年的电大学习之路&#xff0c;饱含了汗水和收获。总结是一面镜子&am…

python - 字符串的格式化输出

# -*- coding:utf-8 -*-project: jiaxyauthor: Jimmyfile: study_2_str.pyide: PyCharm Community Editiontime: 2018-11-01 15:12blog: https://www.cnblogs.com/gotesting/# 字符串s #空字符串# 1:字符串拼接# 1.1:字符串与字符串的拼接用 连接s_1 hellos_2 worlds_3 5…

一个冷僻的知识点try直接返回finally里的设置null其实无效

先看引用类型的代码&#xff1a; import java.util.HashMap; import java.util.Map;public class trycatchefinally {public static void main(String[] args) {System.out.println(getMap().get("KEY"));}public static Map<String, String> getMap() {Map&l…

​身份证工具类

2019独角兽企业重金招聘Python工程师标准>>> 身份证工具类 package com.pqs.common.tools;import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util…

目前常用的服务器端网络操作系统有,目前常用的服务器端网络操作系统是()。...

在一台IP地址为192.168.1.1的Windows Server 2008 R2计算机上安装活动目录&#xff0c;建立一个森林根域test.com&#xff0c;保留默认的域功能级别&#xff0c;同时使该计算机成为域test.com的首台域控制器并承担着DNS服务器和全局编录服务器的角色。  操作步骤&#xff…

如何处理用代码创建SD Sales order时遇到的错误消息KI 180

2019独角兽企业重金招聘Python工程师标准>>> 错误消息KI 180:You must enter a company code for transaction Create sales document 代码: REPORT zcreate_so.DATA: ls_header TYPE bapisdhd1,ls_headerx TYPE bapisdhd1x,lt_bapiret2 LIKE bapiret2 OCCURS …

Flink 基本原理与生产实践分享【入门必读,概念清晰】

Flink 基本原理与生产实践分享【入门必读&#xff0c;概念清晰】 https://zh.wikipedia.org/zh-hans/Apache_Flink Apache Flink是由Apache软件基金会开发的开源流处理框架&#xff0c;其核心是用Java和Scala编写的分布式流数据流引擎。Flink以数据并行和流水线方式执行任意流…

数据库模型设计——主键的设计

在数据库设计时&#xff0c;主要就是对实体和关系的设计&#xff0c;实体表现出来就是表&#xff0c;关系表现出来就是外键。而对于一个表&#xff0c;由两部分组成&#xff1a;主键和属性。主键的简单定义就是表中为每一行数据的唯一标识。其实更准确的说法&#xff0c;每一行…

jsp ajax动态添加数据,jquery Ajax实现Select动态添加数据

jquery Ajax实现Select动态添加数据&#xff0c;具体内容如下1.背景最近在工作中&#xff0c;遇到了一个关于select的问题。一般情况下&#xff0c;select下拉框中的数据都是固定的或者直接在jsp中读取列表值显示。但是&#xff0c;这次要实现select与别的选项框联动&#xff0…

Spring Boot(十一)Redis集成从Docker安装到分布式Session共享

2019独角兽企业重金招聘Python工程师标准>>> 一、简介 Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&#xff0c;并提供多种语言的API&#xff0c;Redis也是技术领域使用最为广泛的存储中间件&#xff0c;它是「…

Java线上问题排障:Linux内核bug引发JVM死锁导致线程假死

Java本质上还是离不开操作系统&#xff0c;一来Java源码是用C/C实现的&#xff0c;二来java进程还是需要依附于操作系统和硬件资源&#xff0c;有时候一些问题是操作系统级别导致的&#xff0c;下面的整个事件是源自一则真实的线上案例。 过程&#xff1a; JVM死锁导致线程不可…

从AdventureWorks学习数据库建模——保留历史数据

在业务需求中&#xff0c;经常需要我们在系统中能够记录历史信息&#xff0c;能够查看到历史变动情况&#xff0c;这时我们可以通过增加开始结束时间字段来记录数据的历史版本。对数据的历史记录主要分为&#xff1a;关系、属性历史&#xff0c;实体历史和变更历史。 关系、属性…

因特网的域名服务器系统的好处,dns域名服务器的作用是什么

大家好&#xff0c;我是智能客服时间君&#xff0c;上述问题将由我为大家进行解答。dns是域名系统 (Domain Name System) 的缩写&#xff0c;该系统用于命名组织到域层次结构中的计算机和网络服务。DNS 命名用于Internet等TCP/IP网络中&#xff0c;通过用户友好的名称查找计算机…

Openssl私建CA

构建私有CA: 在确定配置为CA的服务上生成一个自签证书&#xff0c;并为CA提供所需要的目录及文件即可&#xff1b;步骤&#xff1a; (1) 生成私钥&#xff1b;[rootcentos7 ~]# (umask 077; openssl genrsa -out /etc/pki/CA/private/cakey.pem 4096)Generating RSA priva…