Fluentd Bit

在 Fluentd Bit 中可以使用 read 或 socket 方式处理日志

  • read 用於读容器的日志档范例,无法明确知道是哪个容器传送的 log,阅读性没 socket 方式高
  • socket 用於在 docker-compose 上配置将 log 透过 socket 方式传至 fluentd

在 docker-compose 中当有服务要转发 Log 到 EFK 平台我们可以如下配置,24224 port 就是与 Fluentd Bit 沟通的点。

    logging:
      driver: fluentd
      options:
        fluentd-address: 192.168.101.129:24224
        tag: web-backend

在过程中发现先前已开发完的应用程序,要如何区分开发环境,以利於分析时做区分使用以下打 labels 方式。抑或着在在开发的应用程序上进行打标签的动作来识别,以 spring boot 来说可以在 logback 中定义。

logging:
      driver: fluentd
      options:
        fluentd-address: "192.168.101.129:3003"
        labels: "production_status"
    labels:
      production_status: "dev"

目前在调研的时候有发现配置档名称需要是 fluent-bit.conf,否则会出现无法读取到档案的问题,但这问题也不确定是不是我的问题XD

概念

Event or Record

每个传入数据(Log、Metric)都视为一个事件(Event)或记录(Record)

Mar  8 10:03:36 ubuntu dockerd[18162]: time="2021-03-08T10:03:36.491688014+08:00" level=info msg="NetworkDB stats ubuntu(857ee003b9b7) - netID:zkgfqq2qthpzdtgrk2w3clhqo leaving:false netPeers:1 entries:2 Queue qLen:0 netMsg/s:0"
Mar  8 10:03:36 ubuntu dockerd[18162]: time="2021-03-08T10:03:36.493309528+08:00" level=info msg="NetworkDB stats ubuntu(857ee003b9b7) - netID:6r7udn06llggcz5awzjfm992m leaving:false netPeers:1 entries:3 Queue qLen:0 netMsg/s:0"
Mar  8 10:07:43 ubuntu systemd[1]: Started Session 124 of user xxxx.
Mar  8 10:08:36 ubuntu dockerd[18162]: time="2021-03-08T10:08:36.691648447+08:00" level=info msg="NetworkDB stats ubuntu(857ee003b9b7) - netID:zkgfqq2qthpzdtgrk2w3clhqo leaving:false netPeers:1 entries:2 Queue qLen:0 netMsg/s:0"

上面提供的日志共有 4 个独立事件,而每个事件由一些特定的组件组合,像是 TIMESTAMP、MESSAGE 等。

Filtering

对事件进行修改或删除都视为过滤(Filtering)。

范例

  • 为事件新增 IP 位置
  • 选择特定事件内容
  • 删除与特定模式匹配的事件
Tag

被转发至 Fluent Bit 的每个事件都被分配一个标签(Tag)。标签是一个内部字串,路由器在之後阶段用它确定它必须经过哪个 FilterOutput 阶段。

input 为 Forward 是不分配标签。标记必须始终匹配规则,这与路由会有关连。

Timestamp

用於表示创建事件的时间,每个事件都会包含。

Match

Fluentd bit 允许将收集和处理的事件透过路由传递到一个或多个目的地,这是使用匹配(Match)来完成。

匹配是一个简单的规则,用於选择与标签(Tag)匹配已定义规则的事件。

Structured Message

来源端数据可以是结构或是非结构化。结构化可以有 Key:Value 格式,并在做过滤时可更加方便。

Buffering 性能与数据安全

Fluent Bit 处理数据时,使用系统记忆体堆作为主要和临时的位置来储存事件,接着再将它们发送到私有储存区中,以处理事件。可以这麽的理解用於将处理後的数据放置到临时位置,直到准备好发送为止

在记忆体中缓冲是一个最快的机制,缓冲(Buffering)是一个储存事件的位置,在处理和提交事件时,仍然能够储存事件。

当获取第三方服务事件时,该服务的网路故障或延迟非常普遍时,当接收到要处理的新数据时无法够快交付数据时,将可能会面临backpressure,使得记忆体大量被消耗。而 Mem_Buf_Limit 能够抑制获取的事件数据量,进而避免。

Data Pipeline

整体资料流程如下图所示

每个步骤都有相关的套件可使用

  • Input
    • 定义来源来收集数据
  • Parser
    • 从非结构化数据转换为结构化数据
  • Filter
    • 在将数据传递到某个目的地之前对其进行更改
  • Buffer
    • 提供一种统一持久性机制来储存数据
    • 此步骤处於不可变状态的数据,因此无法再使用 Filter 进行处里
  • Routing
    • 藉由 Filter 将数据路由到一个或多个目的地
    • 依赖 Tag 和 Match 规则

范例

[INPUT]
    Name cpu
    Tag  my_cpu

[INPUT]
    Name mem
    Tag  my_mem

[OUTPUT]
    Name   es
    Match  my_cpu

[OUTPUT]
    Name   stdout
    Match  my_mem # 为了将数据输出至目的,因此必须做匹配动作
  • Output
    • 定义数据的目的地

Buffering & Storage

Chunks

当 Input 插件发出事件时,会将事件分组成一个块(Chunk),通常是 2Mb,预设下块都在记忆体中创建。

Buffering and Memory

记忆体是一个很快的机制,对系统附载也小。但当网路发生问题或是有延迟,导致服务无法以正常速率进行传送事件,此使记忆体的消耗将大幅增加并不断累积数据,使得数据超出了传递的大小。这将有机会触发 OOM,因此可使用 mem_buf_limit 方式进行限制,当超过 mem_buf_limit 限制则 Input 会暂停运作,同时间遗失数据的可能性将增加。

Filesystem buffering to the rescue

使用 Filesystem 缓冲有助於 backpressure 和记忆体控制。

为 Input 进行记忆体和档案系统缓冲的配置将会有性能和数据安全的优势。使用 Filesystem 时系统会将块(Chunk)映射至硬碟上形成一个副本,同时会控制块的量以处里记忆体高使用率和 backpressure 产生的作用。

storage.max_chunks_up 预设为在记忆体储存 128 个块。在能够使用块下能够进行交付或接收数据,剩下的块是非启用状态这些将会用在档案系统中,除非可进行交付,否则不再记忆体中使用。

当 Input 启用 mem_buf_limitstorage.type 作为档案系统,当 mem_buf_limit 达到阈值时,不是暂停 Input,而是所有新数据将转到档案系统中已关闭的块(Chunk)。这控制了记忆体也保证数据不遗失。

Limiting Filesystem space for Chunks

块(Chunk)也许会透过 Tag 将其路由至目的地。而目的地可以有很多个目标,而每个传送到目标的速率将会不一样,而这不一样将会使其中一个目标产生 backpressure。可透过 storage.total_limit_size 进行限制,该限制当被触发时,输出到目的地的队列中最旧的块(Chunk)将被丢弃。

相关的储存配置可参考此链接

应用

架构如下图,我们可以这样设计

蓝色为一台主机,而红色是不同开发环境的主机,fluent 充当 agent,在每台主机蒐集 log 并将其传送至 Elasticsearch 上,後须搭配 Praeco 实现 log 告警。

fluent-bit 配置如下,Filter 可以想成是 pipeline 概念。

[SERVICE]
    flush            1
    log_Level        info
    daemon           off
    parsers_File     parsers.conf

# use driver method
[INPUT]
    name   forward
    listen 0.0.0.0
    port   24224
    tag    docker.socket
# use read
[INPUT]
    name              tail
    tag               docker.file
    path              /fluentd/log/containers/web.log
    DB                /var/log/flb_docker.db
    mem_buf_limit     5MB
    skip_long_lines   Off
    refresh_interval  10
    Docker_Mode On
    Docker_Mode_Flush 4
    Docker_Mode_Parser multiline2 # 捕获 JAVA Exception Stack

[FILTER]
    Name parser
    Match docker.socket
    Key_Name log
    Parser spring # 解析 JAVA log 
    Reserve_Data On
    Preserve_Key On

[FILTER]
    Name parser
    Match docker.file
    Key_Name log
    Parser docker # 处里 Json
    Reserve_Data On 
    Preserve_Key On

[FILTER]
    Name parser
    Match docker.file
    Key_Name log
    Parser h365
    Reserve_Data On # 将原始直对保留在解析的结果中
    Preserve_Key On # 将原始的 Key_Name 字段保留在解析的结果中
# 新增 Tag
[FILTER]
    Name record_modifier
    Match docker.file
    Record production_status dev
    Record container_name web
    Remove_key time


[OUTPUT]
    name             es
    match            *
    host             192.168.101.129
    port             3001
    index            fluent-bit
    logstash_format  on
    logstash_Prefix  120.log
    logstash_dateformat %Y%m%d
    replace_dots     on
    retry_limit      false

parser,这部分其实满重要,如果 Log 没制订统一规范时,解析会变得很麻烦。解析部分就得研究正规表示XD

[PARSER]
    Name spring
    Format regex
    Regex /^(?<time>((\d)+((-|:)\d+)+(\W+)\S+)+)(\s)?(?<level>\S+)\W+(?<logger>\S+)\W+(?<message>(\S|\s)*)/
    Time_Key  time
    Time_Format %b %d %H:%M:%S


[PARSER]
    Name multiline2
    Format regex
    Regex /(?<log>^{"log":"((\d)+((-|:)\d+)+.*))/

[PARSER]
    Name        docker
    Format      json
    Time_Key    time
    Time_Format %Y-%m-%dT%H:%M:%S.%L
    Time_Keep   On

[PARSER]
    Name h365
    Format regex
    Regex /^(?<time>((\d)+((-|:)\d+)+))(\S)+(\s)+(?<thread>(\S)+)(\W)+(?<level>\S+)(\W+)(?<message>(\S|\s)*)/
    Time_Key  time
    Time_Format %b %d %H:%M:%S

当然可以用 --log-driver 转发

docker run -it -d -p 80:80 --log-driver fluentd  --log-opt fluentd-address=tcp://192.168.101.129:24224 --log-opt labels=production_statu
s=testing --log-opt tag=web nginx

使用 docker-compose logging 设定进行日志转发,此方式本地不会储存 Log,配置如下

    logging:
      driver: fluentd
      options:
        fluentd-address: "192.168.101.120:24224"
        tag: "spring boot"
        labels: "production_status"
    labels:
      production_status: "dev"

会存在无法分辨是哪个容器产生,因此使用 labels 关键字实现自订义标签。这样可用来解决分辨问题源,可参考此链接


<<:  [DAY-03] 有顶尖的同事 才有一流的工作环境

>>:  [Day 3] - 『转职工作的Lessons learned』 - 资料库转换

机器视觉与影像辨识

第四个范例跟机器视觉与影像辨识有关, 我们先来了解一下什麽是机器视觉. 机器视觉 机器视觉想要做的事...

Ruby on Rails layout

预设版型? 前⾯提到说预设的版型是 app/views/layouts/application.ht...

虾皮串接实作笔记-Access Token

前言 目标:串接虾皮订单、标签资讯,目前串接虾皮 OpenAPI 2.0 版本,串接手册 串接步骤:...

Day27 - 区块链社会学读後感(下) 价值、治理

继上篇主要以区块链三个特徵叙写,下篇笔者将探讨区块链的价值、治理,这篇会是比较实用一点的生活应用面向...

缘起

前言 没错,今年再度在最後一天急急忙忙赶稿。 在这个好像不会任何一个框架,就无法存活的前端圈里 决定...