【Elasticsearch】Elasticsearch 100 个常见 问题

x33g5p2x  于2022-05-28 转载在 ElasticSearch  
字(7.7k)|赞(0)|评价(0)|浏览(563)

1.概述

转载:Elasticsearch 100问(1-30)

第1问-可产品化

问:重启集群后,出现了unassigned shards, 是什么原因:
答:集群的shard数量较多,在节点重启后,由于recovery并发限制,shard分配次数超限,集群就不会在分配shard了,从而出现unassigned shards; 可以使用api对shard进行重新分配:POST _cluster/reroute?retry_failed=true

第2问-可产品化

问:使用ES过程中,出现bulk reject, 查看日志看到bulk queue满了,请问这是什么原因?
答:可以通过GET _cat/thread_pool/bulk?s=queue:desc&v查看正在拒绝或者历史拒绝的个数;一般默认bulk queue大小是1024, 造成bulk reject的大多数原因大概有两种:

  1. shard容量多大,建议每个shard容量控制在20G-50G,shard数量不能过多,也不能过少
  2. shard分布不均,可通过调整index.routing.allocation.total_shards_per_node参数来解决

第3问-可产品化

问:磁盘写满后,清理了一部分数据,此时无法向ES中写入数据,请问是什么原因:
答:磁盘写满后,ES会把集群的block级别改为read_only_allow_delete, 此时需要修改该参数,通过调用

PUT _cluster/settings {cluster. blocks.read_only_allow_delete:"false"}

解决,如果出现index level级别的block贼需要修改对应索引的配置

第4问

问:使用logstash收集日志时,如何把logstash默认添加的@timestamp字段替换为日志中的时间?
答:

filter {
    grok {
        match => ["message", "%{TIMESTAMP_ISO8601:logdate}"
    }
    date {
        match => ["logdate", "yyyy-MM-dd HH:mm:ss,SSS"]
        target => "@timestamp"
    }
}

第5问

问:使用logstash收集日志时,如何修改logstash默认添加的@timestamp字段的时区为东八区?
答:

filter {
  date {
    match => ["message","UNIX_MS"]
    target => "@timestamp"   
  }
  ruby { 
   code=>"event.set('timestamp',event.get('@timestamp').time.localtime + 8*60*60)" 
      }
  ruby {
   code => "event.set('@timestamp',event.get('timestamp'))"
  }
  mutate {
   remove_field => ["timestamp"]
  }
}

第6问-可产品化

问:调用_forcemerge API发现并没有减少segment的数量,请问是什么原因?

答:_forcemerge API执行merge是有条件的,当索引数据量比较大时,经过了一定时间的merge之后,每个segement都会比较大,如果此时indexing的速率较低,merge操作期望可以merge的segment数量比较大,而实际上候选的segment数量没有那么大时,就不会触发merge操作

第7问

问:聚合查询越来越慢,请问是什么原因?

答:需要确认进行聚合的字段唯一值是否比较多,唯一值较多的情况下聚合查询构建Global Ordinals会比较慢,如果索引没有持续写入,构建好的Global Ordinals就会进行缓存,之后的查询就可以使用缓存中的Global Ordinals;但是如果索引在持续写入,每当底层的segment发生变化时(有新数据写入导致产生新的Segment、Segment Merge),就需要重新构建Global Ordinals,随着数据量的增大聚合字段的唯一值越来越多,构建Global Ordinals越来越慢,所以对持续写入的索引,聚合查询会越来越慢。从业务角度进行优化的方案可以参考:https://cloud.tencent.com/developer/article/1421924

第8问

问:在kibana上创建index pattern卡主了,一直转圈圈,无法创建,是什么原因?
答:首先确认下.kibana的索引是否被设置为只读了,当集群出现过磁盘写满时,ES会自动把索引设置block级别设置为readonly_allow_delete, 如果被设置为只读,需要修改block级别

PUT .kibana/_settings {"index.blocks.read_only_allow_delete":false}

第9问

问:通过logstash向ES写入日志报错:"type"=>"illegal_state_exception", "reason"=>"Can't get text on a START_OBJECT, 请问这是什么原因?

答:原因是es对字段解析错误,类型是字符串(keyword或者text)的字段接收到的值为对象(如json对象),出现这种情况,可以在logstash 配置文件中使用json_encode filter plugin对原来是对象的字段转换为字符串。

第10问

问:查询dsl中使用了min_score参数用来限定返回文档的得分,为什么多次执行hit的文档数量不一致?

答:主分片和副本分片的差异导致的,底层segment可能不一致,特别是在有文档被删除的情况下主分片和副本分片的segment中标记删除的文档的数量可能会不一致(比如主分片进行了merge, 副本分片没有进行merge),导致最终主分片和副本分片上文档的得分不同,影响了最终的查询结果;可以在查询时指定preference=_primary指定只查询主分片解决,或者自定义preference解决

第11问

问:completion suggester自动补全功能,在添加seggest inputs时指定了多个词,为什么查询时options只返回一项?
创建索引并添加doc:

curl -XPUT "http://localhost:10001/music" -H 'Content-Type: application/json' -d'
{
    "mappings": {
      "_doc":{
        "properties" : {
            "suggest" : {
                "type" : "completion"
            },
            "title" : {
                "type": "keyword"
            }
        }
    }
}}'

curl -XPUT "http://localhost:10001/music/_doc/7?refresh" -H 'Content-Type: application/json' -d'
{
    "suggest" : {
        "input": [ "bat", "bar"]
    }
}'

查询:

curl -XPOST "http://localhost:10001/music/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "suggest": {
        "song-suggest" : {
            "prefix" : "ba", 
            "completion" : { 
                "field" : "suggest" 
            }
        }
    }
}'

结果:

...
"options": [
          {
            "text": "bar",
            "_index": "music",
            "_type": "_doc",
            "_id": "7",
            "_score": 1,
            "_source": {
              "suggest": {
                "input": [
                  "bat",
                  "bar"
                ]
              }
            }
          }
        ]
...

答: completion suggester返回的options是文档级别的,查询命中后就会提前终止,所以只能返回第一个匹配到的值;解决方法是bat, bar两个词分别放在两个doc中

第12问-可产品化

问:2核4G 3节点的集群,在保证集群性能稳定的情况下,最多可以支持多少shard?

答:每个节点上可以存储的分片数量与可用的堆内存大小成正比关系,分片数量越多,分片的元数据占用的内存越多,一般情况下,1GB的堆内存对应分片数量不超过20

第13问-可产品化

问:请问ES报这个错误是什么原因:

"caused_by"=>{"type"=>"max_bytes_length_exceeded_exception", "reason"=>"max_bytes_length_exceeded_exception: bytes can be at most 32766 in length; got 33023"}

答:原因是索引中有字段为keyword类型,但是写入时的该字段的数据长度超过了keyword类型的最大长度32766个字节,可以把该字段的类型设置为text解决。

第14问

问: 使用filebeat收集日志写入ES中,报错:

"Bulk item insert failed (i=0, status=500): {"type":"string_index_out_of_bounds_exception","reason":"String index out of range: 0"}"

请问是什么原因?

答:当filebeat的output.elasticsearch.index配置项有取自上游event中的某个字段,而某个event中该字段不存在时,想ES写入数据会报错。索引的名称如果要从event中的某个字段获取,需要确保该字段一定会存在。

第15问

问:ES的_refresh和_flush操作的区别是什么?

答:refresh调用了lucene DirectoryReader的 openIfChanged()方法,相当于重新打开了indexReader, 使得写入的数据都可以被搜索到;flush操作调用了luecene IndexWriter的commit()方法,把仍在在文件系统缓存中的segment写入到磁盘中,实现了数据的真正持久化,flush同时还会触发refresh操作。

第16问

问:在ES的script query中,使用doc['my_field'].value和 params['_source']['my_field'],两种方式有什么不同?

答:使用doc[]的方式会把字段的所有terms都加载进内存并且会被缓存,因此比较消耗内存,同时doc[]的方式只支持单值字段;使用_source的方式terms不会被缓存,相比doc[]的方式较慢。

第17问

问:ES的删除操作不是真正的删除,那通过什么方式可以获取到准确的文档数量?

答:通过_cat/count API获取集群中所有文档数量,不包含已删除的文档;通过{index}/_stats API获取索引中的文档数量,结果中docs.count值为除了标记删除文档之外的总的文档数,docs.deleted为标记删除的文档数。

第18问

问:ES的_search API,当不指定索引时是会向集群中所有的索引发起查询请求吗?

答:是默认行为,最好通过指定索引名称或者对多个索引设置别名后进行查询,可以减少不必要的开销;5.6版本以后增加了分片预过滤功能,当要查询的分片数量超过128并且查询可能会被重写为MatchNoneQuery时,会进行过滤,过滤掉不需要的shard,_search API的返回结果中的_shards.skipped表示了过滤掉了多少shard。

第19问

问:如果使用scroll批量获取查询结果,ES执行该查询时还会使用node query cache或者shard request cache吗?

scroll请求不会用到cache,因为使用cache在查询请求执行过程中会修改search context,会破坏掉scroll的context。

第20问

问:如何实现字符串的前后通配符匹配,比如输入bc,想查询出abc, abcd, bcd, 但是不能查询出abdc?
答:使用query_string查询:

{
    "query":{
        "query_string":{
            "query":"field:*ab*"
        }
    }
}

第21问

问:使用query_string查询指定的整型字段,查询的值为正数时正常,值为负数时抛异常,如“status:-1”时会报错,怎么解决?

答:需要把负号转义("status:\-1")或者对负数加引号, 否则会认为负号是一个操作符而解析失败。

第22问

问:在kibana中要对long型的字段进行聚合,但是提示不支持,请问这是什么原因?

答:如果索引是按天创建的,并且一个index pattern下包含多个索引,检查下索引的mapping,是否之前的索引中字段类型是否是字符串类型,如果不同索引中该字段的类型不一致,则不能对该字段进行聚合。
https://github.com/elastic/kibana/issues/3451

第23问

问:通过bulk api向es写数据时,报错failed to execute bulk item (index) BulkShardRequest ...source[n/a, actual length: [4.5kb], max length: 2kb]}], 请问是字段超过了最大长度2kb的限制吗?

答:日志中打出的max length不是字段的最大长度的意思,而是超过了2kb就不把具体的doc信息在日志中打出,bulk失败的信息需要查看日志中后面的异常信息,一般是字段解析失败或者是bulk队列满导致的

第24问

问:索引中有一个字符串型的字段,需要在kibana中这个字段求平均值并且展示出来,该怎么实现呢?

答:参考https://www.elastic.co/guide/en/kibana/current/scripted-fields.html, 使用script fields。

第25问

问: filebeat 7.x版本,在配置文件中定义了index名称,为什么写入到es中仍然生成的是filebeat-*之类的索引?

答: 通过配置setup.ilm.enabled: false解决。索引生命周期管理ilm功能默认开启,开启的情况下索引名称只能为filebeat-*, 通过setup.ilm.enabled: false进行关闭;如果要使用自定义的索引名称,同时又需要启用ilm,可以修改filebeat的模板。

第26问

问: 使用filebeat+es+kibana收集容器中的nginx日志,但是发现kibana中的message是一整段,字段都放在一起了,请问这个该怎么处理?

答: 两种解决办法:

  1. nginx日志配置为json格式, filebeat配置文件中指定解析json格式的日志json.keys_under_root: true
  2. 仍然使用默认的nginx日志格式,在es中自定义ingest pipeline解析每个字段,filebeat配置文件中指定使用定义好的pipeline

第27问

问: 请问ES的fielddata和docvalues有什么区别呢?

答: fielddata是在堆内存的,docvalues是在堆外内存的;docvalues默认对所有not_analyzed字段开启(index时生成),如果要对analyzed字段进行聚合,就要使用fielddata了(使用时把所有的数据全都加载进内存);如果不需要对analyzed字段进行聚合,就可以降低堆内存,Elasticsearch(更快的 GC)和 Lucene(更多的内存用于缓存)的性能越好

第28问

问:ES的ik-analyzer分词插件默认会把英文大写字母转换为小写,但是业务查询时是对大小写敏感的,怎么可以做到使用ik-analyzer分词插件的同时禁止把大写字母转换为小写?

答:基于ik_smart分词类型自定义analyzer, 同时配置参数 "enable_lowercase": false:

{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_ik": {
          "type": "ik_smart",
          "enable_lowercase": false
        }
      }
    }
  }
}

第29问

问:业务日志按文件大小滚动(最大100MB,滚动后压缩),使用filbeat收集日志时,发现在日志滚动较快的情况下filebeat没有释放掉已经被删除掉的日志文件,导致磁盘使用率较高,请问这个怎么解决?

答:可以通过配置close_timeout参数释放掉已经删除文件的文件句柄。

第30问

问:使用filebeat 5.6.4收集nginx日志文件(按天滚动,滚动后压缩),发现filebeat data目录下registry文件越来越大,并没有清理掉很早日志文件的state信息,请问这个怎么解决?

答:通过配置ignore_older和clean_inactive两个参数,清理掉registry中无用的文件state信息。

相关文章