上周五下午,我正悠哉地喝着咖啡,突然客户电话打进来:“网站打不开了,卡得像幻灯片!”我赶紧切到宝塔面板,一看CPU飙到98%,内存也快爆了,第一反应:被CC攻击了?赶紧查日志,结果发现是GoAccess实时日志分析插件在疯狂吃资源——但这不是最坑的,最坑的是,我装了GoAccess之后,连MySQL都跟着崩了。
先说第一个坑:编译安装时的“隐形炸弹”
我习惯用宝塔的“软件商店”一键安装GoAccess,但别高兴太早,商店里那个版本是阉割版,很多关键功能不支持,比如GeoIP地理定位、国家/地区筛选,所以我决定自己编译安装。
宝塔面板+GoAccess,你以为装个插件就完事了?坑我都替你踩过了
结果三连崩:第一次编译,提示缺少libmaxminddb-dev,apt安装后重试,又报openssl版本冲突,等我把依赖全装上,编译到一半,云服务器直接OOM(内存溢出)——阿里云2核4G的小机子扛不住编译过程,我当时看着SSH连接断开的提示,真想砸键盘。
解决方案: 编译前先执行free -h看剩余内存,小于600MB就别硬扛了,用宝塔的swap插件开2G虚拟内存,或者干脆用docker版GoAccess,后来我果断切到Docker一条命令搞定,省得折腾依赖。
第二个坑:Nginx日志格式不匹配,分析结果全乱码
编译安装完GoAccess后,我美滋滋地执行:
goaccess /www/wwwlogs/你的站点.log -o report.html --log-format=COMBINED
结果页面出来,全是乱码和错误计数,IP显示成乱码,URL路径带一堆反斜杠,访问量统计完全不对,我检查了Nginx配置,发现宝塔默认的日志格式是:
log_format combined_realip '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $http_x_forwarded_for';
问题就出在最后一节$http_x_forwarded_for——GoAccess默认的COMBINED格式根本不认这个字段,导致解析错位,解决方法是自定义log-format:
goaccess /www/wwwlogs/你的站点.log -o report.html --log-format='%h - %^ [%d:%t %^] "%r" %s %b "%R" "%u" "%^"'
注意:%h是IP,%d和%t是日期时间,%r是请求,%s是状态码,%b是字节数,%R是referer,%u是user-agent,后面那个就是用来跳过$http_x_forwarded_for的“占位符”。别问我怎么知道的,我对着报错截图盯了半小时才找到规律。
第三个坑:实时分析导致磁盘IO爆炸
生成静态报告没问题,但我想用实时模式(--real-time-html)搞个仪表盘,结果一开启,服务器负载从0.5直接飙到8.0,我sudo iotop一看,GoAccess进程在疯狂读写日志文件,每秒触发好几次磁盘IO,直接拖垮了MySQL的读写性能,导致WordPress站点报“数据库连接错误”。
排查思路: 先停掉GoAccess,用strace -p <pid>追踪系统调用,发现它在不断inotify监听日志文件变化,每次变化都重新解析整个文件,而不是增量处理,对于每天几十万访问量的站点,这就是磁盘杀手。
解决方案: 不用实时模式,改用crontab定时生成,每5分钟跑一次:
*/5 * * * * /usr/bin/goaccess /www/wwwlogs/站点.log -o /www/wwwroot/站点/report.html --log-format='自定义格式' --no-query-string --anonymize-ip
再加个--anonymize-ip,把IP末位替换成“xxx”,既保护用户隐私,又减少数据量。磁盘IO从90%降到了5%以下。
第四个坑:GeoIP数据库配置错误导致崩溃
为了看访客来源国家,我下载了GeoLite2-Country.mmdb,结果执行时直接报段错误(Segmentation fault),查了GitHub issue才知道,GoAccess 1.6以上版本对GeoIP2数据库路径有权限要求,不能放在root目录,必须放在/usr/share/GeoIP/下,且文件属主要改成www用户。
sudo mkdir -p /usr/share/GeoIP/ sudo cp GeoLite2-Country.mmdb /usr/share/GeoIP/ sudo chown www:www /usr/share/GeoIP/GeoLite2-Country.mmdb
然后再在GoAccess配置里指定geoip-database /usr/share/GeoIP/GeoLite2-Country.mmdb,才正常显示地图分布。
预防建议:别让运维工具变成“运维炸弹”
- 测试环境先跑三天:GoAccess装上后,先在测试站观察CPU和磁盘IO,确认正常再上生产。
- 日志切割必须配合:宝塔的日志切割默认每天一个日志文件,但GoAccess默认读最新文件,如果不设置
--log-file指向带日期的文件,第二天它会读一个被重命名的旧日志,导致重复统计,我用logrotate配置了copytruncate,确保GoAccess始终读的是活动日志。 - 磁盘告警必须加上:GoAccess生成HTML报告时,如果日志量巨大(比如超过500MB),生成的页面可能有100MB以上,直接打爆磁盘,我在宝塔计划任务里加了个脚本:如果
/www/wwwlogs/目录占用超过80%,就自动压缩历史日志并清理7天前的。
最后说一句,GoAccess是个好东西,分析日志比AWStats快10倍,但宝塔面板用户尤其要小心日志格式和磁盘IO,别像我一样,一个统计插件装完,MySQL先挂了——那截图我至今留着,当壁纸提醒自己:运维没有银弹,每个工具背后都有要填的坑。



发表评论