将 Vector 与 ClickHouse 集成
能够实时分析日志对于生产应用程序至关重要。您是否想过 ClickHouse 是否擅长存储和分析日志数据?请查看 Uber 的经验,了解他们如何将其日志基础设施从 ELK 转换为 ClickHouse。
本指南展示了如何使用流行的数据管道 Vector 来跟踪 Nginx 日志文件并将其发送到 ClickHouse。以下步骤对于跟踪任何类型的日志文件都是类似的。我们假设您已经安装并运行了 ClickHouse 和 Vector(但无需立即启动它)。
1. 创建数据库和表
让我们定义一个表来存储日志事件
-
我们将从一个名为
nginxdb
的新数据库开始CREATE DATABASE IF NOT EXISTS nginxdb
-
首先,我们只是将整个日志事件作为单个字符串插入。显然,这不是对日志数据执行分析的最佳格式,但我们将在下面使用物化视图来解决这个问题。
CREATE TABLE IF NOT EXISTS nginxdb.access_logs (
message String
)
ENGINE = MergeTree()
ORDER BY tuple()注意目前实际上不需要主键,这就是为什么 ORDER BY 设置为 tuple()。
2. 配置 Nginx
我们当然不想花太多时间解释 Nginx,但我们也不想隐藏所有细节,因此在这一步中,我们将为您提供足够的细节来配置 Nginx 日志记录。
-
以下
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;
} -
如果您必须修改
nginx.conf
,请务必重启 Nginx。 -
通过访问您的 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 的配置文件中定义。
-
以下 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 -
使用上面的配置启动 Vector。 访问 Vector 文档 以获取有关定义源和接收器的更多详细信息。
-
验证访问日志是否正在插入到 ClickHouse 中。运行以下查询,您应该在表中看到访问日志
SELECT * FROM nginxdb.access_logs
4. 解析日志
在 ClickHouse 中拥有日志很棒,但是将每个事件存储为单个字符串不允许进行太多数据分析。让我们看看如何使用物化视图解析日志事件。
-
物化视图(简称 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\""]
-
与 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\""]
-
在查看最终的 CREATE MATERIALIZED VIEW 命令之前,让我们查看另外几个用于清理数据的函数。例如,
RequestMethod
看起来像 "GET,带有一个不需要的双引号。运行以下 trim 函数,它会删除双引号SELECT trim(LEADING '"' FROM '"GET')
-
时间字符串有一个前导方括号,并且也不是 ClickHouse 可以解析为日期的格式。但是,如果我们将分隔符从冒号 (:) 更改为逗号 (,),那么解析效果很好
SELECT parseDateTimeBestEffort(replaceOne(trim(LEADING '[' FROM '[12/Oct/2021:15:32:43'), ':', ' '))
-
我们现在准备好定义我们的物化视图。我们的定义包括 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
注意上面的课程将数据存储在两个表中,但您可以更改初始的
nginxdb.access_logs
表以使用 Null 表引擎 - 解析后的数据仍将最终存储在nginxdb.access_logs_view
表中,但原始数据将不会存储在表中。
总结:通过使用 Vector,它只需要简单的安装和快速配置,我们可以将 Nginx 服务器的日志发送到 ClickHouse 中的表。通过使用巧妙的物化视图,我们可以将这些日志解析为列,以便更轻松地进行分析。