监控日志loging elastIcsearch 规划篇(四)

本文深入探讨了Elasticsearch的存储原理,包括分段存储、延迟写策略和段合并,以及如何规划节点,如主节点、数据节点、协调节点和Ingest节点的角色与职责。此外,文章还讨论了数据写入和搜索机制,以及如何有效地管理分片分配和迁移。
摘要由CSDN通过智能技术生成

elasticsearch 容量规划

一. ES的机制原理

ES的基本概念和基本操作介绍完了之后我们可能还有很多疑惑,它们内部是如何运行的?主分片和副本分片是如何同步的?创建索引的流程是什么样的?ES如何将索引数据分配到不同的分片上的?以及这些索引数据是如何存储的?为什么说ES是近实时搜索引擎而文档的 CRUD (创建-读取-更新-删除) 操作是实时的?以及Elasticsearch 是怎样保证更新被持久化在断电时也不丢失数据?还有为什么删除文档不会立刻释放空间?带着这些疑问我们进入接下来的内容。

写索引原理
下图描述了3个节点的集群,共拥有12个分片,其中有4个主分片(S0、S1、S2、S3)和8个副本分片(R0、R1、R2、R3),每个主分片对应两个副本分片,节点1是主节点(Master节点)负责整个集群的状态。
在这里插入图片描述

写索引是只能写在主分片上,然后同步到副本分片。这里有四个主分片,一条数据ES是根据什么规则写到特定分片上的呢?这条索引数据为什么被写到S0上而不写到S1或S2上?那条数据为什么又被写到S3上而不写到S0上了?

首先这肯定不会是随机的,否则将来要获取文档的时候我们就不知道从何处寻找了。实际上,这个过程是根据下面这个公式决定的:

shard = hash(routing) % number_of_primary_shards

routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到余数 。这个在 0 到 numberofprimary_shards-1 之间的余数,就是我们所寻求的文档所在分片的位置。

这就解释了为什么我们要在创建索引的时候就确定好主分片的数量并且永远不会改变这个数量:因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了。

由于在ES集群中每个节点通过上面的计算公式都知道集群中的文档的存放位置,所以每个节点都有处理读写请求的能力。在一个写请求被发送到某个节点后,该节点即为前面说过的协调节点,协调节点会根据路由公式计算出需要写到哪个分片上,再将请求转发到该分片的主分片节点上。

假如此时数据通过路由计算公式取余后得到的值是 shard = hash(routing) % 4 = 0,则具体流程如下:

客户端向ES1节点(协调节点)发送写请求,通过路由计算公式得到值为0,则当前数据应被写到主分片S0上。
ES1节点将请求转发到S0主分片所在的节点ES3,ES3接受请求并写入到磁盘。
并发将数据复制到两个副本分片R0上,其中通过乐观并发控制数据的冲突。一旦所有的副本分片都报告成功,则节点ES3将向协调节点报告成功,协调节点向客户端报告成功。
存储原理

上面介绍了在ES内部索引的写处理流程,这个流程是在ES的内存中执行的,数据被分配到特定的分片和副本上之后,最终是存储到磁盘上的,这样在断电的时候就不会丢失数据。具体的存储路径可在配置文件 …/config/elasticsearch.yml中进行设置,默认存储在安装目录的data文件夹下。建议不要使用默认值,因为若ES进行了升级,则有可能导致数据全部丢失。

path.data: /path/to/data //索引数据

path.logs: /path/to/logs //日志记录

1.分段存储

索引文档以段的形式存储在磁盘上,何为段?索引文件被拆分为多个子文件,则每个子文件叫作段, 每一个段本身都是一个倒排索引,并且段具有不变性,一旦索引的数据被写入硬盘,就不可再修改。在底层采用了分段的存储模式,使它在读写时几乎完全避免了锁的出现,大大提升了读写性能。

段被写入到磁盘后会生成一个提交点,提交点是一个用来记录所有提交后段信息的文件。一个段一旦拥有了提交点,就说明这个段只有读的权限,失去了写的权限。相反,当段在内存中时,就只有写的权限,而不具备读数据的权限,意味着不能被检索。

段的概念提出主要是因为:在早期全文检索中为整个文档集合建立了一个很大的倒排索引,并将其写入磁盘中。如果索引有更新,就需要重新全量创建一个索引来替换原来的索引。这种方式在数据量很大时效率很低,并且由于创建一次索引的成本很高,所以对数据的更新不能过于频繁,也就不能保证时效性。

索引文件分段存储并且不可修改,那么新增、更新和删除如何处理呢?

新增,新增很好处理,由于数据是新的,所以只需要对当前文档新增一个段就可以了。
删除,由于不可修改,所以对于删除操作,不会把文档从旧的段中移除而是通过新增一个 .del文件,文件中会列出这些被删除文档的段信息。这个被标记删除的文档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。
更新,不能修改旧的段来进行反映文档的更新,其实更新相当于是删除和新增这两个动作组成。会将旧的文档在 .del文件中标记删除,然后文档的新版本被索引到一个新的段中。可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就会被移除。
段被设定为不可修改具有一定的优势也有一定的缺点,优势主要表现在:

不需要锁。如果你从来不更新索引,你就不需要担心多进程同时修改数据的问题。
一旦索引被读入内核的文件系统缓存,便会留在哪里,由于其不变性。只要文件系统缓存中还有足够的空间,那么大部分读请求会直接请求内存,而不会命中磁盘。这提供了很大的性能提升。
其它缓存(像filter缓存),在索引的生命周期内始终有效。它们不需要在每次数据改变时被重建,因为数据不会变化。
写入单个大的倒排索引允许数据被压缩,减少磁盘 I/O 和 需要被缓存到内存的索引的使用量。
段的不变性的缺点如下:

当对旧数据进行删除时,旧数据不会马上被删除,而是在 .del文件中被标记为删除。而旧数据只能等到段更新时才能被移除,这样会造成大量的空间浪费。
若有一条数据频繁的更新,每次更新都是新增新的标记旧的,则会有大量的空间浪费。
每次新增数据时都需要新增一个段来存储数据。当段的数量太多时,对服务器的资源例如文件句柄的消耗会非常大。
在查询的结果中包含所有的结果集,需要排除被标记删除的旧数据,这增加了查询的负担。

2延迟写策略

介绍完了存储的形式,那么索引是写入到磁盘的过程是这怎样的?是否是直接调 fsync 物理性地写入磁盘?

答案是显而易见的,如果是直接写入到磁盘上,磁盘的I/O消耗上会严重影响性能,那么当写数据量大的时候会造成ES停顿卡死,查询也无法做到快速响应。如果真是这样ES也就不会称之为近实时全文搜索引擎了。

为了提升写的性能,ES并没有每新增一条数据就增加一个段到磁盘上,而是采用延迟写的策略。

每当有新增的数据时,就将其先写入到内存中,在内存和磁盘之间是文件系统缓存,当达到默认的时间(1秒钟)或者内存的数据达到一定量时,会触发一次刷新(Refresh),将内存中的数据生成到一个新的段上并缓存到文件缓存系统 上,稍后再被刷新到磁盘中并生成提交点。

这里的内存使用的是ES的JVM内存,而文件缓存系统使用的是操作系统的内存。新的数据会继续的被写入内存,但内存中的数据并不是以段的形式存储的,因此不能提供检索功能。由内存刷新到文件缓存系统的时候会生成了新的段,并将段打开以供搜索使用,而不需要等到被刷新到磁盘。

在 Elasticsearch 中,写入和打开一个新段的轻量的过程叫做 refresh (即内存刷新到文件缓存系统)。默认情况下每个分片会每秒自动刷新一次。这就是为什么我们说 Elasticsearch 是近实时搜索,因为文档的变化并不是立即对搜索可见,但会在一秒之内变为可见。我们也可以手动触发 refresh, POST/_refresh 刷新所有索引, POST/nba/_refresh刷新指定的索引。

Tips:尽管刷新是比提交轻量很多的操作,它还是会有性能开销。当写测试的时候, 手动刷新很有用,但是不要在生产> 环境下每次索引一个文档都去手动刷新。而且并不是所有的情况都需要每秒刷新。可能你正在使用 Elasticsearch 索引大量的日志文件, 你可能想优化索引速度而不是> 近实时搜索, 这时可以在创建索引时在 settings中通过调大 refresh_interval=“30s” 的值 , 降低每个索引的刷新频率,设值时需要注意后面带上时间单位,否则默认是毫秒。当 refresh_interval=-1时表示关闭索引的自动刷新。

虽然通过延时写的策略可以减少数据往磁盘上写的次数提升了整体的写入能力,但是我们知道文件缓存系统也是内存空间,属于操作系统的内存,只要是内存都存在断电或异常情况下丢失数据的危险。

为了避免丢失数据,Elasticsearch添加了事务日志(Translog),事务日志记录了所有还没有持久化到磁盘的数据。添加了事务日志后整个写索引的流程如下图所示。
在这里插入图片描述

一个新文档被索引之后,先被写入到内存中,但是为了防止数据的丢失,会追加一份数据到事务日志中。不断有新的文档被写入到内存,同时也都会记录到事务日志中。这时新数据还不能被检索和查询。
当达到默认的刷新时间或内存中的数据达到一定量后,会触发一次 refresh,将内存中的数据以一个新段形式刷新到文件缓存系统中并清空内存。这时虽然新段未被提交到磁盘,但是可以提供文档的检索功能且不能被修改。
随着新文档索引不断被写入,当日志数据大小超过512M或者时间超过30分钟时,会触发一次 flush。内存中的数据被写入到一个新段同时被写入到文件缓存系统,文件系统缓存中数据通过 fsync 刷新到磁盘中,生成提交点,日志文件被删除,创建一个空的新日志。
通过这种方式当断电或需要重启时,ES不仅要根据提交点去加载已经持久化过的段,还需要工具Translog里的记录,把未持久化的数据重新持久化到磁盘上,避免了数据丢失的可能。

3段合并

由于自动刷新流程每秒会创建一个新的段 ,这样会导致短时间内的段数量暴增。而段数目太多会带来较大的麻烦。每一个段都会消耗文件句柄、内存和cpu运行周期。更重要的是,每个搜索请求都必须轮流检查每个段然后合并查询结果,所以段越多,搜索也就越慢。

Elasticsearch通过在后台定期进行段合并来解决这个问题。小的段被合并到大的段,然后这些大的段再被合并到更大的段。段合并的时候会将那些旧的已删除文档从文件系统中清除。被删除的文档不会被拷贝到新的大段中。合并的过程中不会中断索引和搜索。
在这里插入图片描述

段合并在进行索引和搜索时会自动进行,合并进程选择一小部分大小相似的段,并且在后台将它们合并到更大的段中,这些段既可以是未提交的也可以是已提交的。合并结束后老的段会被删除,新的段被 flush 到磁盘,同时写入一个包含新段且排除旧的和较小的段的新提交点,新的段被打开可以用来搜索。

段合并的计算量庞大, 而且还要吃掉大量磁盘 I/O,段合并会拖累写入速率,如果任其发展会影响搜索性能。Elasticsearch在默认情况下会对合并流程进行资源限制,所以搜索仍然有足够的资源很好地执行。

ES存入数据和搜索数据机制

1)索引对象(blog):存储数据的表结构 ,任何搜索数据,存放在索引对象上 。
2)映射(mapping):数据如何存放到索引对象上,需要有一个映射配置, 包括:数据类型、是否存储、是否分词等。
3)文档(document):一条数据记录,存在索引对象上 。
4)文档类型(type):一个索引对象,存放多种类型数据,数据用文档类型进行标识。

二. Node(节点)规划

集群中的一个节点,节点也有一个名称(默认是随机分配的),节点名称很重要(在执行运维管理操作的时候),默认节点会去加入一个名称为“elasticsearch”的集群,如果直接启动一堆节点,那么它们会自动组成一个elasticsearch集群,当然一个节点也可以组成一个elasticsearch集群。

节点是一个Elasticsearch的实例
本质上就是一个JAVA进程
一台机器上可以运行多个Elasticsearch进程,但是生产环境一般建议一台机器上只运行一个Elasticsearch实例
每一个节点都有名字,通过配置文件配置,或者启动时候 –E node.name=node1 指定
每一个节点启动之后, 会分配一个UID ,保证在data目录下

1. Master-eligible nodes 和 master node

每个节点启动后, 默认就是一个master eligible节点 可以设置node.master:false 禁止

Master-eligible 节点可以参加选主流程,成为master节点
当第一个节点启动时候, 它会将自己选举成master节点
每个节点上都保存了集群的状态, 只有Maseter 节点才能修改集群的状态信息
集群状态, 维护了一个集群中,必要的信息 :
1.所有的节点信息
2.所有的索引和其相关的mapping 与setting信息
3.分片的路由信息
任意节点都能修改信息会导致数据的不一致性

2.Data node

可以保存数据的节点, 叫做data node 负责保存分片数据 在数据扩展上起到了至关重要的作用

Coordinating node
负责接受client 的请求,将请求分发到合适的节点, 最终把结果汇集到一起
每个节点默认都起到了coordinating node 职责

** Hot & warm node**
不同硬件配置的data node 用来实现HOT& warm 架构 降低集群部署的成本

Machine learning node

负责跑 机器学习的JOB, 用来做异常检测
Tribe node
(5.3 开始使用 cross cluster serarch)tribe node 连接到不同的elaticsearch集群
并且支持将这些集群当成一个单独的集群处理

配置节点
开发环境中一个节点可以承担多种角色
生产环境中, 应该设置单一的角色的节点

官网地址
https://www.elastic.co/guide/en/elasticsearch/reference/7.x/modules-node.html

  1. 配置文件中给出了三种配置高性能集群拓扑结构的模式,如下:
    如果你想让节点从不选举为主节点,只用来存储数据,可作为负载器
	node.master: false 
	node.data: true 
	node.ingest: true  #默认true
  1. 如果想让节点成为主节点,且不存储任何数据,并保有空闲资源,可作为协调器
	node.master: true 
	node.data: false
	node.ingest: true
  1. 如果想让节点既不称为主节点,又不成为数据节点,那么可将他作为搜索器,从节点中获取数据,生成搜索结果等
  node.master: false 
  node.data: false 
  node.ingest: true
  1. 仅作为协调器
  node.master: false 
  node.data: false
  node.ingest: false

集群节点角色划分 指责分离的好处

2.1 主节点

主节点负责集群相关的操作,例如创建或删除索引,跟踪哪些节点是集群的一部分,以及决定将哪些分片分配给哪些节点。
拥有稳定的主节点是衡量集群健康的重要标志。
注意:

1、由于索引和搜索数据都是CPU、内存、IO密集型的,可能会对数据节点的资源造成较大压力。
因此,在较大规模的集群里,最好要设置单独的仅主节点角色。(这点PB级集群调优时重点关注)
2、不要将主节点同时充当协调节点的角色,因为:对于稳定的集群来说,主节点的角色功能越单一越好。

2.2 数据节点

数据节点:保存包含索引文档的分片数据,执行CRUD、搜索、聚合相关的操作。
属于:内存、CPU、IO密集型,对硬件资源要求高。

2.3 协调节点

搜索请求在两个阶段中执行(query 和 fetch),这两个阶段由接收客户端请求的节点 - 协调节点协调。

在请求阶段,协调节点将请求转发到保存数据的数据节点。 每个数据节点在本地执行请求并将其结果返回给协调节点。
在收集fetch阶段,协调节点将每个数据节点的结果汇集为单个全局结果集。

2.4 Ingest节点

ingest 节点可以看作是数据前置处理转换的节点,支持 pipeline管道 设置,可以使用 ingest 对数据进行过滤、转换等操作,类似于 logstash 中 filter 的作用,功能相当强大。

我把Ingest节点的功能抽象为:大数据处理环节的“ETL”——抽取、转换、加载。

Ingest 节点能解决什么问题?

上面的Ingest节点介绍太官方,看不大懂怎么办?来个实战场景例子吧。

思考问题1:线上写入数据改字段需求
如何在数据写入阶段修改字段名(不是修改字段值)?

思考问题2:线上业务数据添加特定字段需求
如何在批量写入数据的时候,每条document插入实时时间戳?

这时,脑海里开始对已有的知识点进行搜索。

针对思考问题1:字段值的修改无非:update,update_by_query?但是字段名呢?貌似没有相关接口或实现。

针对思考问题2:插入的时候,业务层面处理,读取当前时间并写入貌似可以,有没有不动业务层面的字段的方法呢?

答案是有的,这就是Ingest节点的妙处。

Ingest节点基本概念

在实际文档索引发生之前,使用Ingest节点预处理文档。Ingest节点拦截批量和索引请求,它应用转换,然后将文档传递回索引或Bulk API。

强调一下: Ingest节点处理时机——在数据被索引之前,通过预定义好的处理管道对数据进行预处理。

默认情况下,所有节点都启用Ingest,因此任何节点都可以处理Ingest任务。我们也可以创建专用的Ingest节点。

要禁用节点的Ingest功能,需要在elasticsearch.yml 设置如下:

node.ingest:false

1
这里就涉及几个知识点:

1、预处理 pre-process
要在数据索引化(indexing)之前预处理文档。

2、管道 pipeline
每个预处理过程可以指定包含一个或多个处理器的管道。
管道的实际组成:

{
“description” : “…”,
“processors” : [ … ]
}

description:管道功能描述。
processors:注意是数组,可以指定1个或多个处理器。

3、处理器 processors
每个处理器以某种特定方式转换文档。
例如,管道可能有一个从文档中删除字段的处理器,然后是另一个重命名字段的处理器。
这样,再反过来看第4部分就很好理解了。Ingest API

Ingest API共分为4种操作,分别对应:
PUT(新增)、
GET(获取)、
DELETE(删除)、
Simulate (仿真模拟)。
模拟管道AP Simulate 针对请求正文中提供的文档集执行特定管道。
除此之外,高阶操作包括:

1、支持复杂条件的Nested类型的操作;
2、限定条件的管道操作;
3、限定条件的正则操作等。
详细内容,参见官网即可。

常见的处理器有如下28种,举例:

append处理器:添加1个或1组字段值;
convert处理器:支持类型转换

Ingest节点和Logstash Filter 啥区别?

业务选型中,肯定会问到这个问题。

区别一:支持的数据源不同。
Logstash:大量的输入和输出插件(比如:kafka,redis等)可供使用,还可用来支持一系列不同的架构。
Ingest节点:不能从外部来源(例如消息队列或数据库)提取数据,必须批量bulk或索引index请求将数据推送到 Elasticsearch.

区别二:应对数据激增的能力不同。
Logstash:Logstash 可在本地对数据进行缓冲以应对采集骤升情况。如前所述,Logstash 同时还支持与大量不同的消息队列类型进行集成。
Ingest节点:极限情况下会出现:在长时间无法联系上 Elasticsearch 或者 Elasticsearch 无法接受数据的情况下,均有可能会丢失数据。

区别三:处理能力不同。
Logstash:支持的插件和功能点较Ingest节点多很多。
Ingest节点:支持28类处理器操作。Ingest节点管道只能在单一事件的上下文中运行。Ingest通常不能调用其他系统或者从磁盘中读取数据。

区别四:排他式功能支持不同。
Ingest节点:支持采集附件处理器插件,此插件可用来处理和索引常见格式(例如 PPT、XLS 和 PDF)的附件。
Logstash:不支持如上文件附件类型。

选型小结:
1、两种方式各有利弊,建议小数据规模,建议使用Ingest节点。原因:架构模型简单,不需要额外的硬件设备支撑。
2、数据规模大之后,除了建议独立Ingest节点,同时建议架构中使用Logstash结合消息队列如Kafka的架构选型。
3、将Logstash和Ingest节点结合,也是架构选型参考方案之一

分片
设置索引的分片数,默认为5

#index.number_of_shards: 5

设置索引的副本数,默认为1:

#index.number_of_replicas: 1

说明:# 同时,如果增加副本数量可以有效的提高搜索性能

需要注意的是,“number_of_shards” 是索引创建后一次生成的,后续不可更改设置

“number_of_replicas” 是可以通过API去实时修改设置的

迁移分片
碎片分配设置编辑
以下动态设置可用于控制分片分配和恢复:

cluster.routing.allocation.enable
启用或禁用特定种类的分片的分配:
all -(默认)允许为所有类型的分片分配分片。
primaries -仅允许为主要分片分配分片。
new_primaries -仅允许为新索引的主碎片分配碎片。
none -不允许对任何索引进行任何类型的分片分配。

迁移数据

方式一. 通过reroute api

elasticsearch可以通过reroute api来手动进行索引分片的分配。
不过要想完全手动,必须先设置cluster.routing.allocation.disable_allocation的值
具体设置参考该值的设置以及解释
官网上的解释官网配置

persistent表示永久生效,transient表示暂时生效,重启后无效

curl -XPUT 172.18.1.22:9200/_cluster/settings -d’{
“transient”: {
“cluster.routing.allocation.enable”: “none”
}
}’
迁移完记得改回来该值

curl -XPUT 172.18.1.22:9200/_cluster/settings -d’{
“transient”: {
“cluster.routing.allocation.enable”: “all”
}
}’
迁移具体的分片到其他节点上去。

curl -XPOST ‘172.18.1.22:9200/_cluster/reroute’ -d ‘{
“commands” : [
{
“move” : {
“index” : “info-test”, “shard” : 3,
“from_node” : “172.18.1.26”, “to_node” : “172.18.1.25”
}
}
]
}’

方式二. 通过cerebro 操作实现分片迁移
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值