Elasticsearch Shard Allocation机制

背景

    Elasticsearch由一些Elasticsearch进程(Node)组成集群,用来存放索引(Index)。为了存放数据量很大的索引,Elasticsearch将Index切分成多个分片(Shard),在这些Shard里存放一个个的文档(document)。通过这一批shard组成一个完整的index。并且,每个Shard可以设置一定数量的副本(Replica),写入的文档同步给副本Shard,副本Shard可以提供查询功能,分摊系统的读负载。在主Shard所在Node(ES进程)挂掉后,可以提升一个副本Shard为主Shard,文档继续写在新的主Shard上,来提升系统的容灾能力。

    既然Shard和Replica有这样的好处,那么Elasticsearch是如何利用和管理这些Shard,让Shard在集群Node上合理的分配,比如,使副本Shard不和主Shard分配在一个Node上,避免容灾失效等。尽量把Shard分配给负载较轻的Node来均摊集群的压力,随着Shard分配,久而久之Shard在集群中会出现分配不均衡的情况,这又该如何才能做到均衡。这便是我们这次讨论的主题:Elasticsearch的分片分配和均衡机制。

触发条件

    先看下在什么场景下会触发Shard的Allocation:

    1、创建/删除一个Index;

    2、加入/离开一个Node;

    3、手动执行了Reroute命令;

    4、修改了Replica设置;

    当触发了Shard的Allocation,Allocation是如何决定将分片分配给哪个Node,Allocation的过程又是怎样的呢?

Decider

    Elasticsearch内有个一个AllocationDecider模块,定义了各种策略决定的四种结果:

四种决定结果

    从字面上便可以看出策略结果的含义。AllocationDecider策略有14种,每种策略是一个单独的实现,继承AllocationDecider类,重写了如下策略方法。如果不重写的话,默认是ALWAYS允许的。

每种策略需要重写的方法

MaxRetryAllocationDecider

    定义了Shard维度的Allocation策略,防止Shard在失败次数达到上限后继续分配,当Shard分配失败一次后,失败次数会加1,当Shard分配次数超过配置的最大次数时,这个策略生效,返回Decision.NO;可以通过配置”index.allocation.max_retries”,来设置分配的最大失败重试次数,默认是5次,当然系统分配到达重试次数后,可以手动分配分片,在URL后带上“?retry_failed”请求参数,可以尝试再次分配分片。

ReplicaAfterPrimaryActiveAllocationDecider

    定义了Shard维度的Allocation策略,在分配副本分片时,检查主分片的状态,防止主分片不是Active情况下分配副本分片。

RebalanceOnlyWhenActiveAllocationDecider

    定义了Rebalance策略,检查所有的主分片副本分片均是Active状态,才允许Rebalance操作。

ClusterRebalanceAllocationDecider

    定义了Rebalance策略,检查系统动态配置”cluster.routing.allocation.allow_rebalance”,可以配置这些选项:

    1、always - 不管如何都允许Rebalance。

    2、indices_primaries_active - 集群内所有主分片都已经分配后,允许Rebalance,也就是在集群是red状态不允许Rebalance。

    3、indices_all_active - (default) 所有的分片一分配才允许Rebalance,此时集群状态要是green状才行。

    4、默认配置是所有分片均已分配,也就是集群是green状态的才允许Rebalance操作。

ConcurrentRebalanceAllocationDecider

    定义了Rebalance策略,检查系统动态配置”cluster.routing.allocation.cluster_concurrent_rebalance”,表示集群同时允许进行rebalance操作的并发数量,默认是2。通过检查RoutingNodes类中维护的relocatingShards计数器,看是否超过系统配置的并发数,超过则不允许执行Rebalance操作。

EnableAllocationDecider

    定义了Allocate策略和Rebalance策略,策略会读取系统动态配置,配置分cluster级别和index级别,如果都配置了,index级别会覆盖cluster级别。 Allocate策略会读取cluster级别”cluster.routing.allocation.enable”配置,默认为all。

    1、all - (默认) 所有类型均允许allocation。

    2、primaries - 只允许allocation主分片。

    3、new_primaries - 只允许allocation 新创建index的主分片。

    4、none - 所有的分片都不允许allocation。

   如果当前index配置了“index.routing.allocation.enable”配置,将覆盖cluster级别配置,内容和上面的一样,也分四种类型Rebalance也会读取cluster级别“cluster.routing.rebalance.enable”配置,默认为all。

    1、all - (默认) 所有类型均允许rebalance。

    2、primaries - 只允许rebalance主分片。

    3、replicas - 只允许rebalance 副本分片。

    4、none - 所有的分片都不允许rebalance。

    index配置是”index.routing.rebalance.enable”,内容和上面的一样,也各分四种类型,含义一样。index级别配置后,会覆盖cluster级别配置。

NodeVersionAllocationDecider

    定义了Allocate策略,检查分片所在Node的版本是否高于目标Node的ES版本,如果高于,不允许allocation,这种策略的目的是避免目标Node无法适配高版本lucencn格式的文件,一般集群ES都是一致的,当集群在进行ES版本滚动升级时,会出现版本不一致的情况。

SnapshotInProgressAllocationDecider

    定义了Allocate策略,根据系统动态配置"cluster.routing.allocation.snapshot.relocation_enabled",决定snapshot期间是否允许allocation,由于snapshot只发生在主分片,所以只会限制主分片的allocation。

FilterAllocationDecider

    定义了Allocate策略,明确指定是否允许分片分配到指定Node上,分为index级别和cluster级别:

    1、index.routing.allocation.require.{attribute}

    2、index.routing.allocation.include{attribute}

    3、index.routing.allocation.exclude.{attribute}

    4、cluster.routing.allocation.require.{attribute}

    5、cluster.routing.allocation.include.{attribute}

    6、cluster.routing.allocation.exclude.{attribute}

    require表示必须分配到指定node,include表示可以分配到指定node,exclude表示不允许分配到指定Node,cluster的配置会覆盖index级别的配置,比如index include某个node,cluster exclude某个node,最后的结果是exclude某个node,上面{attribute}表示node的匹配方式有:

    1、_name 匹配node名称,多个node名称用逗号隔开。

    2、_ip 匹配node ip,多个ip用逗号隔开。

    3、_host 匹配node的host name 多个host name用逗号隔开。

    例如:PUT _cluster/settings{"transient":{"cluster.routing.allocation.exclude._ip":“10.0.0.1,10.0.0.2"}}

SameShardAllocationDecider

    定义了Allocate策略,避免将shard的不同类型(主shard,副本shard)分配到同一个node上,先检查已分配shard的NodeId是否和目标Node相同,相同肯定是不能分配。除了检查NodeId,为了避免分配到同一台机器的不同Node,会检查已分配shard的Node ip和hostname是否和目标Node相同,相同的话也是不允许分配的。

DiskThresholdDecider

    定义了Allocate策略,Remind策略。策略根据Node的磁盘剩余量来决定是否分配到该Node,以及检查Shard是否可以继续停留在当前Node上,会检查系统的动态配置"cluster.routing.allocation.disk.threshold_enabled"。默认“true”,如果为false,该策略允许分配分片。策略里还会用到另外两项系统动态配置:

    1、"cluster.routing.allocation.disk.watermark.low",默认值“85%”,达到这个值后,新索引的分片不会分配到这个Node上,也可以设置具体的byte数大小;

    2、"cluster.routing.allocation.disk.watermark.high",默认值“90%”,达到这个值后,会触发已分配到该节点的Shard Rebalance到其他Node上,配置项可以设置成具体的byte数大小。

ThrottlingAllocationDecider

    定义了Allocate策略,避免过多的Recoving Allocation,结合系统的动态配置,避免过多的Recoving任务导致该Node的负载过高,相关配置有:                1、"cluster.routing.allocation.node_initial_primaries_recoveries",当前Node在进行主分片恢复的数量,默认为四个,ES内部是通过统计主Shard是否处于初始化状态,并且不是出于从其他节点reloacting过来。

    2、"cluster.routing.allocation.node_concurrent_incoming_recoveries",默认是2,通常是其他Node上的副本shard恢复到该Node上。    

    3、"cluster.routing.allocation.node_concurrent_outgoing_recoveries",默认为2,通常是当前节点上的主节点恢复副本Shard到其他Node上。

    4、 "cluster.routing.allocation.node_concurrent_recoveries",用来直接配置上面incoming和outgoing两个值的和。

ShardsLimitAllocationDecider

    定义了Allocate策略

    1、"index.routing.allocation.total_shards_per_node",index级别的,表示这个index每个node的总共允许存在多少个shard,默认值是-1表示无穷多个;

    2、"cluster.routing.allocation.total_shards_per_node",cluster级别,表示集群范围内每个Node允许存在有多少个shard。默认值是-1表示无穷多个。

    如果目标Node的Shard数超过了配置的上限,则不允许分配Shard到该Node上。注意:index级别的配置会覆盖cluster级别的配置。

AwarenessAllocationDecider

    定义了Shard Allocation和Remind策略,类似机架感知。为了将主shard和副本shard跨机架/地区分配。通过设置系统动态配置"cluster.routing.allocation.awareness.attributes:rack_id",这里配置的感知类型为rack_id,相应的在Node配置上增加"node.attr.rack_id:rack_one"后,随后创建的index的主分片与副本分片会跨rack_id分配,避免机架网络设备故障导致整个集群不可用。相应的"cluster.routing.allocation.awareness.force.zone.values"会强制跨机架分配副本shard,如果分配完主分配,无可用其他机架分配副本分片,则副本分片不允许分配。

        所有的Allocation由上面14个策略组成,通过全部的策略该Node才是一个符合策略条件的目标Node,允许进行后面的分片分配过程。Shard Allocation,Shard Move,Shard Rebalance会利用这些Decision,再决定是否进行分片分配,分片迁移,分片均衡等操作。

完整过程

    Allocation

    Allocation的触发条件有以下几种:

Allocation触发条件

    额外说明一下,上表中的第3点,当节点离开后,在系统动态配置"index.unassigned.node_left.delayed_timeout"的超时时间过后,会触发”DelayedAllocationService.DelayedRerouteTask”,会延迟搬迁操作,这样设置是为了避免网络抖动导致节点短暂离开触发Shard搬迁。

    在分配分片时,会先后经过两个维度的验证:一个是Shard维度,一个是Node维度 其中Shard维度有两个Decider: MaxRetryAllocationDecider和ReplicaAfterPrimaryActiveAllocationDecider。接着挨个验证Node级别的分配策略,完成了未分配分片的分配步骤后,接下来会进行分片是否需要迁移的检查,也就是下面的:Move Shard。

Move Shard

    Move Shard过程会经过上面十四个策略实现的canRemain方法,判断当前Shard是否可以继续留在当前的Node上, 会经过:

    1、AwarenessAllocationDecider的canRemain方法,判断是否满足awareness配置的感知参数。

    2、DiskThresholdDecider的canRemain方法,判断当前Node是否超过高水位线。

    3、FilterAllocationDecider的canRemain方法,判断当前Node是否符合过滤策略。

    4、ShardsLimitAllocationDecider的方法,判断当前Node是否满足index维度和cluster维度的限制条件。

    只有上面策略全部通过,Shard才允许停留在当前Node上,否则会执行Relocating Shard过程。完成了分片搬迁,接下来会对集群中的分片均衡性做检查,ES内通过Balancer.balance方法实现,我们看看Rebalance过程是怎样的:

Rebalance

    Rebalance之前会经过上面十四个策略实现的canRebalance方法,全部通过才会执行后面的Rebalance过程:     Rebalance过程是通过调用balanceByWeights()方法,该方法会计算shard所在每个Node的Weight值 其中,weight的计算公式为:

    weightShard = node.numShards() + numAdditionalShards-balancer.avgShardsPerNode()

    weightIndex = node.numShards(index) + numAdditionalShards-balancer.avgShardsPerNode(index)

    weight = theta0 * weightShard + theta1 * weightIndex

    注: numAdditionalShards,一般为0,调用weightShardAdded,weightShardRemoved,分别为1和-1 theta0=“cluster.routing.allocation.balance.shard”系统动态配置项,默认值为0.45f theta1=“cluster.routing.allocation.balance.index”,系统动态配置项,默认值为0.55f。

总结

     这便是Shard分配,搬迁和平衡的全部过程,ElasticSearch通过这三个操作,保证Shard在Node之间均衡的分配,修改动态配置后完成Shard迁移,以及在集群运行过程中的自动均衡。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容