ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TDengine 日志系统深度解析:普通日志、慢日志与日志级别控制机制

TDengine 日志系统深度解析:普通日志、慢日志与日志级别控制机制 TDengine 日志系统深度解析普通日志、慢日志与日志级别控制机制【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengineTDengine 的日志子系统由普通日志与慢日志两条链路组成前者记录引擎侧运行状态采用同步或 20MB 循环缓冲的异步写入模型并带有动态写盘间隔调整与自动归档压缩机制后者将超过阈值的慢操作按集群分组、通过临时文件缓存批量上报用于性能分析与问题排查。读完本文你将完整掌握日志文件的命名与归档规则、numOfLogLines、logKeepDays、asyncLog、slowLogThreshold、monitorInterval等关键配置参数的作用以及基于 bit 位控制的日志级别开关原理并了解其背后的源码实现日志核心实现为线上调参与问题定位提供可靠依据。一、日志体系总览TDengine 通过日志文件记录系统运行状态帮助用户监控系统运行情况、排查问题。整个日志体系分为两类普通日志引擎侧的运行状态全部通过普通日志记录是本仓库中绝大多数模块客户端、服务端、各管理/执行节点统一使用的日志通道底层实现在 source/util/src/tlog.c对外接口声明在 include/util/tlog.h慢日志执行时间超过配置阈值的操作会被记录到慢日志文件中主要面向性能分析与性能问题排查。慢日志除写入本地文件外还会经客户端的 monitor 机制source/client/src/clientMonitor.c上报到 taosKeeper 做结构化存储。两类日志共用同一套底层缓冲写入框架在 日志核心实现 中SLogObj同时持有普通日志缓冲logHandle与慢日志缓冲slowHandle二者都是SLogBuff结构由同一个异步线程轮询刷盘。二、普通日志实现机制2.1 同步写入与异步写入两种模式普通日志分为同步和异步两种方式同步模式日志立即写入日志文件写入路径见 taosPrintLog 调用链在tsAsyncLog为 false 时直接落盘异步模式日志先写入内存 buffer由后台线程定时写入日志文件。异步模式是默认行为源码中tsAsyncLog初始值即为 true默认值定义可通过配置项asyncLog切换该配置在 全局配置注册处 注册且支持运行时动态生效CFG_DYN_BOTH。2.2 20MB 循环 Buffer 与丢日志标记异步方式下日志缓存在一个循环 buffer 中buffer 大小固定为buffSize 20MB慢日志缓冲区为 10MB对应宏定义LOG_DEFAULT_BUF_SIZE (20 * 1024 * 1024)普通日志缓冲LOG_SLOW_BUF_SIZE (10 * 1024 * 1024)慢日志缓冲见 缓冲参数宏定义循环 buffer 的空间管理在taosPushLogBuffer中实现推入逻辑每次写入前计算剩余空间remainSize若某次要写入的日志大小大于剩余可用空间本次日志会被舍弃所有被舍弃的日志不会逐条丢失而是累计计数lostLine等下一次有空间写入时先补写一条...Lost N lines here...标记N 为丢失行数再写入新日志。这样既避免了高负载下的写阻塞又保留了“这里发生过丢日志”的可观测痕迹写入通过taosCopyLogBuffer支持跨 buffer 首尾边界的环形拷贝环形拷贝实现。循环 buffer 的空间结构如下图所示同本文首图写指针环形推进剩余空间不足时补记Lost标记。2.3 异步线程的写盘节奏与动态 Interval异步线程的核心循环在taosAsyncOutputLog异步线程主循环其行为规则如下磁盘空间巡检线程累计睡眠超过 1s 时调用osUpdate()刷新磁盘信息用于判断当前是否仍有空间继续写日志对应count 1000分支轮询写盘线程每隔Interval毫秒处理一次写入。taosWriteLog的写盘判定逻辑写盘判定为若 buffer 中数据小于buffSize/10即minBuffSize2MB不写入磁盘除非累计等待超过 1sLOG_MAX_WAIT_MSEC 1000由lastDuration累计判定若 buffer 中数据大于buffSize/10全部写入磁盘一次写盘后若 buffer 中剩余数据仍大于buffSize/10将writeInterval直接清零下一轮立即继续写直到 buffer 中数据低于阈值才恢复正常轮询节奏。Interval的默认值为25msLOG_DEFAULT_INTERVAL 25取值范围被钳制在5ms ~ 25msLOG_MIN_INTERVAL/LOG_MAX_INTERVAL步进 5msLOG_INTERVAL_STEP见 间隔参数宏。Interval 会根据每次实际写入的数据量动态调整调整规则与源码中taosWriteLog尾部的四个分支完全对应单次写入数据量调整动作源码对应分支小于 buffSize/10增大写入间隔每次 5ms最大 25mspollSize minBuffSize时writeInterval 5大于 buffSize/3立即降到最小间隔 5mspollSize buffSize/3时writeInterval 5大于 buffSize/4 且小于等于 buffSize/3减小写入间隔每次 -5ms最小 5mspollSize buffSize/4时writeInterval - 5大于等于 buffSize/10 且小于等于 buffSize/4写入间隔保持不变无分支命中维持原值这一策略的意图是日志量大时缩短写盘周期、尽快把数据刷出去降低 buffer 被写满丢日志的概率日志量小时放宽周期减少小 IO 次数。普通日志与慢日志两个 buffer 的writeInterval取较小值作为线程本轮睡眠时间取小逻辑保证任一通道积压时都能被及时刷盘。2.4 磁盘空间保护配置项minimalLogDirGB默认 1.0取值范围 0.001 ~ 10000000见 配置注册用于限制日志目录可占用的最小保留空间初始化时被换算为字节并保存到tsLogSpace.reserved空间换算。异步线程每秒刷新一次磁盘信息正是为了在写日志前判断是否还能写入避免日志把磁盘写满。三、普通日志文件命名与归档行为3.1 命名规则同一台机器上可以运行多个客户端进程也可以运行多个服务端进程因此日志命名方式区分两类客户端日志taoslogX.Y。其中 X 为序号取值为空或 0~9Y 为后缀 0 或 1。由于 Windows 限制只有一个序号位Windows 上格式为taoslog.Y服务端日志taosdlog.YY 为后缀 0 或 1。慢日志文件则统一命名为taosSlowLog日期以文件内日志归属日期区分见第五节对应源码中的文件名构造慢日志命名。3.2 序号与后缀的确定规则以日志路径/var/log/taos/为例确定序号系统预置 10 个候选序号即/var/log/taos/taoslog0.Y~/var/log/taos/taoslog9.Y。新进程启动时依次检测每个序号是否已被使用找到第一个未被使用的序号作为该进程日志文件的序号若 10 个序号都被占用则不再使用序号多个进程都往同一个无序号文件taoslog.Y中写。确定后缀后缀为 0 或 1。假设序号确定为 3备选文件名为taoslog3.0与taoslog3.1两个文件都不存在 → 使用后缀 0一个存在、一个不存在 → 使用已存在的那个后缀两个都存在 → 使用修改时间最近的那个后缀。这一策略让重启后的进程能自然接续上次写到一半的日志文件而不会产生大量孤儿文件。3.3 日志归档、压缩与保留归档触发条件当文件中日志行数大于numOfLogLines时触发归档。该参数默认1000 万行取值范围1000 ~ 20 亿见 numOfLogLines 配置注册源码中实际按numOfLogLines - 1000作为切换阈值见 阈值换算。归档流程示例taoslog3.0写满后切换到taoslog3.1继续写taoslog3.0被重命名为taoslog.1735616543时间戳后缀随后被压缩为taoslog.1735616543.gz。同时如果logKeepDays 0归档过程中会检测并删除超时日志文件。整个归档过程由独立的logRotate 线程异步执行不阻塞业务写日志归档线程实现。从源码结构看归档线程的触发周期约为 1 小时LOG_ROTATE_INTERVAL 3600叠加一个随机启动延迟避免多进程同时归档扫描日志目录下与本进程同前缀的文件文件距上次修改不足 30 秒LOG_INACTIVE_TIME的跳过超过logKeepDays保留天数的直接删除否则调用taosKeepOldLog压缩。这与文档描述的“几天之外的日志会在新日志压缩存储时被检测删除、不是按自然天”完全一致。保留天数logKeepDays控制日志文件保存几天配置范围 -365000 ~ 365000默认 0 表示不按天数删除见 logKeepDays 注册 与 默认值。例如配置为 1 时一天之前的日志会在下一次归档压缩时被删除。普通日志相关参数汇总默认值与取值范围均以 配置注册代码 为准参数默认值取值范围说明logDir按平台默认—日志存储目录minimalLogDirGB1.00.001 ~ 10000000日志目录最少保留磁盘空间GBasyncLogtrue布尔true 为异步写日志false 为同步立即写numOfLogLines100000001000 ~ 2000000000单文件行数阈值超过触发归档logKeepDays0-365000 ~ 365000日志保留天数0 不按天数清理四、慢日志缓存、批量上报与文件锁系统除了记录普通日志以外对执行时间超过配置时间的操作会记录到慢日志中。慢查询的触发阈值由slowLogThreshold控制默认 1单位毫秒最小 1见 slowLogThreshold 注册。4.1 上报架构慢日志的上报采用批量模式整体架构为连接层每个 connection产生慢查询 → 放入队列 → slow log 线程消费 → 按 clusterId 分组写入临时文件 → 批量读取临时文件上报。4.2 临时文件缓存逻辑为提高上报效率慢 SQL 日志采用批量上报为防止缓存丢失采用写临时文件方式实现缓存——进程 crash 后数据仍在重启后可补报每生成一条慢 SQL 日志都会放入队列然后通知 slow log 线程从队列获取数据slow log 线程根据数据中的clusterId写到不同文件里。队列元素的数据结构见 MonitorSlowLogData 使用处为typedef struct { int64_t clusterId; // 当前日志所属的慢查询集群 id char *value; // 一条数据json 字符串形式 } MonitorSlowLogData;由于客户端进程中可能存在多个 connection分别连接不同集群慢查询日志需要按clusterId分组。分组通过临时文件名实现目录与命名方式如下目录拼接逻辑见 tmpPath 构造{tmp dir}/tdengine_slow_log/tdengine-{clusterId}-{processId}-{rand}其中processId为进程 ID用于区分多个客户端进程的上报rand为随机值避免同进程同集群文件冲突。按上图示例connection 1 连接 cluster 1connection 2、connection 3 连接 cluster 2那么 connection 1 的慢 SQL 数据写入tdengine-{clusterId1}-{processId}-{rand}connection 2/3 的慢 SQL 数据写入tdengine-{clusterId2}-{processId}-{rand}。4.3 上报逻辑slow log 线程读取tdengine-{clusterId}-{processId}-{rand}临时文件内容每行数据作为 JSON 数组的一个元素组装成 JSON 数组上报文件中数据每接近 1MB 大小上报一次防止文件过大导致单次上报失败上报采用异步方式发起上报后在 callback 中根据上次记录的读取进度继续读取文件并上报直至整个文件读取上报完毕上报成功后记录读取文件进度整个文件上报完毕后清空临时文件callback 中成功或失败都会继续读取上报失败时会记录上报失败的数据日志等待下次重试。4.4 上报时机客户端运行过程中定时上报每个monitorInterval时间间隔上报一次数据。monitorInterval为服务端配置项默认 1 秒取值范围 1 ~ 86400见 monitorInterval 注册客户端正常退出上报所有慢 SQL 日志文件上报成功后删除文件客户端异常退出再次与某个集群clusterId建立新连接后遍历{tmp dir}/tdengine_slow_log/目录下所有tdengine-{clusterId}开头的文件进行重新上报。由于这些文件可能属于另一个客户端进程或本进程正在操作的文件每个文件打开时都需要添加文件锁上报完成后删除该临时文件。4.5 异常行为说明重复上报上报数据与删除文件中的内容无法作为原子操作若上报成功后、删除前 crash下次可能重复上报。重复上报的数据会覆盖不会丢失影响很小断电丢数据为性能考虑slow log 线程把慢 SQL 日志写入临时文件时只刷新到操作系统的磁盘缓冲区并不每次都真正fsync到磁盘机器断电仍可能丢失少量数据。该异常出现概率很小设计上容忍此种丢失。五、慢日志文件存储规则慢日志一方面记录到本地慢日志文件中另一方面在开启monitor开关默认关闭见 monitor 注册会通过 taosAdapter 发送到 taosKeeper 做结构化存储。本地慢日志文件的存储规则慢日志文件一天一个如果当天没有慢日志则没有当天的文件文件名为taosSlowLog.yyyy-mm-dd例如taosSlowLog.2024-08-02日志存储路径通过logDir配置多个客户端的日志存储在相应日志路径下的同一个taosSlowLog.yyyy-mm-dd文件里慢日志文件不自动删除、不压缩慢日志使用与普通日志相同的三个参数logDir、minimalLogDirGB、asyncLog另外两个参数numOfLogLines、logKeepDays不适用于慢日志。由于慢日志不自动清理生产环境中如有长期运行且慢查询较多需要关注logDir所在磁盘空间并结合 taosKeeper 侧的结构化数据做分析。六、日志级别说明与 bit 位开关日志级别分为 9 种定义在 ELogLevel 枚举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;其中 FATAL/ERROR 与 WARN/INFO 分别共用同一 bit 位。日志开关通过bit 位来控制各 bit 含义见本文首图的日志级别示意图bit0 控制 error/fatalbit1 控制 info/warnbit2 控制 debugbit3 控制 tracebit4 控制 dumpbit6 控制是否同时输出到屏幕bit7 控制是否输出到文件。例如131 128 2 1文件 info error135 128 4 2 1文件 debug info error143 128 8 4 2 1文件 trace debug info error通过设置日志开关参数可以开启不同级别的日志。从源码结构看日志开关以“每模块一个 flag”的方式落地dDebugFlag、vDebugFlag、mDebugFlag、cDebugFlag、rpcDebugFlag等一组全局变量按模块独立配置且各模块默认值均为131即默认只写文件、记录 error/warn/info 级别见 各模块默认 flag。各模块的日志宏如uInfo、uError等见 日志宏定义先检查debugFlag 级别位再调用taosPrintLog(flags, level, dflag, format, ...)写入flags 前缀如 UTL INFO标识模块方便日志中按前缀过滤。排查问题的常用组合常规运行保持默认 131怀疑某模块逻辑问题时把对应模块 flag 提到 135含 debug需要跟踪完整调用轨迹如事务、同步流程时提到 143含 trace注意 trace 级日志量较大应结合numOfLogLines与logKeepDays控制磁盘占用排查完毕后恢复。七、小结日志调参速查场景建议日志写满磁盘调小numOfLogLines、设置logKeepDays确认minimalLogDirGB与logDir所在磁盘容量匹配高负载下出现...Lost N lines here...说明异步 20MB buffer 被写满可临时切同步日志asyncLog false或降低日志级别性能问题定位调低slowLogThreshold开启monitor将慢日志推送到 taosKeeper 结构化分析深入排查将对应模块 debug flag 从 131 提升到 135/143排查后恢复以上所有机制——20MB 循环 buffer、5ms~25ms 动态写盘间隔、taoslogX.Y命名与归档压缩、慢日志临时文件分组上报、bit 位日志开关——均可在当前仓库中直接验证核心写入与轮询逻辑在 source/util/src/tlog.c日志接口与级别枚举在 include/util/tlog.h配置项注册与默认值在 source/common/src/tglobal.c慢日志客户端上报在 source/client/src/clientMonitor.c含测试用例 source/client/test/clientMonitorTests.cpp。【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表