面对海量日志,为什么选用fluentd作为核心组件?

2020-06-15 11:09:05 浏览数 (3)

"本文主要讲解了fluentd的为什么选用fluentd作为核心组件,它的优势是什么"

1、前言

我是标题党,所谓佛无南北,架构没有好坏之分,只有是否合适的区别,比如常常被人诟病的单体架构,耦合性高,可扩展性低。事实上,特别对于有成本考虑的初创企业,单体架构常常是最佳选择,因为简单,它能快速帮助企业完成产品和市场的高度契合,但是当企业的用户规模扩大后,这样的架构往往又成为隐患。话又说回来了,没有一个可以适用于所有的产品和规模的完美架构,任何架构只能完成特定的一组目标,或者一系列的需求和条件。随着时间的推移,为了与时俱进,任何产品或者服务功能需要完善,架构也一样,那些在普通用户规模下的架构很少能在100倍规模下有效。

fluentd也一样,当存在多种多样数据源和存储目标时比较合适,因为它支持500 插件进行日志输入输出,特别是大多数数据源都是自定义的应用,你会发现fluentd和这些应用结合起来的能力比其它日志收集框架要简单有效。

2、性能

fluentd的性能已经在各个领域得到了证明,其最大的用户可以从50000 服务器中收集日志,每天处理5TB的数据,峰值时每秒可以处理5万行数据,可以在客户端和服务端分别部署,客户端收集日志发送到服务端(目前大多采用fluent-bit作为客户端)

3、架构

fluentd是一个开源的数据收集器,它统一了数据的收集和使用。它的架构有以下特点(看上图说话):

  • 使用json统一日志格式
  • 可插拔的架构(灵活的插件功能,允许扩展功能)
  • 最少资源占用(C Ruby编写)
  • 可靠性高

4、社区支持

fluentd目前由CNCF社区维护,大名鼎鼎的云原生计算基金会,云时代的操作系统Kubenetes就是由它发起和维护的。社区活跃,详情见下图:

5、安装使用

安装使用简单,支持多种安装方式,具体可以参考官网安装方式,最简单的方式就是直接通过镜像运行,使用方式,如下所示:

1. 拉取镜像

代码语言:javascript复制
docker pull fluent/fluentd:v1.6-debian-1

2. 创建收集配置

代码语言:javascript复制
# /tmp/fluentd.conf
<source>
  @type http
  port 9880
  bind 0.0.0.0
</source>
<match **>
  @type stdout
</match>

3. docker运行,启动fluentd

代码语言:javascript复制
$ docker run -p 9880:9880 -v $(pwd)/tmp:/fluentd/etc -e FLUENTD_CONF=fluentd.conf fluent/fluentd:v1.6-debian-1
2019-08-21 00:30:37  0000 [info]: parsing config file is succeeded path="/fluentd/etc/fluentd.conf"
2019-08-21 00:30:37  0000 [info]: using configuration file: <ROOT>
  <source>
    @type http
    port 9880
    bind "0.0.0.0"
  </source>
  <match **>
    @type stdout
  </match>
</ROOT>
2019-08-21 00:30:37  0000 [info]: starting fluentd-1.6.3 pid=6 ruby="2.6.3"
2019-08-21 00:30:37  0000 [info]: spawn command to main:  cmdline=["/usr/local/bin/ruby", "-Eascii-8bit:ascii-8bit", "/usr/local/bundle/bin/fluentd", "-c", "/fluentd/etc/fluentd.conf", "-p", "/fluentd/plugins", "--under-supervisor"]
2019-08-21 00:30:38  0000 [info]: gem 'fluentd' version '1.6.3'
2019-08-21 00:30:38  0000 [info]: adding match pattern="**" type="stdout"
2019-08-21 00:30:38  0000 [info]: adding source type="http"
2019-08-21 00:30:38  0000 [info]: #0 starting fluentd worker pid=13 ppid=6 worker=0
2019-08-21 00:30:38  0000 [info]: #0 fluentd worker is now running worker=0
2019-08-21 00:30:38.332472611  0000 fluent.info: {"worker":0,"message":"fluentd worker is now running worker=0"}

4. 发送HTTP请求

代码语言:javascript复制
$ curl -X POST -d 'json={"json":"message"}' http://localhost:9880/sample.test
代码语言:javascript复制
$ docker ps -a
CONTAINER ID        IMAGE                          COMMAND                  CREATED              STATUS              PORTS                                         NAMES
775a8e192f2b        fluent/fluentd:v1.6-debian-1   "tini -- /bin/entryp…"   About a minute ago   Up About a minute   5140/tcp, 24224/tcp, 0.0.0.0:9880->9880/tcp   tender_leakey


$ docker logs 775a8e192f2b | tail -n 1
2019-08-21 00:33:00.570707843  0000 sample.test: {"json":"message"}

其它安装和使用方式可参照如下链接:

日志收集工具fluentd安装配置及使用介绍

Kubernetes集群环境下fluentd日志收集方案介绍

6、线上实践

如上图所示,在各个节点上以DaemonSet方式部署fluent-bit,fluent-bit在各个节点上收集事件、日志等信息,收集完成后发送到fluentd进行统一汇总、过滤、存储处理。

示例:

fluentd指令配置信息:

代码语言:javascript复制
<source>
  @type forward
  port 24224
</source>


# http://this.host:9880/myapp.access?json={"event":"data"}
<source>
  @type http
  port 9880
</source>
<match nginx*>                        #匹配有tag为mem的类型
  @type stdout                        #匹配成功直接标准输出
</match>


# Match events tagged with "myapp.access" and
# store them to /var/log/fluent/access.%Y-%m-%d
# Of course, you can control how you partition your data
# with the time_slice_format option.
<match tbsm*>
  @type file
  path /home/logs/${tag}/${tag}
  append true
  <format>
      @type single_value
      message_key log
      add_newline true
  </format>
  <buffer tag,time>
    @type file
    # timekey 5m 每隔5分钟形成一个日志文件
    # timekey_wait 1m 生成等待时间1分钟
    chunk_limit_size 50M
     # 每隔1分钟写一次日志
    flush_interval 1m
    flush_at_shutdown true
    flush_mode interval
  </buffer>
</match>

以上能够满足把集群节点,各个服务的日志进行集中到fluentd节点上进行存储。目前上述指令配置能够把原来各个节点上的日志原封不动的集中到fluend所在服务器,当然你也可以对日志进行处理,比如json格式、添加时间戳、tag标签等。那么日志又是如何传递到fluentd服务呢?

如下所示fluent-bit配置:

代码语言:javascript复制
[SERVICE]
    Flush        1
    Daemon       ON  
    Log_Level    debug




[INPUT]
    Name        tail
    Path        /home/logs/tbsms1/tbsms1.log
    Db          /tmp/tbsms1.db
    Db.sync     Full
    Tag         tbsms1


[INPUT]
    Name        tail
    Path        /home/logs/tbsms2/tbsms2.log
    Db          /tmp/tbsms2.db
    Db.sync     Full
    Tag         tbsms2


[INPUT]
    Name        tail
    Path        /home/logs/tbsms3/tbsms3.log
    Db          /tmp/tbsms3.db
    Db.sync     Full
    Tag         tbsms3


[INPUT]
    Name        tail
    Path        /home/logs/tbsms4/tbsms4.log
    Db          /tmp/tbsms4.db
    Db.sync     Full
    Tag         tbsms4


[INPUT]
    Name        tail
    Path        /home/logs/tbsms5/tbsms5.log
    Db          /tmp/tbsms5.db
    Db.sync     Full
    Tag         tbsms5


[OUTPUT]
    Name        forward
    Match       *
    Host        12.18.1.6
    Port        24224

如上所示就可以把各个服务所在日志路径下的日志信息发送到fluentd,当然,你可能会说,当我的服务出现问题的时候,我不仅会查看服务日志的信息,还会查看当前机器所在节点的内存、cpu等监控信息。fluent-bit也是支持的,具体可以参考:

一文了解日志收集工具fluent-bit

轻量级日志收集转发 | fluent-bit指令详解(一)

轻量级日志收集转发 | fluent-bit配置详解(二)

轻量级日志收集转发 | fluent-bit外部插件详解(三)

7、问题总结

1. 如上示例所示,在使用的过程中,会发现缓存路径${tag}没有被替换掉,如下所示:

代码语言:javascript复制
drwxr-xr-x 3 root root  4096 Feb 14 17:01 logs
drwxr-xr-x 4 root root  4096 Feb 14 17:41 ${tag}

但是当缓存中的数据刷新到file中之后,file中的数据以及tag是正常替换的。个人觉得这是fluentd的一个可以接受的bug。

2. fluent-bit日志收集过程中出现如下文件被跳过问题如何处理?

代码语言:javascript复制
2020/01/20 11:37:55] [debug] [in_tail] file=/home/logs/server/server.2019-12-17.log read=32767 lines=0
[2020/01/20 11:37:55] [debug] [in_tail] file=/home/logs/server/server.2019-12-18.log read=32767 lines=0
[2020/01/20 11:37:55] [error] [in_tail] file=/home/logs/server/server.2019-12-16.log requires a larger buffer size, lines are too long. Skipping file.
[2020/01/20 11:37:55] [error] [in_tail] file=/home/logs/server/server.2019-12-17.log requires a larger buffer size, lines are too long. Skipping file.

添加Buffer_Chunk_Size和Buffer_Chunk_Size,其中Buffer_Chunk_Size默认是32Kb,如果一行数据的长度大于这个值,可能会出现如上错误,其中Buffer_Max_Size默认情况下跟Buffer_Chunk_Size保持一致。当然你也可以配置自动跳过过长数据行。

代码语言:javascript复制
[INPUT]
    Name        tail
    Path        /home/logs/server/*.log
    Db          /tmp/ng.db
    Db.sync     Full
    Tag         nginx-log
    Buffer_Chunk_Size 320KB
    Buffer_Max_Size   520KB

3. 生成如下所示大量日志文件,而我只想每天生成一个文件。如何配置?

代码语言:javascript复制
# append false
file.20140608.log_0
file.20140608.log_1
file.20140609.log_0
file.20140609.log_1

在fluentd配置文件中添加append true配置即可解决,按照指定时间生成,如下所示:

代码语言:javascript复制
# append true
file.20140608.log
file.20140609.log

4. 如何把节点日志从各个节点转发到其中一台机器?

在服务端fluentd配置source,其中source: 数据源配置,可接受log-tail、http、tcp、udp等方式数据如下所示:

代码语言:javascript复制
 <source>
    @type forward
    bind "0.0.0.0"
    port 24222
  </source>

在fluent-bit客户端配置forward,如下所示:

代码语言:javascript复制
[OUTPUT]
    Name        forward
    Match       *
    Host        12.18.71.14
    Port        24222

8、本文总结

本文主要简单介绍fluent-bit&fluentd优势以及在日志收集过程中的总结和心得。如果有用,可以关注、后台回复【pdf】获得详细文档。

0 人点赞