Nginx作为接入层组件,几乎所有业务流量都会经过它。日志文件看似只是请求记录,实际上记录了每个请求的时间、状态码、响应体大小、耗时等信息。把这些数据按时间窗口聚合后,可以得到系统负载的增长曲线。容量规划的核心就是利用这些曲线,判断当前资源还能支撑多久,以及下一次扩容需要提前多久执行。

日志分析不是等到磁盘写满才去看,而是要形成固定频率的采集和计算机制。下面分别从字段选择、趋势指标、预测方法以及自动化脚本几个角度展开。
一、先确定日志里哪些字段对容量判断有用
Nginx默认的combined格式已经包含客户端地址、时间、请求行、状态码、响应大小、Referer和User-Agent,但缺少请求耗时和上游响应时间。对于容量规划来说,状态码和响应大小可以用来计算吞吐量,但是否出现性能瓶颈,更需要$request_time和$upstream_response_time。
建议在http块中定义专门的日志格式,例如增加请求耗时、连接序号和命中的虚拟主机。一个可参考的格式如下:
log_format capacity '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct=$upstream_connect_time '
'urt=$upstream_response_time host=$host';
这段配置里,$request_time表示从客户端发起请求到Nginx返回响应头的耗时,$upstream_response_time表示上游服务响应耗时。容量分析时,如果只关注请求量增长,状态码和响应大小就够了;如果要判断是否需要增加后端节点,还需要观察$upstream_response_time的分位数变化。
另外,日志切割策略会影响趋势分析的准确性。如果按天切割但业务存在明显的晚高峰,日总量会掩盖峰值。更好的方式是按小时甚至更细粒度聚合,保留每小时的最大请求速率、平均响应时间和错误数。这样在容量规划时才能看到峰值与均值的差距,避免按日均值扩容导致高峰仍然打满。
二、趋势指标的计算方式与增长信号
从原始日志到容量判断,需要先定义几个核心指标:请求速率QPS、平均响应大小、带宽吞吐、错误率和P95响应时间。QPS可以通过统计时间窗口内的请求总数除以秒数得到。例如某个小时内有3600000个请求,那么该小时平均QPS约为1000。带宽吞吐则用响应大小累加后乘以8再除以窗口秒数,单位是bit/s。
计算这些指标时,不能只看平均值。Nginx日志中的$request_time经常呈现长尾分布,平均值可能被少量慢请求拉高。容量规划中更推荐使用分位数,例如P95或P99。比如在分析脚本中,把某个时间段的所有耗时排序,取第95百分位作为响应时间水位。如果P95从200毫秒持续上升到500毫秒,即使QPS没有剧烈变化,也说明后端可能已经接近处理能力上限。
趋势识别可以采用移动平均和环比增长。移动平均可以平滑偶发流量尖刺,例如取7天窗口的平均QPS作为趋势基线。环比增长则用本周同一时间段的数值与上周比较,计算增长率。如果连续三周同环比增长超过15%,就需要触发容量评估。另一种信号来自错误率,状态码为502、504的比例升高,通常意味着上游连接池耗尽或后端超时,这是比QPS更前置的容量预警。
此外,日志中$upstream_connect_time如果从几毫秒增长到几十毫秒,也可能表明上游服务的连接建立变慢。这个指标容易被忽略,但在连接数接近上限时,它会先于错误率上升给出提示。因此容量规划不只是看请求量,还要结合连接耗时和错误码一起判断。
三、容量预测的常用方法
容量规划需要预测未来某个时间点的资源需求。最简单的方式是线性回归。假设过去N天的日峰值QPS为时间序列,可以用最小二乘法拟合出一条直线,斜率代表每天新增的QPS需求。根据这条直线,可以推算30天后QPS的估计值。这个方法的优点是计算简单,缺点是当业务增长不是线性时误差较大。
对于有明显周期性的业务,可以使用季节性分解或指数平滑。指数平滑适合短期预测,它对近期数据赋予更高权重,能更快响应趋势变化。比如使用Python的statsmodels库,可以调用SimpleExpSmoothing或Holt方法进行拟合。实际落地时,不必追求特别复杂的模型,先用线性回归和移动平均做基线,再结合业务事件,例如大促、版本发布或市场投放计划,对预测结果进行人工修正。
容量规划还需要设定资源水位线。通常单台Nginx在普通CPU配置下,可以稳定承载数千到数万QPS,但具体数值受连接数、TLS握手、响应大小影响。建议通过压测确定单机安全水位,例如CPU使用率不超过60%时的QPS作为单机承载上限。然后用预测的峰值QPS除以单机安全QPS,得到需要的节点数量。公式可以理解为:节点数 = 预测峰值QPS / 单机安全QPS,再向上取整。
除了应用层QPS,还要考虑带宽。如果响应大小较大,例如静态文件或视频资源,带宽可能先于QPS成为瓶颈。Nginx日志中的$body_bytes_sent可以累加出带宽需求。预测带宽增长后,要与机房的出口带宽或云服务器的带宽上限比较,避免QPS还有余量但带宽已经打满。
四、用脚本实现日志趋势分析和容量提醒
下面给出一段Python脚本的思路,用来读取Nginx日志、按小时聚合请求量,并用线性回归预测未来7天的峰值。脚本假设日志已经按格式输出,并且字段用rt=等标记。
import re
from collections import defaultdict
from datetime import datetime, timedelta
import statistics
LOG_PATTERN = re.compile(
r'\[(?P<time>[^\]]+)\] .*? (?P<status>\d{3}) (?P<size>\d+) '
r'rt=(?P<rt>[\d.]+) .*?urt=(?P<urt>[\d.]+)'
)
def parse_log_line(line):
match = LOG_PATTERN.search(line)
if not match:
return None
time_str = match.group('time')
dt = datetime.strptime(time_str, '%d/%b/%Y:%H:%M:%S %z')
return {
'hour': dt.replace(minute=0, second=0, microsecond=0),
'status': int(match.group('status')),
'size': int(match.group('size')),
'rt': float(match.group('rt')),
'urt': float(match.group('urt')),
}
def aggregate_by_hour(records):
hourly = defaultdict(lambda: {'count': 0, 'bytes': 0, 'errors': 0, 'rts': []})
for rec in records:
bucket = hourly[rec['hour']]
bucket['count'] += 1
bucket['bytes'] += rec['size']
if rec['status'] >= 500:
bucket['errors'] += 1
bucket['rts'].append(rec['rt'])
return hourly
def linear_trend(qps_values):
n = len(qps_values)
if n == 0:
return 0, 0
x_mean = (n - 1) / 2
y_mean = sum(qps_values) / n
numerator = sum((i - x_mean) * (y - y_mean) for i, y in enumerate(qps_values))
denominator = sum((i - x_mean) ** 2 for i in range(n))
slope = numerator / denominator if denominator else 0
intercept = y_mean - slope * x_mean
return slope, intercept
def predict_next_days(slope, intercept, current_index, days):
next_index = current_index + days * 24
return max(0, slope * next_index + intercept)
这段代码先解析日志中的时间、状态码、响应大小和耗时字段,然后按小时汇总请求数、错误数和耗时列表。趋势部分使用线性回归计算每小时QPS的斜率,再根据当前小时索引预测未来几天的QPS。实际使用时,可以把预测结果与单机安全QPS比较,当预测值超过一定比例时输出提醒。
需要注意的是,日志解析依赖统一的时间格式和日志格式。如果Nginx配置中使用了不同的变量顺序,正则表达式需要同步调整。生产环境建议把日志采集到集中式平台,再通过定时任务计算趋势,而不是直接在生产服务器上扫描大文件,避免影响线上性能。
容量规划不是一个一次性的项目,而是需要定期复盘的过程。每次扩容后,新的日志数据又会产生,模型可以继续修正。比较合理的频率是每周生成一次容量趋势报告,每月做一次资源预算评审。当预测结果显示未来四周内水位会超过安全阈值时,提前启动扩容流程,这样可以给采购、部署和压测留出足够时间。