有史以来最香的日志收集平台是怎样练成的

news2024/12/23 9:46:00

作者 观测云 系统开发工程师 李国壮

前言

日志采集(logging)是观测云 DataKit 重要的一项,它将主动采集或被动接收的日志数据加以处理,最终上传到观测云中心。

日志采集的执行过程可大致分为三段,分别是“定位日志”、“数据处理” 和 “状态同步” 。本文将介绍第一段 “定位日志”。

数据源的划分

日志采集按照数据来源可以分为 “网络流数据” 和 “本地磁盘文件” 两种。

网络流数据

基本都是以订阅网络接口的方式,被动接收日志产生端发送过来的数据。

最常见的例子就是查看 Docker 日志,当执行 docker logs -f CONTAIENR_NAME 命令时,Docker 会启动一个单独的进程并连接到主进程,接收主进程发送过来的数据输出到终端。虽然 Docker 日志进程和主进程在同一台主机,但是它们的交互是通过本地环回网络。

更加复杂的网络日志场景比如 Kubenetes 集群,它们的日志分布在不同 Node 上面,需要以 api-server 进行中转,比 Docker 的单一访问链路复杂一倍。

但是大部分通过网络获取日志都存在一个问题 —— 无法指定日志位置。日志接收端只能选择从首部开始接收日志,有多少收多少,可能一次收到几十万条;或从尾部开始,类似 tail -f 只接收当前产生的最新的数据,如果日志接收端的进程重启,那么这期间的日志就丢失了。

DataKit 的容器日志采集最初是使用网络接收的方式,被上述问题困扰许久,后通过逐步调整改为下文提到的 “本地磁盘文件” 采集方式。

本地磁盘文件

采集本地日志文件是最常见和最高效的方式,省去了中间繁杂的传输步骤,直接对磁盘文件进行访问,可操控性更高,但是实现更复杂,会遇到一系列的细节问题,比如:

  • 怎样在磁盘上读取数据更高效?
  • 文件被删除或者执行翻转(rotate)该怎么办?
  • 重新打开文件时该怎样定位上次的位置进行 “续读”?

这些问题等同是将 Docker 日志服务给铺展开,各种细节和执行都交由自己来处理,只省去最后的网络传输部分,实现的复杂度比单纯用网络接收要麻烦很多。

本文将主要针对 “本地磁盘文件”,自底向上,分为 “发现文件”、“采集数据并处理”、“发送和同步” 三个方面,依次介绍 DataKit 日志采集系统的设计和实现细节。

补充,DataKit 日志采集执行流如下,涵盖和细分了上述的 “三个方面” :

    glob 发现文件       Docker API 发现文件      Containerd(CRI)发现文件
         |                       |                            |
         ------------------------------------------------------
                                 |
                   添加到日志调度器,分配到指定 lines
                                 |
         ---------------------------------------------------
         |                |                |               |
       line1            line2            line3          line4
                          |
                          |              |- 采集数据,分行
                          |              |
                          |              |- 数据转码
               |----->    |              |
               |          |              |- 特殊字符处理
               |          |-  文件 A      |
               |          | 一个采集周期   |- 多行处理
               |          |              |
               |          |              |- Pipeline 处理
               |          |              |
               |          |              |- 发送
               |          |              |
               |          |              |- 同步文件采集位置
               |          |              |
               | 流水线    |              |- 文件状态检测
               | 循环      |
               |          |
               |          |-  文件 B |-
               |          |
               |          |
               |          |-  文件 C |-
               |          |
               |----------|

发现和定位日志文件

既然要读取和采集日志文件,那么首先要在磁盘上定位文件位置。在 DataKit 中主要有三种文件日志,其中两种容器日志,一种普通日志,它们的采集方式大同小异,本文也主要介绍这种三种,它们分别是:

  • 普通日志文件
  • Docker Stdout/Stderr,由 Docker 服务本身进行日志管理和落盘(DataKit 目前只支持解析 json-file 驱动)
  • Containerd Stdout/Stderr,Containerd 没有输出日志的策略,现阶段的 Containerd Stdout/Stderr 都是由 Kubenetes 的 kubelet 组件进行管理,后续会统称为 Containerd(CRI)

发现普通日志文件

普通日志文件是最常见的一种,它们是进程直接将可读的记录数据写到磁盘文件,像著名的 “log4j” 框架或者执行 echo "this is log" >> /tmp/log 命令都会产生日志文件。

这种日志的文件路径大部分情况都是固定的,像 MySQL 在 Linux 平台的日志路径是 /var/log/mysql/mysql.log,如果运行 DataKit MySQL 采集器,默认会去找个路径找寻日志文件。但是日志存储路径是可配的,DataKit 无法兼顾所有情况,所以必须支持手动指定文件路径。

在 DataKit 中使用 glob 模式配置文件路径,它使用通配符来定位文件名(当然也可以不使用通配符)。

举个例子,现在有以下的文件:

$ tree /tmp
/tmp
├── datakit
│   ├── datakit-01.log
│   ├── datakit-02.log
│   └── datakit-03.log
└── mysql.d
    └── mysql
        └── mysql.log

3 directories, 4 files

在 DataKit logging 采集器中可以通过配置 logfiles 参数项,指定要采集的日志文件,比如:

  • 采集 DataKit 目录下所有文件,glob 为/tmp/DataKit/*

  • 采集所有带有 DataKit 名字的文件,对应的 glob 为/tmp/DataKit/DataKit-*log

  • 采集 mysql.log,但是中间有 mysql.dmysql 两层目录,有好几种方法定位到 mysql.log 文件:

    • 直接指定:/tmp/mysql.d/mysql/mysql.log
    • 单星号指定:/tmp/*/*/mysql.log,这种方法基本用不到
    • 双星号(double star):/tmp/**/mysql.log,使用双星号 ** 代替中间的多层目录结构,是较为简洁、常用的一种方式

在配置文件中使用 glob 指定文件路径后,DataKit 会定期在磁盘中搜寻符合规则的文件,如果发现没有在采集列表中,便将其添加并进行采集。

定位容器 Stdout/Stderr 日志文件 {#discovery-container-log}

在容器中输出日志有两种方式:

  • 一是直接写到挂载的磁盘目录,这种方式在主机看来和上述的 “普通日志文件” 相同,都是在磁盘固定位置的文件
  • 另一种方式是输出到 Stdout/Stderr,由容器的 runtime 来收集并管理落盘,这也是较为常见的方式。这个落盘路径通过访问 runtime API 可以获取到

DataKit 通过连接 Docker 或 Containerd 的 sock 文件,访问它们的 API 获取指定容器的 LogPath,类似在命令行执行 docker inspect --format='{{{{.LogPath}}}}' $INSTANCE_ID

$ docker inspect --format='{{`{{.LogPath}}`}}' cf681e
/var/lib/docker/containers/cf681eXXXX/cf681eXXXX-json.log

获取到容器 LogPath 后,会使用这个路径和相应配置创建日志采集。

重置日志偏移位置

“定位日志” 不仅是找到这个磁盘文件,还包括管理文件的偏移位置,这也是为什么放弃使用网络流而直接访问磁盘,正是为了更细致地操控 “偏移量(offset)”。

正常情况下,查看日志都使用类似 tail -f 命令,从文件尾部开始输出日志。这也是 DataKit 最早的做法,即每次打开日志文件都将 offset 调整到文件尾部,在 linux 系统中表现为 SEEK_END

如果 DataKit 重启,将重新从文件末尾开始采集,在此期间产生的日志数据会全部丢失,因为 DataKit 跳过了这段数据。为了避免这种情况,DataKit 有三种设置 offset 的策略。

记录的偏移量位置

首先,最重要和优先级最高的策略,当然是 “记录偏移量位置”。

DataKit 会定期在数据采集、处理和发送等一系列操作完成后,将此段数据在文件的 offset 记录下来,然后写入到 cache 文件。即使 DataKit 重启,在创建新的日志文件采集时,也可以根据文件特征(例如文件名、inode),从 cache 文件中找到自己的 offset,然后从此处开始采集。

记录和使用 offset 是一个很简单的方案,没有很高深的细节管理,却可以最大限度的减少数据丢失、数据采集重复。

从文件首部或尾部

如果一个文件是新创建的、没有被采集过,或者 cache 文件被删除了找不到对应的 offset,那么只能最原始的方法——首部,或尾部。

对此,DataKit 有自己的区分方式。

  • 如果这个文件是新创建的,它的 create_time 距离当前时间不超过 2 分钟,那么会设置为从文件首部读取,可以涵盖这个文件的所有数据。
  • 如果文件不是新创建的,此时就不能从文件首部读取,否则会采集整个文件的所有数据,会占用大量资源,且更多是过期的数据。在这种情况下只能从文件尾部读取,回到最常用的 tail -f 命令模式。

总结

“定位日志” 是日志采集系统的第一步,都说 “万事开头难”,只要在这一步处理妥当,就可以最大程度避免文件没采集、数据重复等问题。

下一步将开始读取文件数据,并做处理,会放在本系列的第二章节。

图片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1015962.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

听GPT 讲Istio源代码--pilot

File: istio/operator/pkg/translate/translate.go 在Istio项目中,istio/operator/pkg/translate/translate.go文件的作用是处理Istio Operator的配置信息和Kubernetes的资源对象之间的翻译和转换。 首先,scope和componentToAutoScaleEnabledPath是用于记…

趣谈网络协议_1

趣谈网络协议_1 第1讲 | 为什么要学习网络协议?第4讲 | DHCP与PXE:IP是怎么来的,又是怎么没的?动态主机配置协议(DHCP) 第5讲 | 从物理层到MAC层:如何在宿舍里自己组网玩联机游戏?第…

WPF 如何让xmal的属性换行显示 格式化

WPF 如何让UI的xmal 按照下面的格式化显示 首先格式化显示在VS中的快捷键是 Ctrl KD 然后需要配置,工具 选项 -文本编辑器 -xmal -格式化-间距 更改成如下就可以了

分布式锁的三种实现方式!

分布式锁是一种用于保证分布式系统中多个进程或线程同步访问共享资源的技术。同时它又是面试中的常见问题,所以我们本文就重点来看分布式锁的具体实现(含实现代码)。 在分布式系统中,由于各个节点之间的网络通信延迟、故障等原因…

基于java求长方形的周长和面积详细方法

一、方法 要使用Java求长方形的周长和面积,可以通过定义长方形的长度和宽度,然后使用相应的公式进行计算。 首先,定义长方形的长度和宽度: double length 10.0; double width 5.0;然后,使用以下公式计算长方形的周…

RK3588 添加I2C模拟芯片CH423

一.简介 有时候会遇到IO不够用的情况,例如说驱动LED灯,那么有没有什么便宜的,容易买到的芯片?我这次就考虑使用WCH的CH423S,这是一个比较新的IO扩展芯片。 二.硬件原理图 使用gpio来模拟IIC,飞线处理&…

2020-2023中国高等级自动驾驶产业发展趋势研究-概念界定

1.1 概念界定 自动驾驶发展过程中,中国出现了诸多专注于研发L3级以上自动驾驶的公司,其在业界地位也越来越重要。本报告围绕“高等级自动驾驶” 展开,并聚焦于该技术2020-2023年在中国市场的变化趋势进行研究。 1.1.1 什么是自动驾驶 自动驾驶…

发现matplotlib的一个问题

今天在做需求的时候发现一个问题,就是当传一个‘o’时,调用plt.plot画图会自动成为散点图,而不是折线图,代码如下: import pandas as pd import numpy as np import matplotlib.pyplot as plt ds pd.date_range(star…

直播视频处理过程

视频其实就是快速播放一连串连续的图片。 每一张图片,我们称为一帧。只要每秒钟帧的数据足够多,也即播放得足够快。比如每秒 30 帧,以人的眼睛的敏感程度,是看不出这是一张张独立的图片的,这就是我们常说的帧率&#…

JavaScript 中的 `this` 指向问题与其在加密中的应用

JS中的 this 关键字是一个非常重要的概念,它在不同情况下会指向不同的对象或值。在本文中,我们将深入探讨 JavaScript 中 this 的各种情况,并思考如何将其应用于 JS加密中的一些有趣用途。 1. 全局上下文中的 this 在全局上下文中&#xff…

cs224w_colab3_2023 And cs224w_colab4_2023学习笔记

class GNNStack(torch.nn.Module):def __init__(self, input_dim, hidden_dim, output_dim, args, embFalse):super(GNNStack, self).__init__() #这里的继承表示参见 https://blog.csdn.net/wanzew/article/details/106993425 # 继承时运行继承类别的函数 总之 __mro__的目的…

C++ 太卷,转 Java?

最近看到知乎、牛客等论坛上关于 C 很多帖子,比如: 2023年大量劝入C 2023年还建议走C方向吗? 看了一圈,基本上都是说 C 这个领域唯一共同点就是都使用 C 语言,其它几乎没有相关性。 的确是这样,比如量化交…

解决IDEA actiBPM插件之.bpmn文件中文乱码

1、修改IDEA编辑器编码为utf8,File->Settings->Editor->File Encodings,都改为UTF-8 2、在IDEA安装bin目录下,找到 idea.exe.vmoptions 和 idea64.exe.vmoptions 两个文件,打开编辑分别在文本最末端添加下面代码&#xf…

postman接口传参案例

目录 案例1: 接口A 接口B 案例2: //断言 案例1: 接口A 根据返回值需要从返回值中提取userid值,在Tests标签栏下编写脚本 //获取返回的响应值,并转化为json格式 var jsonData pm.response.json(); // 获取返回…

AIGC(生成式AI)试用 5 -- 从模糊到精确,再一步

参考 AIGC(生成式AI)试用 4 -- 从模糊到精确_Rolei_zl的博客-CSDN博客 提问信息不足时,生成式AI有的会引导提问者给出更多信息,有的会按自己的理解给出一个在某些方面正确的答案 随着提供的信息越来越多,生成式AI给…

E-kit 一体化电子工具箱

详细请见: E-kit: E-kit 一体化电子工具箱 (github.com) 在个人博客页查看本文 E-kit E-kit 一体化电子工具箱,STM32 实现,示波器 函数发生器 幅频特性仪器… 目前此项目已归档 注意:工程采用 GB2312 编码 基本功能 STM32F1…

RabbitMQ:基于DelayExchange插件实现延迟队列

因为延迟队列的需求非常多,所以RabbitMQ的官方也推出了一个插件,原生支持延迟队列效果。 这个插件就是DelayExchange插件。参考RabbitMQ的插件列表页面:Community Plugins — RabbitMQ 使用方式可以参考官网地址:Scheduling Mes…

OPC UA协议报文,基础介绍+Hello报文解析

消息主要分为:消息头和附加字段 通讯过程 协议标准第一部分进行总体介绍;协议标准第四部分有详细介绍通讯过程 流程介绍 整体流程 连接套接字》Hello》打开安全信道》创建会话》关闭安全信道》关闭套接字 订阅等事件 服务器审核行为 聚合的服务器审…

你已经应用了哪种服务注册和发现的模式呢?

前面历史文章中我们有说过关于微服务的注册和发现,并以 etcd 作为简单例子简单阐述了关于服务注册和发现的应用 那么日常工作中,你已经使用了服务注册和发现的哪些模式呢? 服务注册和发现的作用 首先,简单说明一下服务注册和发…

大数据知识点之大数据5V特征

大数据的特征可以浓缩为五个英文单词,Volume(大量)、Variety(多样性)、Velocity(速度)、Value(价值)、Veracity(准确性)。因为是5个特征都是以“V”开头的英文单词,又叫大数据5V特征。 概述&…