必须启用mod_logio模块并用%o字段统计带宽,%o是socket层实际发送的总字节数,含响应头、压缩内容和chunked分隔符;默认%b不准确。

要准确监控网站带宽消耗,不能只看默认日志里的 %b(响应体字节数),它不包含响应头、压缩后体积、chunked 分隔符等真实发出的数据。必须启用 mod_logio 模块,用 %O 字段——这才是服务器 socket 层实际发送的总字节数,是带宽统计的可靠依据。
确认并启用 mod_logio 模块
模块未加载时,%I 和 %O 在日志中恒为 -,不是配置问题,而是功能不可用。
- Debian/Ubuntu 系统:运行
apache2ctl -M | grep logio,看到logio_module (shared)才算成功;若无输出,执行a2enmod logio && systemctl reload apache2 - RHEL/CentOS 系统:运行
httpd -M | grep logio,若无结果,编辑/etc/httpd/conf/httpd.conf,取消#LoadModule logio_module modules/mod_logio.so的注释,再重载服务 - 验证方式:临时在 LogFormat 中加入
%I %O,访问一次页面,检查日志对应行是否输出数字而非- -
为每个站点单独配置带宽日志格式
不能复用全局 common 或 combined 格式——它们不含 %I/%O,也无法区分站点流量。必须在每个 <virtualhost></virtualhost> 块内定义专属格式:
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
- 写入如下配置(示例):
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" site_a_bandwidth -
%I是客户端发来的原始 HTTP 请求字节数(含请求头、CRLF、请求体) -
%O是 Apache 实际调用send()发出的响应总字节数(含响应头、gzip 后内容、chunked 分隔符、代理追加头等) - 二者均为纯整数,单位字节,无逗号、无单位,适合脚本直接解析
绑定独立日志路径并实时提取静态资源带宽
多个站点必须使用不同日志文件,否则数据混杂、无法归因:
- 在同个
<virtualhost></virtualhost>块中添加:CustomLog /var/log/apache2/example.com-bandwidth.log site_a_bandwidth - 路径需确保 Apache 进程有写权限(如
chown root:www-data /var/log/apache2/) - 实时统计静态资源(JS/CSS/PNG 等)的带宽消耗:
tail -f /var/log/apache2/example.com-bandwidth.log | awk '$7 ~ /\.(js|css|png|jpg|webp|woff2?|ttf|svg)$/ && $6 == 200 {sum += $12} END {print "Static KB:", int(sum/1024)}'
(注意:列数以你 LogFormat 中字段顺序为准,%O通常是第 12 列)
理解 %O 的实际含义与常见偏差
%O 不等于 Content-Length,也不等于浏览器最终接收量,但它最贴近服务器侧真实发出量:
- 启用
mod_deflate时:%O是压缩后大小,%b却仍是原始大小或- - 走反向代理(如
mod_proxy)时:%O包含额外响应头(如X-Forwarded-For)和 chunked 编码标记(如"5a\r\n") - 流式响应(SSE、大文件下载)场景下:
%O可能只记录日志写入时刻已发出的部分,不是最终总量 - HTTP/2 下仍有效,但数值更紧凑(无 HTTP/1.1 的换行与空格开销)










