Elasticsearch内部分片及分片处理机制
副本分片介绍
什么是副本分片?
副本分片的主要目的就是为了故障转移,如果持有主分片的节点挂掉了,一个副本分片就会晋升为主分片的角色。
在索引写入时,副本分片做着与主分片相同的工作。新文档首先被索引进主分片然后再同步到其它所有的副本分片。增加副本数并不会增加索引容量。
无论如何,副本分片可以服务于读请求,如果你的索引也如常见的那样是偏向查询使用的,那你可以通过增加副本的数目来提升查询性能,但也要为此,增加额外的硬件资源。
Elasticsearch内部分片处理机制
逆向索引
与传统的数据库不同,在Elasticsearch中,每个字段里面的每个单词都是可以被搜索的。如teacher:“zls,bgx,lidao,oldboy,alex”我们在搜索关键字oldboy时,所有包含oldboy的文档都会被匹配到Elasticsearch的这个特性也叫做全文搜索。
为了支持这个特性,Elasticsearch中会维护一个叫做“invertedindex”(也叫逆向索引)的表,表内包含了所有文档中出现的所有单词,同时记录了这个单词在哪个文档中出现过。
如:文档
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个分片。
#在每个节点上执行,分配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命令获取集群的状态.
[root@elkstack02 ~]# curl –sXGET http://10.0.0.51:9200/_cluster/health?pretty=true
执行结果如下图所示:
获取到的是一个json格式的返回值,那就可以通过python对其中的信息进行分析,例如对status进行分析,如果等于green(绿色)就是运行在正常,等于yellow(黄色)表示副本分片丢失,red(红色)表示主分片丢失。
python脚本检测
#编写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 "\033[1;32m 集群运行正常 \033[0m" elif status == "yellow": print "\033[1;33m 副本分片丢失 \033[0m" else: print "\033[1;31m 主分片丢失 \033[0m" #执行结果如下 [root@elkstack01 ~]# python es_cluster_status.py 集群运行正常