我已经建立了一个新的概念验证 logstash 系统
CentOS 6.6 (on Vmware 5.5) - single CPU VM with 12G RAM allocated
通过 RPM 安装 Elasticsearch 和 Logstash……
# rpm -q elasticsearch logstash
elasticsearch-1.7.1-1.noarch
logstash-1.5.3-1.noarch
JVM: 1.8.0_51
我输入的数据是以下形式的简单记录……
M1234 z123 2015-01-31 23:28:09.417 8.55373
(字段包括机器名称、用户 ID、日期、时间、登录时间 - 所有内容都是简单的 US-ASCII)
下面是 Logstash 配置(这些数据来自 MSSQL 数据库,目前我正在将其导出到文本文件并将文件传输到 logstash 服务器)。
这对于一天的日志(11K 条记录)来说很有效,但是当我尝试处理今年的积压日志时,它就“挂起了”。
症状包括
- elasticsearch 仍然响应迅速 - 搜索和配置访问仍然正常
- 索引中的文档数量停止增加
- 系统变得必不可少的空闲 - 只有后台磁盘活动和最低限度的 CPU 使用率
- 如果我尝试停止 logstash 进程(仍在运行),它只会终止
kill -9
。
这似乎发生在 200K 左右的文档中。它不受索引数量的影响 - 我从每日索引开始,然后改为每周索引 - 它仍然在 200K 左右的文档中停止。
因为这是在单台机器上运行的概念证明,所以我将副本数减少到 0,并将分片数减少到 1 - 我认为这对这个问题不会产生任何影响。
尽管我提高了 Logstash 和 Elasticsearch 日志的详细程度,但我没有在 Logstash 和 Elasticsearch 日志中看到任何错误。
我不认为系统耗尽了内存、磁盘空间和文件描述符。
我不确定还要看什么。这感觉像是一个微不足道的问题(对于 ELK 而言),而且我没有在处理我们邮件日志的现有 ELK 设置中看到这个问题(尽管它运行的是早期版本并且有多个 elasticsearch 存储节点)
尽管我确信输入文件中没有奇数字节序列,但我已charset => "US-ASCII"
在file
输入插件节中明确将输入声明为 US_ASCII。我不认为这会带来任何影响(测试仍在进行中)。
更新:虽然导入停滞时日志中没有什么有趣的内容,但是logstash
要求关闭时记录的行很有趣……
{:timestamp=>"2015-08-03T10:17:39.104000+0100", :message=>["INFLIGHT_EVENTS_REPORT", "2015-08-03T10:17:39+01:00", {"input_to_filter"=>20, "filter_to_output"=>0, "outputs"=>[]}], :level=>:warn}
对我来说,问题出在过滤阶段,而不是输出到elasticsearch
。我已经确认,首先删除elasticsearch
输出,只保留stdout
。这显示了相同的行为 - 导入在一段时间后停滞。
将elasticsearch
输出放回去但清除filter
部分中的所有内容使我成功完成了数据导入。
我现在已经解决了这个问题 - 详情请见答案。
input {
file {
path => "/var/lib/clusters/*"
type => "clusterF"
start_position => "beginning"
}
}
filter {
mutate {
remove_field => [ "path", "host" ]
}
# 13COMP014 nabcteam 2015-07-29 11:09:21.353 153.493
if [type] == "clusterF" {
grok {
match => { "message" => "%{NOTSPACE:client} +%{WORD:userid} +%{TIMESTAMP_ISO8601:datestamp} +%{BASE10NUM:elapsed:float}" }
}
}
if [elapsed] < 0 {
drop {}
}
if [elapsed] > 1000.0 {
drop {}
}
if [userid] =~ "[a-z][0-9]{7}" {
mutate {
add_field => [ "userClass", "student" ]
}
} else if [userid] =~ "n[a-z].*" {
mutate {
add_field => [ "userClass", "staff" ]
}
} else {
mutate {
add_field => [ "userClass", "other" ]
}
}
date {
match => [ "datestamp", "ISO8601" ]
}
mutate {
remove_field => [ "message" ]
}
}
output {
elasticsearch {
bind_host => "clog01.ncl.ac.uk"
protocol => "http"
cluster => "elasticsearch"
flush_size => 10
index => "clusters-%{+xxxx.ww}"
}
}
答案1
一旦我知道摊位就在附近,filter
就更output
容易找到了。
将elasticsearch
输出放回去但清除filter
部分中的所有内容使我成功完成了数据导入。
我编写了一个简单的perl
脚本来根据规范验证输入行grok
- 这表明一些用户 ID 包含连字符(这是我没有想到的)。在原始配置中替换+%{WORD:userid}
为+%{NOTSPACE:userid}
给了我一个有效的设置。我怀疑我首先应该做的是在成功时添加一个字段,grok
并且仅在该字段存在时才应用其他过滤规则。
我从中得到的主要教训是,简化这类问题很重要,否则寻找潜在原因的空间就会太大。