跳到主要内容
跳到主要内容

将 Vector 与 ClickHouse 集成

能够实时分析日志对于生产应用程序至关重要。您是否想过 ClickHouse 是否擅长存储和分析日志数据?请查看 Uber 的经验,了解他们如何将其日志基础设施从 ELK 转换为 ClickHouse。

本指南展示了如何使用流行的数据管道 Vector 来跟踪 Nginx 日志文件并将其发送到 ClickHouse。以下步骤对于跟踪任何类型的日志文件都是类似的。我们假设您已经安装并运行了 ClickHouse 和 Vector(但无需立即启动它)。

1. 创建数据库和表

让我们定义一个表来存储日志事件

  1. 我们将从一个名为 nginxdb 的新数据库开始

    CREATE DATABASE IF NOT EXISTS nginxdb
  2. 首先,我们只是将整个日志事件作为单个字符串插入。显然,这不是对日志数据执行分析的最佳格式,但我们将在下面使用物化视图来解决这个问题。

    CREATE TABLE IF NOT EXISTS  nginxdb.access_logs (
    message String
    )
    ENGINE = MergeTree()
    ORDER BY tuple()
    注意

    目前实际上不需要主键,这就是为什么 ORDER BY 设置为 tuple()

2. 配置 Nginx

我们当然不想花太多时间解释 Nginx,但我们也不想隐藏所有细节,因此在这一步中,我们将为您提供足够的细节来配置 Nginx 日志记录。

  1. 以下 access_log 属性以 combined 格式将日志发送到 /var/log/nginx/my_access.log。此值位于您的 nginx.conf 文件的 http 部分

    http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    access_log /var/log/nginx/my_access.log combined;
    sendfile on;
    keepalive_timeout 65;
    include /etc/nginx/conf.d/*.conf;
    }
  2. 如果您必须修改 nginx.conf,请务必重启 Nginx。

  3. 通过访问您的 Web 服务器上的页面,在访问日志中生成一些日志事件。combined 格式的日志具有以下格式

    192.168.208.1 - - [12/Oct/2021:03:31:44 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
    192.168.208.1 - - [12/Oct/2021:03:31:44 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "https://127.0.0.1/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
    192.168.208.1 - - [12/Oct/2021:03:31:49 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"

3. 配置 Vector

Vector 收集、转换和路由日志、指标和追踪(称为 )到许多不同的供应商(称为 接收器),包括与 ClickHouse 的开箱即用兼容性。源和接收器在名为 vector.toml 的配置文件中定义。

  1. 以下 vector.toml 定义了一个 file 类型的 ,它跟踪 my_access.log 的末尾,并且还将 接收器 定义为上面定义的 access_logs

    [sources.nginx_logs]
    type = "file"
    include = [ "/var/log/nginx/my_access.log" ]
    read_from = "end"

    [sinks.clickhouse]
    type = "clickhouse"
    inputs = ["nginx_logs"]
    endpoint = "http://clickhouse-server:8123"
    database = "nginxdb"
    table = "access_logs"
    skip_unknown_fields = true
  2. 使用上面的配置启动 Vector。 访问 Vector 文档 以获取有关定义源和接收器的更多详细信息。

  3. 验证访问日志是否正在插入到 ClickHouse 中。运行以下查询,您应该在表中看到访问日志

    SELECT * FROM nginxdb.access_logs
    View the logs

4. 解析日志

在 ClickHouse 中拥有日志很棒,但是将每个事件存储为单个字符串不允许进行太多数据分析。让我们看看如何使用物化视图解析日志事件。

  1. 物化视图(简称 MV)是一个基于现有表的新表,当向现有表进行插入时,新数据也会添加到物化视图中。让我们看看如何定义一个 MV,其中包含 access_logs 中日志事件的解析表示,换句话说

    192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"

    ClickHouse 中有各种函数可以解析字符串,但首先让我们看看 splitByWhitespace - 它通过空格解析字符串,并在数组中返回每个标记。为了演示,运行以下命令

    SELECT splitByWhitespace('192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"')

    请注意,响应非常接近我们想要的!一些字符串有一些额外的字符,用户代理(浏览器详细信息)不需要解析,但我们将在下一步中解决这个问题

    ["192.168.208.1","-","-","[12/Oct/2021:15:32:43","+0000]","\"GET","/","HTTP/1.1\"","304","0","\"-\"","\"Mozilla/5.0","(Macintosh;","Intel","Mac","OS","X","10_15_7)","AppleWebKit/537.36","(KHTML,","like","Gecko)","Chrome/93.0.4577.63","Safari/537.36\""]
  2. splitByWhitespace 类似,splitByRegexp 函数根据正则表达式将字符串拆分为数组。运行以下命令,它返回两个字符串。

    SELECT splitByRegexp('\S \d+ "([^"]*)"', '192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"')

    请注意,返回的第二个字符串是从日志成功解析的用户代理

    ["192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] \"GET / HTTP/1.1\" 30"," \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36\""]
  3. 在查看最终的 CREATE MATERIALIZED VIEW 命令之前,让我们查看另外几个用于清理数据的函数。例如,RequestMethod 看起来像 "GET,带有一个不需要的双引号。运行以下 trim 函数,它会删除双引号

    SELECT trim(LEADING '"' FROM '"GET')
  4. 时间字符串有一个前导方括号,并且也不是 ClickHouse 可以解析为日期的格式。但是,如果我们将分隔符从冒号 (:) 更改为逗号 (,),那么解析效果很好

    SELECT parseDateTimeBestEffort(replaceOne(trim(LEADING '[' FROM '[12/Oct/2021:15:32:43'), ':', ' '))
  5. 我们现在准备好定义我们的物化视图。我们的定义包括 POPULATE,这意味着 access_logs 中的现有行将被立即处理和插入。运行以下 SQL 语句

    CREATE MATERIALIZED VIEW nginxdb.access_logs_view
    (
    RemoteAddr String,
    Client String,
    RemoteUser String,
    TimeLocal DateTime,
    RequestMethod String,
    Request String,
    HttpVersion String,
    Status Int32,
    BytesSent Int64,
    UserAgent String
    )
    ENGINE = MergeTree()
    ORDER BY RemoteAddr
    POPULATE AS
    WITH
    splitByWhitespace(message) as split,
    splitByRegexp('\S \d+ "([^"]*)"', message) as referer
    SELECT
    split[1] AS RemoteAddr,
    split[2] AS Client,
    split[3] AS RemoteUser,
    parseDateTimeBestEffort(replaceOne(trim(LEADING '[' FROM split[4]), ':', ' ')) AS TimeLocal,
    trim(LEADING '"' FROM split[6]) AS RequestMethod,
    split[7] AS Request,
    trim(TRAILING '"' FROM split[8]) AS HttpVersion,
    split[9] AS Status,
    split[10] AS BytesSent,
    trim(BOTH '"' from referer[2]) AS UserAgent
    FROM
    (SELECT message FROM nginxdb.access_logs)
  6. 现在验证它是否有效。您应该看到访问日志已很好地解析为列

    SELECT * FROM nginxdb.access_logs_view
    View the logs
    注意

    上面的课程将数据存储在两个表中,但您可以更改初始的 nginxdb.access_logs 表以使用 Null 表引擎 - 解析后的数据仍将最终存储在 nginxdb.access_logs_view 表中,但原始数据将不会存储在表中。

总结:通过使用 Vector,它只需要简单的安装和快速配置,我们可以将 Nginx 服务器的日志发送到 ClickHouse 中的表。通过使用巧妙的物化视图,我们可以将这些日志解析为列,以便更轻松地进行分析。