背景
Nginx 完成请求处理后会记录客户端请求信息到 access log。与业务请求数量成正比,access log 文件内容日积月累,占用大量磁盘的存储空间的同时,数据量增长也使分析 access log 变得困难。
阿里云日志服务(SLS)是云原生观测分析平台,为Log/Metric/Trace等数据提供大规模、低成本、实时平台化服务。一站式提供数据采集、加工、分析、告警可视化与投递功能,全面提升研发、运维、运营和安全等场景数字化能力。
在 web 服务器上部署 Logtail 客户端,实时采集 Nginx access log 数据到 SLS 存储:
- 问题一:存储空间持续增加
以 34K TPS 的请求量计算,每条日志 500 Bytes,一个月累计后达到 42 TB。但 access log 随时间推移逐渐从温数据变为冷数据,这带来一笔不小的存储开销。
- 问题二:分析计算消耗大
假设对 30 天的数据分析小时级流量特征,如果每次对全量数据做即时分析,计算成本是巨大的,计算延时的增加也影响了体验。
以 host、method 分组计算小时级流量特征为例:
* | select (__time__ - __time__ % 3600) as dt, method, host, sum(request_length)/1024.0/1024.0 as request_MB, sum(body_byte_sent)/1024.0/1024.0 as body_sent_MB, avg(upstream_response_time) as avg_latency, avg(request_time) as avg_request_time group by dt, method, host order by dt asc limit 10000
随着查询时间范围增加,计算引擎需要扫描更多的数据量做计算,增加了资源开销与分析延时。
数据查询范围 |
扫描日志条数 |
计算耗时 |
24 hours |
14,397,600 |
1,390ms |
30 days |
431,884,800 |
13,291ms |
方案
本文介绍一种预计算方案:
- 优化冷数据:历史数据降精度存储。
- 降分析延时:将全量数据计算拆分为多次增量计算。
具体来说,是将 SQL 计算任务托管在后台,周期性运行,得到一个个时间区间的统计值,将这些统计结果写入存储库,可达到如下效果:
- 降维后的数据满足固定的统计需求,对于 30 天前的日志原文,如不需要做细节问题调查,甚至可以缩短存储 TTL 到 7 天。
- 统计结果直接存储下来,可以被多种下游系统直接使用,例如可视化大盘、告警监控、入库数仓等。
- 查询引擎在降维后数据上计算,由于要处理的数据量大大降低,达到秒开的效果。
Scheduled SQL 实践
Scheduled SQL 是一项由 SLS 全托管的功能,解决场景需求:
- 定时分析数据:根据业务需求设置 SQL 语句或查询分析语句,定时执行数据分析,并将分析结果存储到目标库中。
- 全局聚合:对全量、细粒度的数据进行聚合存储,汇总为存储大小、精度适合的数据,相当于一定程度的有损压缩数据。
本节介绍如何通过 Scheduled SQL 对 Nginx access log 做指标预计算。
原始日志库中执行 SQL 分析
索引字段配置如下:
指标要求:按照时间( 5 分钟粒度)、请求方法(method)、主机(host)维度分组,统计每个时间段内客户端请求服务端的流量总计(request_MB)、服务端返回给客户端的流量总计(body_sent_MB)、后端响应平均延时(avg_latency)、客户端请求平均耗时(avg_request_time)。
SQL 代码如下:
* | select (__time__ - __time__ % 300) as dt, method, host, sum(request_length)/1024.0/1024.0 as request_MB, sum(body_byte_sent)/1024.0/1024.0 as body_sent_MB, avg(upstream_response_time) as avg_latency, avg(request_time) as avg_request_time group by dt, method, host order by dt asc limit 10000
在 SLS 控制台上分析预览:
确认结果符合预期后,以当前 SQL 语句创建 Scheduled SQL 作业。
计算配置
资源池有免费(Project 级别 15 并行度)、增强型(收费,但资源可扩展,适用于大量计算且有 SLA 要求的业务场景)两种,按照你的需求来设置即可。
注意为目标库 nginx_access_log_rollup 也提前准备好数据索引,如下图:
调度配置
设置 SQL 每 5 分钟执行一次,每次执行处理最近 5 分钟窗口的数据。
注意:
1. 设置延迟执行参数,上游 Logstore 的数据到来可能延迟,建议设置大一些的值做等待来保证计算数据的完整性。
2. SQL 运行超过指定次数或指定时间后,这一次的 SQL 实例会失败并继续下一个实例的调度。
实例查看、管理
可以在控制台上查看刚才创建的 Scheduled SQL 作业:
在作业管理页面内,可以查看到每一次执行的实例列表。
每个实例信息中有 SQL 查询区间,如果任务失败(权限、SQL 语法等原因)或 SQL 处理行数指标为 0(数据迟到或确实没有数据),可以对指定实例做重试运行(失败告警功能开发中)。
效果
Nginx access log 预计算之后数据格式:
预计算结果之上用 SQL 分析流量、延时的时间趋势,对分析结果添加仪表盘来实现一个业务大盘。
- 延时统计
统计 client 请求延时趋势图:
* | select from_unixtime(dt - dt % 3600) as t, concat('host:', host, '#method:', method) as host_method, round(max(avg_request_time), 3) as max_request_time group by dt, host_method order by dt asc limit 10000
选择流图,图表类型为线图:
服务端响应延时用相同方式处理,SQL 语句:
* | select from_unixtime(dt - dt % 3600) as t, concat('host:', host, '#method:', method) as host_method, round(max(avg_latency), 3) as max_latency group by dt, host_method order by dt asc limit 10000
- 流量统计
统计 response 流量趋势图:
* | select from_unixtime(dt - dt % 3600) as t, concat('host:', host, '#method:', method) as host_method, round(sum(body_sent_MB), 3) as sum_body_sent_MB group by dt, host_method order by dt asc limit 10000
选择流图,图表类型为面积图:
request 流量用相同方式处理,SQL 语句:
* | select from_unixtime(dt - dt % 3600) as t, concat('host:', host, '#method:', method) as host_method, round(sum(request_MB), 3) as sum_request_MB group by dt, host_method order by dt asc limit 10000
- 流量、延时分析大盘
将以上四个图表保存到仪表盘中,效果如下:
更多内容请参考: