ElasticSearch简介

文章目录

    • 介绍
    • 概念
    • 3C
    • 脑裂
    • 写入索引流程
    • 查询索引流程

介绍

ElasticSearch是目前非常流行的分布式全文搜索引擎,通过它可以快速的存储、搜索和分析海量数据。ElasticSearch底层使用Lucence,Lucence是一个非常受欢迎的开源java信息检索引擎,提供了完整的查询和存储引擎,ElasticSearch基于Lucene进行封装,提供大数据量、高并发的准实时搜索场景

概念

ElasticSearch核心概念如下

  • Index:索引,类比于关系型数据库的一个库(database),由一个或者多个分片组成
  • Type:类别,类比于关系型数据库的一张表(table),ElasticSearch6.0以上的版本,不支持在同一个Index中拥有不同的Type,也就是一个Index只能包含一个Type,并且在7.0版本以后将废弃Type的API,在8.0完全移除Type
    ElasticSearch简介_第1张图片
  • Document:文档,类比于关系型数据库中的一条数据,索引中的每一条数据叫作一个文档,通过_id在Type内唯一标识
  • Cluster:集群,由一个或者多个ElasticSearch节点构成
  • Node :节点,组成ElasticSearch的一个单元,集群内节点名字不能重复,一个节点可以包含多个分片(Shards)
  • Shards:分片,当索引上数据量太大的时候,通常会将一个索引上的数据进行水平拆分,查分出来的每个数据块叫一个分片,在创建索引是需要制定分片数量,一旦创建将不能更改(因为ElasticSearch是通过hash值 % 分片数来确定数据所在分片,一旦更改分片数,将导致查询不到数据),每个分片必须具有一个主分片和零到多个副分片
  • Replicas:备份也叫作副本,指对主分片的备份,主分片和副分片都可以提供查询服务,写操作先在主分片上完成,然后分发到备份上。当主分片不可用时,会在备分片中选举一个作为主分片,备份可以提升系统的高可用性和查询性能,但如果数量过多,也会导致写操作的数据同步时间
  • Settings:对索引进行配置,如设置索引的分片数,副本数等
  • Mapping:类似于关系型数据库中的表结构信息,用于定义字段类型、分词方式等。ElasticSearch的mapping是可以自动映射的,没有特殊要求,可不用手动创建,若mapping已经创建并且索引中有数据将不可修改
  • Analyzer:字段的分词方式
    ElasticSearch的节点分类
  • 主节点(Master Node):主节点负责创建索引、删除索引、分配分片、追踪集群中的节点状态等工作
  • 数据节点(Data Node):负责数据的存储和数据的创建、修改、删除、搜索、聚合等操作,通过配置node.data=true来设置该节点为数据节点
  • 客户端节点(Client Node):既不做主节点也不做数据节点,只负责请求的分发、汇总,单独增加这样的节点是为了提高并发性
  • 部落节点(Tribe Node):部落节点可以跨越多个集群,可以接受每个集群的转态,然后合并为一个全局的集群状态,可以读写每个集群的数据
  • 协调节点(Coordinating Node):是一种角色,而不是真实的节点,集群中任意节点都可以充当协调节点的的角色,当一个节点A接受到请求,然后将请求分发到其他的节点,合并各个节点返回的结果,最后返回给客户端,这个过程中节点A就充当了协调节点的角色

3C

  • 共识性(Consensus):共识性是分布式系统中最基础也是最主要的的一个组件,在分布式系统中的所有节点必须对给定的数据或者节点的状态达成共识。目前有成熟的共识算法Raft、Paxos等,也有成熟的开源软件zookeeper,但是ElasticSearch并没有使用它们,而是自己实现的共识系统zen discovery
  • 并发(Concurrency):ElasticSearch是一个分布式系统。写请求在发送到主分片是,同时也会以并行的形式发送到备分片,但是这些请求送达的时间可能是无序的,ElasticSearch使用乐观锁(Optimistic Concurrency Control)并发控制来保证新版本的数据不会被老版本的数据覆盖。
    乐观并发控制是一种乐观锁,另外一种常用的乐观锁即多版本并发控制(Mutil-Version Concurrency Control),主要区别如下:
    乐观并发控制(OCC):是一种用来解决写-写冲突的无锁并发控制,认为事物间的竞争不激烈是,就先进行修改,在提交事务前检查数据有没有变化,如果没有就提交,如果有就放弃并重试,乐观并发控制类似于自旋锁,适用于竞争不激烈冲突较少的场景
    多版本并发控制:是一种用来解决读写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。这样在读操作不用阻塞写操作且写操作不用阻塞读操作的同时,避免了赃读和不可重复读。
  • 一致性(Consistency):ElasticSearch集群保证写入一致性的方式是在写入之前先检查有多少个分片可供写入,如果达到了写入条件,则进行写操作,否则,ElasticSearch会等待更多的分片出现,默认一分钟。
    有如下三种设置来判断是否允许写操作:
    One:只要主分片可用,就可以进行写操作。
    All:只有当主分片和所有副分片都可用时,才允许写操作。
    Quorum:是ElasticSearch的默认选项,当有半数以上分片可用时,才允许写操作

脑裂

在ElasticSearch集群中主节点通过ping命令来检查集群中的其他节点是否处于可用状态,同时非主节点通过ping命令来检查主节点是否可用。当集群中网络不稳定时,有可能出现一个节点ping不同Master节点,则会认为Master节点已经发生了故障,然后重新选举一个Master节点,导致一个集群中出现多个Master节点,这种现象称为脑裂

写入索引流程

ElasticSearch写索引具体过程如下
  首先,当有数据写入时,为了提升写入速度,并没有把数据直接写在磁盘上,而是先写入到内存中,但是如果数据在内存中还没有持久化到磁盘上发生断电等不可控故障,就可能丢失数据,为了避免丢失数据,会追加一份数据写入到事物(Translog)日志里,在内存中的数据是检索不到的,ElasticSearch具备延迟写的特征,所以是一个准实时的搜索引擎,而不是实时的。
  然后,当达到一定条件时(比如时间到达刷新的阈值或者内存使用到达一定量时),会触发一次刷新(Refresh),主要步骤如下
(1)将内存中的数据刷新到一个新的段中,但是该段并没有持久化到硬盘中,而是缓存在操作系统的文件缓存系统中,但是内存中的数据和文件缓存系统里的数据有以下区别:

  • 内存使用的是JVM内存,而文件缓存系统使用的操作系统的内存。
  • 内存的数据不是以段的形式存储的,并且可以持续向内存中写数据,而文件缓存系统中的数据是以段的形式存储的,只能读,不能写
  • 内存中的数据是搜索不到的,文件缓存系统中的数据是可以搜索的

(2)打开保存在文件缓存系统中的段,使其可被搜索。
(3)清空内存,准备接收新的数据,日志不做清空处理
  最后,刷新(Flush),当日志数据大小超过512M或者时间超过30是分钟时,需要触发一次刷新。主要步骤为
(1)在文件缓存系统中创建一个新的段,并将内存中的数据写入,使其可被搜索。
(2)清空内存,准备接收新的数据。
(3)将文件缓存系统中的数据刷新到硬盘中
(4)删除旧的日志,创建一个空的日志
  由上面的流程可知,内存中的数据并没有直接被持久化到硬盘,而是先到了文件缓存系统,因为持久化到硬盘十分耗费资源,频繁的调用会使写入性能急剧下降,所以ElasticSearch充分利用内存和文件缓存系统来提高写入性能,并使用日志在防止数据丢失。
  重启ElasticSearch时,不仅要加载已经持久化的数据,还需要根据事务日志的记录,将未持久化的数据重新持久化到磁盘上
假设一个集群由三个节点构成Node1、Node2、Node3,包含两个主分片和每个主分片有两个副分片的索引,Node1为Master节点,负责管理集群的状态,p0和p1是主分片,其余为副分片,如图所示
ElasticSearch简介_第2张图片
  将数据分片是为了减小数据的容量和易于水平扩展,副本分片是为了提高集群的高可用以及提高并发量,在主分片挂掉后,会从副本中选举一个升级为主分片,集群状态也会从green变为yellow,但集群任然可用,由此可知副分片越多,集群的可用性就越高,但是每个分片都会占用一定的文件句柄,内存以及CPU,并且分片数也多,写数据同步时间就越长,所以在设置副分片时可以根据实际需要来进行权衡。
  写索引时只能在主分片上完成,然后同步到副本上,那么,一条数据应该写入到那个分片上,则根据路由计算得知

                                 shard = hash(routing) % 分片数

routing是一个可选择的值,默认为文档的_id(文档的唯一主键),这也是索引一旦创建后不能更改分片数的原因,因为改变了分片数,之前的数据都将检索不到

  由于ElasticSearch集群中每个节点都知道集群中的文档存放位置,所以每个节点都有处理读写请求的能力,一个协调节点接收到写请求后,根据路由公式计算出具体写那个分片,然后将请求转发到该主分片所在节点上进行处理,流程如下
(1)客户端向Node1(协调节点)发送写请求
(2)Node1通过文档的_id(默认是_id,可以指定其他值)确定文档属于哪个分片(比如分片0),请求将转发到该主分片所在节点Node3上
(3)Node3在主分片上执行请求,如果成功,则将请求并行转发到Node1和Node2的副分片上。一旦所有副分片都执行成功,则Node3将协调及节点Node1返回成功结果,协调节点然后向客户端返回成功
ElasticSearch简介_第3张图片

查询索引流程

  根据routing字段进行的单个文档的查询,在ElasticSearch集群上可以在主分片或者副分片上完成,查询字段刚好是routing的分片字段如 _id 的查询流程如下。
(1)客户端向集群发送查询请求,集群在随机选择一个节点作为协调节点(Node1),负责处理这次查询任务
(2)Node1使用文档的routing id来计算要查询的文档在哪个分片上,比如在0分片上,分片0在三个节点都存在,这种情况下,协调节点将请求转到任意节点,比如这次转发到Node2上
(3)Node2执行查询,并将查询结果返回给协调节点Node1,Node1在将文档返回给客户端。
ElasticSearch简介_第4张图片
  如果是普通查询,则查询前不知道在哪个分片上,这就需要查询所有的分片,然后汇总数据,把满足条件的数据返回给客户端,这种查询相比routing id查询要复杂很多,性能也会差很多,详细流程如下
(1)客户端发送一个查询请求到任意节点(如Node3)
(2)Node3将查询请求转发到索引的每个主分片或副分片上,每个分片执行查询并将结果添加到返回队列中
(3)默认情况将每个分片将返回所有的文档id和score(查询相关度)给协调节点,协调节点将合并这些值并生成一个全局排序的结果列表。
(4)Node3进行二次排序后找出需要返回的文档id,并向相关的分片请求数据。
(5)相关分片返回数据给Node3,然后Node3进行数据汇总。
(6)将汇总的数据返回给客户端
普通查询过程主要分为两个步骤

  • 第一次查询满足要求的id和score
  • 第二次根据具体条件来筛选出的id来查询所有的返回给客户端的数据

在指定查询条件中{“from”:20,“size”:10},from相当于关系型数据库中offset,size相当于limit ,当from很大时查询叫做深翻(Deep Pagination),这时候第一次查询会检索出大量的无用数据,导致占用大量的cpu,内存和带宽资源,所以尽量避免使用深翻

你可能感兴趣的:(ElasticSearch)