日志服务汇总数据指南

中州
  • 收获赞:25
  • 擅长领域:这个同学很专业,但是有点神秘哟~

本文为您介绍基于SLS推出的ScheduledSQL功能,对历史数据进行汇总压缩,降低使用存储成本。

背景

日志服务 SLS通过丰富灵活的方式将多种类型(日志、指标)的数据接入到服务中,并随着时间不断沉淀;之后,用户就可以通过SLS强大的查询分析能力对多个维度的数据进行搜索、分析。虽然历史数据同样有较高的查询分析价值,但是大量历史数据的存储成本也不能忽视。因而SLS的用户一般会给数据设置一个固定的保留日期,定期清理历史数据,减轻成本压力。为了解决这一问题,SLS近期推出了新功能ScheduledSQL,让用户定时保存SLS中的汇总数据,既保存了历史数据供以后查询分析,同时又减轻了存储的成本压力。

汇总数据

日志、指标类的数据都会随着时间的推移不断累积。例如一个系统每秒产生1000条日志,日志的平均大小为500byte,一小时就会有1.8GB的日志,一年就会产生15T的数据。虽然数据使用方希望能够尽可能多的保存这15T数据以供查询分析使用,但是这些历史数据在提供分析价值的同时,也造成了较高的成本压力。定期删除历史数据虽然能够解决成本问题,但同时也给数据使用方带来了不便。

数据价值的时间梯度

从使用频率、数据权重等维度不难看出,数据的价值是随着时间不断降低的。例如用户页面查看日志,需要查看最近七天单个用户每天的特定页面的访问数,最近一月单个用户每天的访问数,最近一年单个用户每月的访问数。假设有2万用户,20可供用户访问的页面:

数据维度

时间梯度

保存时长

汇总数据量(条)

原始数据量(条)

汇总占比

user/page

7天

2万 * 20 * 7 = 280万

2万 * 20 * 7 = 280万

100%

user

30天

2万 * 30 = 60万

2万 * 20 * 30 = 1200万

5%

user

1年

2万* 12 = 24万

2万 * 20 * 365 = 1.4亿

0.16%

可以看到在上述场景下,随着时间推移,数据具有极高的可压缩比率。相对于直接删除历史数据,可以通过保存汇总数据来降低存储成本。这样即能够查询分析历史数据,又不必花费极高的存储成本。

汇总数据结构

在生成汇总数据的时候,首先需要评估数据的使用场景。不同场景、不同类型的数据的使用方式千差万别,其评估方式也不尽相同。下面介绍下不同类型数据的评估方式。

数值型数据

指标数据是典型的数值型数据,一条典型的指标日志如下所示:

{
    "bucket_location": "oss-cn-*****-h",
    "bucket": "buc*****65",
    "object": "245-***************.model",
    "operation": "PostObject",
    "time": "23/Jun/2021:10:23:50",
    "object_size": "3188",
    "__time__": 1624443830,
    "key": "data-***************.txt",
    "content_length_out": "22583527",
    "content_length_in": "46803694",
    "http_status": "200",
    "response_time": "7339",
    "__tag__:__receive_time__": "1624443838"
}

这条日志的字段可以分为时间,数值字段,分组字段三类,例如:

字段名称

字段值

类型

bucket

buc*****65

分组

object

245-***************.model

分组

operation

PostObject

分组

object_size

3188

数值

content_length_in

46803694

数值

content_length_out

22583527

数值

__time__

1624443830

时间

__tag__:__receive_time__

1624443838

时间

数值字段即为具体的指标值,维度和时间字段一般用作分组值,在计算指标的聚合值时作为分组依据。例如,如果要计算OSS每个bucket每小时写入的数据量,则需要使用维度字段operation和bucket,时间字段__time__,数值字段content_length_out:

operation: PostObject | select bucket, date_trunc("hour", __time__) as tm, sum(content_length_in) as total from log group by bucket, tm

如果使汇总数据支持上述场景,需要在汇总数据中保存分组字段operation和bucket,精确到小时级别的__time__字段,以及content_length_in的聚合值。所以可以通过如下sql语句计算汇总数据,支持上述场景:

operation: PostObject | select bucket, operation, date_trunc("hour", __time__) as tm, sum(content_length_in) as size from log group by bucket, operation, tm

如果还需要汇总数据同时支持计算每小时单次写入数据量的平均值,则需要通过如下sql语句计算汇总数据:

operation: PostObject | select bucket, operation, date_trunc("hour", __time__) as tm, avg(content_length_in) as avg, count(1) as size from log group by bucket, operation, tm

得到如下所示的汇总数据:

字段名称

字段样例

字段说明

bucket

buc*****65

bucket名称

operation

PostObject

操作名称

tm

1624442400

取整到小时的时间戳

avg

22583527

单次写入数据大小的平均值

size

65

写入数据请求的次数

基于得到的汇总数据,可以通过如下sql语句进行计算

  1. 计算OSS每个bucket每小时写入的数据量

operation: PostObject | select bucket, tm, sum(avg * size) as total from log
  1. 每小时单次写入数据量的平均值

operation: PostObject | select bucket, tm, avg from log

可以看出,随着场景的不同,计算汇总数据所需的sql语句也不尽相同。可以从以下几个方面评估如何计算汇总数据:

  1. 选择分组字段。

  2. 选择数值字段的聚合值:计数、求和、平均、最大、最小。

  3. 选择时间粒度:分钟、小时、天。

采样历史数据

采样历史数据则较为简单,在历史数据中按照一定的规则挑选合适的数据存储即可。例如对于系统日志,可以选择存储日志级别为WARNING或者ERROR的数据进行存储,忽略INFO级别的日志。

汇总数据的限制

汇总数据本质上是对原始数据在更粗时间粒度的聚合,并且聚合分组、计算都是按照对汇总数据的预期使用方式来选择的。

  1. 时间粒度

如果汇总数据的时间粒度是小时,则使用汇总数据进行数据分析只能够得到以小时为单位的聚合结果,无法得到更细粒度的数据。

  1. 聚合函数

聚合函数只能够使用汇总数据中聚合值支持的。如果汇总结果中不包含最小值,则基于汇总结果进行聚合计算的时候,是无法精确得到最小值的。

  1. 分组数据

由于汇总数据只保存了部分分组数据,在使用汇总数据进行数据分析时只能够使用保存的部分。

日志服务中的汇总数据

下面以OSS访问日志为例,说明如何基于SLS推出的ScheduledSQL功能,对历史数据进行汇总压缩,从而降低使用存储成本。

评估使用场景

一条完整的OSS访问日志如下:

{
    "__topic__": "oss_access_log",
    "bucket_location": "oss-cn-****-p",
    "bucket": "bucket****",
    "object": "245-************.model",
    "client_ip": "127.0.0.1",
    "operation": "PutObject",
    "logging_flag": "false",
    "time": "23/Jun/2021:13:07:30",
    "server_cost_time": "8636",
    "object_size": "7748",
    "vpc_addr": "127.0.0.1",
    "sync_request": "cdn",
    "__time__": 1624453650,
    "key": "data*****6958txt",
    "delta_data_size": "3938",
    "__source__": "127.0.0.1",
    "error_code": "network disconnected",
    "content_length_out": "79193322",
    "response_body_length": "717233083",
    "request_uri": "/request/path-2/file-9",
    "content_length_in": "1823770",
    "http_method": "GET",
    "http_status": "200",
    "request_length": "4099",
    "response_time": "398",
    "__tag__:__receive_time__": "1624453651",
    "owner_id": "ln***v2",
    "http_type": "https",
    "bucket_storage_type": "archive"
}

需要基于OSS访问数据构建如下的几类关键结果:

名称

时间粒度

分组依据

聚合函数

单位时间请求次数

小时

bucket, operation

count

单位时间请求错误

小时

bucket, operation, http_status

count

单位时间写入数据量

小时

bucket, operation

sum

单位时间平均写入数据量

小时

bucket, operation

avg, count

单位时间读取数据量

小时

bucket, operation

sum

单位时间平均读取数据量

小时

bucket, operation

avg, count

根据上面的使用场景,可以通过如下语句计算汇总数据:

operation: PostObject | select bucket, operation, http_status, date_trunc('hour', __time__) as tm, avg(content_length_out) as out_avg, avg(content_length_in) as in_avg, count(1) as size from log group by bucket, operation, http_status, tm

创建ScheduledSQL任务

执行查询语句

在SLS的控制台中执行上述查询语句,随后点击创建ScheduledSQL。

计算配置

此处填入合适的作业名称、以及目标库即可。此处需要注意开启目标库的索引。

调度配置

这里调度间隔和时间窗口都选择小时级别,点击确认即可。关于调度配置的详细信息,可以参考官方文档

在任务执行成功之后,就可以在目标库中看到汇总数据。

汇总数据的使用

基于ScheduledSQL任务生成的汇总数据,可以为上述场景提供支撑。

名称

查询语句

单位时间请求次数

*| select bucket, tm, sum(1) as total group by bucket, tm

单位时间请求错误

not http_status: 200 | select bucket, count(1) as cnt group by bucket

单位时间写入数据量

operation: PostObject | select bucket, tm, sum(avg_out * size) as total from log

单位时间平均写入数据量

operation: PostObject | select bucket, tm, sum(avg_out * size) as total from log

单位时间读取数据量

operation: GetObject | select bucket, tm, sum(avg_in * size) as total from log

单位时间平均读取数据量

operation: GetObject | select bucket, tm, sum(avg_in * size) as total from log

总结

通过汇总数据支撑历史数据分析,能够较大的减轻存储成本上的压力。虽然同原始数据相比,其在使用场景以及灵活性方面都有所欠缺,但是如果能够提前做好规划,就能够很好的支撑大部分的使用场景。