如何防止 "Timeout executing grok" 和 _groktimeout 标记

How to prevent "Timeout executing grok" and _groktimeout tag

我有一个日志条目,其最后部分根据少数 HTTPS 条件不断变化。

示例日志:

INFO  [2021-09-27 23:07:58,632] [dw-1001 - POST /abc/api/v3/pqr/options] [386512709095023:] [ESC[36mUnicornClientESC[0;39m]: 
<"type": followed by 11000 characters including space words symbols <----- variable length.

神交模式:

%{LOGLEVEL:loglevel}\s*\[%{TIMESTAMP_ISO8601:date}\]\s*\[%{GREEDYDATA:requestinfo}\]\s*\[%{GREEDYDATA:logging_id}\:%{GREEDYDATA:token}\]\s*\[(?<method>[^\]]+)\]\:\s*(?<messagebody>(.|\r|\n)*)

(.|\r|\n)*) 如果日志的可变部分很小,这可以正常工作,但是当遇到大日志时,它会抛出异常:

[2021-09-27T17:24:40,867][WARN ][logstash.filters.grok    ] Timeout executing grok '%{LOGLEVEL:loglevel}\s*\[%{TIMESTAMP_ISO8601:date}\]\s*\[%{GREEDYDATA:requestinfo}\]\s*\[%{GREEDYDATA:logging_id}\:%{GREEDYDATA:token}\]\s*\[(?<method>[^\]]+)\]\:\s*(?<messagebody>(.|\r|\n)*)' against field 'message' with value 'Value too large to output (178493 bytes)! First 255 chars are: INFO  [2021-09-27 11:50:14,005] [dw-398 - POST /xxxxx/api/v3/xxxxx/options] [e3acfd76-28a6-0000-0946-0c335230a57e:]

和 CPU 在 kibana 中开始阻塞和持续队列增加和滞后。有什么建议吗?

grok 中的性能问题和超时在模式与消息匹配时通常不是问题,在模式不匹配时才是问题。

首先要做的是尽可能锚定你的模式。 This blog post 有关于其有效性的性能数据。在您的情况下,当模式不匹配时,grok 将从行首开始查看 LOGLEVEL 是否匹配。如果它不匹配,那么它将从该行的第二个字符开始并查看 LOGLEVEL 是否匹配。如果它一直不匹配,它将不得不进行数千次匹配模式的尝试,这非常昂贵。如果您将模式更改为以 ^%{LOGLEVEL:loglevel}\s*\[ 开头,则 ^ 意味着 grok 只需在 [message] 的每一行的开头评估与 LOGLEVEL 的匹配。如果将其更改为 "\A%{LOGLEVEL:loglevel}\s*\[,那么它只会评估 [message] 字段开头的匹配项。

其次,如果可能,请避免 GREEDYDATA,除非在模式的末尾。当将 10 KB 字符串与具有多个 GREEDYDATA 的模式进行匹配时,如果模式不匹配,则每个 GREEDYDATA 将针对数千个不同的子字符串进行尝试,从而导致为每个事件进行数百万次匹配尝试(这不是那么简单,但不匹配确实会变得非常昂贵)。尝试将 GREEDYDATA 更​​改为 DATA,如果它仍然有效,则保留它。

第三,如果可能,用自定义模式替换GREEDYDATA/DATA。例如,在我看来 \[%{GREEDYDATA:requestinfo}\] 可以替换为 \[(?<requestinfo>[^\]]+) 并且我希望当整体模式不匹配时它会更便宜。

第四,我会认真考虑使用 dissect 而不是 grok

dissect { mapping => { "message" => "%{loglevel->} [%{date}] [%{requestinfo}] [%{logging_id}:%{token}] [%{method}]: %{messagebody}" } }

但是,解剖过滤器中有一个 bug,如果在映射中使用“->”,则单个定界符不匹配,需要多个定界符。因此 %{loglevel->} 将匹配 INFO [2021,但不会匹配 ERROR [2021。我经常

mutate { gsub => [ "message", "\s+", " " ] }

并删除 -> 以解决此问题。 dissect 远不如 grok 灵活和强大,这使得它便宜得多。请注意,dissect 将创建空字段,例如启用 keep_empty_captures 的 grok,因此您将获得一个 [token] 字段,其中包含该消息的“”。