尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

深入理解rsyslog配置:从基础到生产级日志管理实战

深入理解rsyslog配置:从基础到生产级日志管理实战 1. 从“能用”到“精通”为什么你需要深入理解rsyslog配置如果你在运维Linux服务器或者负责一个分布式系统的日志管理那么rsyslog这个名字你一定不陌生。它几乎是现代Linux发行版默认的日志守护进程从systemd的journal到传统的syslog消息最终大多都流向了它。很多人对rsyslog的认知停留在“改改/etc/rsyslog.conf把日志写到另一个文件”的层面这确实能解决80%的基础需求。但当你面对海量日志、需要复杂的过滤、转发、格式化或者遇到性能瓶颈时那种“翻遍全网只找到只言片语”的无力感就会袭来。官方文档虽然全面但过于庞杂像一本字典不适合快速解决问题。这篇内容就是为你准备的。它不是官方文档的翻译而是一个在日志管理一线摸爬滚打多年的工程师对rsyslog v7/v8版本核心配置的实战解读。我会聚焦于那些真正高频使用、能解决实际问题的配置模块和指令用大白话讲清楚它们的工作原理和组合方式。至于那些生僻的、一年也用不上一次的参数我的建议和标题一样真遇到了再去翻官网罢。我们的目标是让你手里这份rsyslog.conf从一个黑盒脚本变成一件得心应手的工具。2. 配置文件的结构与核心语法理解rsyslog的“语言”在动手修改任何配置之前你必须先理解rsyslog配置文件的“语法”。它看起来简单但细微之处藏着很多坑。一个典型的rsyslog.conf文件通常由以下部分组成理解这个结构是后续一切操作的基础。2.1 模块加载赋予rsyslog超能力rsyslog的强大源于其模块化设计。核心的rsyslogd进程只负责调度具体的输入、输出、过滤、转换等功能都由模块实现。加载模块的指令是module。# 加载imjournal模块用于从systemd journal读取日志 module(loadimjournal) # 加载imuxsock模块用于接收本机应用程序通过Unix socket发送的日志 module(loadimuxsock) # 加载imklog模块用于接收内核日志 module(loadimklog) # 加载omfile模块这是最常用的输出模块用于将日志写入文件 module(loadomfile) # 加载omfwd模块用于将日志转发到远程服务器 module(loadomfwd) # 加载mmnormalize或pmnormalize模块用于日志的规范化解析在复杂过滤时非常有用 module(loadmmnormalize)为什么是im和om这是rsyslog的命名约定im代表输入模块Input Moduleom代表输出模块Output Module。此外还有mmMessage Modification消息修改、pmParser Module解析模块等。在v7/v8版本推荐使用新式的module(load...)语法它比旧式的$ModLoad更清晰。一个关键经验模块不是加载得越多越好。只加载你需要的模块。例如如果你的服务器没有启用systemd journal或者你确定不需要从journal读日志就不要加载imjournal。每加载一个模块都会占用少量内存并在规则处理时引入微小的开销。在生产环境尤其是容器或资源受限的环境中这一点点优化累积起来也很可观。2.2 全局指令设定rsyslog的“性格”全局指令作用于整个rsyslog守护进程通常放在配置文件开头模块加载之后。它们定义了日志的默认格式、队列行为、工作目录等全局属性。# 设置全局的默认日志模板。这里的RSYSLOG_TraditionalFileFormat是一个内置模板。 global(workDirectory/var/lib/rsyslog) global(defaultNetstreamDrivergtls) global(defaultNetstreamDriverCAFile/etc/rsyslog.d/ca.pem)workDirectory这个目录非常重要rsyslog会在这里创建队列文件、状态文件等。确保这个目录有足够的磁盘空间和正确的权限通常rsyslog用户可写。如果这个目录满了rsyslog可能会停止工作或丢失日志。关于模板虽然这里提到了模板但更复杂的模板定义通常放在后面。全局指令中的模板设置往往是最后兜底的默认选项。2.3 规则Rules配置的灵魂所在规则是rsyslog配置的核心它告诉rsyslog“如果收到一条日志且它符合某个条件那么就执行某个动作”。其基本语法在新旧版本间有差异但逻辑相通。传统选择器Selector语法仍广泛支持facility.priority actionfacility设施 表示日志的来源。常见的有auth,authpriv: 安全和认证相关消息。cron: 定时任务。daemon: 系统守护进程。kern: 内核消息。mail: 邮件系统。syslog: rsyslog自身产生的消息。user: 用户级程序默认值。local0~local7: 留给自定义程序使用非常有用。*: 通配符代表所有设施。priority优先级 表示日志的严重等级从低到高debug,info,notice,warning,err,crit,alert,emerg。指定一个优先级如err会捕获该等级及更高等级err,crit,alert,emerg的所有日志。none是一个特殊关键字用于排除某个设施。action动作 对匹配的日志执行的操作。最常见的是写入文件。示例# 将所有内核消息无论级别记录到 /var/log/kern.log kern.* /var/log/kern.log # 将mail设施中warning及以上级别的日志记录到 /var/log/mail.warn mail.warning /var/log/mail.warn # 将所有设施的emerg级别日志发送给所有登录用户 *.emerg :omusrmsg:* # 排除authpriv设施的所有日志不记录 authpriv.none /var/log/secureRainerScript语法v7推荐这是更现代、更强大、更易读的配置方式尤其适合复杂的条件判断和动作设置。它看起来像一种脚本语言。# 使用if...then...else结构进行条件判断 if $syslogfacility-text local0 and $msg contains ERROR then { action(typeomfile file/var/log/myapp-error.log) stop # 处理停止本条日志不再匹配后续规则 } # 使用property-based过滤器 if $msg startswith Connection from then { action(typeomfwd target192.168.1.100 port514 protocoltcp) }新旧语法如何选择对于简单的、基于设施和优先级的过滤传统语法非常简洁。但一旦你需要基于日志内容$msg、主机名$hostname、程序名$programname等属性进行过滤或者需要执行多个动作、使用复杂的逻辑判断RainerScript是唯一的选择。在v7/v8的配置中两者可以混用但我强烈建议在新项目或修改配置时逐步转向RainerScript它的可维护性要好得多。3. 高频实战模块与指令详解掌握了基本语法我们来看看那些能解决实际问题的“利器”。这些模块和指令的组合能帮你搭建起从简单到复杂的日志处理流水线。3.1 输入模块日志从何而来除了默认加载的imuxsock本地socket和imklog内核以下几个输入模块非常实用。imjournal 对接systemd journal如果你的系统使用systemdCentOS 7, RHEL 7, Ubuntu 16.04等这是读取系统日志的主要方式。module(loadimjournal PersistStateInterval100) # 加载模块PersistStateInterval 这个参数至关重要。它定义了rsyslog将读取journal的游标位置持久化到磁盘的频率单位消息条数。如果这个值设得太大当rsyslog重启时可能会重复处理大量已经读过的journal日志。对于日志量大的系统建议设置为100或更小。但设置太小会增加磁盘I/O。你需要根据日志量权衡。RateLimit.interval和RateLimit.burst 如果journal中瞬间产生海量日志例如某个服务崩溃疯狂刷日志rsyslog可能会被压垮。这两个参数用于限流例如RateLimit.interval2和RateLimit.burst10000表示在2秒内最多处理10000条消息。imfile 追踪文本文件这是收集应用日志的神器。很多应用程序如Nginx, Tomcat, 自定义业务程序并不通过syslog协议写日志而是直接写入一个文本文件。imfile模块可以像tail -f一样实时读取这些文件并将其内容作为syslog消息送入rsyslog处理管道。module(loadimfile) # 加载模块 # 定义一个输入文件 input(typeimfile File/var/log/nginx/access.log # 要监控的文件路径 Tagnginx-access: # 为此类日志打上一个标签方便后续过滤 Severityinfo # 默认严重级别 Facilitylocal0 # 使用自定义的local0设施便于区分 PersistStateInterval1 # 持久化文件读取位置的间隔行数防止重启后重复读取 )踩坑点文件权限 确保rsyslog进程的运行用户通常是rsyslog有权限读取你监控的文件。inode问题 如果被监控的日志文件发生了轮转log rotation例如被logrotate重命名并新建了一个空文件imfile必须能识别这个变化。较新版本的imfile模块通过PersistStateInterval和内部机制通常能处理好。但如果发现轮转后日志不更新了可以尝试在logrotate配置中增加postrotate脚本向rsyslog主进程发送HUP信号kill -HUP或重启rsyslog服务。性能 监控大量文件或增长极快的文件会消耗较多CPU和I/O资源。对于超高频日志需要考虑业务侧是否应该直接使用syslog输出而非让rsyslog去“尾随”文件。3.2 输出模块日志去往何处omfile 写入本地文件最常用的输出但绝不简单。action(typeomfile file/var/log/remote.log templateMyTemplate # 指定使用的模板 flushInterval10 # 批量写入的间隔秒0为立即写入 asyncWritingon # 启用异步写入大幅提升性能 queue.typelinkedList # 使用内存队列缓冲 queue.size100000 # 队列大小 queue.highWatermark80000 # 高水位线达到此值会触发某些行为 queue.lowWatermark20000 # 低水位线 queue.discardMark97500 # 丢弃标记队列达到此大小开始丢弃消息 queue.discardSeverity5 # 丢弃低于此优先级的消息5notice queue.maxFileSize10m # 队列溢出到磁盘文件时的单个文件大小 )性能三剑客asyncWriting、flushInterval和queue是解决磁盘I/O瓶颈的关键。开启异步写入后rsyslog会将日志先放入内存队列然后根据flushInterval定期批量刷入磁盘。这能减少磁盘寻址次数极大提升吞吐量在高流量场景下是必选项。队列配置 队列是缓冲区的核心。linkedList队列性能最好。size是队列容量。当队列快满时达到highWatermarkrsyslog会尝试减缓输入如果队列继续增长到discardMark则会开始丢弃消息优先丢弃低优先级的。这些参数需要根据你的日志流量和服务器内存来调整。一个经验值对于单日百GB级日志量的应用queue.size500000起步并密切监控队列使用率。文件同步sync 默认情况下omfile写入后不会立即调用fsync同步到物理磁盘。这意味着在系统崩溃时可能会丢失最后几秒的日志。如果你对日志的完整性要求极高如审计日志可以设置syncon但这会带来巨大的性能损耗通常不建议。omfwd 转发到远程服务器构建日志中心这是实现集中式日志管理的核心。action(typeomfwd Targetlogserver.company.com Port514 Protocoltcp # 使用TCP可靠性高于UDP TemplateForwardFormat # 指定转发模板 StreamDrivergtls # 启用TLS加密 StreamDriverMode1 # 客户端模式 StreamDriverAuthModex509/name # 认证模式 StreamDriverPermittedPeers*.company.com # 允许的服务器证书名 queue.typelinkedList queue.size100000 queue.saveOnShutdownon # 关闭时保存队列到磁盘防止丢失 action.resumeRetryCount-1 # 网络中断后无限重试 )TCP vs UDP 生产环境强烈建议使用TCP。UDP不可靠网络抖动就可能导致日志丢失且没有拥塞控制可能冲垮接收端。TCP保证了传输的可靠性和顺序。TLS加密 如果日志内容敏感或者需要穿越公网必须启用TLSStreamDrivergtls。这需要配置CA证书、客户端证书和密钥。虽然配置稍复杂但对于安全要求高的环境是必须的。队列与重试 网络是不稳定的。queue在这里起到了断网缓冲的作用。当网络中断时日志会堆积在本地队列中。action.resumeRetryCount-1意味着会不断尝试重连。queue.saveOnShutdownon确保即使rsyslog进程重启队列中的日志也不会丢失。这是远程转发稳定性的生命线。多目标负载均衡omfwd支持指定多个Targetrsyslog会以轮询方式将消息转发到不同服务器实现简单的负载均衡。omelasticsearch 写入Elasticsearch对于想要构建ELK或EFK栈的用户这个模块可以直接将日志写入Elasticsearch省去Logstash的解析步骤。module(loadomelasticsearch) action(typeomelasticsearch serveres01.company.com serverport9200 templatees_template # 需要一个特制的、输出JSON的模板 searchIndexsyslog-%Y.%m.%d # 按日期滚动的索引名 bulkmodeon # 开启批量提交提升性能 queue.typelinkedList queue.size100000 )模板是关键 你必须定义一个输出为JSON格式的模板template其字段结构要符合Elasticsearch的映射需求。这通常需要结合mmnormalize或mmjsonparse模块来解析原始日志。批量提交bulkmodeon会累积一定数量的文档后通过Elasticsearch的_bulkAPI提交这比单条插入效率高几个数量级。错误处理 需要仔细处理Elasticsearch集群不可用、索引只读等情况。omelasticsearch有相关的错误处理参数需要配置。3.3 模板与属性如何塑造日志的样貌模板决定了日志消息最终以何种格式呈现。rsyslog的属性系统则让你可以访问消息的每一个部分。内置模板与自定义模板# 使用内置模板传统格式 $template TraditionalFormat,%timegenerated% %HOSTNAME% %syslogtag%%msg%\n # 自定义一个JSON格式的模板推荐用于结构化日志处理 template(nameJsonTemplate typelist) { constant(value{) constant(value\timestamp\:\) property(nametimereported dateFormatrfc3339) constant(value\,\host\:\) property(namehostname) constant(value\,\severity\:\) property(namesyslogseverity-text) constant(value\,\facility\:\) property(namesyslogfacility-text) constant(value\,\tag\:\) property(namesyslogtag) constant(value\,\message\:\) property(namemsg) constant(value\}\n) }property() 这是模板的基石用于插入消息的属性。例如property(namemsg)获取原始消息property(namehostname)获取主机名property(nametimereported dateFormatrfc3339)获取ISO 8601格式的时间戳。constant() 插入固定的字符串比如JSON的括号、逗号、字段名。为什么用JSON结构化日志JSON是现代日志系统的首选。它便于后续的解析、索引和查询在Elasticsearch, Splunk等系统中。相比于一整行需要复杂正则解析的文本JSON字段可以直接被利用极大降低了处理复杂度。常用属性速查在过滤条件和模板中你会频繁用到这些属性$msg 日志消息体本身。$rawmsg 未经任何修改的原始消息。$hostname 产生日志的主机名。$programname 产生日志的程序名如nginx,java。$syslogfacility-text/$syslogseverity-text 设施和优先级的文本形式如local0,err。$timereported 日志被报告的时间。$timegenerated rsyslog收到日志的时间。$syslogtag 通常由programname和可选的PID组成如nginx[1234]:。3.4 过滤与解析从海量数据中提炼黄金单纯的转发和存储只是第一步有价值的往往是过滤和解析后的数据。基于属性的过滤RainerScript这是最灵活的过滤方式。# 过滤包含特定关键词的日志 if $msg contains OutOfMemoryError then { action(typeomfile file/var/log/critical-oom.log) # 可以同时发送邮件或告警 } # 过滤来自特定主机的日志 if $hostname web-server-01 then { action(typeomfwd targetspecial-logserver port514) } # 复杂的正则表达式匹配 if re_match($msg, ^ERROR.*user\[.*\]) then { action(typeomfile file/var/log/user-errors.log) } # 组合条件 if ($programname nginx and $msg contains 500 ) or $syslogseverity 3 { # severity 3 对应 err, crit, alert, emerg action(typeomfile file/var/log/critical-errors.log) }mmnormalize模块日志解析利器当你的日志有固定格式时如Nginx访问日志使用mmnormalize比写复杂的正则更高效、更易维护。它基于liblognorm库使用规则库rulebase来定义日志格式。定义规则库文件(nginx.rulebase)rule:%client_ip:word% %ident:word% %auth:word% [%timestamp:char-to:]%] %method:word% %request:char-to()% %status:number% %bytes_sent:number% %referrer:char-to()% %agent:char-to()%在rsyslog配置中加载和使用module(loadmmnormalize) # 定义规则库 action(typemmnormalize ruleBase/etc/rsyslog.d/nginx.rulebase) # 使用解析后的字段 if $!status 500 then { # 使用$!前缀访问解析出的字段 action(typeomfile file/var/log/nginx-500.log) } template(nameNginxJson typelist) { constant(value{) constant(value\client_ip\:\) property(name$!client_ip) # ... 输出其他解析字段 constant(value\}\n) }mmnormalize将非结构化的日志行解析成了结构化的字段$!client_ip,$!status等后续的过滤和模板化就变得极其简单直观。4. 高级主题与性能调优实战当你处理日均TB级别的日志时默认配置很快就会成为瓶颈。以下是一些高级主题和调优经验。4.1 多线程与多队列榨干硬件性能rsyslog支持多线程处理可以充分利用多核CPU。# 在主队列后创建多个工作队列Worker Threads main_queue( queue.workerThreads4 # 启动4个工作线程 queue.workerThreadMinimumMessages1000 # 每个线程一次处理的最小消息数 queue.dequeueBatchSize256 # 从主队列取出的批量大小 ) # 对于特定的、高负载的动作可以配置独立的异步队列 action(typeomfwd targetcentral-log ... queue.workerThreads2 ...)如何设置线程数一个常见的起点是设置为CPU核心数。但并非越多越好需要结合I/O磁盘/网络瓶颈来考虑。可以通过监控rsyslogd进程的CPU使用率和队列深度来调整。如果CPU使用率不高但队列持续增长可能瓶颈在I/O增加线程数帮助不大。监控队列 使用rsyslogd -N1命令或查看/proc/下rsyslog进程的状态可以观察各个队列的当前大小、丢弃消息数等。这是性能调优最重要的依据。4.2 磁盘缓冲与可靠性保障前面提到了内存队列queue.typelinkedList。当内存队列满了或者为了在关机时持久化需要用到磁盘辅助队列DA Disk-Assisted。action(typeomfwd ... queue.typelinkedList queue.size500000 # 内存队列大小 queue.highWatermark450000 queue.lowWatermark20000 queue.discardMark480000 queue.discardSeverity5 queue.fileNamefwdQueue # 磁盘队列文件的前缀 queue.maxDiskSpace2g # 磁盘队列最大总大小 queue.saveOnShutdownon queue.workerThreads2 )工作流程 当内存队列达到highWatermark时rsyslog开始将消息写入磁盘文件fwdQueue.00000001等。当内存队列消费到lowWatermark以下时再从磁盘读回。这防止了内存被日志撑爆。saveOnShutdown 设为on后rsyslog在正常关闭时会将内存队列持久化到磁盘。结合磁盘队列这提供了很强的可靠性保证即使服务器意外断电重启后也能恢复大部分未发送的日志。这是生产环境高可靠配置的基石。磁盘空间监控 务必监控queue.maxDiskSpace设定的目录。如果磁盘队列也满了rsyslog将不得不丢弃新消息。4.3 一个生产级配置片段示例让我们看一个综合性的例子将日志同时写入本地文件异步缓冲、转发到远程中心带TLS和磁盘缓冲、并过滤出错误日志发送告警。# 1. 加载必要模块 module(loadimuxsock) module(loadimjournal) module(loadomfile) module(loadomfwd) module(loadmmjsonparse) # 假设我们处理JSON日志 # 2. 全局设置 global(workDirectory/var/lib/rsyslog) # 3. 定义JSON模板 template(nameAppJsonTemplate typelist) { constant(value{) constant(value\timestamp\:\) property(nametimereported dateFormatrfc3339) constant(value\,\host\:\) property(namehostname) constant(value\,\level\:\) property(namesyslogseverity-text) constant(value\,\app\:\) property(nameprogramname) constant(value\,\message\:\) property(namemsg) constant(value\}\n) } # 4. 主队列多线程处理 main_queue(queue.workerThreads4 queue.size100000) # 5. 规则所有日志的通用处理流程 # 5.1 首先尝试解析JSON格式的msg。如果不是JSON此动作无效。 action(typemmjsonparse cookiecee:) # 5.2 将原始日志结构化后写入本地文件使用异步队列缓冲防止磁盘IO阻塞。 if $programname ! rsyslogd then { # 避免记录rsyslog自身的日志形成循环 action(typeomfile file/var/log/all-apps.json templateAppJsonTemplate asyncWritingon flushInterval5 ioBufferSize64k # 增大IO缓冲区 queue.typelinkedList queue.size50000 queue.highWatermark40000 queue.discardMark48000 queue.discardSeverity6 # 丢弃info及以下级别的日志当队列压力大时 ) } # 5.3 将日志转发到远程日志中心启用TLS和磁盘辅助队列确保网络中断时不丢数据。 if $programname ! rsyslogd then { action(typeomfwd Targetlog-central.example.com Port6514 # TLS常用端口 Protocoltcp StreamDrivergtls StreamDriverMode1 StreamDriverAuthModex509/name StreamDriverPermittedPeerslog-central.example.com TemplateAppJsonTemplate queue.typelinkedList queue.size100000 queue.fileNameforwardQueue queue.maxDiskSpace1g queue.saveOnShutdownon action.resumeRetryCount-1 queue.workerThreads2 ) } # 5.4 特别关注ERROR及以上级别的日志将其写入单独的文件并可以在此处集成邮件或HTTP告警接口。 if $syslogseverity 3 then { # err, crit, alert, emerg action(typeomfile file/var/log/critical-errors.json templateAppJsonTemplate) # 此处可以添加 omail 或 omhttp 模块调用发送告警 }这个配置展示了一个兼顾性能、可靠性和功能性的生产环境思路。它采用了异步写入、队列缓冲、多线程、磁盘辅助、TLS加密等一系列技术能够应对较高的日志负载并在出现局部故障磁盘慢、网络中断时保证核心日志不丢失服务不中断。
返回列表