TDengine 中的日志系统

概述

TDengine 通过日志文件记录系统运行状态,帮助用户监控系统运行情况,排查问题,这里详细介绍 TDengine 日志的实现原理和使用方法。

Log 分为普通日志和慢日志。引擎测的运行状态通过普通日志的方式记录下来,系统运行相关的慢日志操作则记录到慢日志文件里。

普通日志:

普通日志实现逻辑

  1. 普通日志分同步和异步两种方式,同步立即写入日志文件,异步写入到 buff 里,然后定时写入日志文件。
  2. 异步方式日志文件缓存在循环 buff 里, buff 的大小为 buffSize = 20 M。如果某次写buf 的日志大小大于buf 可用空间,本次日志会舍弃,日志里记录: ...Lost N lines here...
  1. 异步线程里每隔 1 s 会更新磁盘信息用于判断是否有空间写日志
  2. 异步线程每隔 Interval 时间处理一次写入逻辑。写入规则如下:
    1. 如果buff 里数据小于 buffSize/10,不写入磁盘,除非超过1 s。
    2. 如果buff 里数据大于 buffSize/10,全部写入磁盘。
  3. Interval 默认值为 25 ms,Interval 值会根据每次写入日志的大小动态调整。Interval 调试规则如下:
    • 数据量小时(小于 buffSize/10),增大写入间隔,Interval 每次增加 5ms,最大25ms。
    • 数据量大时(大于 buffSize/3),写入间隔最小,Interval 为 5ms。
    • 数据量比较大时(大于 buffSize/4,小于等于buffSize/3),减小写入间隔,Interval 每次减小 5ms,最小5ms。
    • 数据量适中时(大于等于 buffSize/10,小于等于buffSize/4),写入间隔不变。

普通日志行为说明

  • 普通日志命名规则

    1. 同一台机器上可以起多个客户端进程,所以客户端日志命名方式为 taoslogX.Y,其中 X 为序号,为空或者 0 到 9,Y 为后缀 0 或者 1 (windows 限制只有一个序号,所以格式为 taoslog.Y)。
    2. 同一台机器上可以起多个服务端进程。所以服务端日志命名方式为 taosdlog.Y,其中 Y 为后缀, 0 或者 1。
  • 序号和后缀确定规则如下(假设日志路径为 /var/log/taos/)

    1. 确定序号:使用 10 个序号作为日志命名方式,/var/log/taos/taoslog0.Y - /var/log/taos/taoslog9.Y,依次检测每个序号是否使用,找到第一个没使用的序号作为该进程的日志文件使用的序号。 如果 10 个序号都被进程使用,不使用序号,即 /var/log/taos/taoslog.Y,进程都往相同的文件里写(序号为空)。
    2. 确定后缀:0 或者 1。比如确定序号为 3,备选的日志文件名就为 /var/log/taos/taoslog3.0 /var/log/taos/taoslog3.1。如果两个文件都不存在用后缀 0,一个存在一个不存在,用存在的后缀。两个都存在,用修改时间最近的那个后缀。
    3. 如果日志文件超过配置的条数 numOfLogLines,会切换后缀名,继续写日志,比如/var/log/taos/taoslog3.0 写够了,切换到 /var/log/taos/taoslog3.1 继续写日志。/var/log/taos/taoslog3.0 会添加时间戳后缀重命名并压缩存储(异步线程操作)。
    4. 通过配置 logKeepDays 控制日志文件保存几天,几天之外的日志会被删除。比如配置为 1,则一天之前的日志会在新日志压缩存储时检测删除。不是自然天。
  • 日志归档

    当文件里日志行数大于 numOfLogLines(默认 1000w,取值范围 1000-20亿)时,会触发日志归档。

    举例:

    taoslog3.0 写满了,切换到 taoslog3.1 继续写。taoslog3.0 重命名为 taoslog.1735616543,然后压缩为 taoslog.1735616543.gz。同时,如果 logKeepDays > 0,会检测是否有超时的日志文件,然后删除。(该过程异步执行)

慢日志

系统除了记录普通日志以外,对于执行时间超过配置时间的操作,会被记录到慢日志中。慢日志文件主要用于分析系统性能,排查性能问题。

慢日志实现逻辑

上报架构

整体流程图如下:

缓存逻辑

  1. 为了提高上报效率,慢 sql 日志上报方式为批量上报。
  2. 慢 sql 日志上报为了防止缓存丢失,采用写临时文件方式来实现缓存(crash 后不会丢失)。
  3. 每生成一条慢 sql 日志都会放到队列里,然后通知 slow log 线程从队列获取数据,slow log 线程根据数据里 clusterId 写到不同的文件里。

数据格式如下(其中,clusterId 为当前日志所属的慢查询集群id,value 为一条数据(json字符串形式))

SQL 复制代码
typedef struct {
  int64_t clusterId;
  char    *value;
}MonitorSlowLogData
  1. 说明:

    1. 因为客户端进程里可能存在很多个链接 connection,所以需要将慢查询日志根据 clusterId 来分组。分组方式通过临时文件名来实现,命名方式为 {tmp dir}/tdengine_slow_log/tdengeine-{clusterId1}-{processId}-{rand},processId 为进程ID,主要为了区分多个客户端的上报。
    2. 如上图 connection 1 连接的是 cluster 1。connection 2,connection 3 连接的是 cluster 2,所以connection 1 的慢 sql 数据写入文件 {tmp dir}/tdengine_slow_log/tdengeine-{clusterId1}-{processId}-{rand},connection 2 和 connection 3的慢 sql 数据写入文件 {tmp dir}/tdengine_slow_log/tdengeine-{clusterId1}-{processId}-{rand}

上报逻辑

  1. 读取 {tmp dir}/tdengine_slow_log/tdengeine-{clusterId1}-{processId}-{rand} 临时文件内容,每行数据作为 json 数组的一个元素,组装成 json 数组上报(文件里数据每接近 1M大小上报一次,上报成功后记录读取文件进度,上报采用异步上报方式。在 callback 里继续根据上次的进度,继续读取文件的内容上报,直至整个文件读取上报完毕,上报完毕后,会清空临时文件,callback 里成功或失败都会继续读取文件,失败时会记录上报失败的数据日志)。每接近 1M 上报一次主要为了防止文件太大,放在一次上报失败)。

上报时机

  1. 客户端运行过程中定时上报
    1. 每个 monitorInterval 时间间隔上报数据。
  2. 客户端正常退出
    1. 上报所有慢 sql 日志文件, 上报成功后,删除文件。
  3. 客户端异常退出
    1. 异常退出后再次与某个集群(clusterId)建立新的链接后遍历 {tmp dir}/tdengine_slow_log/ 目录下tdengine-{clusterId}开头的所有文件进行重新上报(这些文件可能是另一个客户端进程或本进程正在操作的。所以每个文件打开时都需要添加文件锁),然后删除这个临时文件。

一些异常行为说明

  1. 因为上报数据和删除文件里的上报内容没法作为一个原子操作,所以如果上报后还没删除数据就 crash,可能导致下次重复上报,重复上报的数据会覆盖,并没丢失,影响很小。

  2. 另外为了保证性能, slow log thread 线程把慢 sql 日志写入临时文件缓存,只保证刷新到操作系统的磁盘缓冲区,并不真正每次都 fsync 到磁盘,所以如果机器断电,仍可能丢失数据。该异常出现概率很小,可以容忍此种情况下的数据丢失。

慢日志行为说明

  1. 慢日志一方面会记录到本地慢日志文件中,另一方面会通过 taosAdapter 发送到 taosKeeper 进行结构化存储(需打开 monitorr 开关)。
  2. 慢日志文件存储规则为:
    1. 慢日志文件一天一个,如果当天没有慢日志,没有当天的文件。
    2. 文件名为 taosSlowLog.yyyy-mm-dd(taosSlowLog.2024-08-02),日志存储路径通过 logDir 配置。
    3. 多个客户端的日志存储在相应日志路径下的同一个 taosSlowLog.yyyy.mm.dd 文件里。
    4. 慢日志文件不自动删除,不压缩。
    5. 使用和普通日志文件相同的三个参数 logDir, minimalLogDirGB, asyncLog。另外两个参数 numOfLogLines,logKeepDays 不适用于慢日志。

日志级别说明:

日志级别分为9种,如下所示:

C++ 复制代码
typedef enum {
  DEBUG_FATAL = 1,
  DEBUG_ERROR = 1,
  DEBUG_WARN = 2,
  DEBUG_INFO = 2,
  DEBUG_DEBUG = 4,
  DEBUG_TRACE = 8,
  DEBUG_DUMP = 16,
  DEBUG_SCREEN = 64,
  DEBUG_FILE = 128
} ELogLevel;

日志开关通过 bit 位来控制,具体如下:

例如:

131 = 128 + 2 + 1 文件 + info + error

135 = 128 + 4 + 2 + 1 文件 + debug + info + error

143 = 128 + 8 + 4 + 2 + 1 文件 + trace + debug + info + error

通过设置日志开关的参数,可以开启不同级别的日志。

日志相关参数说明:

Log 相关的功能受参数的影响很大,特别是有的日志受到开关的影响,必须打开相应的开关才可启用。具体参数的含义可以参见 这里

思考

  1. 普通日志切换归档的逻辑可以优化,目前为了防止日志丢失,等待20s 后开始压缩,应该通过信号来精确同步,同时保证进程可以快速正常退出。
  2. taos 日志10个序号,taosd 日志1个序号,在进程很多时,存在多个进程往一个文件里写日志的情况。
  3. 慢日志直接上报,不批量上报。

访问官网

更多内容欢迎访问 TDengine 官网

相关推荐
小周不摆烂1 小时前
Java Web从入门到精通:全面探索与实战(一)
java
cherryc_1 小时前
JavaSE基础——第六章 类与对象(二)
java·开发语言
快来卷java1 小时前
JVM虚拟机篇(三):JVM运行时数据区与方法区详解
java·jvm·mysql
共享家95271 小时前
Linux常用命令详解:从基础到进阶
linux·服务器·数据库
whltaoin2 小时前
Java实现N皇后问题的双路径探索:递归回溯与迭代回溯算法详解
java·算法
nlog3n4 小时前
Java策略模式详解
java·bash·策略模式
我是个假程序员5 小时前
sql server数据库可疑修复
数据库
极限实验室6 小时前
如何使用 Nginx 代理 Easysearch 服务
数据库·nginx
whn19776 小时前
selectdb修改表副本
数据库
Mryan20057 小时前
解决GraalVM Native Maven Plugin错误:JAVA_HOME未指向GraalVM Distribution
java·开发语言·spring boot·maven