ElasticSearch 入门学习

1.基本概念

1.1 基本概念和原理

ES是实时的分布式搜索分析引擎,内部用Lucene做索引与搜索。

1.1.2 分片(shard)

分片:为了水平扩容,将数据分成不通小块到不通机器上。

副本:复制多个副本,放不通机器,增加系统可用性。并发读,分担集群压力。

主分片(primary shard)和副分片(replica shard):为了应对并发更新问题,将副本分为主从2部分。

写过程先写主分片,成功后再写副分片,恢复阶段以主分片为准。

 

关系:

一个ES索引包含很多分片,一个分片是一个Lucene的索引,它本身是一个完整的搜索引擎,可以独立的执行建立索引和搜索任务。

Lucene索引又有很多分段组成,每个分段都是一个倒排索引。Es每次refresh(用户缓存写入os缓存)都会生成一个新的分段(segment)

1.1.3 动态更新索引

倒排索引被写入文件之后就不再改变

好处:对文件的访问不需要加锁,读取索引可以被文件系统缓存。

更新

新增内容写入到一个新的倒排索引中,查询的时候每个倒排索引都被轮流查询,查询完在对结果进行合并。

也就是每次内存缓冲被写入文件,都会产生一个新的Lucene段,每个段都是一个倒排索引。

更新删除等操作实际上是将数据标记为删除,记录到单独的位置,因此删除部分数据不会释放磁盘空间。

1.1.4 近实时搜索

写操作:

现在内存中缓冲一段数据,再将这些数据写入磁盘,每次写入磁盘的这批数据被称为一个分段。

es每秒产生一个新分段,新分端先写入文件系统缓冲,但稍后再刷入磁盘。写入系统缓冲,就可以被读取了。很快。

translog事务日志:

由于刷磁盘不会立即执行,所以为了防止以外,丢失数据,ES进行操作都会记录事务日志。启动的时候,重放translog中所有最后一次提交后发生的变更操作。

1.1.5 段合并

refresh:

Es中,每秒清空一次写缓冲,将数据写入系统缓冲,这个过程叫做refresh,每次refresh都会创建一个新的Lucene段。

分段太多:会消耗文件句柄和内存,还需要遍历每个分段合并结果,分段越多搜索也就越慢,

合并

通常选择大小相似的分端合并。合并去除标记删除的数据,合并结束后,删除旧分端。这个时候标记删除的数据才从磁盘删除。

es的refresh调用Lucene的flush, flush调用Lucene的commit

refresh写入系统缓存,flush写入磁盘。

1.2 集群内部原理

1.2.1 集群节点角色

  1. 主节点(Master node)

    负责集群层面的相关操作,管理集群变更。 配置:node.master

  2. 数据节点(Data node)

    负责保存数据,执行数据相关操作:CRUD、搜索、聚合等。 配置:node.data:true 成为数据节点

  3. 预处理节点(Ingest node)

    重5.0引入的概念。预处理操作在索引文档前,即写入数据前,通过一系列的处理器和管道,对数据进行转换、富化。

  4. 协调节点(Coordinating node)

    客户端请求协调节点,协调节点将请求转发到数据及节点进行处理,然后返回结果给协调节点。协调节点处理合并数据返回给客户端。

  5. 部落及诶单(Tribe node )

    针对多个集群的搜索,可以充当联合客户端。

1.2.2 集群健康状态

  1. green 所有主分片和副分片都正常运行

  2. Yellow 主分片正常,但不是所有副分片都正常,也就是存在单点故障

  3. Red 有主分片没能正常运行。

每个索引也有这三种状态。如:丢了一个副分片,该分片所属的索引和整个集群变为Yellow,其他索引为Green。

1.3 主要内部模块

  1. Cluster

    Cluster模块是主节点执行集群管理的封装实现,管理集群状态,维护集群层面的配置信息。

    1. 管理集群窗台

    2. 调用allocation模块执行分片分配。

    3. 在集群各节点中直接迁移分片,保持数据平衡。

  2. allocation

    分装了分片分配相关的功能和策略,包括主分片的分配和副分片的分配,本模块由主节点调用。创建索引、集群完全重启都需要分片分配的过程。

  3. Discovery

    发现模块负责发现集群中的节点,以及选举主主节点。当节点加入或者退出集群时,主节点会采取相应的行动。

  4. gateway

    负责对收到Master广播下来的集群状态(cluster state)数据的持久化存储,并在集群完全重启时恢复他们。

  5. Indices

    索引模块管理全局级的索引设置,不包括索引级(索引设置分为全局级和每个索引级)。它还分装了索引数据回复功能。集群重启阶段需要的主分片恢复和副分片恢复就是这个模块实现的。

  6. HTTP

    http模块允许通过JSON over HTTP的方式访问ES的API,HTTP模块本质上是完全异步的,这意味着没有阻塞线程等待响应。异步同行解决C10K问题(10k量级的并发连接)。

  7. Transport

    传输模块用于集群内节点之间的内部通信。从一个节点到另一个节点的每个请求都使用传输模块。完全异步。使用tcp通信,

  8. Engine

    engine模块封装了对Lucene的操作以及translog的调用,他是对一个分片读写操作的最终提供者。

2 集群启动流程

 

选主-》发布元信息-》分片分配-》恢复

2.1 选举主节点

若干节点正在启动,第一件事就是从已知的活跃机器列表中选择一个作为主节点。

ES选主算法基于Bully算法改进,Bully主要思路是对节点Id进行排序,取Id最大的座位Master。

ES有三个约定条件:

  1. 参选人数过半,就选出临时的主节点。

    节点可能因为网络分区或者启动速度的原因,导致差异。比如5台。节点1:{1,2,3,4} =》4,

    节点2:{2、3、4、5}=》5。

  2. 得票数需要过半。

    某节点被选为主节点,必须判断加入它的节点过半,才能确认Master身份,解决第一个问题。

  3. 探测到节点离开,重新判断

    如果节点离开后,判断当前节点数是否过半,如果达不到quorum的话放弃Master身份,重新加入集群。比如:五台机器。2台一组,3台一组,Master位于2台中的一个,分区后,3台一组会重新选出Master。2台的探测到节点离开,需要放弃master身份,否则脑列。

集群并不知道自己有多少节点,quorum值从配置中读取,我们需要设置配置项discovery.zen.minumum_master_nodes

2.2 选举集群元信息

选举出的Master和集群元信息的新旧程度没有关系。因此第一个任务是选举元信息。让各个节点把各自存储的元信息发过来,根据版本号确定新的元信息,然后把这个信息广播下去。

选举包括2个级别:集群级和索引级。

为了集群的一致性,参与选举的元信息数量要过半。

在选举过程中,不接受新节点的加入请求。

集群元信息选举完毕后,Master发布首次集群状态,然后开始选举shard级元信息。

2.3 allocation 过程

选举shard级元信息,构建内存路由表,是在allocation模块完成的。在初始阶段,所有shard都处于UNASSIGNED(未分配)状态。通过该过程决定哪个分片位于哪个节点,重构内容路由表。

  1. 选主分片

    Master向所有的主分片询问,大家把website分片的元信息发给我。Master等待所有请求返回,然后根据某种策略选一个作为主分片。这种询问=shard数x节点数。所以shard的总规模别太大。一个索引可以分为多个shard,一个shard可以有多个主分片,多个副分片。

    ES5.x以后,会给每个shard设置一个UUID,然后在集群级元信息中记录那个shard最新。所以如果集群元信息最新列表中存在,并且在汇报信息也存在,那么就可以确定。

  2. 选举副分片

    从汇总的shard信息中选择一个副本或者重新分配一个全新的副本。

allocation过程允许新节点加入。

2.4 index recovery

主分片的recovery不会等其他副分片成功才开始recovery。副分片需要等主分片恢复完毕才开始。

原因:主:可能有些数据还没来得及刷盘。 副:与主分片数据不一致。

  1. 主分片 recovery

    通过translog事务日志。将最后一次提交(Lucene的一次提交就是一次刷盘过程)之后的translog重放,建立Lucene索引。

  2. 副分片 recovery

    恢复期间允许新的索引操作。

    1. 第一阶段:

      主分片shard做快照,发给副本节点。在第一阶段结束前告诉副分片启动engine,开始处理正常请求。

    2. 第二阶段

      对translog做快照,这个快照包含从第一阶段开始到执行translog快照期间的新增索引。

3.写流程

ES写入单个文档被称为Index请求,批量写入被称为Bulk请求。使用相同的处理逻辑,请求被统一分装为BulkRequest。

在ES中,对文档的操作有下面几种类型:

  1. INDEX

    向索引put一个文档的操作被称为索引一个文档。

  2. CREATE

    put请求可以通过op_type参数设置操作类型为create,在这种情况下,如果文档存在,则请求失败。

  3. UPDATE

    默认情况,put一个文档时,如果文档存在,则更新它。

  4. DELETE

    在putAPI中,通过op_type参数指定操作类型。

3.1 Index/Bulk 基本流程

  1. 客户端向协调节点发送写请求。

  2. 协调节点使用文档ID来确定文档所属分片,通过集群状态中的内容路由表信息获知分片的主分片位于的节点。将请求转发到该节点。

  3. 主分片所在的节点执行写操作。写入成功后,将请求转发到副分片所在的节点上,等待返回结果。当所有副分片都报告成功。主分片所在的节点向协调节点报告成功。

  4. 协调节点给客户端返回成功。

3.1.2 创建索引

如果是创建索引,协调节点会把请求发送到Master,

3.1.3路由算法

shard_num = hash(_routing) % num_primary_shards

默认情况下, _routing值就是文档id。

3.1.4 主分片节点流程

  1. 检查请求

  2. 写Lucene和事务日志

    先写Lucene,后写translog。

  3. flush translog

    刷盘translog

  4. 写副分片

  5. 处理副分片写失败情况

    写失败向Master发送请求,Master更新集群状态,这个shard将会:

    1. 从in_sync_allocation列表中删除

    2. 在路由表的shard列表中将状态置位UNASSIGNED

    3. 添加到routingNodes的unssignedShards列表。

3. GET流程

ES 的读取被分为GET和Search两种操作。

get必须指定 _index _type _id 。 search根据关键字搜索。

3.1 get基本流程

搜索和读取文档都属于读操作,可以从主分片或者副分片中读取数据。

读取单个文档的流程:

  1. 客户端想协调节点发送请求。

  2. 协调节点根据文档id,来确定文档所属的分片。通过集群状态中的内容路由表信息获取分片的副本(主分片+副分片)所在的节点,将请求发送到任意一个节点。

  3. 副本分片所在的节点将文档返回给协调节点,协调节点返回给客户端。

写入返回成功,意味着主副分片都是可用的。 读取可能打到主或者副,如果副分片还没有同步数据,有可能返回不存在。

4. search 流程

由于不知道文档位于哪个分片,因此索引的所有分片都要参与搜索,然后协调节点将结果合并,在根据文档ID获取文档内容。

有2中搜索类型:

  1. DFS_QUERY_THEN_FETCH

  2. QUERY_THEN_FETCH(默认)

4.1 Query阶段

查询可以指定参数{from:90, size:10},表示从第91个开始的10个结果,用来确定优先队列的大小。

  1. 客户端发送请求到协调节点

  2. 协调节点将查询请求转发到索引的每个分片的其中一个副本。

  3. 每个分片在本地执行查询,并将信息进行打分,然后添加结果到本地的有序优先队列中。

  4. 每个分片返回各自优先队列中所有文档的ID和排序值给协调节点,协调节点合并这些值到自己的优先队列中,产生一个全局排序后的列表。

结果:协调节点根据关键字,维护了一个文档id和排序值的列表。

4.2 Fetch 阶段

  1. 协调节点根据文档id,得知所属分片,然后根据集群信息中的内容路由表信息获取分片的副本信息。然后将请求发送到任意一个节点。

  2. 副本分片所在的节点向协调节点返回数据。

  3. 协调节点等待所有文档被获取,然后返回给客户端。

5、写入速度优化

  1. 加大translog flush间隔,目的是较低iops(每秒读写次数), writeblock

  2. 加大index refresh间隔,除了降低I/O,更重要的是降低了segment merge评率

  3. 调整bulk请求

  4. 优化磁盘的任务均匀情况,将shard尽量均匀分布到物理主机的各个磁盘

  5. 优化节点间的任务分布,将任务尽量均匀的发到各个节点。

  6. 优化Lucene层简建立索引的过程,目的是降低CPU占用率及I/O。列如:禁用_all字段。

    1. 自动生成文档id

    2. 调整mappings字段,去除不用的字段、设置不需要分词的,用不通的分词器

  7. 减少副本,可以先设置为0,启动后再增加。

5.1 translog flush间隔调整

默认的设置:每个请求都会flush translog。只有这样,写操作才是可靠的。

index.translog.durability:async 可以将策略改成异步,index.translog.sync_interval:120s 按照这个时间周期进行。

index.translog.flush_threshold_size:1025mb : 重启时回放translog,超过这个大小会导致refresh操作,产生新的分段默认为512MB。

5.2 索引刷新间隔

默认情况下刷新建个为1s,每次刷新都会产生一个新的Lucene 的segment。

增大刷新间隔。index.refresh_interval:120s

5.3 段合并优化

merge由Lucene控制,对I/O和内存占用比较高。

//线程数
//默认 Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors()/2))
//也就是如果有效进程数的一版大于4,就是4个。
index.merge.scheduler.max_therad_count
//策略
index.merge.policy.*

如果只有一块硬盘,非SSD,最好把线程设为1,因为寻址的原因,会降低写入速度。

5.4 indexing buffer

indexing buffer是在为doc建立索引时使用,当缓冲满会刷入磁盘,生成一个新的segment。每个分片上都有自己的indexing buffer.

indices.memory.index_buffer_size:所有总的大小,分片上的大小需要除以分片数,默认为整个堆空间的10%。

5.5 使用bulk

使用批量请求写数据。但是不要太大,最好不要超过几十M。

5.6 磁盘间的任务均衡

如果有多块磁盘,ES分配shard时,可能会不均匀。

  1. 简单磁盘轮询

  2. 基于剩余空间的动态加权轮询。

5.7 索引阶段

1.自动生成文档id

手写会去查询是否存在,存在则更新。自动生成,不需要查询。

2.调整字段mappings,去除不需要的,设置不需要分词的,选择不通的分词器。

6、搜索速度优化

6.1 选择好的硬盘

6.2 预留足够的内存

6.3 合并分段

为不再更新的只读数据,合并为一个分段,提升查询速度。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七号公园的忧伤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值