ES

2024-06-26  本文已影响0人  cc_daily

1. 百科概述

Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能很方便的使大量数据具有搜索、分析和探索的能力。充分利用Elasticsearch的水平伸缩性,能使数据在生产环境变得更有价值。Elasticsearch 的实现原理主要分为以下几个步骤,首先用户将数据提交到Elasticsearch 数据库中,再通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据,当用户搜索数据时候,再根据权重将结果排名,打分,再将返回结果呈现给用户。

Elasticsearch是与名为Logstash的数据收集和日志解析引擎以及名为Kibana的分析和可视化平台一起开发的。这三个产品被设计成一个集成解决方案,称为“Elastic Stack”(以前称为“ELK stack”)。

2. 概念

2.1. 节点(Node)

代表节点,是组成 Elasticsearch 集群的基本服务单元,集群中的每个运行中的Elasticsearch 服务器都可称之为节点。 作为集群的一部分,它存储你的数据,参与集群的索引和搜索功能。

2.1.1. 节点种类

数据节点:包含已创建的索引文档的分片。数据节点处理数据相关的操作。例如CRUD,搜索和聚合等。

主节点:负责集群范围内轻量级的操作,例如创建或删除索引。跟踪哪些节点是集群的一部分以及确定将哪些碎片分配给哪些节点

调节节点:仅可路由请求,处理搜索缩减阶段并分配批量索引。本质上,仅协调节点充当智能负载平衡器

2.2. 集群(Cluster)

Elasticsearch 的集群是由具有相同 cluster.name (默认值为elasticsearch)的一个或多个 Elasticsearch 节点组成的,各个节点协同工作,共享数据。多台ES服务器的结合的统称叫ES集群,一个集群包含多台服务器,多个节点。

注意事项:

1.同一个集群内的各个节点名字不能重复,但集群名称一定要相同。

2.在实际使用 Elasticsearch 集群时,一般需要给集群起一个合适的名字来替代 cluster.name的默认值。自定义集群名称的好处是,可以防止一个新启动的节点加入相同网络中的另一个同名的集群中。

集群节点状态判断指标(重点):

在 Elasticsearch 集群中,节点的状态有 Green、Yellow 和 Red 三种:

Green(绿色):表示节点运行状态为健康状态。所有的主分片和副本分片都可以正常工作,集群 100%健康。

Yellow(黄色):表示节点的运行状态为预警状态。所有的主分片都可以正常工作,但至少有一个副本分片是不能正常工作。此时集群依然可以正常工作,但集群的高可用性在某种程度上被弱化。

Red(红色):表示集群无法正常使用。此时,集群中至少有一个分片的主分片及它的全部副本分片都不可正常工作。虽然集群的查询操作还可以进行,但是也只能返回部分数据(其他正常分片的数据可以返回),而分配到这个有问题分片上的写入请求将会报错,最终导致数据丢失。

2.3. 索引(Index)

一个索引就是一个拥有几分相似特征的文档的集合。比如说,业务上:你可以有一个客户数据的索引,还有一个订单数据的索引;或者我们常用的日志的索引等等。 一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。

2.4. 分片(Shards)

当索引的数据量太大时,受限于单个节点的内存、磁盘处理能力等节点无法足够快地响应客户端的请求,此时需要将一个索引上的数据进行水平拆分。拆分出来的每个数据部分称之为一个分片。

ES的一个索引可以包含多个分片;每一个分片都是一个最小的工作单元,承载部分数据;一个分片本身就是一个完整的搜索引擎。(水平分割和扩展我们存放的内容索引;分发和并行跨碎片操作提高性能/吞吐量;)

文档存储在分片中,而分片会被分配到集群中的各个节点中,随着集群的扩大和缩小,ES会自动的将分片在节点之间进行迁移,以保证集群能保持一种平衡。

注意事项:

1.实际应用中,每个分片都会放到不同的服务器上。进行分片操作之后,索引在规模上进行扩大,性能也会提升。

2.es依赖 lucene,es中的每个分片都是 lucene 中的一个索引文件(一个实例),所以每个分片必须有一个主分片和零到多个副本分片。

3.当设置有多分片的索引中写入数据时,是通过路由来确定具体写入哪个分片中的,因此在创建索引时需要指定分片的数量,并且分片的数量一旦确定就不能更改(默认值为5)。

4.当查询索引时,需要在索引对应的多个分片上进行查询。es会把查询发送给每个相关的分片,并汇总各个分片的查询结果。

5.对上层的应用程序而言,分片是透明的,也就是说应用程序并不知道分片的存在。

6.当增减节点时,shards会自动在nodes中做负载均衡;

7.一个文档只能完整的存放在一个shard上

8.每一个shard关联的副本分片(replica shard)的数量(默认值为1),这个设置在任何时候都可以修改。

2.4.1. 节点和分片如何工作?

一个集群至少有一个节点,而一个节点就是一个es进程,节点可以有多个默认索引,如果创建索引,索引将会由5个默认的分片(primary shard,又称主分片)构成,每一个分片会有一个复制分片


1.png

2.5. 副本(Replicasedit)

副本/备份 是对分片的复制,这种备份是精确复制模式。

目的是为了当分片/节点发生故障时,可以在所有副本上并行的执行搜索,主分片和备份分片都可以对外提供数据查询服务,加速查询索引的功能,能提高服务可用性;冗余备份,防止数据丢失;总结就是异常时负责容错机制和负载均衡。

注意事项:

1.复制分片是不和主分片在一起的,一个主分片在一台机器上,它的复制分片可能分布在其它N台机器上。

2.当主分片不可用时,Elasticsearch 会在备份分片中选举出一个分片作为主分片,从而避免数据丢失。

3.若备份分片数量设置得太多,则在写操作时会增加数据同步的负担。(当构建索引进行写入操作时,首先在主分片上完成数据的索引,然后数据会从主分片分发到备份分片上进行索引。)

4.每个分片会包含部分索引文件。文件由sgment组成 。

注意:副本是乘法,越多越浪费,但也越保险。分片是除法,分片越多,单分片数据就越少也越分散。

2.6. 文档(Document)

一个文档是一个可被索引的基础信息单元。比如,一个客户的数据文档。文档以JSON格式来表示。

6.0以前 文档必须被索引/赋予一个索引的type。索引中的每一条数据叫作一个文档,一条文档数据通过 id 在 Type 内进行唯一标识。

2.7. 类型(Type)

6.0.0版本中已经弃用

类型,曾经是索引的逻辑分区,允许在同一索引中存储不同类型的文档。通过 Type 的名字在索引内进行唯一标识。

在一个索引中,你可以定义一种或多种类型。比如上面说的用户的类别,和订单的类别。一个类型是你的索引的一个逻辑上的一个分类or分区。

2.png

2.8. 其他字段含义

Settings:Settings是对集群中索引的定义信息,比如一个索引默认的分片数、副本数等。

Mapping:Mapping 表示定义索引中字段(Field)的存储类型、分词方式是否存储等信息,类似于mysql数据库中的表结构信息。

在es中,Mapping 可以动态识别。如果没有特殊需求,则不需要手动创建 Mapping,因为 Elasticsearch 会根据数据格式自动识别它的类型。当需要对某些字段添加特殊属性时,如定义使用其他分词器、是否分词、是否存储等,就需要手动设置 Mapping 。

一个索引的 Mapping一旦创建,若已经存储了数据,就不可修改了。

Analyzer:表示字段分词方式的定义。

Recovery:代表数据恢复或叫数据重新分布,es在有节点加入或退出时会根据机器的负载对索引分片进行重新分配,挂掉的节点重新启动时也会进行数据恢复。

River:代表es的一个数据源,也是其它存储方式(如:数据库)同步数据到es的一个方法。它是以插件方式存在的一个es服务,通过读取river中的数据并把它索引到es中,官方的river有couchDB的,RabbitMQ的,Twitter的,Wikipedia的。

Gateway:代表es索引快照的存储方式,es默认是先把索引存放到内存中,当内存满了时再持久化到本地硬盘。gateway对索引快照进行存储,当这个es集群关闭再重新启动时就会从gateway中读取索引备份数据。es支持多种类型的gateway,有本地文件系统(默认),分布式文件系统,Hadoop的HDFS和amazon的s3云存储服务。

Discovery.zen:代表es的自动发现节点机制,es是一个基于p2p的系统,它先通过广播寻找存在的节点,再通过多播协议来进行节点之间的通信,同时也支持点对点的交互。

Transport:代表es内部节点或集群与客户端的交互方式,默认内部是使用tcp协议进行交互,同时它支持http协议(json格式)、thrift、servlet、memcached、zeroMQ等的传输协议(通过插件方式集成)。

3. 与传统的关系型数据库中概念进行对比

关系型数据库 -> Databases(库) -> Tables(表) -> Rows(行) -> Columns(列)。

Elasticsearch -> Indeces(索引) -> Types(类型) -> Documents(文档) -> Fields(属性)。


image.png

1.关系型数据库中的数据库(database),等价与ES索引(index)

2.一个数据库下面有N张表(table),等价与1个索引Index下面有N多类型(Type)

备注:(ES6.0之后被废弃,es7中完全删除)

3.一个数据库表(table)下的数据有多行(row)多列(colum)组成,等价与一个Type由多文档(document)多字段(field)组成

4.在一个关系型数据库中,索引(Schema)定义了表,每个表的字段,还有表和字段的之间关系,与之对应,在ES中:反向索引(Mapping)定义索引下的Ttype的字段的处理规则,即如何建立、索引类型、是否保存原始索引JSON文档、是否压缩原始JSON文档、是否需要分词处理、如何进行分词处理等

5.在数据库中新增 INSERT、删除 DELTE、修改 UPDATE、查询 SEARCH操作等价于ES中的新增PUT/POST、删除DELETE、修改_update、查询GET

3.png

4. ES的五层架构

4.png

5. ES的特性

速度快、易扩展、弹性、灵活、操作简单、多语言客户端、X-Pack、hadoop/spark强强联手、开箱即用。

分布式:横向扩展非常灵活

全文检索:基于lucene的强大的全文检索能力;

近实时搜索和分析:数据进入ES,可达到近实时搜索,还可进行聚合分析

高可用:容错机制,自动发现新的或失败的节点,重组和重新平衡数据

模式自由:ES的动态mapping机制可以自动检测数据的结构和类型,创建索引并使数据可搜索。

RESTful API:JSON + HTTP

6. ES的CRUD

6.1. 查询

5.png

1.客户端给node1发送请求,查询名字叫张三的数据

2.P1节点接收到请求,判断出当前数据的_ID对应的分片0,且分片P1中的数据对应复制分片R0,R1都有,就会将请求转发到R0进行处理

3.取出文档数据返回给P1,最终返回给前端

6.2. 搜索

6.png

6.3. 写入

7.png

客户端选择一个 node 发送请求过去,这个 node 就是 coordinating node (协调节点)。

coordinating node 对 document 进行路由,将请求转发给对应的 node(有 primary shard)。

实际的 node 上的 primary shard 处理请求,然后将数据同步到 replica node 。

coordinating node 如果发现 primary node 和所有 replica node 都搞定之后,就返回响应结果给客户端。

写请求是写入 primary shard,然后同步给所有的 replica shard;读请求可以从 primary shard 或 replica shard 读取,采用的是随机轮询算法。

8.png

1.先写入内存 buffer,同时将数据写入 translog 事务日志文件。PS:在 buffer 里的时候数据是搜索不到的

2.如果 buffer 快满了,或者到一定时间,就会将内存 buffer 数据 refresh 到一个新的 segment file 中(存在os cache),但是此时数据不是直接进入 segment file 磁盘文件,而是先进入 os cache 。此时可以被检索到,这个过程就是 refresh。

3.每隔 1 秒钟,es 将 buffer 中的数据写入一个新的 segment file ,每秒钟会产生一个新的磁盘文件 segment file (这个 segment file 中就存储最近 1 秒内 buffer 中写入的数据)。

4.每次 refresh 完 buffer 清空,translog 保留。重复上面的步骤,新的数据不断进入 buffer 和 translog,不断将 buffer 数据写入一个又一个新的 segment file 中去。translog 会变得越来越大。当 translog 达到一定长度的时候,就会触发 commit 操作。

5.这个 commit 操作叫做 flush 。默认 30 分钟自动执行一次 flush ,但如果 translog (512M)过大,也会触发 flush 。(我们可以通过 es api,手动执行 flush 操作)translog也是先写入 os cache 的,默认每隔 5 秒刷一次到磁盘中去。

6.commit 操作发生第一步,就是将 buffer 中现有数据 refresh 到 os cache 中去,清空 buffer。然后,将一个 commit point 写入磁盘文件,里面标识着这个 commit point 对应的所有 segment file ,同时强行将 os cache 中目前所有的数据都 fsync 到磁盘文件中去。最后清空 现有 translog 日志文件,重启一个 translog,此时 commit 操作完成。

内存->系统缓存->磁盘

延迟写策略

段合并机制

操作系统里面,磁盘文件其实都有一个东西,叫做 os cache ,即操作系统缓存,就是说数据写入磁盘文件之前,会先进入 os cache ,先进入操作系统级别的一个内存缓存中去。只要 buffer 中的数据被 refresh 操作刷入 os cache 中,这个数据就可以被搜索到了。(所以es是NRT特性)

为什么叫 es 是准实时的? NRT ,全称 near real-time 。默认是每隔 1 秒 refresh 一次的,所以 es 是准实时的,因为写入的数据 1 秒之后才能被看到。可以通过 es 的 restful api 或者 java api ,手动执行一次 refresh 操作,就是手动将 buffer 中的数据刷入 os cache 中,让数据立马就可以被搜索到。只要数据被输入 os cache 中,buffer 就会被清空了,因为不需要保留 buffer 了,数据在 translog 里面已经持久化到磁盘去一份了。(translog 默认5s 从os cache 落地到磁盘)

translog 日志文件的作用是什么?你执行 commit 操作之前,数据要么是停留在 buffer 中,要么是停留在 os cache 中,无论是 buffer 还是 os cache 都是内存,一旦这台机器死了,内存中的数据就全丢了。所以需要将数据对应的操作写入一个专门的日志文件 translog 中,一旦此时机器宕机,再次重启的时候,es 会自动读取 translog 日志文件中的数据,恢复到内存 buffer 和 os cache 中去。

translog 其实也是先写入 os cache 的,默认每隔 5 秒刷一次到磁盘中去,所以默认情况下,可能有 5 秒的数据会仅仅停留在 buffer 或者 translog 文件的 os cache 中,如果此时机器挂了,会丢失 5 秒钟的数据。但是这样性能比较好,最多丢 5 秒的数据。也可以将 translog 设置成每次写操作必须是直接 fsync 到磁盘,但是性能会差很多。

其实 es 第一是准实时的,数据写入 1 秒后可以搜索到;可能会丢失数据的。有 5 秒的数据,停留在 buffer、translog os cache、segment file os cache 中,而不在磁盘上,此时如果宕机,会导致 5 秒的数据丢失。

总结一下,数据先写入内存 buffer,然后每隔 1s,将数据 refresh 到 os cache,到了 os cache 数据就能被搜索到(所以我们才说 es 从写入到能被搜索到,中间有 1s 的延迟)。每隔 5s,将数据写入 translog 文件(这样如果机器宕机,内存数据全没,最多会有 5s 的数据丢失),translog 大到一定程度,或者默认每隔 30mins,会触发 commit 操作,将缓冲区的数据都 flush 到 segment file 磁盘文件中。

数据写入 segment file 之后(从buffer 刷新到os cache),同时就建立好了倒排索引。

6.4. 删除

9.png

如果是删除操作,commit 的时候会生成一个 .del 文件,里面将某个 doc 标识为 deleted 状态,那么搜索的时候根据 .del 文件就知道这个 doc 是否被删除了。

Segment的merge操作

●随着时间,磁盘上的segment越来越多,需要定期进行合并。

●Es和Lucene 会自动进行merge操作,合并segment和删除已经删除的文档。

6.5. 更新

10.png

就是将原来的 doc 标识为 deleted 状态,然后新写入一条数据。

7. 其他

7.1. es节点自动发现机制

为什么需要es节点自动发现机制?

因为在es内部,我们可以通过在集群中配置一个相同的集群名称(clustername),就能将不同的节点连接到同一个集群。而这个过程中就使用了节点自动发现机制。

四种自动发现机制:

es内嵌自动发现功能,提供了四种发现机制。其中一种是默认实现,其他都是通过插件来实现。

Azure discovery 插件方式:多播模式。

EC2 discovery 插件方式:多播模式。

Google Compute Engine (GCE) discovery 插件方式:多播模式。

Zen Discovery,支持多播模式和单播模式。(默认机制)

Zen Discovery 是es内置的默认发现模块。发现模块用于发现集群中的节点及选举主节点(master 节点)。

Zen Discovery 提供单播模式和基于文件的发现,并且可以扩展为通过插件支持其他形式的发现机制。

7.1.1.

●es支持多播模式和单播模式两种节点自动发现机制,不过多播模式已经不被大多数操作系统所支持,加之其安全性不高,所以一般我们会主动关闭多播模式。

●在es中,发现机制默认被配置为使用单播模式,以防止节点无意中加入集群。

●Elasticsearch 支持同一个主机启动多个节点,因此只有在同一台机器上运行的节点才会自动组成集群。

●当集群的节点运行在不同的机器上时,在单播模式下,我们需要为es配置一些它应该去尝试连接的节点列表。

单播就是在配置中读取到 master 节点信息,直接连入,其效率和安全性都高于多播模式,但是单播存在的问题是如果新增节点是 master 候选节点,则必须更改集群中所有节点的配置。

集群构建及主节点选举过程: 节点启动后先执行 ping 命令(这里提及的 ping 命令不是 Liux 环境用的 ping 命令,而是Elasticsearch 的一个 RPC 命令),ping 命令的返回结果会包含该节点的基本信息及该节点认为的主节点。 在选举开始时,主节点先从各节点认为的 master 中选。选举规则比较简单,即按照 ID的字典序排序,取第一个。 若各节点都没有认为的 master,则从所有节点中选择,规则同上。 若节点数达不到最小值的限制,则循环上述过程,直到节点数超过最小限制值,才可以开始选举。 最后选举出一个主节点,若只有一个本地节点,则主节点就是它自己。 若当前节点是主节点,则开始等待节点数达到最小,再提供服务。若当前节点不是主节点,则尝试加入主节点所在集群。

7.2. 副本的数据一致性

通过什么协议来实现的?

副本控制协议。让用户通过一定的方式即可读取分布式系统内部各个副本的数据,这些数据在一定的约束条件下是相同的,即副本数据一致性(Consistency)。

一致性的分类:

在分布式系统中,一致性分为强一致性 (Strong Consistency)、弱一致性 (WeekConsistency),还有介于二者之间的会话一致性 (Session Consistency) 和最终一致性(Eventual Consistency )。

1.强一致性最难实现。强一致性要求任何时刻用户都可以读到最近一次成功更新的副本数据。

2.弱一致性与强一致性正好相反,数据更新后,用户无法在一定时间内读到最新的值,因此在实际中使用很少。

3.会话一致性指的是在一次会话内,用户一旦读到某个数据的某个版本的更新数据,则在这个会话中就不会再读到比当前版本更老旧的数据。

4.最终一致性指的是集群中各个副本的数据最终能达到完全一致的状态。

注意事项:

副本数据一致性是针对分布式系统中各个节点而言的,不是针对某节点的某个副本而言的。

从副本的角度而言,强一致性是最佳的,但对于分布式系统而言,还要考虑其他方面,如分布式系统的整体性能(即系统的吞吐)、系统的可用性、系统的可拓展性等。这也是系统设计要全盘考虑的原因。

7.3. 副本数据的分布方式

数据分布方式:

主要有哈希方式、按数据范围分布、按数据量分布、一致性哈希方式(Consistent Hashing),等等。

1.哈希方式。最简单的方式,简单是最大优势,但缺点也同样明显。一方面,可扩展性不高,一旦存储规模需要扩大,则所有数据都需要重新按哈希值分发;另一方面,哈希方式容易导致存储空间的数据分布不均匀。

2.按数据范围分布。该种方式也较常见,是将数据按特征值的范围划分为不同的区间,使得集群中不同的服务器处理不同区间的数据。这种方式可以避免哈希值带来的存储空间数据分布不均匀的情况。

3.按数据量分布。同按数据范围分布方式的设计核心思路较接近。一般是将数据看作一个顺序增长的,并将数据集按照某一较为固定的大小划分为若干数据块,把不同的数据块分布到不同的服务器上。

4.一致性哈希方式。在实践中使用较为广泛的一种,基本思路是使用一个哈希函数计算数据的哈希值,而哈希函数的输出值会作为一个封闭的环,我们会根据哈希值将节点随机分布到这个环上,每个节点负责处理从自己开始顺时针至下一个节点的全部哈希值域上的数据。

2种数据分布形态:

一种以服务器为核心,另一种是以数据为核心。

以机器为核心时,机器之间互为副本,副本机器之间的数据完全相同。以机器为核心的策略适用于上述各种数据分布方式,最主要的优点就是简单,容易落地;缺点也很明显,一旦数据出问题,在数据恢复时就需要恢复多台服务器中的数据,效率很低,而且增加服务器后,会带来可扩展性低的问题。一般会采用哈希方式、一致性哈希方式。

以数据为核心时,一般将数据拆分为若干个数据段,以数据段为单位去分发,每个数据段的大小尽量相等,而且限制数据量大小的上限。在不同的系统中,数据段有很多不同的称谓,如在 Lucene 和es中称之为 segment,在 Kafka 中称之为 chunk 和partition等。

注意事项:

将数据拆分为数据段,意味着副本的管理将以数据段为单位进行展开,因此副本与机器不再强相关,每台机器都可以负责一定数据段的副本。这带来的好处是当某台服务器中的数据有问题时,我们可以从集群中的任何其他服务器恢复数据,因此数据的恢复效率很高。

7.3.1. 副本分发策略

指主节点和副本节点之间副本数据同步的方法。

2大类分发策略:

中心化方式:

设计思路:由一个中心节点协调副本数据的更新、维护副本之间的一致性。数据的更新可以是主节点主动向副本节点推送,也可以是副本节点向主节点推送。

优缺点:设计思路简单,缺点明显,数据的同步及系统的可用性都有“单点依赖”的风险,即依赖于中心化节点。一旦中心化节点发生异常,则数据同步和系统的可用性都会受到影响。

去中心化方式:

设计思路:就是没有中心节点,所有的节点都是 P2P 形式,地位对等,节点之间通过平等协商达到一致。

优缺点:不会因为某个节点的异常而导致系统的可用性受到影响。但各个节点达成共识的过程较长,需要反复进行消息通信来确认内容,实现较为复杂。

上一篇 下一篇

猜你喜欢

热点阅读