共计 12573 个字符,预计需要花费 32 分钟才能阅读完成。
背景
VictoriaLogs 是 VictoriaMetrics 团队发布的日志存储系统。在此之前,文章 Prometheus 替代方案:VictoriaMetrics 中,我已经将监控由 Prometheus 切换为了VM。
几个月下来的使用感受很好。VictoriaMetrics 文档详实,性能优异,资源占用率低,兼容性佳,我几乎没有遇到任何故障。
在 2023 年底时,我使用了 Grafana 团队发行的日志系统 Loki:Nginx 日志分析之 Loki。实际使用下来性能并不太好。尽管我的数据量并不大,但是也偶尔会出现性能问题。
基于对 VictoriaMetrics 的好感,且在24年11月发行了 VictoriaLogs 的正式版本,下文进行介绍和实践。
介绍
功能
参考链接:docs.victoriametrics.com/victorialogs/
VictoriaLogs 提供以下功能:
- 它可以接受来自流行日志收集器的日志。
- 与 Elasticsearch 和 Grafana Loki 相比,它的设置和操作要容易得多。
- 它提供了简单但功能强大的查询语言,可对所有日志字段进行全文搜索。
- 它提供了用于查询VictoriaLogs的交互式命令行工具。
- 它可以与传统的 Unix 日志分析工具(如、、、、等)无缝结合。
grep
有关详细信息,请参阅这些文档。 - VictoriaLogs 的容量和性能与可用资源(CPU、RAM、磁盘 IO、磁盘空间)成线性关系。它可以在 Raspberry PI 以及具有数百个 CPU 核心和数 TB RAM 的服务器上顺利运行。
- 在相同硬件上运行时,它可以处理比 Elasticsearch 和 Grafana Loki 高达 30 倍的数据量。
- 它为具有高基数(例如,大量唯一值)的日志字段
trace_id
(例如、user_id
和ip
)提供开箱即用的快速全文搜索。 - 它支持多租户。
- 它支持无序日志的提取,又称回填。
- 它支持对新摄取的日志进行实时跟踪。
- 支持选择所选日志前后的周围日志。
- 它提供了用于查询日志的 Web UI –
- 它提供了用于查询日志的Grafana插件。
- 它支持警报 。
架构
由于发布时间并不长,尽管在计划中会有集群版本,但是当前只能使用二进制单节点版。
如果是大规模的生产环境,目前可能不太能够满足需求。小规模测试环境可以先行使用,后续等待更新。
单节点实现高可用需要进行双写,不建议这么做,安心等待集群版,官方也有计划发布数据迁移工具。
数据存储
目前仅支持本地存储,后续计划支持对象存储,同时也会提供迁移工具。
数据模型
参考链接:docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields
VLogs 的数据模型中包含三个字段:
- 消息字段:
_msg
包含日志数据 - 时间字段:
_time
包含日志时间戳 - 流字段:
_stream
唯一标志生成的应用程序实例。VLogs 优化了日志流的存储和查询。
重点在于日志流,选用合适的字段作为流字段可以提高性能。例如 container
、instance
、host
、domain
等。
- 如果您要在搜索期间使用这些字段并希望使用流过滤器
job
加快搜索速度,则将此类字段添加到日志流中是有意义的。 -
没有必要将所有常量字段添加到日志流中,因为这可能会增加数据提取和查询期间的资源使用量。
-
如果非常量字段可能随着同一流的每个日志条目而变化,则切勿将其添加到流中。例如,
ip
和user_id
绝trace_id
不能与日志流相关联,因为这可能导致高基数问题。
建议使用 流过滤器 和消息过滤器相结合,以实现高性能的快速查询。
Tips:
- 流过滤器并不支持 AND 等语法组合,每次仅能查询单个流,不知道后期是否会改进。
- 流过滤器语法类似 Prometheus QL,即使用
{}
匹配条件,例如{status=~"2.*"}
- 消息过滤器则类似 EQL。
实践
操作系统为:CentOS 7,环境如下:
software | IP | port |
---|---|---|
victoria-logs v1.4.0 | 192.168.2.10 | 9428 |
filebeat 8.15.1 | 192.168.2.11 | – |
grafana 10.4.0 | 192.168.2.10 | 3000 |
nginx 1.27.3 | 192.168.2.10 | 80,443 |
下图为数据流向:
Nginx
nginx 的日志配置可参考文章:Nginx 日志分析之 Loki
# cat /etc/nginx/nginx.conf
...
log_format json_analytics_default escape=json '{'
'"remote_addr": "$remote_addr",'
'"time_local": "$time_local",'
'"time_iso8601": "$time_iso8601",'
'"request": "$request",'
'"request_uri": "$request_uri",'
'"request_method": "$request_method",'
'"request_time": "$request_time",'
'"status": "$status",'
'"body_bytes_sent": "$body_bytes_sent",'
'"http_referer": "$http_referer",'
'"http_user_agent": "$http_user_agent",'
'"http_x_forwarded_for": "$http_x_forwarded_for",'
'"http_host": "$http_host",'
'"host": "$host",'
'"ssl_protocol": "$ssl_protocol",'
'"scheme": "$scheme",'
'"server_protocol": "$server_protocol",'
'"upstream_addr": "$upstream_addr",'
'"upstream_cache_status": "$upstream_cache_status",'
'"upstream_response_time": "$upstream_response_time"'
'}';
access_log /data/logs/nginx/json_access.log json_analytics_default;
...
截取一条日志如下:
{"remote_addr": "192.168.2.10","time_local": "09/Jan/2025:11:45:25 +0800","time_iso8601": "2025-01-09T11:45:25+08:00","request": "GET / HTTP/1.1","request_uri": "/","request_method": "GET","request_time": "0.128","status": "200","body_bytes_sent": "104746","http_referer": "","http_user_agent": "Go-http-client/2.0","http_x_forwarded_for": "110.42.99.40, 117.68.3.229","http_host": "www.opshub.cn:443","host": "www.opshub.cn","ssl_protocol": "TLSv1.2","scheme": "https","server_protocol": "HTTP/1.1","upstream_addr": "192.168.2.11:8000","upstream_cache_status": "","upstream_response_time": "0.128"}
VictoriaLogs 部署
参考链接:docs.victoriametrics.com/victorialogs/quickstart/#pre-built-bina…
目前 VictoriaLogs 仅支持单节点版本。
VictoriaLogs 不需要进行太多复杂配置,团队宣称默认参数基本就是最优的,默认值会根据可用的 CPU 和 RAM 资源自动调整,无需额外调整。操作系统也无需额外调优,只需要把允许打开的文件句柄数量调大即可。
我在配置文件中仅指定了数据存储路径和日志保存周期,其他均遵循默认参数,未进行额外配置。(默认端口:8428)
# 下载
cd /tmp/
curl -L -O https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.4.0-victorialogs/victoria-logs-linux-amd64-v1.4.0-victorialogs.tar.gz
tar xf victoria-logs-linux-amd64-v1.4.0-victorialogs.tar.gz
mv victoria-logs-prod /usr/local/bin/victoria-logs-prod
# 配置数据目录
mkdir /var/lib/victoria-logs/
useradd -system --no-create-home --shell /usr/sbin/nologin victorialogs
chown -R /var/lib/victoria-logs/
# 配置systemd
# vim /etc/systemd/system/victorialogs.service
[Unit]
Description=VictoriaLogs service
After=network.target
[Service]
Type=simple
User=victorialogs
Group=victorialogs
ExecReload=/bin/kill -HUP $MAINPID
ExecStart=/usr/local/bin/victoria-logs-prod \
-storageDataPath=/var/lib/victoria-logs \
-retentionPeriod=8w
SyslogIdentifier=victorialogs
Restart=always
PrivateTmp=yes
ProtectHome=yes
NoNewPrivileges=yes
ProtectSystem=full
[Install]
WantedBy=multi-user.target
# 启动和开机自启
systemctl start victorialogs.service
systemctl enable victorialogs.service
systemctl status victorialogs.service
FileBeat 部署
参考链接:docs.victoriametrics.com/victorialogs/data-ingestion/filebeat/,https://www.elastic.co/downloads/past-releases#filebeat
mkdir -p /usr/local/filebeat && cd /usr/local/filebeat
wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.15.1-linux-x86_64.tar.gz
tar xf filebeat-8.15.1-linux-x86_64.tar.gz
cd filebeat-8.15.1-linux-x86_64
mv filebeat.yml filebeat.yml-default
# 创建配置文件
# vim filebeat.yml
filebeat.inputs:
- type: filestream
id: nginx-json-logs
enabled: true
paths:
- /data/logs/nginx/json*.log
# 将json中的字段提取为顶级字段
json.keys_under_root: true
json.add_error_key: true
# 添加处理器,提取json日志中的字段为适合 Elastic Stack(比如 Elasticsearch)格式的键值对
processors:
- decode_json_fields:
fields: ["message"]
target: ""
overwrite_keys: true
- add_host_metadata:
when.not.contains.tags: forwarded
output.elasticsearch:
hosts: ["http://localhost:9428/insert/elasticsearch/"]
parameters:
_msg_field: "message"
_time_field: "@timestamp"
# 以4个字段创建日志流,其中 host.hostname由add_host_metadata获取,log.file.path为默认字段,http_host、status由decode_json_fields获取
_stream_fields: "host.hostname,log.file.path,http_host,status"
allow_older_versions: true
# 测试配置文件是否正确
./filebeat -e -c filebeat.yml
# 使用systemd管理 filebeat
# vim /etc/systemd/system/filebeat.service
[Unit]
Description=Filebeat Service
After=network.target
[Service]
User=root
Group=root
ExecStart=/usr/local/filebeat/filebeat-8.15.1-linux-x86_64/filebeat -c /usr/local/filebeat/filebeat-8.15.1-linux-x86_64/filebeat.yml
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
# 启动和开机自启
systemctl start filebeat
systemctl enable filebeat
systemctl status filebeat
关键点在于要使 filebeat 能够提取 json 中的字段,并使 victorialogs 能够创建 stream。合理的 stream 能够有效提升 victorialogs 的存储和查询效率。
Grafana 集成数据源
参考链接:docs.victoriametrics.com/victorialogs/victorialogs-datasource/
由于 VictoriaLogs 数据源 还没发布到 Grafana 市场,需要手动安装。
# 修改配置文件
# vim /etc/grafana/grafana.ini
[plugins]
allow_loading_unsigned_plugins = victoriametrics-logs-datasource
# 创建vm数据源配置文件
# vim /etc/grafana/provisioning/datasources/vm.yml
apiVersion: 1
datasources:
# <string, required> Name of the VictoriaLogs datasource
# displayed in Grafana panels and queries.
- name: VictoriaLogs
# <string, required> Sets the data source type.
type: victoriametrics-logs-datasource
# <string, required> Sets the access mode, either
# proxy or direct (Server or Browser in the UI).
access: proxy
# <string> Sets URL for sending queries to VictoriaLogs server.
# see https://docs.victoriametrics.com/victorialogs/querying/
url: http://192.168.2.10:9428
# <string> Sets the pre-selected datasource for new panels.
# You can set only one default data source per organization.
isDefault: true
# 手动下载插件
cd /tmp && wget wget https://github.com/VictoriaMetrics/victorialogs-datasource/releases/download/v0.13.1/victoriametrics-logs-datasource-v0.13.1.zip
tar xf victoriametrics-logs-datasource-v0.13.1.zip
mv victoriametrics-logs-datasource /var/lib/grafana/plugins/
chown grafana:grafana -R /var/lib/grafana/plugins/victoriametrics-logs-datasource
# 重启grafana
systemctl restart grafana-server
此时在数据源中可以看到:
VMUI
浏览器访问 192.168.2.10:9428/ 可以使用原生的 WebUI进行查询。
VMUI 目前功能很简陋,只能执行查询,结果 limit ,展示查询结果,对比 Kibana 有较大差距。
要绘制监控面板,看下文接入 Grafana 后的实现。
上图案例中,查询条件是 *,limit:50。结果有两部分,上部是图表,每条线代表一个独立的 log stream。下部是日志详情。
LogsQL
参考链接:docs.victoriametrics.com/victorialogs/logsql/
文档写的非常详实,所以下面只做简单介绍。
LogsQL 提供了多种过滤器、管道、排序、限制器等。
和 Loki 的异同。
- 相同之处:在未创建 steram 的情况下也可以实现全文搜索。在 Loki 中可以使用 json 管道解析序列化的 json日志,Vlogs可用unpack_json 解析。
- 不同之处:Loki 几乎完全继承了 Prometheus QL语法,而 LogsQL 仅在匹配流字段时相似,其他时候更像是 ElasticSeatch 8后的 EQL。
性能优化点:
- 强烈建议指定时间过滤器以将搜索范围缩小到特定的时间范围。
- 强烈建议指定流过滤器以将搜索范围缩小到特定的日志流。
- 将单词过滤器和短语过滤器等速度更快的过滤器移至查询的开头。此规则不适用于时间过滤器和流过滤器,它们可以放在查询的任何位置。
- 将匹配较少日志条目的更具体的过滤器移至查询的开头。此规则不适用于时间过滤器和流过滤器,它们可以放在查询的任何位置。
- 如果选定的日志被传递到管道进行进一步的转换和统计计算,则建议使用更具体的过滤器来减少选定日志的数量,从而返回更少数量的日志供管道处理。
- 最好使用单词过滤器和短语过滤器,因为子字符串过滤器可能非常慢。
LogsQL示例见下文,通过 Grafana 查询验证。
Grafana 绘制图表
参考链接:https://docs.victoriametrics.com/victorialogs/querying/
VictoriaLogs 提供以下 HTTP 端点:
-
/select/logsql/query
用于查询日志。 -
/select/logsql/tail
用于实时跟踪查询结果。 -
/select/logsql/hits
用于查询给定时间范围内的日志命中统计信息。 -
/select/logsql/facets
用于查询所选日志中每个字段最常见的值。 -
/select/logsql/stats_query
用于查询给定时间的日志统计信息。 -
/select/logsql/stats_query_range
用于查询给定时间范围内的日志统计信息。 -
/select/logsql/stream_ids
用于查询日志流_stream_id
的值。 -
/select/logsql/streams
用于查询日志流。 -
/select/logsql/stream_field_names
用于查询日志流字段名称。 -
/select/logsql/stream_field_values
用于查询日志流字段值。 -
/select/logsql/field_names
用于查询日志字段名称。 -
/select/logsql/field_values
用于查询日志字段值。
Grafana 对于 VLogs 数据源,支持3种方式查询,分别是:
- range :
/select/logsql/stats_query_range
- RAW Logs:
/select/logsql/query
- instance:
/select/logsql/stats_query
对于 json 这类序列化数据,需要使用 unpack_json 解包后才可以提取到字段直接匹配,否则只能使用正则、短语等过滤器匹配。
range示例:
# 统计 Nginx QPS
# 使用 时间过滤器、count管道
_time:5m
| stats by (_time:1s) count(*) as QPS
RAW Logs 示例:
15分钟内,域名为:*opshub.cn,状态码不为2xx的日志:
# 使用字符串模糊匹配
# 使用时间过滤器、短语过滤器、精确前缀过滤器
_time:15m | .opshub.cn | !~'"status": "2'*
# 使用 unpack_json 管道解析 Json Message 提取了日志字段
# 使用 re2语法的正则表达式过滤器
_time:15m
| unpack_json fields(status, http_host)
| http_host ~ ".*opshub.cn.*"
| status !~ "^2"
instance 示例:
统计15分钟内域名为 opshub.cn,状态码非 200 的条数
# 使用字符串模糊匹配
# 使用短语过滤器、正则表达式过滤器
_time:15m | .opshub.cn | !~'"status": "2'* |count () as opshub.cn_15m_count
# 使用 unpack_json 管道解析 Json Message
# 使用正则表达式过滤器
_time:15m
| unpack_json fields(status, http_host)
| http_host ~ ".*opshub.cn.*"
| status != "200"
| count() as opshub.cn_15m_count
更多LogsQL示例:
统计每类请求方法的个数:
_time:5m
| unpack_json fields(request_method)
| stats by(request_method) count() as count
统计5分钟内每类状态码的个数:
# 使用字符串模糊匹配
# 正则表达式过滤器
_time:5m
| stats count() total,
count() if (~'"status": "2') as status_2xx,
count() if (~'"status": "3') as status_3xx,
count() if (~'"status": "4') as status_4xx,
count() if (~'"status": "5') as status_5xx
# 使用 unpack_json 管道解析 Json Message
# 使用流过滤器,由于流过滤器不能同时匹配多个查询条件,所以需要每类状态码都要写单独的查询规则
_time:5m
| unpack_json fields(status)
| {status=~"2.*"}
| count() as status_2xx
_time:5m
| unpack_json fields(status)
| {status=~"3.*"}
| count() as status_3xx
_time:5m
| unpack_json fields(status)
| {status=~"4.*"}
| count() as status_4xx
_time:5m
| unpack_json fields(status)
| {status=~"5.*"}
| count() as status_5xx
# 统计每类状态码的占比
# 使用正则表达式过滤器、Conditional extract 管道、count 管道
_time:5m
| stats count() total,
count() if (~'"status": "2') as status_2xx,
count() if (~'"status": "3') as status_3xx,
count() if (~'"status": "4') as status_4xx,
count() if (~'"status": "5') as status_5xx
| math status_2xx / total as status_2xx_pct,
status_3xx / total as status_3xx_pct,
status_4xx / total as status_4xx_pct,
status_5xx / total as status_5xx_pct
| fields status_2xx_pct, status_3xx_pct, status_4xx_pct, status_5xx_pct
统计指定域名www.opshub.cn 每类状态码的占比:
# 先使用流过滤器提高查询性能,再使用正则过滤器等其他过滤器
_time:60m | {http_host=www.opshub.cn}
| stats count() total,
count() if (~'"status": "2') as status_2xx,
count() if (~'"status": "3') as status_3xx,
count() if (~'"status": "4') as status_4xx,
count() if (~'"status": "5') as status_5xx
| math status_2xx / total as status_2xx_pct,
status_3xx / total as status_3xx_pct,
status_4xx / total as status_4xx_pct,
status_5xx / total as status_5xx_pct
| fields status_2xx_pct, status_3xx_pct, status_4xx_pct, status_5xx_pct
# 直接使用正则过滤器
_time:60m | ~'"http_host": "www.opshub.cn"'
| stats count() total,
count() if (~'"status": "2') as status_2xx,
count() if (~'"status": "3') as status_3xx,
count() if (~'"status": "4') as status_4xx,
count() if (~'"status": "5') as status_5xx
| math status_2xx / total as status_2xx_pct,
status_3xx / total as status_3xx_pct,
status_4xx / total as status_4xx_pct,
status_5xx / total as status_5xx_pct
| fields status_2xx_pct, status_3xx_pct, status_4xx_pct, status_5xx_pct
TIPS:
- 当在 grafana 中使用了RAW Logs或 Range 方式查询时,由于和时间序列有关,结果会同时被语句中的 _time:60m 和 Grafana 中自带的时间选择器影响。
- 流过滤器可以提高性能,但是每条查询仅能匹配单个流,无法在一条查询中匹配多个不同流的结果。这种情况下需要结合或只使用其他过滤器实现。
监控
参考链接:docs.victoriametrics.com/victorialogs/#monitoring
VictoriaLogs 在页面上以 Prometheus 展示格式公开内部指标 `http://localhost:9428/metrics`,所以只需要在 victoriameteics 中添加一个 job,再导入官方的 dashboard 即可实现监控。
# vim /etc/victoria-metrics/prometheus.yml
- job_name: 'victorialogs'
static_configs:
- targets: ['192.168.2.10:9428']
metrics_path: /metrics
scheme: http
# 重载
systemctl reload victoriametrics.service
面板预览如下:
告警
此处我没有进行实践验证,由于 VictoriaLogs 发行的时间过短,我之前使用的告警组件 夜莺 不能支持对 VLogs 的查询。
文档:docs.victoriametrics.com/victorialogs/vmalert/ 中表示能够使用 vmalert 集成 VictoriaLogs 数据源。
- 能够通过 Recording rules 配置 LogsQL 查询,将查询结果回填到 任何与 PromQL/MetricsQL 兼容的数据源。
- 能够通过 Alerting rules 配置 LogsQL 查询,将查询结果发送到 Alertmanager。
我有几个猜想:
- 既然能够配置 Recording rules 将查询结果写入到 Prometheus,是否意味着夜莺能够以 Prometheus 或 VM 数据源实现对 VLogs 的告警?
- Recording rules 方式,将查询结果写入 Prometheus 过程中,怎么保证不丢失日志细节?将日志字段通过 label(key:value) 方式写入到 metrics ?
- Grafana 在添加 victoriametrics-logs-datasource 插件后,可以实现对 VLogs 的查询,是否意味着能够通过 Grafana alert 原生组件实现告警?
有兴趣的朋友可以自行验证。
总结
因为对 VictoriaMtrics 的好感,试用了 VictoriaLogs。总体感觉延续了团队之前项目文档详实、兼容性佳、性能优良(待考证)的风格。
但由于项目发布周期较短,目前很多功能仍有缺漏,持续关注等待项目方改进~
本文属于专题:日志
- Nginx 日志分析之 Loki
- 新一代日志分析:VictoriaLogs
引用链接
- Prometheus 替代方案:VictoriaMetrics
- Nginx 日志分析之 Loki
- docs.victoriametrics.com/victorialogs/
- docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields
- 高基数问题
- docs.victoriametrics.com/victorialogs/quickstart/#pre-built-bina...
- docs.victoriametrics.com/victorialogs/data-ingestion/filebeat/
- https://www.elastic.co/downloads/past-releases#filebeat
- docs.victoriametrics.com/victorialogs/victorialogs-datasource/
- 192.168.2.10:9428/
- docs.victoriametrics.com/victorialogs/logsql/
- docs.victoriametrics.com/victorialogs/#monitoring
- 夜莺
- docs.victoriametrics.com/victorialogs/vmalert/
- Alertmanager