Skip to content

Latest commit

 

History

History
187 lines (100 loc) · 15.5 KB

常见FAQ.md

File metadata and controls

187 lines (100 loc) · 15.5 KB

1.环境说明

详见LogiEM部署手册。

2.ES基础知识

2.1 集群

一个集群就是由一个或多个服务器节点组织在一起,共同持有整个的数据,并一起提供索引和搜索功能。一个 Elasticsearch 集群有一个唯一的名字标识,这个名字默认就是”elasticsearch”。这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群。

2.2 节点

集群中包含很多服务器,一个节点就是其中的一个服务器。作为集群的一部分,它存储数据,参与集群的索引和搜索功能。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点,并假定它们能够相互发现彼此,它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中。

2.3 分片

一个索引可以存储超出单个节点硬件限制的大量数据。比如,一个具有 10 亿文档数据的索引占据 1TB 的磁盘空间,而任一节点都可能没有这样大的磁盘空间。或者单个节点处理搜索请求,响应太慢。为了解决这个问题,Elasticsearch 提供了将索引划分成多份的能力,每一份就称之为分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。

2.4 副本

在一个网络 / 云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch 允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片(副本)。

2.5 一些常见概念

  • 索引(Index):相当于关系数据库中的 database 概念,一个集群中可以包含多个索引;
  • 类型(Type): 相当于数据库中的 table 概念,目前版本一索引对应一type,并且默认 type 名为“type”,后期用户不需要再关心 type 的概念;
  • 文档(Document):相当于数据库中的 row;
  • 字段(Field)相当于数据库中的 column;
  • 映射(Mapping):相当于数据库中的 schema,用来约束字段的类型,不过 Elasticsearch 的 mapping 可以自动根据数据创建。

2.6 ES的学习资料

2.7 ES集群健康状态

从数据完整性的角度划分,集群健康状态分为三种:

  • Green,所有的主分片和副分片都正常运行;
  • Yellow,所有的主分片都正常运行,但不是所有的副分片都正常运行。这意味着存在单点故障风险;
  • Red,有主分片没能正常运行。

每个索引也有上述三种状态,假设丢失了一个副分片,该分片所属的索引和整个集群变为 Yellow 状态,其他索引仍为 Green。

3.索引相关知识

3.1 appid应用级别限流和查询模板级别限流的是什么?

appid 应用级别限流是针对整个应用每秒最多能查询多少次,如果触发到appid应用级别限流,会接收到 FlowLimitException 错误。查询模板级别限流是针对相同结构的查询语句每秒最多能查询多少次,如果触发到查询模板级别限流,会接收到 DslRateLimitException 错误。

3.2 为什么多type方式被移除?

最初,我们谈到“索引”类似于SQL数据库中的“数据库”,“类型”等同于“表”。这是一个错误的类比,导致了错误的假设。在SQL数据库中,表是相互独立的。一个表中的列与另一个表中同名的列没有关系,相同列名的数据类型可以不同。在 Elasticsearch 索引中,在不同映射类型中具有相同名称的字段在内部由相同的 Lucene 字段支持。换句话说,相同字段名在不同type中必须具有相同的映射(定义)。除此之外,在同一索引中存储相同字段很少或没有字段的不同实体会导致数据稀疏,并干扰 Lucene 高效压缩文档的能力。不同 type 的数据存储在相同的 Lucene 文件中。

3.3 索引与分片的关系

一个 ES 索引包含很多分片,一个分片是一个 Lucene 的索引,它本身就是一个完整的搜索引擎,可以独立执行建立索引和搜索任务。Lucene 索引又由很多分段组成,每个分段都是一个倒排索引。ES 每次“refresh”都会生成一个新的分段,其中包含若干文档的数据。在每个分段内部,文档的不同字段被单独建立索引。每个字段的值由若干词(Term)组成,Term 是原文本内容经过分词器处理和语言处理后的最终结果(例如,去除标点符号和转换为词根)。

4.查询相关问题

4.1 DSL查询语法如何编写?

参考官网手册:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html

4.2 为什么不能查询排序在10000条以后的数据?

很多用户都有疑问,ES 为什么不能查询 10000 条之后的数据。了解这个问题需要了解到es的分布式原理。ES 一个索引是对应到多个shard(数据分片),对于带size的查询,es是在每个shard上都会返回size条数据,如果索引有 100 个 shard,那就是得先汇聚 100*size 条数据,然后再排序选出size条数据。所以分页太深,ES 汇聚的数据量太大,会导致 ES 节点不堪重负。如果用户想查看深分页的数据,有两种方式,一种是带上 where 条件,让10000条之后的数据能通过查询条件,在前面被查出来。另一种是针对获取大量数据的场景,使用 ES 的 scroll 方式,可以批量捞取全量的数据。不过官方不再建议使用scroll API进行深度分页。如果要分页检索超过 Top 10,000+ 结果时,推荐使用:PIT + search_after。

4.3 如何通过scroll方式获取全量的查询结果?

4.4 关于分页查询

4.4.1 主要有三种分页查询方式:

  • From + Size 查询:优点是支持随机翻页,受制于 max_result_window 设置,不能无限制翻页,存在深度翻页问题,越往后翻页越慢,深分页不推荐使用;
  • Search After 查询:查询本质是使用前一页中的一组排序值来检索匹配的下一页,并且不严格受制于 max_result_window,可以无限制往后翻页,但是不支持随机翻页;
  • Scroll 查询:相比于 From + Size 和 search_after 返回一页数据,Scroll API 可用于从单个搜索请求中检索大量结果(甚至所有结果),其方式与传统数据库中游标(cursor)类似,支持全量遍历,但是响应时间是非实时 ,并且保留上下文需要足够的堆内存空间。

4.4.2 分别的使用场景:

  • From + Size 查询:非常适合小型数据集或者大数据集返回 Top N(N <= 10000)结果集的业务场景,支持随机跳转分页的业务场景;

  • Search After 查询:不支持随机翻页,更适合手机端应用的场景(一直往下滑动刷新数据的场景);

  • Scroll 查询:全量或数据量很大时遍历结果数据,而非分页查询,并且对实时性要求不高的场景。关于具体的使用方式请见官方文档。

5.Mapping相关

5.1 mapping是什么?

  • mapping 是处理数据的方式和规则方面做一些限制,如:某个字段的数据类型、默认值、分析器、是否被索引等等。这些都是映射里面可以设置的,其它就是处理 ES 里面数据的一些使用规则设置也叫做映射,按着最优规则处理数据对性能提高很大,因此才需要建立映射,并且需要思考如何建立映射才能对性能更好。
  • 参考官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/2.3/mapping.html

5.2 数据已经接放ES,现在想增加一些新的字段 ,该怎么做?

对于上报数据将增加字段,ES 会动态判断该字段类型并建立索引,并且会按照该字段首次出现的类型来定义该字段。例如: 新增字段 {"name":"dididatabus"} es会判断为 string 类型。

5.3 时间字段起到什么作用?

时间字段主要用于时间分区的作用,为了防止索引膨胀,ES 会根据时间字段写入索引名称,分区主要有按天、按月两种,例如(indexname_2018-08-08、indexname_201808),默认情况下保存天数超过一个月会按月建立索引,其它时间会按天进行建立。

6.常用ES配置说明

6.1 elasticsearch.yml

  • cluster.name: elasticsearch,配置es的集群名称,默认是elasticsearch;
  • node.name: "node1",节点名;node.master: true,指定该节点是否有资格被选举成为node;
  • node.data: true,指定该节点是否存储索引数据;
  • path.data: /es/data,设置索引数据的存储路径,默认是es根目录下的data文件夹,可以设置多个存储路径,用逗号隔开,例:path.data: /path/to/data1,/path/to/data2;
  • path.logs: /path/to/logs,设置日志文件的存储路径,默认是es根目录下的logs文件夹;
  • path.plugins: /path/to/plugins,设置插件的存放路径,默认是es根目录下的plugins文件夹
  • network.host: 0.0.0.0,网段访问设置;
  • transport.tcp.port: 9300,设置节点间交互的tcp端口,默认是9300;
  • http.port: 9200,设置对外服务的http端口,默认为9200;
  • discovery.zen.minimum_master_nodes: 1,形成集群需要符合主节点的最小节点数;
  • discovery.zen.ping.unicast.hosts: ["host1:port", "host2:port"],设置集群中master节点的初始列表,可以通过这些节点来自动发现新加入集群的节点。

6.2 discovery.zen.minimum_master_nodes

符合主节点的节点都知道为了形成集群需要符合主节点的最小节点数。为了避免脑裂,它的值应该是半数以上(quorum):(master_eligible_nodes / 2) + 1。例如,如果有 3 个具备 Master 资格的节点,则这个值至少应该设置为(3/2)+ 1 = 2。

7.最佳实践

见LogiEM 最佳实践。

8. 术语问题

8.1 什么是动态更新索引?

  • 通过增加新的补充索引来反映新近的修改,而不是直接重写整个倒排索引。每一个倒排索引都会被轮流查询到,从最早的开始查询完后再对结果进行合并。当一个查询被触发,所有已知的段按顺序被查询。词项统计会对所有段的结果进行聚合,以保证每个词和每个文档的关联都被准确计算。 这种方式可以用相对较低的成本将新文档添加到索引。段是不可改变的,所以既不能从把文档从旧的段中移除,也不能修改旧的段来进行反映文档的更新。 取而代之的是,每个提交点会包含一个 .del 文件,文件中会列出这些被删除文档的段信息。
  • 当一个文档被 “删除” 时,它实际上只是在 .del 文件中被标记删除(�逻辑删除)。一个被标记删除的文档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。文档更新也是类似的操作方式:当一个文档被更新时,旧版本文档被标记删除,文档的新版本被索引到一个新的段中。可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就已经被移除。

8.2 什么是近实时搜索?

在 Elasticsearch 中,写入和打开一个新段的轻量的过程叫做 refresh。 默认情况下每个分片会每秒自动刷新一次。这就是为什么我们说 Elasticsearch 是近实时搜索:文档的变化并不是立即对搜索可见,但会在一秒之内变为可见。这些行为可能会对新用户造成困惑:他们索引了一个文档然后尝试搜索它,但却没有搜到。 这个问题的解决办法是用 refresh API 执行一次手动刷新: /users/_refresh。

8.3 什么是持久化变更?

如果没有用 fsync 把数据从文件系统缓存刷(flush)到硬盘,我们不能保证数据在断电甚至是程序正常退出之后依然存在。为了保证 Elasticsearch 的可靠性,需要确保数据变化被持久化到磁盘。在动态更新索引,我们说一次完整的提交会将段刷到磁盘,并写入一个包含所有段列表的提交点。Elasticsearch 在启动或重新打开一个索引的过程中使用这个提交点来判断哪些段隶属于当前分片。即使通过每秒刷新(refresh)实现了近实时搜索,仍然需要经常进行完整提交来确保能从失败中恢复。但在两次提交之间发生变化的文档怎么办?如果不希望丢失掉这些数据。Elasticsearch 增加了一个 translog ,或者叫事务日志,在每一次对 Elasticsearch 进行操作时均进行了日志记录。translog 提供所有还没有被刷到磁盘的操作的一个持久化纪录。当 Elasticsearch 启动的时候, 它会从磁盘中使用最后一个提交点去恢复已知的段,并且会重放 translog 中所有在最后一次提交后发生的变更操作。

8.4 什么是段合并?

由于自动刷新流程每秒会创建一个新的段,这样会导致短时间内的段数量暴增。而段数目太多会带来较大的麻烦。 每一个段都会消耗文件句柄、内存和 cpu 运行周期。更重要的是,每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢。 Elasticsearch 通过在后台进行段合并来解决这个问题。小的段被合并到大的段,然后这些大的段再被合并到更大的段。 段合并的时候会将那些旧的已删除文档从文件系统中清除。被删除的文档(或被更新文档的旧版本)不会被拷贝到新的大段中。

9.其他问题

9.1 可能的触发old gc的情况

  • 6.x堆内存设置大小问题,和常驻的segment内存的相比,是否内存太小了;
  • 可能是聚合查询导致,可以看慢查日志,以及用 _tasks?nodes=xxx?detailed 分析下指定节点进行中的查询耗时长的任务;
  • 可能是大量 put mapping 导致,这个可以看底层引擎日志是否有大量这种操作,一般出现是bulk写入中含有动态的字段;client gc,写入字段解析异常,看引擎测日志是否有大量这种报错;
  • 检查下写入和查询是否突增;
  • 最后通用的方式,dump 堆内存进行内存分析,看哪块内存比较大。

9.2 索引分片未分配

可以用_cluster/allocation/explain 看下具体未分配原因。

9.3 cpu负载高

一般cpu负载高,很可能是查询的流量上来导致的,可以结合es的 hot/thread 以及 jstack 分析具体线程。

9.4 节点掉线问题

  • 是否是网络的问题;
  • 查看这个节点的指标(cpu load等),是不是gc导致的,这个概率较大;
  • 是否有大量的请求导致 netty 连接池满了,可以用 jstack 分析下,看看那些 nettyworker 是否都在执行某些任务。