基本概念

节点

节点: 节点就是一个ES的实例,本质上是一个java进程

每个节点都有名字,通过配置文件配置或者启动命令 -E node.name=xx指定; 每个节点在启动后,都会分配一个UID,保存在data目录下

Coordinating Node

也就是协调节点,是指处理请求的节点

  • 负责路由请求到正确的节点,例如创建索引的请求,需要路由到Master节点(创建删除)
  • 所有节点默认都是 Coordinating Node

Data Node

  • 可以保存数据的节点,启动默认就是数据节点,可以设置 node.data: false禁用
  • 由Master Node 决定如何把分片分发到数据节点上
  • 通过增加数据节点解决数据水平扩展和解决数据单点问题

    Master Node

  • 处理创建、删除索引 等请求,决定分片被分配到哪个节点

  • 维护并更新 Cluster State

Master Eligible Node 及选主流程

  • Master Eligible Node是指 master的候选节点,这些节点在master故障时会参与选主流程。
  • 每个节点启动后,默认就是Master Eligible Node,可以禁用:node.master: false
  • 当集群内第一个Master Eligible Node启动,它会将自己选举成Mster节点

    互相 Ping 对⽅,Node Id 低的会成为被选举的节点; 其他节点会加⼊集群,但是不承担 Master 节点的⻆⾊。⼀旦发现被选中的主节点丢失, 就会选举出新的 Master 节点

如何避免脑裂
限定选举条件,设置仲裁 quorum,只有当master eligible 节点数> quorum,才能进行选举
quorum=(节点总数/2)+1

分片

主分片、副本分片,是ES分布式存储的基石

主分片 Primary Shard

通过主分片,将数据分布在所有节点(data node)上, 主分片数在索引创建时指定,后续默认不能修改,如果修改需要重建索引。

副本分片 Replica Shard

提高数据的可用性,通过引⼊副本分片 (Replica Shard) 提⾼数据的可⽤性。⼀旦主分⽚丢失,副本分⽚可以 Promote 成主分片。副本分片数可以动态调整。每个节点上都有完备的数据。如果不设置副本分⽚,⼀旦出现节点硬件故 障,就有可能造成数据丢失。
副本分⽚由主分⽚(Primary Shard)同步。通过⽀持增加 Replica 个数,⼀定程度可以提⾼读取的吞吐量。
3个节点,3个分片,2个副本,保证每个节点的数据是全的
ES分片.png
文档到分片的路由算法
shard = hash(_routing) % number_of_primary_shards

默认的 _routing 值是⽂档 id

分片的内部原理

  • 在Lucene中单个倒排索引文件被称为 Segment。Segment 是自包含的,不可变更的。 多个 Segments 汇总在一起,称为 Lucene 的 Index,其对应的就是 ES 中的 Shard
  • 当有新⽂档写⼊时,会⽣成新 Segment,查询时会同时查询所有 Segments,并且对结果汇总。Lucene 中有⼀个⽂件,⽤来记录所有Segments 信息,叫做 Commit Point
  • 删除的⽂档信息,保存在“.del”⽂件中

ES分片内部原理.png

什么是refresh

  • 将 Index buffer 写⼊ Segment 的过程叫Refresh。Refresh 不执⾏ fsync 操作
  • Refresh 频率:默认 1 秒发⽣⼀次,可通过index.refresh_interval 配置。Refresh 后,数据就可以被搜索到了。这也是为什么Elasticsearch 被称为近实时搜索
  • 如果系统有⼤量的数据写⼊,那就会产⽣很多的 Segment
  • Index Buffer 被占满时,会触发 Refresh,默认值是 JVM 的 10%

ES refresh.png

什么是Transaction Log

  • Segment 写⼊磁盘的过程相对耗时,借助⽂件系统缓存,Refresh 时,先将Segment 写⼊缓存以开放查询
  • 为了保证数据不会丢失。所以在 Index ⽂档时,同时写 Transaction Log,⾼版本开始,Transaction Log 默认落盘。每个分⽚有⼀个 Transaction Log
  • 在 ES Refresh 时,Index Buffer 被清空,Transaction log 不会清空

ES transactionLog.png

什么是flush

  • 调⽤ Refresh,Index Buffer 清空并且 Refresh
  • 调⽤ fsync,将缓存中的 Segments写⼊磁盘
  • 清空(删除)Transaction Log
  • 默认 30 分钟调⽤⼀次
  • Transaction Log 满 (默认 512 MB)

    Merge

    Segment 很多,需要被定期被合并
    ES 和 Lucene 会⾃动进⾏ Merge 操作

查询原理

ES搜索分两阶段

  1. QUERY
  2. FETCH

    QUERY

  3. ⽤户发出搜索请求到 ES 节点。节点收到请求后, 会以 Coordinating 节点的身份,在 6 个主副分⽚中随机选择 3 个分⽚,发送查询请求

  4. 被选中的分⽚执⾏查询,进⾏排序。然后,每个分⽚都会返回 From + Size 个排序后的⽂档 Id 和排序值 给 Coordinating 节点

    FETCH

  5. Coordinating Node 会将 Query 阶段,从从每个分⽚获取的排序后的⽂档 Id 列表,重新进⾏排序。选取 From 到 From + Size个⽂档的 Id

  6. 以 multi get 请求的⽅式,到相应的分⽚获取详细的⽂档数据

    Query Then Fetch潜在问题

  7. 性能问题

    每个分⽚上需要查的⽂档个数 = from + size; 最终协调节点需要处理:number_of_shard * ( from+size ) 深度分⻚

  8. 相关性算分

每个分⽚都基于⾃⼰的分⽚上的数据进⾏相关度计算。这会导致打分偏离的情况,特别是数据量很少时。相关性算分在分⽚之间是相互独⽴。当⽂档总数很少的情况下,如果主分⽚⼤于 1,主分⽚数越多 ,相关性算分会越不准

解决办法:1.主分片设置为1,数据量大不适用;

  1. 使用DFS Query Then Fetch,把每个分片的词频文档进行搜集,然后进行完整算分,耗费CPU和内存。性能也低

深度分页问题

Search After避免深度分页

  • 不指定页数
  • 只能往下翻