Elasticsearch内部分片及分片处理机制介绍

副本分片

什么是副本分片

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

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

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

Elasticsearch内部分片处理机制

逆向引索

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

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

例:

当有4个文档

txt1:“aaa,bbb,ccc”

txt2:“aaa,ddd,eee”

txt3:“bbb,ccc,ddd”

txt4:“ddd,eee”

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

Term txt1 txt2 txt3 txt4
aaa
bbb
ccc
ddd
eee

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

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

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

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

Segment

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

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

image

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

Elasticsearch如何合理分配索引分片

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

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

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

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

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

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

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

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

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

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

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

谨慎分片

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

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

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

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

稍有富余是好的, 但过度分配分片却是大错特错. 具体定义多少分片很难有定论, 取决于用户的数据 量和使用方式.

我们要熟知以下几点内容:

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

测试数据提交

{
  "name": "nb",
  "age": "18"
}

img

验证索引及页面详解

img

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

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

集群检测实战

python脚本检测

[root@elk2 ~]# vim es.py
#!/usr/bin/env python
#coding:utf-8
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
import subprocess
body = ""
false = "false"
clusterip = "10.0.0.82"
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 "\033[1;32m 集群运行正常 \033[0m"
elif status == "yellow":
    print "\033[1;33m 副本分片丢失 \033[0m"
else:
    print "\033[1;31m 主分片丢失 \033[0m"

[root@elk2 ~]# python es.py 
 集群运行正常