Fluentd的使用入门到熟练

1. fluentd

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

fluentd 常常被拿来和Logstash比较,我们常说ELK,L就是这个agent。fluentd 是随着Docker,GCP 和es一起流行起来的agent。

这篇文章里概括一下的话,有以下区别:

  • fluentd 比 logstash 更省资源;
  • 更轻量级的 fluent-bid 对应 filebeat,作为部署在结点上的日志收集器;
  • fluentd 有更多强大、开放的插件数量和社区。插件列表这一点值得多说,插件太多了,也非常灵活,规则也不复杂。

安装的话。mac 自带gem。 sudo gem install fluentd即可完成安装。

2. fluentd helloword

Fluent 配置文件


  @type http
  port 4888
  bind 0.0.0.0



  @type stdout

启动fluentd: fluentd -c in_http.conf

发起http请求:curl -i -X POST -d ‘json={“action”:“login”,“user”:2}’ http://localhost:4888/test.cycle
Fluentd的使用入门到熟练_第1张图片

3. fluent 的事件

  • tag: 事件来自何处,是如何被路由的依据。

  • time: 时间戳

  • record:消息体,也就是具体的日志内容,json格式。

    事件是由input plugin 负责去产生的,例如 in_tail 这个plugin,从文件末尾读取文本行

    192.168.0.1 - - [28/Feb/2013:12:00:00 +0900] "GET / HTTP/1.1" 200 777
    

    事件的内容将会是:

    tag: apache.access # set by configuration
    time: 1362020400   # 28/Feb/2013:12:00:00 +0900
    record: {"user":"-","method":"GET","code":200,"size":777,"host":"192.168.0.1","path":"/"}
    

4. 事件的处理

  1. ​ match

    以上述为例,match 就是通过 tag 匹配 source,然后执行指定的命令来分发日志,最常见的用法就是将 source 收集的日志转存到数据库。上例中的 test.cycle 就是 tag,tag 有好几种匹配模式:

    • *:匹配任意一个 tag;
    • **:匹配任意数量个 tag;
    • a b:匹配 a 或 b;
    • {X,Y,Z}:匹配 X, Y, Z 中的一个。

    Match 的匹配顺序:

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

    match 不仅仅用来处理输出,还有一些高级功能,比如日志事件进行一些处理后重新抛出,当成一个新的事件从新走一遍流程。

  2. filter

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

    我们对上述的 in_http.conf 作下修改,增加:

    
      @type record_transformer
      
        host "#{Socket.gethostname}"
      
    
    
      @type stdout
    
    
      @type grep
      
        key action
        pattern ^logout$
      
    
    

    然后重启fluentd。
    Fluentd的使用入门到熟练_第2张图片

    注意:

    • 左侧有三个请求,其中中间的请求在经过第三个filter的时候,被中断掉了,且每一个事件被新增了主机名称。所以三个请求,标准输出产生了5个记录。

    • filter 匹配顺序与 match 相同,我们应该在 之前放置

    • Input -> filter 1 -> … -> filter N -> Output(Match tag)

  3. label

    当我们的规则变得复杂以后,文件开始会变得复杂,并且不易阅读。label是一种新的方式能够改善这个问题。我们对上述文件稍作修改。

    
      @type http
      port 4888
      bind 0.0.0.0
    
    
    
      @type http
      port 4887
      bind 0.0.0.0
      @label @ADD
    
    
    
      @type stdout
    
    
      @type grep
      
        key action
        pattern ^logout$
      
    
    
    
      @type stdout
    
    

    很快会发现区别在哪儿:

    Fluentd的使用入门到熟练_第3张图片

    第二个请求,我们请求的是4887端口,它打了一个label,叫做@ADD,那么这个 source 所触发的事件就会被发送给指定的 ADD label 所包含的任务,而跳过被其紧跟其后的其他任务。

  4. buffers

    上边的例子,我们使用了非-buffered 的stdout 输出。但在生产中,你可以在buffered模式下使用输出,例如 es,forward,mongodb,s3等。buffered模式下的输出插件首先将接收到的事件存储到缓冲区中(“内存”或“file”)当满足刷新条件时才将缓冲区写入目的地址。 因此,使用缓冲输出,与stdout非缓冲输出不同,我们不会立即看到接收到的事件。

    这个插件不好演示,我不演示了。

    算了,还是演示下吧。修改下,label @ADD的部分。

    
    

    这里的含义是,把发给4887的日志,经过filter组成的pipeline以后,最终会输出到file类型里,path是必须的。如果你啥不配置的话,就每天的0:10左右,刷进去文件里。所以,你配置了file的时候,会发现没有马上看到文件。

    • timekey: 100 (单位是秒),指定的是多久会产生一个chunk。把时间轴按照100s去分割。

      timekey 60: ["12:00:00", ..., "12:00:59"], ["12:01:00", ..., "12:01:59"], ...
      timekey 180: ["12:00:00", ..., "12:02:59"], ["12:03:00", ..., "12:05:59"], ...
      timekey 3600: ["12:00:00", ..., "12:59:59"], ["13:00:00", ..., "13:59:59"], ...
      
      假如配置了 timekey = 1h, 那么CHUNK分别这么如下产生。
      
      11:59:30 web.access {"key1":"yay","key2":100}  ------> CHUNK_A
      
      12:00:01 web.access {"key1":"foo","key2":200}  --|
                                                       |---> CHUNK_B
      12:00:25 ssh.login  {"key1":"yay","key2":100}  --|
      
    • timekey_wait: 1m 是指当前chunk 结束了以后,延迟1m,才把该chunk flush到文件里。比如,当你配置了,timekey: 3600以后,那么啥时候产生最终落地的文件呢?如下图所示。

      timekey: 3600
       -------------------------------------------------------
       time range for chunk | timekey_wait | actual flush time
        12:00:00 - 12:59:59 |           0s |          13:00:00
        12:00:00 - 12:59:59 |     60s (1m) |          13:01:00
        12:00:00 - 12:59:59 |   600s (10m) |          13:10:00
      

Buffer 的保存路径最终是这样的:

$ tree /tmp/logs/
/tmp/logs/
├── ${tag}
│   ├── buffer.b57fb1dd96306dd0b308e094f7ec2228f.log
│   ├── buffer.b57fb1dd96306dd0b308e094f7ec2228f.log.meta
│   ├── buffer.b57fb1dd96339a870530991d4871cfe11.log
│   └── buffer.b57fb1dd96339a870530991d4871cfe11.log.meta
├── current-dummy1 -> /tmp/logs/${tag}/buffer.b57fb1dd96339a870530991d4871cfe11.log
└── current-dummy2 -> /tmp/logs/${tag}/buffer.b57fb1dd96306dd0b308e094f7ec2228f.log

#5.总结:

除了玲琅满目官方插件之外,我们还可以自己去编写灵活的插件。@type指定即可。

一旦事件由Fluentd 配置的Source产生,就可以一步步被瀑布流般地处理或在引用的Label内部处理,任何事件都可能随时被过滤掉。 

你可能感兴趣的:(EFK)