https://tangxusc.github.io/blog/2019/03/fluentd-%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AE%E4%BD%BF%E7%94%A8%E4%BB%8B%E7%BB%8D/

fluentd 安装、配置、使用介绍

fluentd2 是一个针对日志的收集、处理、转发系统。通过丰富的插件系统, 可以收集来自于各种系统

fluentd2 是一个针对日志的收集、处理、转发系统。通过丰富的插件系统, 可以收集来自于各种系统或应用的日志,转化为用户指定的格式后,转发到用户所指定的日志存储系统之中。

通过 fluentd,你可以非常轻易的实现像追踪日志文件并将其过滤后转存到 MongoDB 这样的操作。fluentd 可以彻底的将你从繁琐的日志处理中解放出来。

用图来做说明的话,使用 fluentd 以前,你的系统是这样的:

使用了 fluentd 后,你的系统会成为这样:

此文将会对 fluentd 的安装、配置、使用等各方面做一个简要的介绍。

fluentd 既可以作为日志收集器安装到每一个结点上, 也可以作为一个服务端收集各个结点上报的日志流。 你甚至也可以在各个结点上都部署 fluentd 收集日志,然后上报到一个 fluentd 集群做统一处理, 然后再转发到最终的日志存储服务器。

所以在一个完整的日志收集、处理系统里,你可以构建一个这样的日志处理流:

Apps (with fluentd/fluent-bit) -> broker (kafka) -> fluentd cluster -> elasticsearch -> kibana

其中提到的 fluent-bit 是一个极简版的 fluentd,专门用作日志的收集和转发, 可以在应用结点上取代 fluentd 收集日志,满足极端的资源要求。

1、与 logstash 的对比
通过上述描述,你也许会觉得和 ELK 中的 Logstash 高度相似。事实上也确实如此,你完全可以用 fluentd 来替换掉 ELK 中的 Logstash。

有两篇文章对这两个工具做了很好的对比:

 Fluentd vs. Logstash: A Comparison of Log Collectors
 Log Aggregation with Fluentd, Elasticsearch and Kibana

概括一下的话,有以下区别:

 fluentd 比 logstash 更省资源;
 更轻量级的 fluent-bid 对应 filebeat,作为部署在结点上的日志收集器;
 fluentd 有更多强大、开放的插件数量和社区。

1、安装 fluentd
详细可参见官方文档。

以 CentOS 为例:

安装

$ curl -L https://toolbelt.treasuredata.com/sh/install-redhat-td-agent3.sh | sh

通过 systemd 启动

$ sudo systemctl start td-agent.service
$ sudo systemctl status td-agent.service

或者也可以手动启动

$ /etc/init.d/td-agent start
$ /etc/init.d/td-agent stop
$ /etc/init.d/td-agent restart
$ /etc/init.d/td-agent status

2、安装插件

#从 rpm 安装的话,

#比如要使用下例的 mongo,需要安装

# $ sudo td-agent-gem install fluent-plugin-mongo
$ sudo td-agent-gem <PLUGIN_NAME>

#从 gem 安装的话

$ sudo gem install <PLUGIN_NAME>

三、配置文件
1、路径
分为两种情况:

如果是通过 gem 安装的,那么可以通过下列命令生成和编辑配置文件

$ sudo fluentd --setup /etc/fluent
$ sudo vi /etc/fluent/fluent.conf

如果是通过 RPM, Deb 或 DMG 安装的,那么配置文件在:

$ sudo vi /etc/td-agent/td-agent.conf

2、重用
你可以在配置文件里使用 @include 来切分你的配置文件,include 支持多种写法:

#绝对路径
include /path/to/config.conf

#相对路径
@include conf.d/*.conf

#甚至 URL
@include http://example.com/fluent.conf

3、数据格式
在配置文件里你需要为很多参数赋值,这些值必须使用 fluentd 支持的数据格式,有下列这些:

string:字符串,最常见的格式,详细支持语法见文档1;
integer:整数
float:浮点数;
size 大小,仅支持整数
<INTEGER>k 或 <INTERGER>K;
<INTEGER>m 或 <INTERGER>M;
<INTEGER>g 或 <INTERGER>G;
<INTEGER>t 或 <INTERGER>T。
time:时间,也只支持整数;
<INTEGER>s 或 <INTERGER>S;
<INTEGER>m 或 <INTERGER>M;
<INTEGER>h 或 <INTERGER>H;
<INTEGER>d 或 <INTERGER>D。
array:按照 JSON array 解析;
hash:按照 JSON object 解析。

四、命令
配置文件的核心是各种命令块(directives),每一种命令都是为了完成某种处理,命令与命令之间还可以组成串联关系,以 pipline 的形式流式的处理和分发日志。

命令的主要组成部分有:

source
filter
match
label
error

最常见的方式就是 source 收集日志,然后由串联的 filter 做流式的处理,最后交给 match 进行分发。match 是日志流程的终点,一旦匹配了某一个 match,就不会再继续往下匹配了。

同时你还可以用 label 将任务分组,用 error 处理异常,用 system 修改运行参数。

不同的命令中,都可以通过 @type 指定想要使用的插件名字,而且还可以传入各式各样的插件参数, 由丰富的插件提供强大的功能,下面是详细一些的说明。(关于参数的说明在下面一章。)

1、source
source 是 fluentd 的一切数据的来源,每一个 source 内都包含一个输入模块,比如原生集成的包含 http 和 forward 两个模块,分别用来接收 HTTP 请求和 TCP 请求:

# Receive events from 24224/tcp
# This is used by log forwarding and the fluent-cat command
<source>
  @type forward
  port 24224
</source>

# http://this.host:9880/myapp.access?json={"event":"data"}
<source>
  @type http
  port 9880
</source>

当然,除了这两个外,fluentd 还有大量的支持各种协议或方式的 source 插件,比如最常用的 tail 就可以帮你追踪文件。

每一个具体的插件都包含其特有的参数,比如上例中 port 就是一个参数,当你要使用一个 source 插件的时候,注意看看有哪些参数是需要配置的,然后将其写到 source directive 内。

source dirctive 在获取到输入后,会向 fluent 的路由抛出一个事件,这个事件包含三个要素:

tag
time
record
那上例代码中的第二个 source 举例,当我们发起一个 http://this.host:9880/myapp.access?json={"event":"data"} 的请求时,这个 source 会抛出:

generated by http://this.host:9880/myapp.access?json={"event":"data"}

tag: myapp.access
time: (current time)
record: {“event”:”data”}

关于如何编写一个输入插件,可以参考文档4。

2、match
match 用来指定动作,通过 tag 匹配 source,然后执行指定的命令来分发日志,最常见的用法就是将 source 收集的日志转存到数据库。

# http://this.host:9880/myapp.access?json={"event":"data"}
<source>
  @type http
  port 9880
</source>

# 将标记为 myapp.access 的日志转存到文件
<match myapp.access>
  @type file
  path /var/log/fluent/access
</match>

上例中的 myapp.access 就是 tag,tag 有好几种匹配模式:

:匹配任意一个 tag;
*
:匹配任意数量个 tag;
a b:匹配 a 或 b;
{X,Y,Z}:匹配 X, Y, Z 中的一个。
比如我可以写成这样:

<match a.>
<match **>
<match a.{b,c}>
<match a.
b.*>

match 是从上往下依次匹配的,一旦一个日志流被匹配上,就不会再继续匹配剩下的 match 了。 所以如果有 <match **> 这样的全匹配,一定要放到配置文件的最后。

用法和 source 几乎一模一样,不过 source 是抛出事件,match 是接收并处理事件。你同样可以找到大量的各式各样的输出插件,也可以参考文档5自己写一个。

而且 match 不仅仅用来处理输出,还可以对日志事件进行一些处理后重新抛出,当成一个新的事件从新走一遍流程,比如可以用 rewrite_tag_filter 插件为日志流重新打上 tag,实现通过正则来对日志进行分流的需求:

<match app>
  # 捕获被打上了 app tag 的日志
  ...
</match>

<match cp>
  # 捕获被打上了 cp tag 的日志
  ...
</match>

<match **>
  # https://docs.fluentd.org/v0.12/articles/out_rewrite_tag_filter
  # 被打上 tag 的日志会被从头处理,从而被上面的 match 捕获,实现了日志的分流
  @type rewrite_tag_filter
  <rule>
    key log  # 指定要处理的 field
    pattern ^.*\ c\.p\.\ .*  # 匹配条件
    tag cp  # 打上 tag `cp`
  </rule>
  <rule>
    key log
    pattern ^.*
    tag app  # 其余日志打上 tag `app`
  </rule>
</match>

3、filter
filter 和 match 的语法几乎完全一样,但是 filter 可以串联成 pipeline,对数据进行串行处理,最终再交给 match 输出。

#http://this.host:9880/myapp.access?json={"event":"data"}
<source>
  @type http
  port 9880
</source>

<filter myapp.access>
  @type record_transformer
  <record>
    host_param "#{Socket.gethostname}"
  </record>
</filter>

<match myapp.access>
  @type file
  path /var/log/fluent/access
</match>

这个例子里,filter 获取数据后,调用原生的 @type record_transformer 插件,在事件的 record 里插入了新的字段 host_param,然后再交给 match 输出。

你可以参考文档6来学习如何编写自定义的 filter。

4、system
fluentd 的相关设置,可以在启动时设置,也可以在配置文件里设置,包含:

log_level
suppress_repeated_stacktrace
emit_error_log_interval
suppress_config_dump
without_source
五、插件介绍 Plugins
Fluentd 有一个非常活跃社区,提供了大量的插件,你可以在这里看到大多数常见插件的列表:List of All Plugins。

Fluentd 支持 7 种类型的插件:

Input:事件流入口;
Parser:修改 Input 插件中事件格式,用于 Source;
Filter: 修改事件流,用于 Filter;
Output:输出插件,用于 Match;
Formatter:修改 Output 插件中事件流的格式,用于 Match;
Buffer:在 Output 插件中指定 buffer,用于 Match;
Storage:将插件状态存入内存或数据库,可用于 Source、Filter 和 Match,需要插件支持 storage 命令。

六、插件参数 Parameters
不同的插件都可以设定不同的参数,拿最简单的 forward 举个例子:

<source>
  @type http
  port 9880
</source>

其中 @type、port 都是参数,一个指明了插件的名字,另一个指明了监听的端口。

fluentd 里有两种类型的参数:

默认参数:以 @ 开头的都是默认参数;
插件参数:其余的参数都是插件参数,为插件做配置,可以在插件文档里查阅。
1、默认参数 Common plugin parameter
fluentd 里只有四个默认参数:

@type:用于指定插件类型;
@id:指定插件 id,在输出监控信息的时候有用;
@label:指定分组标签,可以对日志流做批处理;
@log_level:为每一组命令设定日志级别。
label
label 用于将任务进行分组,方便复杂任务的管理。

你可以在 source 里指定 @label @, 这个 source 所触发的事件就会被发送给指定的 label 所包含的任务, 而不会被后续的其他任务获取到。

需要注意的是,label 一旦被声明了,就必须在后面被用到,否则会报错。

看个例子:

<source>
  @type forward
</source>

<source>
  # 这个任务指定了 label 为 @SYSTEM
  # 会被发送给 <label @SYSTEM>
  # 而不会被发送给下面紧跟的 filter 和 match
  @type tail
  @label @SYSTEM
</source>

<filter access.**>
  @type record_transformer
  <record>
    # ...
  </record>
</filter>
<match **>
  @type elasticsearch
  # ...
</match>

<label @SYSTEM>
  # 将会接收到上面 @type tail 的 source event
  <filter var.log.middleware.**>
    @type grep
    # ...
  </filter>
  <match **>
    @type s3
    # ...
  </match>
</label>

error
用来接收插件通过调用 emit_error_event API 抛出的异常,使用方法和 label 一样,通过设定 <label @ERROR> 就可以接收到相关的异常。

log_level
官方文档

目前支持的日志级别参数值有:

fatal
error
warn
info
debug
trace

从上往下依次递减,当你指定了一个级别后,会捕获大于等于该级别的所有日志。

比如如果你指定 @log_level info,就会获取到 info, warn, error, fatal 级别的日志。

2、其他插件参数
除了默认参数外,各个插件还可以定制自己的参数,这个就需要查阅你所用插件的文档页面了。

拿 tail 举个例子,我们可以查阅 文档, 可以看到它有 tag, path, exclude_path, … 等一系列的参数,比如其中 tag 就可以为日志流打上供 match 使用的 tag。

七、高可用
内容来源于官方文档:Fluentd High Availability Configuration。

1、Message Delivery Semantics
任何消息传递系统,都需要考虑消息递交语义(delivery semantics):

At most once:最多传递一次,有可能会丢消息,但是不会重复;
At least once:最少传递一次,不会丢消息,但是可能重复;
Exactly once:确切的只传递一次,需要多次确认消息状态,会极大的牺牲性能。
一般来说,我们会根据业务场景,在前两种中选择一种,第三种因为性能较差,只适合在小型内部系统上玩玩。

2、网络拓扑
一个日志收集系统由两个角色组成:

log forwarders:负责日志采集和转发;
log aggregators:负责日志收集和汇总处理。
fluentd 可以扮演上述两个角色(或者由 fluent-bit 扮演 forwarders 角色),为了保证高可用, 对 aggregators 做多点备份:

Fluentd的安装与简单实用(第一章)-yellowcong
https://blog.csdn.net/yelllowcong/article/details/80749505

文档更新时间: 2020-09-21 12:11   作者:月影鹏鹏