Apache的mod_bandwidth模块提供了一种在响应输出阶段控制传输速率的手段。当服务器向外发送大文件时,如果不做任何限制,单连接可能会占满全部上行带宽,影响其他用户的正常请求。mod_bandwidth通过注册输出过滤器,对已发送的字节数进行统计,并根据设定的速率决定是否需要延迟发送,从而将整体传输速度压制在目标范围内。

这个模块最初面向Apache 1.3系列,后来也有针对Apache 2.x的移植版本。虽然新版本Apache自带的mod_ratelimit也能实现类似功能,但mod_bandwidth在一些老旧系统或定制环境中仍然被使用,而且它支持按目录、按文件类型甚至按远程地址进行差异化限速,配置思路直接,适合运维人员快速落地。
mod_bandwidth的工作原理
mod_bandwidth的核心逻辑并不复杂。它在Apache的输出过滤器链中插入自己的处理函数,每当响应数据需要向下游发送时,模块会先检查当前连接的配额使用情况。模块维护每个连接已发送的字节数和时间戳,利用时间差与预设速率计算出允许发送的数据量。如果已经超出配额,模块会让连接进入短时间的等待状态,然后继续发送下一段数据。这种方式不是一次性把文件读入内存再慢慢吐出去,而是在发送每一块数据时动态判断,因此内存占用相对可控。
限速的粒度取决于配置参数。模块支持全局默认速率、按目录覆盖速率、按文件大小分段限速,还可以针对特定客户端地址取消限制。配置项通常写在httpd.conf或对应的虚拟主机配置中。例如设置全局带宽为100KB/s时,所有匹配到的请求都会共享这个速度上限;而如果针对某个目录单独设置了50KB/s,该目录下的文件传输则会进一步收紧。需要注意的是,这里的速率单位是字节/秒,不是比特/秒,很多新手容易把10KB/s与80kbps混为一谈,实际前者是后者的约八分之一。
另外,mod_bandwidth对动态脚本产生的内容是否生效存在限制。如果响应经过其他过滤器处理,或者数据已经全部缓冲,模块可能无法准确控制速率。对于PHP、Python等生成的流式输出,效果取决于响应头是否包含Content-Length以及是否使用了输出缓冲。实践中建议将限速重点放在静态资源和大文件下载路径上。
编译安装mod_bandwidth
如果当前Apache没有内置mod_bandwidth,需要从源码编译。早期源码包可以在Apache模块仓库中找到,比如mod_bandwidth.c文件。编译前确认系统安装了Apache开发工具apxs,通常包含在httpd-devel或apache2-dev包中。使用apxs编译的命令非常简单:
apxs -i -a -c mod_bandwidth.c
这条命令会自动完成编译、安装并修改httpd.conf加载模块。如果没有自动加载成功,可以手动在配置文件中添加语句。
LoadModule bandwidth_module modules/mod_bandwidth.so
需要注意的是,Apache 2.4之后模块API有变化,一些老版本mod_bandwidth源码可能无法直接编译,需要打补丁或寻找适配版本。编译完成后重启Apache使模块生效。可以使用httpd -M命令查看模块列表中是否出现bandwidth_module,以确认加载成功。对于使用Windows二进制包的场景,需要下载对应版本的编译好的mod_bandwidth.so文件,并将其放到modules目录下,再在httpd.conf中加入LoadModule指令。
常用配置参数与限速策略
mod_bandwidth的主要配置指令包括BandWidthModule、BandWidth、BandWidthPulse和LargeFileLimit。下面表格整理了这些参数的用途。
| 参数 | 作用 | 示例 |
|---|---|---|
| BandWidthModule | 启用或禁用模块 | BandWidthModule On |
| BandWidth | 设置限速值及作用范围 | BandWidth all 10240 |
| BandWidthPulse | 检查时间片,单位微秒 | BandWidthPulse 1000 |
| LargeFileLimit | 大文件阈值及单独限速 | LargeFileLimit * 100 50000 |
BandWidth指令的格式比较灵活。第一个参数通常是匹配范围,可以是all表示所有请求,也可以是具体的客户端IP、网段或主机名。第二个参数是速率,单位字节/秒。例如BandWidth all 10240表示全局所有请求限速10KB/s。BandWidthPulse控制模块判断速率的频率,数值越小,限速越平滑,但CPU占用会略高。一般保持默认1000微秒即可。
LargeFileLimit用于对大文件实施不同策略。其语法为LargeFileLimit 文件类型 阈值 限速值,文件类型可以使用通配符,例如*表示所有文件,阈值的单位是KB。比如LargeFileLimit *.zip 500 20480表示下载zip格式且大小超过500KB的文件时限速20KB/s。这个指令可以灵活地对视频、压缩包等大体积资源进行单独控制,避免小文件也受到不必要的速度压制。
实战:按目录与文件类型差异化限速
假设一个网站的下载目录位于/var/www/html/downloads,其中包含软件包和视频文件。需求是:全局默认不限速,但下载目录整体限制在80KB/s;视频文件超过10MB时限速120KB/s;内部测试IP地址192.168.1.100完全不受限。配置片段如下:
<IfModule bandwidth_module>
BandWidthModule On
BandWidthPulse 1000
# 全局默认不限速,实际上省略或设为0
BandWidth all 0
# 内部测试机不受限
BandWidth 192.168.1.100 0
# 下载目录整体限速80KB/s
<Directory "/var/www/html/downloads">
BandWidth all 81920
</Directory>
# 视频文件超过10MB时限速120KB/s
LargeFileLimit *.mp4 10240 122880
LargeFileLimit *.mkv 10240 122880
</IfModule>
这段配置里BandWidth all 0表示不限制速率,0在模块中代表关闭限速。针对目录的限速会覆盖全局设置,因此进入/var/www/html/downloads的请求会按照80KB/s执行。同时大文件规则独立生效,视频文件超过10MB后速度会进一步降到120KB/s。注意目录限速和大文件限速是叠加关系还是覆盖关系,取决于模块版本和指令顺序,部署前建议在测试环境中实际下载验证。
如果希望所有图片都不限速,而只有压缩包限速,可以写成LargeFileLimit *.jpg 0 0之类的规则,但要注意不同版本的模块对通配符匹配的顺序敏感。建议将更具体的规则放在前面。
常见问题与替代方案
mod_bandwidth的一个常见问题是它对动态内容支持不完善。如果站点大量使用PHP输出文件流,限速效果可能时好时坏。原因是动态脚本可能先一次性生成全部内容再发送,输出过滤器无法在生成阶段介入,或者响应没有明确的Content-Length导致模块无法预判总数据量。针对这种情况,可以考虑在应用层实现限速,例如PHP读取文件时手动sleep,或者使用Nginx的limit_rate指令来做反向代理层的控制。
另一个问题是模块与压缩模块的交互。如果启用了mod_deflate,响应数据先被压缩再交给mod_bandwidth,那么限速计算的是压缩后的流量,而用户实际下载的是压缩前大小,可能造成限速不一致。如果把mod_bandwidth放在压缩过滤器之前,则能对原始数据限速,但配置顺序比较讲究,新手容易踩坑。通常可以通过调整输出过滤器顺序解决,但Apache的过滤器链顺序调整并不直观。
在Apache 2.4及以上版本中,官方提供了mod_ratelimit模块,其配置更简单,直接使用SetOutputFilter RATE_LIMIT和SetEnv rate-limit 400即可实现每连接400KB/s的限速。不过mod_ratelimit无法像mod_bandwidth那样按文件类型或目录进行复杂规则匹配,只支持基于环境变量的全局或局部设置。如果维护的是旧系统,mod_bandwidth仍然是可行的选择;如果是新部署,优先考虑mod_ratelimit或前置Nginx做限速,维护成本更低。
Apache限速mod_bandwidth带宽控制修改时间:2026-10-01 02:08:18