使用Vector将Nginx日志实时发送到Clickhouse

2023年 9月 22日 63.3k 0

有很多方法可以将数据提供给Clickhouse。一种情况是您需要不断将数据从日志文件馈送到您喜欢的分析数据库。在考虑高级消息传递解决方案之前,让我们看一下将Nginx(但不仅是)日志文件管道到Clickhouse(称为Vector)的超级简单但功能强大的方法。

配置Nginx日志

修改nginx配置参数:

log_format track '$remote_addr - $time_iso8601 "$request_uri" '
                 '$status $body_bytes_sent "$http_user_agent"';server {
  location / {
    access_log /var/log/track.log track;
    return 200 'ok';
  }
}

所有请求记录到文件,例如:/var/log/track.log

127.0.0.1 - 2022-08-01T17:19:38+03:00 "/?test=1" 200 2 "curl/7.81.0"

请求curl

curl "http://127.0.0.1/?test=1"

安装Clickhouse

安装命令

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://packages.clickhouse.com/rpm/clickhouse.repo
sudo yum install -y clickhouse-server clickhouse-client

sudo /etc/init.d/clickhouse-server start
clickhouse-client # or "clickhouse-client --password" if you set up a password.

创建表

现在,让我们创建一个 Clickhouse 表来将日志数据写入到:

CREATE TABLE log
(
    `ip` String,
    `time` Datetime,
    `url` String,
    `status` UInt8,
    `size` UInt32,
    `agent` String
)
ENGINE = MergeTree
ORDER BY date(time)

此表将允许我们进行一些非常基本的请求分析。

[root@vms89 ~]# clickhouse-client
ClickHouse client version 23.8.2.7 (official build).
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 23.8.2 revision 54465.

Warnings:
 * Linux transparent hugepages are set to "always". Check /sys/kernel/mm/transparent_hugepage/enabled
 * Maximum number of threads is lower than 30000. There could be problems with handling a lot of simultaneous queries.

vms89.rhce.cc :) CREATE TABLE log
(
    `ip` String,
    `time` Datetime,
    `url` String,
    `status` UInt8,
    `size` UInt32,
    `agent` String
)
ENGINE = MergeTree
ORDER BY date(time)

CREATE TABLE log
(
    `ip` String,
    `time` Datetime,
    `url` String,
    `status` UInt8,
    `size` UInt32,
    `agent` String
)
ENGINE = MergeTree
ORDER BY date(time)

Query id: f7cc43f3-5b08-4f6d-8aa3-dd87aeb2b866

Ok.

0 rows in set. Elapsed: 0.002 sec.

vms89.rhce.cc :)

设置Vector

安装

curl -1sLf 'https://repositories.timber.io/public/vector/cfg/setup/bash.rpm.sh' 
  | sudo -E bash
sudo yum install vector -y

并通过检查版本确保它已准备好使用:

[root@vms89 ~]# vector --version
vector 0.32.2 (x86_64-unknown-linux-gnu beb74c1 2023-09-20 19:46:02.271601143)

配置Vector

image.png
使用矢量进行流水线工作非常简单。我们配置“规则”,Vector将根据这些规则收集数据,处理数据并将其发送到目的地(在我们的例子中为Clickhouse):

配置基于三个基本步骤在文件中完成:/etc/vector/vector.toml

  • [source.***]定义要从中收集数据的源。
  • [transforms.***]块定义如何从非结构化数据中构建结构。
  • [sinks.***]块定义要向其发送/存储结构化数据的目标。
  • 代替的所有内容都是块名称。我们可以选择任何并稍后参考。我们可以拥有任意数量的任何类型的布洛克。***

    收集数据

    由于我们(有意)更改了标准 Nginx 访问日志格式,因此我们需要手动配置管道。我们的日志文件现在只是一个包含 Vector 非结构化数据的文本文件。首先,我们需要教 Vector 如何读取这些数据:/var/log/track.log

    [sources.track]
    type = "file"
    include = ["/var/log/track.log"]
    read_from = "end"
    

    在这里,我们要求 Vector 从给定的日志文件中读取数据。请注意,当Nginx实时添加新条目时,Vector会自动从日志文件中提取新条目。

    转换数据

    为了制作结构化数据,我们将使用正则表达式和在 VRL 中实现的命名捕获组,通过块处理每个条目:transform

    [transforms.process]
    type = "remap"
    inputs = ["track"]
    source = '''
    . |= parse_regex!(.message, r'^(?Pd+.d+.d+.d+) - (?Pd+-d+-d+)T(?Pd+:d+:d+).+?"(?P.+?)" (?Pd+) (?Pd+) "(?P.+?)"$')
    '''
    

    转换代码在参数中。此代码将解析数据并将捕获的数据保存到数据对象的新字段中。然后,这些字段将可用于发送到Clickhouse(或进一步处理它们)。source

    存储数据

    在将数据存储到 Clickhouse 之前,让我们检查一下构建的数据是什么样的。为此,我们将使用接收器:console

    [sinks.print]
    type = "console"
    inputs = ["process"]
    encoding.codec = "json"
    

    如我们所见,我们要求 Vector 打印转换中的数据(我们之前已经定义过)。保存更改并以交互模式运行 Vector(我已经在单独的终端中发送了单个示例请求):process/etc/vector/vector.toml127.0.0.1/?test=3

    root@desktop:~# vector
    ...
    2022-08-01T14:52:54.545197Z  INFO source{component_kind="source" component_id=track component_type=file component_name=track}:file_server: vector::internal_events::file::source: Resuming to watch file. file=/var/log/track.log file_position=497{"agent":"curl/7.81.0","date":"2022-08-01","file":"/var/log/track.log","host":"desktop","ip":"127.0.0.1","message":"127.0.0.1 - 2022-08-01T17:52:58+03:00 "/?test=3" 200 2 "curl/7.81.0"","size":"2","source_type":"file","status":"200","time":"17:52:58","timestamp":"2022-08-01T14:53:04.803689692Z","url":"/?test=3"}
    

    我们可以看到解析的字段以及多个标准属性,例如 or .在将数据保存到 Clickhouse 之前,我们还应该对转换过程进行其他更改:messagetimestamp

  • 从解析的和 创建单个属性。datetimedatetime
  • 转换和转换为整数。statussize
  • 让我们通过改变我们的块来实现这一点:[transforms.process]

    [transforms.process]
    type = "remap"
    inputs = ["track"]
    source = '''
    . |= parse_regex!(.message, r'^(?Pd+.d+.d+.d+) - (?Pd+-d+-d+)T(?Pd+:d+:d+).+?"(?P.+?)" (?Pd+) (?Pd+) "(?P.+?)"$')
    .status = to_int!(.status)
    .size = to_int!(.size)
    .time = .date + " " + .time
    '''
    

    再次检查以确保我们得到所需的更改:

    {"agent":"curl/7.81.0","date":"2022-08-01","file":"/var/log/track.log","host":"desktop","ip":"127.0.0.1","message":"127.0.0.1 - 2022-08-01T18:05:44+03:00 "/?test=3" 200 2 "curl/7.81.0"","size":2,"source_type":"file","status":200,"time":"2022-08-01 18:05:44","timestamp":"2022-08-01T15:05:45.314800884Z","url":"/?test=3"}
    

    一切都如预期。最后,我们可以将数据存储配置为Clickhouse。我们为此添加新的接收器(我们可以保留或删除以前的接收器,它将解析的数据输出到):stdout

    [sinks.clickhouse]
    type = "clickhouse"
    inputs = ["process"]
    endpoint = "http://127.0.0.1:8123"
    database = "default"
    table = "log"
    skip_unknown_fields = true
    

    在这里,我们要求 Vector 从转换中获取数据并将其发送到 Clickhouse 的表中。我们还使用选项来跳过不必要的字段。processdefault.logskip_unknown_fields

    我们保存更改,启动Vector并向Nginx发送一些请求。我们几乎可以立即在 Clickhouse 表中看到日志数据:

    1695351574122.jpg

    启动

    配置准备就绪并经过测试后,启动 Vector 服务以在后台工作:

    systemctl start vector --now
    

    性能注意事项

    我的本地内核和计算机可以轻松处理线程中每秒发送的请求。然后,还需要几秒钟才能在Clickhouse表中查看该数据。我们仍然可以考虑使用缓冲区表来优化插入,因为我们预计这里会频繁插入。16 32G 20k 100

    总结

    Vector数据流水线工具是将数据直接从Nginx日志实时传输到Clickhouse的好方法。它具有强大的工具来构建数据,因此适用于任何数据格式。

    将自定义 Nginx 访问日志管道传输到 Clickhouse 表的示例配置:

    [sources.track]
    type = "file"
    include = ["/var/log/track.log"]
    read_from = "end"
    [transforms.process]
    type = "remap"
    inputs = ["track"]
    source = '''
    . |= parse_regex!(.message, r'^(?Pd+.d+.d+.d+) - (?Pd+-d+-d+)T(?Pd+:d+:d+).+?"(?P.+?)" (?Pd+) (?Pd+) "(?P.+?)"$')
    .status = to_int!(.status)
    .size = to_int!(.size)
    .time = .date + " " + .time
    '''
    [sinks.clickhouse]
    type = "clickhouse"
    inputs = ["process"]
    endpoint = "http://127.0.0.1:8123"
    database = "default"
    table = "log"
    skip_unknown_fields = true
    

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论