跳转到主内容
跳转到主内容

将 Vector 与 ClickHouse 集成

Partner Integration

实时分析日志对于生产应用程序至关重要。 ClickHouse 在存储和分析日志数据方面表现卓越,这得益于其出色的压缩能力(日志压缩率可达 170 倍)以及快速聚合海量数据的能力。

本指南将介绍如何使用流行的数据管道工具 Vector 来跟踪 Nginx 日志文件并将其发送到 ClickHouse。 以下步骤同样适用于跟踪任何类型的日志文件。

前置条件:

  • 您已部署并运行 ClickHouse
  • 您已安装 Vector

创建数据库和表

定义一个表来存储日志事件:

  1. 首先创建一个名为 nginxdb 的新数据库:
CREATE DATABASE IF NOT EXISTS nginxdb
  1. 将整个日志事件作为单个字符串插入。显然,这并不是便于对日志数据进行分析的理想格式,不过我们会在下文中通过使用 materialized views 来解决这一点。
CREATE TABLE IF NOT EXISTS  nginxdb.access_logs (
  message String
)
ENGINE = MergeTree()
ORDER BY tuple()
注意

由于目前尚不需要主键,因此将 ORDER BY 设置为 tuple()(空元组)。

配置 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;
}
  1. 如果你对 nginx.conf 做了修改,请务必重启 Nginx。

  2. 通过访问你的 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 "http://localhost/" "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"

配置 Vector

Vector 可以收集、转换和路由日志、指标和追踪数据(称为 sources)到多个不同的供应商(称为 sinks)中,包括开箱即用地兼容 ClickHouse。 Sources 和 sinks 在名为 vector.toml 的配置文件中定义。

  1. 下面的 vector.toml 文件定义了一个类型为 filesource,它会以尾部跟踪(tail)的方式读取 my_access.log 文件末尾的新内容,同时还定义了一个 sink,将数据写入上面定义的 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
  1. 使用上述配置启动 Vector。有关如何定义 sources 和 sinks 的更多详细信息,请参阅 Vector 的文档

  2. 通过运行以下查询,验证访问日志是否已写入 ClickHouse。你应该能够在表中看到这些访问日志:

SELECT * FROM nginxdb.access_logs
以表格形式查看 ClickHouse 日志

解析日志

将日志存储在 ClickHouse 中固然很好,但如果将每个事件都存储为单个字符串,就很难进行有效的数据分析。 接下来我们将介绍如何使用 materialized view 来解析日志事件。

物化视图的作用类似于 SQL 中的插入触发器。当数据行被插入到源表时,物化视图会对这些行进行转换,并将结果插入到目标表中。 The materialized view can be configured to configure a parsed representation of the log events in access_logs. An example of one such log event is shown below:

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\""]

有些字符串包含一些多余字符,而且用户代理字符串(浏览器信息)其实无需解析,不过 生成的数组已经与所需结果非常接近。

类似于 splitByWhitespacesplitByRegexp 函数会基于正则表达式将字符串拆分为数组。 运行以下命令,它会返回两个字符串。

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"')

请注意,返回的第二个字符串是从日志中成功解析出的 User-Agent:

["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\""]

在查看最终的 CREATE MATERIALIZED VIEW 命令之前,先来看几个用于清理数据的函数。 例如,RequestMethod 的值是 "GET,其中包含一个多余的双引号。 可以使用 trimBoth(别名 trim) 函数来移除这个双引号:

SELECT trim(LEADING '"' FROM '"GET')

时间字符串开头有一个左方括号,而且其格式也不是 ClickHouse 能够解析为日期的格式。 但是,如果我们把分隔符从冒号(:)改成逗号(,),那么就可以顺利完成解析:

SELECT parseDateTimeBestEffort(replaceOne(trim(LEADING '[' FROM '[12/Oct/2021:15:32:43'), ':', ' '))

现在我们可以定义 materialized view 了。 下面的定义中包含 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)

现在验证一下它是否生效。 你现在应该能看到访问日志已经被整齐地解析到各个列中:

SELECT * FROM nginxdb.access_logs_view
以表格形式查看解析后的 ClickHouse 日志
注意

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

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