Fluent Bit介绍

Fluent Bit

Logo

Fluent Bit 是一款开源的日志收集组件,资源开销非常小,小到甚至能在嵌入式系统上运行,支持日志解析&过滤&转发,同时作为云原生基金会下的一个子项目,天然支持容器和 k8s 场景。

基本概念

大部分日志收集组件都将系统大致分为输入、缓冲区、输出三大部分,输入部分负责采集日志,采集了之后放在缓冲区,然后输出部分将其再转发到其他系统。

Fluent Bit 将这三大部分细分成了:输入、解析、过滤、缓冲区、路由、输出六个部分:

  • 输入部分负责采集原始日志;
  • 解析部分将原始日志结构化,比如提取字段、解转义等操作;
  • 过滤部分可以对日志做一些的统一的过滤和修改操作,比如增加一些统一的字段,过滤一些脏日志等等
  • 然后日志会被放到缓冲区等待发送
  • 路由部分会决策这个包应该发送到哪些输出
  • 输出将日志真正转发出去

image-20210421173801544

数据流

输入:INPUT

一个Fluent Bit 可以有多个输入,输入部分是插件化的,提供了许多种常用的插件供我们使用,常见的日志采集方式,如:文件、TCP、HTTP、MQTT、标准输入这些都是支持的,除此之外,Fluent Bit还支持一些带业务含义的插件,如:采集内存、CPU、磁盘、温度等信息;采集进程状态;采集 Linux 内核、systemd 日志;采集 windows 事件等等。

一个文件采集输入的配置例子:

[INPUT]
    Name             tail
    Tag              api.log             # 打标签,后面处理和转发会根据这个标签来匹配
    Path             /var/log/api/*.log  # 采集/var/log/api目录下所有 log 后缀的文件

解析:PARSER

解析器主要用于将原始日志进行结构化,支持 JSON、LTSV、logfmt 等格式的解析,对于非规则的日志也可以通过正则解析器来提取。

一个通过正则匹配提取 apache 日志的解析器例子:

[PARSER]
    Name   apache
    Format regex
    Regex  ^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$
    Time_Key time
    Time_Format %d/%b/%Y:%H:%M:%S %z
    Types code:integer size:integer

原始 HTTP 日志:

192.168.2.20 - - [29/Jul/2015:10:27:10 -0300] "GET /cgi-bin/try/ HTTP/1.0" 200 3395

解析之后:

{
    "host": "192.168.2.20",
    "user": "-",
    "method": "GET",
    "path": "/cgi-bin/try/",
    "code": "200",
    "size": "3395",
    "referer": "",
    "agent": ""
}

过滤:FILTER

Filter 部分允许我们在发送前对日志进行修改,是很有用的一个模块,filter 也是插件化的,同时一个实例内支持使用多个 filter 插件,常用的 filter 插件包括:

  • Grep 正则过滤日志
  • GeoIP2 Filter查询 IP 库给 IP 字段附加地理信息
  • Lua 可以直接嵌入 lua 脚本对数据进行修改
  • Modify 重命名、添加、删除字段

配置例子:过滤所有 debug 级别的日志:

[FILTER]
    name   grep
    match  *
    exclude ^\[debug\] .+ # 正则

缓冲:BUFFER

日志经过 filter 处理完之后就会在缓存区先放着,可以避免突然的大流量导致输出模块处理不过来从而导致日志丢失,也可以让输出模块攒一批日志然后批量发送提升性能。

和大部分的日志收集组件一样,Fluent Bit 也支持内存和磁盘两种 buffer,内存速度会快一些,但是稳定性不如磁盘,断电后内存 buffer 里的数据就丢了,而磁盘则正好相反,不会丢日志但是速度慢。

路由:ROUTING

路由部分会决定日志要发往哪些输出,不过在配置文件并没有单独的实体存在,主要依赖标签机制来实现,在日志通过输入模块流入时可以给日志打上标签,然后 router 会读取输出插件的 Match字段进行正则匹配,来判断要不要发往这个输出。

[INPUT]
    Name             tail
    Tag              api.log             # 打标签,后面处理和转发会根据这个标签来匹配
    Path             /var/log/api/*.log  # 采集/var/log/api目录下所有 log 后缀的文件
    
[INPUT]
    Name             tail
    Tag              api.log             # 打标签,后面处理和转发会根据这个标签来匹配
    Path             /var/log/api/*.log  # 采集/var/log/api目录下所有 log 后缀的文件
    
[OUTPUT]

输出:OUTPUT

输出部分也是插件化的,我们可以通过多种方式将日志发送到它的目的地。

常用的输出插件如下:

  • S3对象存储
  • ES
  • 文件
  • Forward:将日志用 forward 协议发出去,常用于边缘 fluent bit + 中心 fluentd 架构
  • HTTP
  • InfluxDB
  • Kafka
  • Loki
  • PostgresQL
  • TCP
  • Websocket

例子:将日志通过HTTP的方式输出到目标接口:

[OUTPUT]
    Name  http
    Match *    # 匹配所有日志
    Host  log.example.com
    Port  80
    URI   /something
    Format json

值得一提的是,output 插件还支持用 Go 语言开发,只需要实现指定的几个方法,编译出一个动态链接库即可,详情参考:https://docs.fluentbit.io/manual/development/golang-output-plugins

Fluent Bit 和 Fluentd

image-20210506171952172

fluentdfluent bit 师出同门,先有的 fluentd,后来 Treasure Data 基于 fluentd 的架构思想 又设计开源了更轻量的 fluent bit,功能虽然没有前者多,但是基本够用,胜在轻量,fluent bit 之于 fluentd 类似 filebeat 之于 logstash

很常见的一种应用场景是在边缘部署更轻量 fluent-bit 然后汇总到中心的 fluentd 处理:

img

详细对比:

Fluentd Fluent Bit
使用范围 容器 / 服务器 嵌入式 Linux / 容器 / 服务器
语言 C & Ruby C
内存 ~40MB ~650KB
性能
日志聚合 YES NO
依赖 依赖一些 ruby gem 零依赖
插件 1000+ 70+
Github Star 10.2k 2.7k

HELLO WORLD

安装

CentOS

先配置YUM源:

echo '[td-agent-bit]
name = TD Agent Bit
baseurl = https://packages.fluentbit.io/centos/7/$basearch/
gpgcheck=1
gpgkey=https://packages.fluentbit.io/fluentbit.key
enabled=1' > /etc/yum.repos.d/td-agent-bit.repo

fluent-bit 是以 td-agent-bit的名称分发的,我们 直接安装即可:yum install td-agent-bit

可以直接手动启动二进程程序,这样更直观:

/opt/td-agent-bit/bin/td-agent-bit -i mem -o stdout -f 1

或者通过 systemd 托管启动:

sudo service td-agent-bit start

Docker【推荐】

用 docker 安装通常来说会是一种更便捷及标准化的做法,我们只需要一行命令就能直接体验 fluent bit:

# 输入:CPU信息采集 输出:标准输出 FLUSH: 1秒一次
docker run -it fluent/fluent-bit:1.7 /fluent-bit/bin/fluent-bit -i cpu -o stdout -f 1

实践:采集Docker日志到ES

一种很常见的场景,我们的业务代码中打了日志,然后希望收集到 ES 中通过 Kibana 查看日志,这个时候我们就可以使用 Fluent Bit 来实现日志的收集与转发。

搭建 ES + Kibana

业务上有现成的 ES 肯定最方便,如果是想从零开始体验的话,我们可以直接拉起一套容器环境:

docker run --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -d elasticsearch:7.12.0
docker run --name kibana --link=elasticsearch:test  -p 5601:5601 -d kibana:7.12.0

然后创建一个 ES 索引用来放日志:

curl -X PUT 'http://127.0.0.1:9200/api-log'

配置容器日志

首先,在业务代码中,我们需要将日志打成 JSON 格式到标准输出中供 docker 收集,这里可以使用 logrus 框架

Docker 默认的日志驱动是 json-file,会将日志写入到 /var/lib/docker/containers/<container id>/<container id>-json.log中,理论上我们可以配置日志采集程序直接监听这个文件即可,不过 docker 1.8 后有了更高效的选择,docker 原生支持了 **fluentd fluent bit**,我们只需要配置一下容器的驱动即可,然后 docker 就会将日志通过 fluent bit 能够识别的FORWARD协议转发到 tcp://localhost:24224

docker run --log-driver=fluentd api-system:latest

配置 Fluent Bit

这一步是最为关键的,我们需要合理地配置 fluent bit,来让它可以收集 docker 日志,然后转发到 ES 的接口中去。

另外,docker 过来的日志本来就是 json 格式,而我们业务上的 json 日志则会被转义放入 log 字段中,所以我们需要将业务日志反转义然后提取到最上一级的 json 结构下,这样才能直观的在 kibana 中看到我们的字段。

配置文件如下:

/etc/fluent-bit/fluent-bit.conf

[SERVICE]
    Parsers_File parser.conf # 解析文件位置
    Flush        5           # 5秒写入一次ES
    Daemon       Off
    Log_Level    debug

[INPUT]
    Name   forward           # forward 协议
    Listen 0.0.0.0
    Port   24224             # 默认端口,如果需要修改的话,Docker日志驱动参数也要同步

[FILTER]
    Name         parser
    Key_Name     log
    Parser       docker      # 指定使用 docker 解析器来处理日志,定义于 parser.conf 中
    Match        *

[FILTER]
    Name nest  
    Match *
    Operation lift
    Nested_under log         # 将 log 下的所有 json 字段上移一级

[OUTPUT]
    Name es                  # 转发日志到指定地址的 es 中
    Match *
    Host  127.0.0.1
    Port  9200
    Index api-log            # es 索引,需要提前创建好

/etc/fluent-bit/parser.conf

[PARSER]
    Name         docker
    Format       json
    Time_Key     time
    Time_Format  %Y-%m-%dT%H:%M:%S.%L
    Time_Keep    On
    Decode_Field_As    escaped     log  # 解转义
    Decode_Field_As    json        log  # json解析,而不是视为纯字符串

启动 Fluent Bit

这里我们直接用容器的方式启动一个 Fluent Bit 进程,同时直接和宿主机共用网络空间减少网络包跨越网络空间带来的损耗,另外我们需要将我们上面的配置文件地址映射到容器内的默认配置读取目录,来使我们的配置生效:

docker run  --name fluent-bit --network host  -d -v /etc/fluent-bit/:/fluent-bit/etc fluent/fluent-bit:1.7

然后理论上我们就能方便地在 kibana 中查看我们的日志了。

参考

  1. https://logz.io/blog/fluentd-vs-fluent-bit/
  2. https://docs.fluentbit.io/manual/
  3. https://github.com/fluent/fluent-bit