第二章·Elasticsearch内部分片及分片处理机制介绍

2022-09-26 11:11:04 浏览数 (1)

  • 副本分片介绍
  • Elasticsearch如何合理分配索引分片
  • 分片操作实战
  • 集群检测实战

曾志高翔, 江湖人称曾老大。多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 个人博客:"DBA老司机带你删库跑路"

副本分片介绍

什么是副本分片?

副本分片的主要目的就是为了故障转移,如果持有主分片的节点挂掉了,一个副本分片就会晋升为主分片的角色。

在索引写入时,副本分片做着与主分片相同的工作。新文档首先被索引进主分片然后再同步到其它所有的副本分片。增加副本数并不会增加索引容量。

无论如何,副本分片可以服务于读请求,如果你的索引也如常见的那样是偏向查询使用的,那你可以通过增加副本的数目来提升查询性能,但也要为此,增加额外的硬件资源。


Elasticsearch内部分片处理机制

逆向索引

与传统的数据库不同,在Elasticsearch中,每个字段里面的每个单词都是可以被搜索的。如teacher:“zls,bgx,lidao,oldboy,alex”我们在搜索关键字oldboy时,所有包含oldboy的文档都会被匹配到Elasticsearch的这个特性也叫做全文搜索。

为了支持这个特性,Elasticsearch中会维护一个叫做“invertedindex”(也叫逆向索引)的表,表内包含了所有文档中出现的所有单词,同时记录了这个单词在哪个文档中出现过。

例:

当前有4个文档

txt1:“zls,bgx,lidao” txt2:“zls,oldboy,alex” txt3:“bgx,lidao,oldboy” txt4:“oldboy,alex”

那么Elasticsearch会维护下面一个数据结构表:

Term

txt1

txt2

txt3

txt4

zls

Y

Y

bgx

Y

Y

lidao

Y

Y

oldboy

Y

Y

Y

alex

Y

Y

随意搜索任意一个单词,Elasticsearch只要遍历一下这个表,就可以知道有些文档被匹配到了。

逆向索引里面不止记录了单词与文档的对应关系,它还维护了很多其他有用的数据。如:每个文档一共包含了多少个单词,单词在不同文档中的出现频率,每个文档的长度,所有文档的总长度等等。这些数据用来给搜索结果进行打分,如搜索zls时,那么出现zls这个单词次数最多的文档会被优先返回,因为它匹配的次数最多,和我们的搜索条件关联性最大,因此得分也最多。

逆向索引是不可更改的,一旦它被建立了,里面的数据就不会再进行更改。这样做就带来了以下几个好处:

  • 1.没有必要给逆向索引加锁,因为不允许被更改,只有读操作,所以就不用考虑多线程导致互斥等问题。
  • 2.索引一旦被加载到了缓存中,大部分访问操作都是对内存的读操作,省去了访问磁盘带来的io开销。
  • 3.因为逆向索引的不可变性,所有基于该索引而产生的缓存也不需要更改,因为没有数据变更。
  • 4.使用逆向索引可以压缩数据,减少磁盘io及对内存的消耗。

Segment

既然逆向索引是不可更改的,那么如何添加新的数据,删除数据以及更新数据?为了解决这个问题,lucene将一个大的逆向索引拆分成了多个小的段segment。每个segment本质上就是一个逆向索引。在lucene中,同时还会维护一个文件commit point,用来记录当前所有可用的segment,当我们在这个commit point上进行搜索时,就相当于在它下面的segment中进行搜索,每个segment返回自己的搜索结果,然后进行汇总返回给用户。

引入了segment和commit point的概念之后,数据的更新流程如下图:

  • 1.新增的文档首先会被存放在内存的缓存中
  • 2.当文档数足够多或者到达一定时间点时,就会对缓存进行commit
    • a. 生成一个新的segment,并写入磁盘
    • b. 生成一个新的commit point,记录当前所有可用的segment
    • c. 等待所有数据都已写入磁盘
  • 3.打开新增的segment,这样我们就可以对新增的文档进行搜索了
  • 4.清空缓存,准备接收新的文档

Elasticsearch如何合理分配索引分片

为什么要考虑副本分片数量?

大多数ElasticSearch用户在创建索引时通用会考虑一个重要问题是:我需要创建多少个分片?

分片分配是个很重要的概念, 很多用户对如何分片都有所疑惑, 当然是为了让分配更合理. 在生产环境中, 随着数据集的增长, 不合理的分配策略可能会给系统的扩展带来严重的问题。

同时, 这方面的文档介绍也非常少。很多用户只想要明确的答案而不仅仅一个数字范围, 甚至都不关心随意的设置可能带来的问题。

首先,我们需要了解ES中以下几个名词,是做什么的:

集群(cluster):由一个或多个节点组成, 并通过集群名称与其他集群进行区分

节点(node):单个ElasticSearch实例. 通常一个节点运行在一个隔离的容器或虚拟机中

索引(index):在ES中, 索引是一组文档的集合(就是我们所说的一个日志)

分片(shard):因为ES是个分布式的搜索引擎, 所以索引通常都会分解成不同部分, 而这些分布在不同节点的数据就是分片. ES自动管理和组织分片, 并在必要的时候对分片数据进行再平衡分配, 所以用户基本上不用担心分片的处理细节,一个分片默认最大文档数量是20亿.

副本(replica):ES默认为一个索引创建5个主分片, 并分别为其创建一个副本分片. 也就是说每个索引都由5个主分片成本, 而每个主分片都相应的有一个copy.

对于分布式搜索引擎来说, 分片及副本的分配将是高可用及快速搜索响应的设计核心.主分片与副本都能处理查询请求, 它们的唯一区别在于只有主分片才能处理索引请求.


谨慎分片

副本对搜索性能非常重要, 同时用户也可在任何时候添加或删除副本。额外的副本能给你带来更大的容量, 更高的呑吐能力及更强的故障恢复能力。

当在ElasticSearch集群中配置好你的索引后, 你要明白在集群运行中你无法调整分片设置。既便以后你发现需要调整分片数量, 你也只能新建创建并对数据进行重新索引(reindex)(虽然reindex会比较耗时, 但至少能保证你不会停机)。

主分片的配置与硬盘分区很类似, 在对一块空的硬盘空间进行分区时, 会要求用户先进行数据备份, 然后配置新的分区, 最后把数据写到新的分区上。

在分片时,主要考虑数据集的增长趋势,一定要做到不要过度分片,并不是分片越多越好,从ES社区用户对这个热门主题(分片配置)的分享数据来看, 用户可能认为过度分配是个绝对安全的策略(这里讲的过度分配是指对特定数据集, 为每个索引分配了超出当前数据量(文档数)所需要的分片数)。

稍有富余是好的, 但过度分配分片却是大错特错. 具体定义多少分片很难有定论, 取决于用户的数据量和使用方式. 100个分片, 即便很少使用也可能是好的;而2个分片, 即便使用非常频繁, 也可能是多余的.


我们要熟知以下几点内容: 1.每分配一个分片,都会有额外的成本。 2.每个分片本质上就是一个Lucene索引,因此会消耗相应的文件句柄,内存和CPU资源。 3.每个搜索请求会调度到索引的每个分片中。如果分片分散在不同的节点倒是问题不太。但当分片开始竞争相同的硬件资源时,性能便会逐步下降。 4.ES使用词频统计来计算相关性。当然这些统计也会分配到各个分片上。如果在大量分片上只维护了很少的数据,则将导致最终的文档相关性较差。


大规模数据集场景

如果真的担心数据的快速增长, 我们建议你多关心这条限制: ElasticSearch推荐的最大JVM堆空间是30~32G, 所以把你的分片最大容量限制为30GB, 然后再对分片数量做合理估算. 例如, 你认为你的数据能达到200GB, 我们推荐你最多分配7到8个分片.

总之, 不要现在就为你可能在三年后才能达到的10TB数据做过多分配. 如果真到那一天, 你也会很早感知到性能变化的.

尽管本部分并未详细讨论副本分片, 但我们推荐你保持适度的副本数并随时可做相应的增加. 如果你正在部署一个新的环境, 也许你可以参考我们的基于副本的集群的设计.这个集群有三个节点组成, 每个分片只分配了副本. 不过随着需求变化, 你可以轻易的调整副本数量.

对大数据集, 我们非常鼓励你为索引多分配些分片--当然也要在合理范围内. 上面讲到的每个分片最好不超过30GB的原则依然使用.

不过, 你最好还是能描述出每个节点上只放一个索引分片的必要性. 在开始阶段, 一个好的方案是根据你的节点数量按照1.5~3倍的原则来创建分片. 例如:如果你有3个节点, 则推荐你创建的分片数最多不超过9(3x3)个.

随着数据量的增加,如果你通过集群状态API发现了问题,或者遭遇了性能退化,则只需要增加额外的节点即可. ES会自动帮你完成分片在不同节点上的分布平衡.

再强调一次, 虽然这里我们暂未涉及副本节点的介绍, 但上面的指导原则依然使用: 是否有必要在每个节点上只分配一个索引的分片. 另外, 如果给每个分片分配1个副本, 你所需的节点数将加倍. 如果需要为每个分片分配2个副本, 则需要3倍的节点数.


总结

再次声明, 数据分片也是要有相应资源消耗,并且需要持续投入.

当索引拥有较多分片时, 为了组装查询结果, ES必须单独查询每个分片(当然并行的方式)并对结果进行合并. 所以高性能IO设备(SSDs)和多核处理器无疑对分片性能会有巨大帮助. 尽管如此, 你还是要多关心数据本身的大小,更新频率以及未来的状态. 在分片分配上并没有绝对的答案, 只希望大家能从本博客中受益.

分片操作实战

分片

正如上文中提到,创建分片,不超过3倍,在本课程中,我们有两个节点,所以我们可以设置6个分片。

代码语言:javascript复制
#在每个节点上执行,分配1个副本6个分片
[root@elkstack01 ~]# curl -XPUT 10.0.0.51:9200/_template/my_template -d'
{    "template": "*",
     "settings": {
        "index": {
            "number_of_shards": 6,
            "number_of_replicas": 1
        }
     }
}'

#返回结果为true,分片成功
{"acknowledged":true}

测试提交数据

打开浏览器,访问:http://10.0.0.51:9100/


验证索引及页面详解


主节点和副本节点的区别

主节点的职责: 统计各node节点状态信息、集群状态信息统计、索引的创建和删除、索引分配的管理、关闭node节点等。

副本节点的职责: 同步数据,等待机会成为Master(当主节点宕机或者重启时)。

集群检测实战

检测集群状态

在linux中,我们可以通过curl命令获取集群的状态.

代码语言:javascript复制
[root@elkstack02 ~]# curl –sXGET http://10.0.0.51:9200/_cluster/health?pretty=true

执行结果如下图所示: 获取到的是一个json格式的返回值,那就可以通过python对其中的信息进行分析,例如对status进行分析,如果等于green(绿色)就是运行在正常,等于yellow(黄色)表示副本分片丢失,red(红色)表示主分片丢失。


python脚本检测

代码语言:javascript复制
#编写python脚本
[root@elkstack01 ~]# vim es_cluster_status.py
#!/usr/bin/env python
#coding:utf-8
#Author:_DriverZeng_
#Date:2017.02.12

import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
import subprocess
body = ""
false = "false"
clusterip = "10.0.0.51"
obj = subprocess.Popen(("curl -sXGET http://" clusterip ":9200/_cluster/health?pretty=true"),shell=True, stdout=subprocess.PIPE)
data =  obj.stdout.read()
data1 = eval(data)
status = data1.get("status")
if status == "green":
    print "33[1;32m 集群运行正常 33[0m"
elif status == "yellow":
    print "33[1;33m 副本分片丢失 33[0m"
else:
    print "33[1;31m 主分片丢失 33[0m"

#执行结果如下
[root@elkstack01 ~]# python es_cluster_status.py
集群运行正常

0 人点赞