vector实践-性能吊打logstash

# 0. 前言 简单来说 vector 扮演着类似 logstash 的角色,但有着比 logstash 强悍太多的性能、简单明了的配置文件、强大的数据处理函数、智能均衡 kafka 分区消费等等!下面请跟随笔者的脚步,对 vector 实践一番吧。

# 0.1 vector 是什么 vector 是什么?以下描述翻译自 vector 官网:https://vector.dev (opens new window)

Vector 是一种高性能的可观察性数据管道,可以收集、转换所有日志、指标和跟踪信息( logs, metrics, and traces),并将其写到您想要的存储当中;Vector 可以实现显着的成本降低、丰富的数据处理和数据安全;且开源,比所有替代方案快 10 倍。

1简单来说,它扮演着类似 logstash 的角色,但有着比 logstash 强悍太多的性能、简单明了的配置文件、强大的数据处理函数、智能均衡 kafka 分区消费等等;在这些特性中,性能直接关乎成本,相信这是每一家公司都会重点关注的;而从官方介绍中我们已经可以窥探一二,以下是官网给出的一些实践数据:

# 0.2 为什么用 vector 如果说官方有自卖自夸之嫌,那么我给出自身实践的数据以供参考:

本人所在公司每天产生约 15T 的日志量,在公司日志架构中 logstash 起着这样的作用:从 kafka 中消费数据,然后进行清洗、格式转换,最终写入 elasticsearch;公司一共有 34 台 16c64g 规格的 logstash 机器,然而这样的高配集群在晚高峰的时候会显得很吃力,每晚必定会报一堆 kafka 堵塞的告警;经过调研决定使用 vector 替换 logstash,最终只用了 10 台 16c16g 的机器便完成替换,并且之后再也没有报过 kafka 堆积告警!

# 1. 安装部署 官方提供了安装包、docker 等多种安装方式,这里我们使用 docker 安装等方式来进行演示

# 1.1 使用 docker-compose 安装 vector 准备好 docker-compose.yaml 文件

version: '3'

services:

vector:

image: timberio/vector:latest-alpine # 镜像

container_name: vector # 容器名

volumes:

- /data/vector/config/:/etc/vector/ # 挂载配置文件

- /etc/localtime:/etc/localtime # 跟宿主机时区保持一致

ports:

- 9598:9598 # metrics信息暴露端口,后面会讲到

# environment: # 开启DEBUG模式,这里不开启

# VECTOR_LOG: debug

entrypoint: "vector -c /etc/vector/*.toml -w /etc/vector/*.toml" # 启动命令

restart: always

1234567891011121314然后在 docker-compose.yaml 文件所在目录执行以下命令即可启动 vector:

docker-compose up -d

1使用 docker logs -f vector 可以看到一些信息,如果 vector 无法启动一般先从这里获取报错信息

# 1.2 vector 配置文件 在上述 docker-compose.yaml 中,我们挂载了本地准备好的配置文件,接下来我们便来讲一讲配置文件一般如何配置;在此之前我们大概讲一讲配置文件的组成,大概可以分为这么几个模块:

tips:注意,以下任何模块(source、transforms、sinks)都可以配置多个元素,但是要保证不能同名

# 1.2.1 来源(sources) 即 vector 的数据来源,它支持文件、kafka、http、各类 metrics 等等数据源,详细请看:https://vector.dev/docs/reference/configuration/sources/ (opens new window),各类数据源均可在文档中找到配置方式,这里我们使用 kafka 演示:

[sources.kafka-nginx-error] # “数据源”名称

type = "kafka" # 类型

bootstrap_servers = "10.xxx.xxx.xxx:9092,10.xxx.xxx.xxx:9092" # kafka链接地址

group_id = "consumer-group-name" # 消费组id

topics = [ "^(prefix1|prefix2)-.+" ] # topic,支持正则

12345# 1.2.2 变换[可选](transforms) 如果原始数据足够完美无需任何处理,那么这一块可以忽略,但是实际上大部分情况下还是需要这一步的,这里我们讲几个最常用的“变换”,详细请看:https://vector.dev/docs/reference/configuration/transforms/ (opens new window)

# 1.2.2.1 remap remap 在 vector 中使用 VRL(Vector Remap Language,一种面向表达式的语言,旨在以安全和高性能的方式处理可观察性数据)来实现,这里我们看一看公司使用 vector 处理 nginx 错误日志的配置:

[transforms.remap-nginx-error] # “变换”名称

type = "remap" # 类型

inputs = ["kafka-nginx-error"] # 输入,这里的输入自然是上一层的“来源”

source = ''' # 正式开始处理

. = parse_json!(.message) # 首先将每一条错误日志解析成json,message的值就是从kafka中读取到的原始值

del(.@metadata) # 删除Vector自动携带的一些信息

.parse = parse_nginx_log!(.message, "error") # 解析nginx错误日志

'''

12345678可以看到,在上述处理过程中,只是用了 parse_json、del、parse_nginx_log 三个函数便将错误日志处理完成,实际上解析 nginx 错误日志是一个非常困难的事情,因为 nginx 错误日志的格式不固定,我们很难通过通用的步骤来指定字段、取值,而 Vector 自带来解析 nginx 错误日志函数,一行代码搞定!我们可以对比之前使用 logstash 时的处理方式:

grok {

match => [

"message", "(?

"message", "(?

}

12345类似的处理函数还有很多,这里不一一列举!

# 1.2.2.2 filter 很多时候从数据源采集过来的数据我们并不是全部都需要,filter 顾名思义便是用来解决这一问题的,下面的配置也很好理解:包含 spanID 字段的数据才保留,不包含的丢弃

[transforms.filter-jaeger-span]

type = "filter"

inputs = [ "remap-ssd" ]

condition = "exists(.spanID) == true"

1234# 1.2.3 水槽(sinks) 可以理解为数据往哪发送,它支持 console(如果是 docker 启动直接打到 docker log 中)、elasticsearch、kafka、vector、http 等等,详细请看:https://vector.dev/docs/reference/configuration/sinks/ (opens new window),这里使用 elasticsearch 来演示

[sinks.elasticsearch-ssd] # “水槽”名称

type = "elasticsearch" # 类型

inputs = [ "remap-ssd" ] # 输入,这里的输入是上一层的“变换”名称

endpoint = "http://10.xxx.xxx.xxx:9200" # 输出的链接地址

bulk.index = "{{ project_name }}-{{ env }}-%Y-%m-%d" # 索引名称,这里看到我们使用了日志当中的字段作为变量、以及日期来作为索引名称

12345申明

原创文章eryajf,未经授权,严禁转载,侵权必究!此乃文中随机水印,敬请读者谅解。

Copyright 二丫讲梵 (opens new window) 版权所有

# 2. 实践 经过以上介绍,相信你已经可以搞定单个日志的 vector 配置,但是实际使用场景中,会有太多日志,而且各个部门的日志格式也不尽相同,所以实际使用场景中需要用到一些实用技巧,这里列举几个比较典型的

# 2.1 将结果输出到 console 这是我们调试时的利器,我们经常需要掌握我们拿到了什么样的数据,或者了解我们将要写入下游的数据是否符合我们的预期:

[sinks.console]

type = "console"

inputs = [ "remap-ssd" ]

encoding.codec = "json" # 可选json 或者 text

1234# 2.2 多配置文件启动 实际上聪明的你已经发现,在上文介绍 docker-compose 中,已经使用了该配置

vector -c /etc/vector/*.toml -w /etc/vector/*.toml

1这样我们便可以给多个日志配置相应的配置文件,最好使用 git 管理,部署时直接 pull 下来,然后所有配置文件一起启动即可;这里还是用到了-w 参数,意思是关注配置文件中的更改,并相应地重新加载;再次提醒:即使是多个配置文件,在同一个 vector 实例中各阶段的命名也不能重名

# 2.3 多 topic 使用正则匹配 各个部门可能对应的统一过日志格式,他们的处理方式可能都一样,这样我们可以在“来源”中指定消费同一类 topic

topics = [ "^(prefix1|prefix2)-.+" ]

1# 2.4 索引使用日志中的字段值作为索引名称 topic 可以使用正则消费多个 topic,但是我们不能把这些日志一起打到同一个索引中,如果各部门日志格式统一的话,可以使用日志中的字段值作为变量名称,使用变量的方式就是,此外还可以使用%Y、%m、%d 分别表示年、月、日,这是一种很好的日志索引管理方式

bulk.index = "{{ project_name }}-{{ env }}-%Y-%m-%d"

1# 2.5 查看 vector 各任务的处理情况 在 vector 启动之后,我们可能会关心各任务的处理情况,我们只需要在某个配置文件中(或者单独创建一个配置文件)加入以下配置,让 vector 启动时加载该配置文件,便能以命令行的方式实时查看各任务的处理情况

[api]

enabled = true

12然后执行以下命令即可:

docker exec -it vector sh

vector top

12

# 2.6 vector 更加详细的 metrics 指标 vector 提供了详细的自身指标供我们查看,不过截止目前,该功能还是测试版,我们可以先看看实际效果,在某个配置文件中(或者单独创建一个配置文件)加入以下配置,vector 加载后便会启动 9598 端口,配置文件中我们指定了使用 prometheus_exporter 格式的输出,熟悉 prometheus 的你一定会发现返回的数据格式非常熟悉

[sources.metrics]

type = "internal_metrics"

namespace = "vector"

scrape_interval_secs = 30

[sinks.prometheus]

type = "prometheus_exporter"

inputs = [ "metrics" ]

address = "0.0.0.0:9598"

default_namespace = "service"

12345678910

# 2.7 vector 的自动均衡 kafka 消费[重要] 在使用 vector 之前,logstash 经常会出现消费不均匀的情况,导致部分 logstash 节点负载高、另一部分节点却又很空闲,在使用了 vector 之后这个问题自动解决了,从下图可以看出每个 vector 实例自动消费了 6 个分区;其实这是一个非常有用的功能:在使用 logstash 时,由于它不能自动均衡消费,所以我们需要评估各个 topic 的数据量,然后给其分配机器,比如 20 台机器专门消费数据量大的 topic,5 台专门消费数据小的 topic;但是这个数据量和消费能力其实都是我们根据以往的经验判断的,给 topic 分配的机器数量也是拍脑袋决定的,并不是非常准确;而 vector 就自然而然的解决了这个问题,我们无需考虑太多,无需区分机器,所有的机器都一起消费所有的 topic!

# 2.8 自适应并发请求 在 0.17.0 版本后默认启用了自适应并发,这是一个智能、强大的功能,官方介绍请看https://vector.dev/blog/adaptive-request-concurrency/ (opens new window),这里大致介绍一下:

vector往下游写数据的速度非常快,这对下游如elasticsearch等接收器提出了重大挑战,因为这些服务无法始终像vector一样快速处理事件负载;在0.11之前的vector版本中,我们可以设置限速来解决这类问题,可是这又引发了另一个问题,限速作为后备是不错,但它会将您锁定在一个永久循环中:

在这个恶性循环中,您需要不断避免两种结果:

- 您将限制设置得太高,进而会压倒您的服务、损害系统可靠性,这时候就需要降低限制并重新评估了。

- 将限制设置得太低并浪费资源,您的 Elasticsearch 集群可能能够处理比您提供的更多的并发性,这时候又需要重新评估了。

1234为了解决这个问题,vector 推出了自适应并发的功能,它会重点观察两件事:请求的往返时间 (RTT) 和 HTTP 响应代码(失败与成功),从而决策出一个最佳的速率!

# 2.9 性能效果对比[重要] 拿同一个 topic、同一个消费组来做对比,consumergroup:mg topic:mg-sale-api 每晚都会告警 kafka 堆积,堆积量都在 2000w 以上

在使用 vector 之后,晚高峰最大的未消费数只有不到 5k,这还是节点从 34 台 16c64g 缩容到 10 台 16c16g 的结果

# 3. 小结 实践下来可以发现 vector 是一款功能强大、性能优秀的数据管道工具,但在国外火热的它却在国内使用的人数寥寥无几,相关资料也少之又少,不过笔者相信是金子总会发光的,相信以后 vector 会被更多人发掘,从而在更多的公司里发光发热!特此感谢微拍堂同事 -- 李秋阳在项目期间提供的指引以及鼎力支持!