日志存储分析

更新时间:
复制为 MD 格式

本文将引导您基于 SelectDB 搭建一套高性能、低成本的日志存储与分析平台。内容涵盖从资源规划、实例优化、表结构设计,到数据采集与查询分析的全流程。

第一步:规划资源

在创建 SelectDB 实例前,精确的资源评估至关重要,这能确保系统在满足业务需求的同时,实现成本效益最大化。评估主要围绕写入、查询和存储三个维度展开。

评估方法与案例

您可以参考下方的关键指标表,根据您的业务指标估算所需资源。为了方便您理解,我们提供了一个具体案例作为参考。

案例场景:假设某业务每日新增 100 TB 原始日志,数据压缩比为 5:1,热数据保留 3 天,冷数据保留 30 天。写入峰值是平均值的 2 倍,单核写入性能按 10 MB/s 估算。

关键指标参考表

1. 业务指标输入(根据您的业务场景预估)

关键指标

案例值

说明

每日原始数据增量 (TB)

100

每日产生的原始日志总量。

数据压缩比

5

日志数据(包括索引)的典型压缩比为 3:1 到 10:1。

热数据存储周期(天)

3

热数据在本地磁盘的存储时长。

冷数据存储周期(天)

30

冷数据在对象存储的存储时长。

写入峰值/均值比

200%

预估业务写入的峰值,通常为平均值的 2-3 倍。

查询预留 CPU 比例

50%

为查询负载预留的 CPU 资源。建议初始值为 50%,后续可根据实际负载进行调整。

2. 资源需求计算

总数据生命周期 (天)

33

计算公式:热数据存储周期 + 冷数据存储周期

平均写入吞吐 (MB/s)

1214

计算公式:每日原始数据增量 / 86400 s

峰值写入吞吐 (MB/s)

2427

计算公式:平均写入吞吐 × 写入峰值/均值比

写入所需 CPU 核数 (峰值)

242.7

计算公式:峰值写入吞吐 / 单核写入性能 (本例中单核性能按 10 MB/s 估算)

BE 节点总 CPU 核数

485.4

计算公式:写入所需 CPU 核数 (峰值) / (1 - 查询预留 CPU 比例)

本地磁盘所需空间 (TB)

60

计算公式:每日原始数据增量 / 数据压缩比 × 副本数 × 热数据存储周期

:本案例计算时副本数取 1,生产环境建议设为 3 以保证高可用。

对象存储所需空间 (TB)

600

计算公式:每日原始数据增量 / 数据压缩比 × 副本数 × 冷数据存储周期

:本案例计算时副本数取 1。

估算结论

根据以上估算,该案例的推荐资源配置如下:

  • BE 节点:总计约 480 vCPU 和 1920 GB 内存 (vCPU:内存建议为 1:4)。

  • 对象存储:约 600 TB,用于存储冷数据。

第二步:优化实例配置

实例创建后,建议您针对日志场景优化 FE 和 BE 的参数,以提升写入、压缩和查询性能。在创建实例时,在应用场景中选择日志分析场景;或在配置管理界面应用日志分析场景配置模板。

以下是日志分析场景的核心参数建议,您可以根据实际需求进行调整。

FE 配置

参数

配置目的与说明

autobucket_min_buckets = 10

目的:提升动态分桶灵活性。

将自动分桶的最小分桶数从 1 调大到 10,以应对日志量快速增长时可能出现的分桶不足问题。

BE 配置

参数

配置目的与说明

enable_file_cache = true

目的:加速冷数据查询。

开启文件缓存,将访问过的对象存储数据缓存到本地磁盘。

write_buffer_size = 1073741824

目的:提升写入性能。

将 MemTable 写入缓冲区大小增加至 1 GB,以减少小文件生成。

max_tablet_version_num = 20000

目的:防止高频写入被阻塞。

配合 `time_series` Compaction 策略,该参数允许更多数据版本在后台异步合并,从而避免因版本数超限而阻塞写入。

max_cumu_compaction_threads = 8

目的:平衡系统资源。

建议将该参数设置为 BE 节点 CPU 核数的 1/4。这有助于平衡系统资源:约 1/4 CPU 用于写入,1/4 用于后台 Compaction,剩余 1/2 留给查询。

inverted_index_compaction_enable = true

目的:降低查询 CPU 消耗。

在 Compaction 过程中合并倒排索引,以减少索引文件数量,从而降低查询时的 CPU 消耗。

enable_segcompaction = false

enable_ordered_data_compaction = false

目的:节约系统资源。

关闭在日志场景下非必需的 Compaction 功能,以节约系统资源。

enable_compaction_priority_scheduling = false

目的:提升 Compaction 整体效率。

在日志场景下,所有 Compaction 任务同等重要。关闭优先级调度可以避免因磁盘并发限制而影响整体效率。

total_permits_for_compaction_score = 200000

目的:适配 `time_series` 策略。

调整 Compaction 任务的内存控制参数,以适配 `time_series` 策略。

disable_storage_page_cache = true

inverted_index_searcher_cache_limit = 30%

目的:提升全文检索性能。

由于日志数据量大,Page Cache 的缓存命中率通常较低。建议关闭 Page Cache,并将节省的内存(例如 30%)分配给倒排索引缓存,以提升全文检索性能。

inverted_index_cache_stale_sweep_time_sec = 3600

index_cache_entry_stay_time_after_lookup_s = 3600

目的:提高常用索引的缓存命中率。

将倒排索引在内存中的缓存保留时间延长至 1 小时,以提高常用索引的缓存命中率。

enable_inverted_index_cache_on_cooldown = true

enable_write_index_searcher_cache = false

目的:优化写入性能与冷数据查询。

开启索引在数据下沉至对象存储时自动缓存的功能,以加速冷数据查询。同时,关闭写入时缓存索引的功能,以优化写入性能。

第三步:设计日志表结构

合理的表结构是发挥 SelectDB 性能的关键。针对日志数据的写入和查询特点,我们推荐采用以下建表策略。

以下是一个典型的日志表建表示例,其中包含了多项针对性的优化配置:

CREATE DATABASE log_db;
USE log_db;

CREATE TABLE log_table
(
  `ts` DATETIME,
  `host` TEXT,
  `path` TEXT,
  `message` TEXT,
  -- 对需要过滤的字段创建倒排索引,加速文本检索
  INDEX idx_host (`host`) USING INVERTED,
  INDEX idx_path (`path`) USING INVERTED,
  -- 对 message 字段创建倒排索引,并配置分词器以支持全文检索
  INDEX idx_message (`message`) USING INVERTED PROPERTIES("parser" = "unicode", "support_phrase" = "true")
)
ENGINE = OLAP
DUPLICATE KEY(`ts`) -- 使用时间戳作为排序键,加速时序查询
PARTITION BY RANGE(`ts`) () -- 按时间进行范围分区
DISTRIBUTED BY RANDOM BUCKETS 20 -- 使用随机分桶,提升写入效率
PROPERTIES (
  "compression" = "zstd", -- 使用 zstd 压缩算法,兼顾压缩比与性能
  "compaction_policy" = "time_series", -- 采用 time_series compaction 策略,优化时序数据写入
  -- 开启并配置动态分区,实现分区的自动管理
  "dynamic_partition.enable" = "true",
  "dynamic_partition.create_history_partition" = "true",
  "dynamic_partition.time_unit" = "DAY",
  "dynamic_partition.start" = "-30",
  "dynamic_partition.end" = "1",
  "dynamic_partition.prefix" = "p",
  "dynamic_partition.buckets" = "60"
);

关键配置说明

分区与排序:优化时序数据管理与查询

  • 分区策略:使用时间字段(如 `ts`)进行 Range 分区(PARTITION BY RANGE(ts)),并开启动态分区("dynamic_partition.enable" = "true")。系统将根据您的配置自动创建和删除分区,从而极大简化数据生命周期管理。

  • 排序键:使用时间字段作为排序键(DUPLICATE KEY(ts)),可以加速“查询最新的 N 条日志”这类时序查询。

分桶:提升写入并发与负载均衡

  • 分桶策略:使用随机分桶(DISTRIBUTED BY RANDOM),配合导入参数 `load_to_single_tablet`,可以有效提升批量写入效率并避免写倾斜。建议您根据数据量规划分桶数,使每个分桶压缩后的数据量保持在 1-10 GB 范围内。

Compaction 与压缩:降低存储成本与写放大

  • Compaction 策略:务必使用 `time_series` 策略("compaction_policy" = "time_series")。该策略专为时序数据设计,可以显著降低高并发写入场景下的写放大和资源消耗。

  • 压缩算法:推荐使用 `zstd` 压缩算法("compression" = "zstd"),它在提供较高压缩比的同时,也具有良好的解压性能。

索引:加速文本检索与过滤

  • 倒排索引:对需要作为筛选条件的字段(例如 `host`、`path`、`message`)创建倒排索引(USING INVERTED),以加速文本检索和等值查询。

  • 全文检索:对于需要进行全文检索的字段(例如 `message`),建议将分词器(parser)设置为 `unicode` 以支持中英文混合分词。如果您需要进行短语精确匹配查询,请开启 `support_phrase`;否则建议关闭该选项,以节约存储空间和索引开销。

更多建表指引,请参考 第三步:学习数据库表设计要点

第四步:采集与导入日志

SelectDB 兼容 Apache Doris 的数据导入 API,可以与 Logstash、Filebeat、Kafka 等主流采集工具无缝集成。本节将介绍如何配置这些工具,从而高效地将日志数据导入 SelectDB。

Logstash

  1. 下载并安装 Logstash Doris Output 插件,支持以下两种方式:

    • 直接下载:点此下载

    • 从源码编译,并运行下方命令安装:

      ./bin/logstash-plugin install logstash-output-doris-1.2.0.gem
  2. 配置 Logstash。需配置以下参数:

    • logstash.yml:配置 Logstash 批处理日志的条数和时间,用于提升数据写入性能。

      pipeline.batch.size: 1000000  
      pipeline.batch.delay: 10000
    • logstash_demo.conf:配置所采集日志的具体输入路径和输出到 SelectDB 的设置。

      input {  
          file {  
          path => "/path/to/your/log"  
        }  
      }  
      
      output {  
        doris {  
          http_hosts => [ "<http://fehost1:http_port>", "<http://fehost2:http_port>", "<http://fehost3:http_port">]  
          user => "your_username"  
          password => "your_password"  
          db => "your_db"  
          table => "your_table"  
          
          # doris stream load http headers  
          headers => {  
          "format" => "json"  
          "read_json_by_line" => "true"  
          "load_to_single_tablet" => "true"  
          }  
          
          # field mapping: doris fileld name => logstash field name  
          # %{} to get a logstash field, [] for nested field such as [host][name] for host.name  
          mapping => {  
          "ts" => "%{@timestamp}"  
          "host" => "%{[host][name]}"  
          "path" => "%{[log][file][path]}"  
          "message" => "%{message}"  
          }  
          log_request => true  
          log_speed_interval => 10  
        }  
      }
  3. 按照下方命令运行 Logstash,采集日志并输出至 SelectDB。

    ./bin/logstash -f logstash_demo.conf

更多关于 Logstash 配置和使用的说明,可参考 Logstash Doris Output Plugin

Filebeat

  1. 获取支持输出至 SelectDB 的 Filebeat 二进制文件:下载地址

  2. 配置 Filebeat。需配置以下参数:

    • filebeat_demo.yml:配置所采集日志的具体输入路径和输出到 SelectDB 的设置。

      # input
      filebeat.inputs:
      - type: log
        enabled: true
        paths:
          - /path/to/your/log
        # multiline 可以将跨行的日志(比如 Java stacktrace)拼接起来
        multiline:
          type: pattern
          # 效果:以 yyyy-mm-dd HH:MM:SS 开头的行认为是一条新的日志,其他都拼接到上一条日志
          pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}'
          negate: true
          match: after
          skip_newline: true
      
      processors:
      # 用 js script 插件将日志中的 \t 替换成空格,避免 JSON 解析报错
      - script:
          lang: javascript
          source: >
              function process(event) {
                  var msg = event.Get("message");
                  msg = msg.replace(/\t/g, "  ");
                  event.Put("message", msg);
              }
      # 用 dissect 插件做简单的日志解析
      - dissect:
          # 2024-06-08 18:26:25,481 INFO (report-thread|199) [ReportHandler.cpuReport():617] begin to handle
          tokenizer: "%{day} %{time} %{log_level} (%{thread}) [%{position}] %{content}"
          target_prefix: ""
          ignore_failure: true
          overwrite_keys: true
      
      # queue and batch
      queue.mem:
        events: 1000000
        flush.min_events: 100000
        flush.timeout: 10s
      
      # output
      output.doris:
        fenodes: [ "http://fehost1:http_port", "http://fehost2:http_port", "http://fehost3:http_port" ]
        user: "your_username"
        password: "your_password"
        database: "your_db"
        table: "your_table"
        # output string format
        ## %{[agent][hostname]} %{[log][file][path]} 是filebeat自带的metadata
        ## 常用的 filebeat metadata 还是有采集时间戳 %{[@timestamp]}
        ## %{[day]} %{[time]} 是上面 dissect 解析得到字段
        codec_format_string: '{"ts": "%{[day]} %{[time]}", "host": "%{[agent][hostname]}", "path": "%{[log][file][path]}", "message": "%{[message]}"}'
        headers:
          format: "json"
          read_json_by_line: "true"
          load_to_single_tablet: "true"

  3. 按照下方命令运行 Filebeat,采集日志并输出至 SelectDB。

    chmod +x filebeat-doris-2.1.1  
    ./filebeat-doris-2.1.1 -c filebeat_demo.yml

更多关于 Filebeat 配置和使用的说明,可参考 Beats Doris Output Plugin

Kafka

将 JSON 格式的日志写入 Kafka 的消息队列,创建 Kafka Routine Load,即可让 SelectDB 从 Kafka 主动拉取数据。

可参考如下示例。其中,property.× 是 Librdkafka 客户端相关配置,根据实际 Kafka 集群情况配置。

-- 准备好 kafka 集群和 topic log__topic_  
-- 创建 routine load,从 kafka log__topic_将数据导入 log_table 表  
CREATE ROUTINE LOAD load_log_kafka ON log_db.log_table  
COLUMNS(ts, clientip, request, status, size)  
PROPERTIES (
"max_batch_interval" = "60",
"max_batch_rows" = "20000000",
"max_batch_size" = "1073741824", 
"load_to_single_tablet" = "true",
"format" = "json"
)
FROM KAFKA (  
"kafka_broker_list" = "host:port",  
"kafka_topic" = "log__topic_",  
"property.group.id" = "your_group_id",  
"property.security.protocol"="SASL_PLAINTEXT",  
"property.sasl.mechanism"="GSSAPI",  
"property.sasl.kerberos.service.name"="kafka",  
"property.sasl.kerberos.keytab"="/path/to/xxx.keytab",  
"property.sasl.kerberos.principal"="<xxx@yyy.com>"  
);  
-- 查看 routine 的状态  
SHOW ROUTINE LOAD;

更多关于 Kafka 配置和使用的说明,可参考Routine Load

自定义程序采集日志

可通过 HTTP API Stream Load 自定义程序将日志数据导入 SelectDB。示例代码:

curl   
--location-trusted   
-u username:password   
-H "format:json"   
-H "read_json_by_line:true"   
-H "load_to_single_tablet:true"   
-H "timeout:600"   
-T logfile.json   
http://fe_host:fe_http_port/api/log_db/log_table/_stream_load

在使用自定义程序时,需注意以下关键点:

  • 使用 Basic Auth 进行 HTTP 鉴权,用命令 echo -n 'username:password' | base64 进行计算。

  • 设置 HTTP header "format:json",指定数据格式为 JSON。

  • 设置 HTTP header "read_json_by_line:true",指定每行一个 JSON。

  • 设置 HTTP header "load_to_single_tablet:true",指定一次导入写入一个分桶减少导入的小文件。

  • 建议写入客户端单个 Batch 大小为 100MB~1GB。Apache Doris 2.1 及更高版本需通过服务端 Group Commit 功能降低客户端 Batch 大小。

第五步:查询与分析日志

数据成功导入后,您可以通过标准 SQL 或可视化平台对日志进行查询和分析。

使用 SQL 进行查询

SelectDB 兼容 MySQL 协议,因此您可以使用任何 MySQL 客户端或通过 JDBC/ODBC 连接到集群,并执行 SQL 进行查询分析。

mysql -h fe_host -P fe_mysql_port -u your_username -D log_db

以下是一些常见的日志查询示例:

  • 查看最新的 10 条日志

    SELECT * FROM log_table ORDER BY ts DESC LIMIT 10;
  • 查询指定 `host` 的最新 10 条日志

    SELECT * FROM log_table WHERE host = '8.8.8.8' ORDER BY ts DESC LIMIT 10;
  • 全文检索:查询 `message` 字段中包含 `error` 或 `404` 的日志

    SELECT * FROM log_table WHERE message MATCH_ANY 'error 404' ORDER BY ts DESC LIMIT 10;
  • 全文检索:查询 `message` 字段中同时包含 `image` 和 `faq` 的日志

    SELECT * FROM log_table WHERE message MATCH_ALL 'image faq' ORDER BY ts DESC LIMIT 10;
  • 全文检索:查询 `message` 字段中包含精确短语 `image faq` 的日志

    SELECT * FROM log_table WHERE message MATCH_PHRASE 'image faq' ORDER BY ts DESC LIMIT 10;

可视化日志分析

云数据库 SelectDB 集成了数据开发与管理工具作为可视化日志分析平台。使用说明参考数据开发与管理

  • 支持全文检索和 SQL 两种模式。

  • 支持在时间框和直方图上选择查询日志的时间段。

  • 支持日志明细展示,可展开为 JSON 或表格格式。

  • 支持在日志数据上交互式添加和删除筛选条件。

  • 搜索结果的字段 Top 值展示,便于发现异常值和进一步下钻分析。