问题原因
- 起因之前我们项目是采用elk(elasticsearch+logstash+kibana)的方式下部署日志采集系统,今天突然发现Kibana中所有项目日志都没打印,更奇怪的是线上的项目都正常运行,并无异常,这时让人陷入了深思,难道是因为logstash没有收集到日志,去看了logstash日志,都是正常,而且正在以1000/s的行的速度疯狂输出。此时人已经彻底傻掉!
问题排查
-
首先排查所有服务是否正常,如:elasticsearch logstash kibana 和项目服务
-
排查磁盘是否已经打满
-
检查当前 elasticsearch 设置的索引数量是多少,7.x默认【1000】在Dev Tools控制台中,执行以下Elasticsearch Cat API命令:
GET /_cluster/settings?include_defaults=true
- 检查索引是否已经打满,在Dev Tools控制台中,执行以下Elasticsearch Cat API命令:
GET /_cat/indices?v
- 查询得知索引数量已经为1000,发现了问题删掉几月前没用的索引,先恢复日志
修改索引数量
- 这里暂时修改10000,大家根据自己的需求修改
- 请注意,您使用的是transient关键字,这意味着设置是临时的,将在Elasticsearch重启后丢失。如果您希望设置在重启后仍然生效,应该使用persistent关键字代替transient。
- transient 临时修改
PUT /_cluster/settings
{
"transient": {
"cluster": {
"max_shards_per_node": 1000
}
}
}
- persistent 方式修改
PUT /_cluster/settings
{
"persistent": {
"cluster": {
"max_shards_per_node": 1000
}
}
}
虽然现象问题解决了,但是本质问题依旧存在。
-
思考几个问题:
-
shard能达到1000,那未来是不是会到达10000,导致出现同样的问题?
为了避免这样的问题再次出现,那就要控制shard的数量,那么shard的数量和什么有关系?
如何控制shard的数量?
首先,回答第一个问题,先要搞清楚,什么是shard?
-
分片是 Elasticsearch 在集群中分发数据的关键。
-
把分片想象成数据的容器。文档存储在分片中,然后分片分配到集群中的节点上。当集群扩容或缩小,Elasticsearch 将会自动在节点间迁移分片,以使集群保持平衡。
一个分片(shard)是一个最小级别“工作单元(worker unit)”,它只是保存了索引中所有数据的一部分。 -
这类似于 MySql 的分库分表,只不过 Mysql 分库分表需要借助第三方组件而 ES 内部自身实现了此功能。
-
默认情况下,一个索引被分配 5 个主分片
-
可以看到,分片的数量和索引的数量是成正比的,也就是说索引越多,分片越多;再结合我们ES的实际配置,索引命名方式:环境+日期,环境是固定的,但是日期是每天增加的,那么索引每天都会增加,也就是说分片的数量也会随着时间推移,逐日增加,直到达到最大索引。
-
所以,针对第一个问题,即使最大分片数是10000,也会出现同样的问题。
那么如何控制shard数量呢?
- 其实控制shard数量,就是控制索引的数量,控制索引的数量,就是控制保存的log的数量,而log的数量可以通过控制保存的日志有效期天数来决定。
解决方案【修改logstash.conf】
- 原来的logstash.conf配置文件
# 输入环境配置
input {
tcp {
mode => "server"
host => "0.0.0.0"
port => 4560
codec => json_lines
}
}
# 输出环境配置
output {
# 输出到控制台
stdout {
codec => rubydebug
}
elasticsearch {
hosts => "es:9200"
user => "elastic"
password => "bmallelasticsearch"
index => "logstash-%{[spring.application.name]}-%{+YYYY.MM.dd}"
}
}
- 上面这里logstash配置文件中日志是按照【年月日】成索引,我这里根据【月份】成索引。
# 输入环境配置
input {
tcp {
mode => "server"
host => "0.0.0.0"
port => 4560
codec => json_lines
}
}
# 输出环境配置
output {
# 输出到控制台
stdout {
codec => rubydebug
}
elasticsearch {
hosts => "es:9200"
user => "elastic"
password => "bmallelasticsearch"
index => "logstash-%{[spring.application.name]}-%{+YYYY.MM}"
}
}