elasticsearch分片分配和路由配置

本文基于es7.3版本。
集群级别的分片分配配置,主要有下面几个:

cluster.routing.allocation.enable:启用或禁止特定种类分片的分配。有下面四种取值:

  • all - (default) Allows shard allocation for all kinds of shards.允许所有种类分片的分配,包括primary和replica。默认行为。
  • primaries - Allows shard allocation only for primary shards.仅允许primary分片的分配,节点重启后,replica的分片不恢复。
  • new_primaries - Allows shard allocation only for primary shards for new indices.仅允许新建索引的primary分片的分配。测试了一下,貌似与上面的区别不大。
  • none - No shard allocations of any kind are allowed for any indices.不允许任何种类分片的分配。新建的索引也不会分配primary和replica分片。

仅影响变化的分片。默认情况下,集群中某个节点失败后,此节点上的shard会恢复到其他节点上,设置非all值,会导致失败节点上shard不会恢复到其他节点。这在集群维护时非常有用,避免了节点重启时,分片在节点间移动的开销。需要注意的是,无论何种取值,节点重启后,如果此节点上存在某分片的replica copy,并且集群中没有此分片的primary copy,则此replica copy会恢复为primary copy。另外,即使在none下,新建索引不分配任何分片,但是集群重启后,仍然会分配primary分片。

cluster.routing.allocation.node_concurrent_incoming_recoveries:单个节点的入口并发恢复的分片数量。表示此节点作为恢复目标节点,分片在其他节点或者是由于Rebalance或者是由于其他节点失败,导致需要在此节点上恢复分片。默认是2个并发分片。

cluster.routing.allocation.node_concurrent_outgoing_recoveries:单个几点的出口并发恢复的分片数量。表示此节点作为恢复的源节点,由于Rebalance导致需要从此节点迁移部分分片到其他节点。默认是2个并发分片。

cluster.routing.allocation.node_concurrent_recoveries:用于快速设置上面两个参数,至于这个是总数两个平分,还是分别设置两个限制,目前未知。先留个坑,等我翻看源码再回来填。从下面的代码看,是分别设置。
 

//ThrottlingAllocationDecider.java
public static final int DEFAULT_CLUSTER_ROUTING_ALLOCATION_NODE_CONCURRENT_RECOVERIES = 2;
    public static final int DEFAULT_CLUSTER_ROUTING_ALLOCATION_NODE_INITIAL_PRIMARIES_RECOVERIES = 4;
    public static final String NAME = "throttling";
    public static final Setting CLUSTER_ROUTING_ALLOCATION_NODE_CONCURRENT_RECOVERIES_SETTING =
        new Setting<>("cluster.routing.allocation.node_concurrent_recoveries",
            Integer.toString(DEFAULT_CLUSTER_ROUTING_ALLOCATION_NODE_CONCURRENT_RECOVERIES),
            (s) -> Setting.parseInt(s, 0, "cluster.routing.allocation.node_concurrent_recoveries"),
            Property.Dynamic, Property.NodeScope);
    public static final Setting CLUSTER_ROUTING_ALLOCATION_NODE_INITIAL_PRIMARIES_RECOVERIES_SETTING =
        Setting.intSetting("cluster.routing.allocation.node_initial_primaries_recoveries",
            DEFAULT_CLUSTER_ROUTING_ALLOCATION_NODE_INITIAL_PRIMARIES_RECOVERIES, 0,
            Property.Dynamic, Property.NodeScope);
    public static final Setting CLUSTER_ROUTING_ALLOCATION_NODE_CONCURRENT_INCOMING_RECOVERIES_SETTING =
        new Setting<>("cluster.routing.allocation.node_concurrent_incoming_recoveries",
            CLUSTER_ROUTING_ALLOCATION_NODE_CONCURRENT_RECOVERIES_SETTING::getRaw,
            (s) -> Setting.parseInt(s, 0, "cluster.routing.allocation.node_concurrent_incoming_recoveries"),
            Property.Dynamic, Property.NodeScope);
    public static final Setting CLUSTER_ROUTING_ALLOCATION_NODE_CONCURRENT_OUTGOING_RECOVERIES_SETTING =
        new Setting<>("cluster.routing.allocation.node_concurrent_outgoing_recoveries",
            CLUSTER_ROUTING_ALLOCATION_NODE_CONCURRENT_RECOVERIES_SETTING::getRaw,
            (s) -> Setting.parseInt(s, 0, "cluster.routing.allocation.node_concurrent_outgoing_recoveries"),
            Property.Dynamic, Property.NodeScope);

cluster.routing.allocation.node_initial_primaries_recoveries:单个节点并行initial  primary恢复的并发数。指的是在节点restart后,本来属于此节点的primary shard进行的恢复。从本地磁盘进行的恢复。因此恢复较快。默认值为4。

cluster.routing.allocation.same_shard.host:设置是否检查同一台主机不能存放多个shard的copy。仅针对一个主机上运行同个集群的多个节点的情况。默认为false。

与恢复相关的其他参数:

indices.recovery.max_bytes_per_sec:单个几点进行恢复的inbound和outbound带宽的和。默认40mb。
indices.recovery.max_concurrent_file_chunks:每一个shard恢复可以并行发送的file chunk的数量。默认值为2。file chunk可理解为将文件内容分割为一个一个的chunk,类似操作系统的page的概念。oracle中共享池的内存分配单元就是按chunk来的,尽管各个chunk的大小不同。

集群级别的分片Rebalance配置:

cluster.routing.rebalance.enable:启用或禁止特定种类分片的Rebalance。有四种取值:

  • all - (default) Allows shard balancing for all kinds of shards. 启用所有类别分片的Rebalance。
  • primaries - Allows shard balancing only for primary shards.仅启用primary分片的Rebalance。
  • replicas - Allows shard balancing only for replica shards.仅启用replica分片的Rebalance。
  • none - No shard balancing of any kind are allowed for any indices.禁止分片Rebalance。

cluster.routing.allocation.allow_rebalance:指定何时可以进行分片Rebalance。有三种取值:

  • always - Always allow rebalancing. 总是允许。
  • indices_primaries_active - Only when all primaries in the cluster are allocated.仅仅当集群中所有primary分片都active的时候。
  • indices_all_active - (default) Only when all shards (primaries and replicas) in the cluster are allocated.仅仅当集群中所有分片都active。

cluster.routing.allocation.cluster_concurrent_rebalance:控制集群范围内并发Rebalance的分片数量。默认为2。仅仅影响由于分片分布不平衡产生的Rebalance操作。不影响因为分片分配过滤allocation filtering或者强制 awareness引起的分片迁徙。

shard rebalance heuristics设置参数:

cluster.routing.allocation.balance.shard:rebalance相关的分片因子,默认值为0.45f;
cluster.routing.allocation.balance.index:rebalance相关的索引因子,默认值为0.55f;与上面的配置参数一起,一起带入BalancedShardsAllocator类的静态内部类WeightFunction中进行计算。

//BalancedShardsAllocator.java
public static final Setting INDEX_BALANCE_FACTOR_SETTING =
        Setting.floatSetting("cluster.routing.allocation.balance.index", 0.55f, 0.0f, Property.Dynamic, Property.NodeScope);
    public static final Setting SHARD_BALANCE_FACTOR_SETTING =
        Setting.floatSetting("cluster.routing.allocation.balance.shard", 0.45f, 0.0f, Property.Dynamic, Property.NodeScope);
    public static final Setting THRESHOLD_SETTING =
        Setting.floatSetting("cluster.routing.allocation.balance.threshold", 1.0f, 0.0f,Property.Dynamic, Property.NodeScope);

@Inject
    public BalancedShardsAllocator(Settings settings, ClusterSettings clusterSettings) {
        setWeightFunction(INDEX_BALANCE_FACTOR_SETTING.get(settings), SHARD_BALANCE_FACTOR_SETTING.get(settings));
        setThreshold(THRESHOLD_SETTING.get(settings));
        clusterSettings.addSettingsUpdateConsumer(INDEX_BALANCE_FACTOR_SETTING, SHARD_BALANCE_FACTOR_SETTING, this::setWeightFunction);
        clusterSettings.addSettingsUpdateConsumer(THRESHOLD_SETTING, this::setThreshold);
    }

    private void setWeightFunction(float indexBalance, float shardBalanceFactor) {
        weightFunction = new WeightFunction(indexBalance, shardBalanceFactor);
    }


public static class WeightFunction {

        private final float indexBalance;
        private final float shardBalance;
        private final float theta0;
        private final float theta1;


        public WeightFunction(float indexBalance, float shardBalance) {
            float sum = indexBalance + shardBalance;
            if (sum <= 0.0f) {
                throw new IllegalArgumentException("Balance factors must sum to a value > 0 but was: " + sum);
            }
            theta0 = shardBalance / sum;
            theta1 = indexBalance / sum;
            this.indexBalance = indexBalance;
            this.shardBalance = shardBalance;
        }

        public float weight(Balancer balancer, ModelNode node, String index) {
            return weight(balancer, node, index, 0);
        }

        public float weightShardAdded(Balancer balancer, ModelNode node, String index) {
            return weight(balancer, node, index, 1);
        }

        public float weightShardRemoved(Balancer balancer, ModelNode node, String index) {
            return weight(balancer, node, index, -1);
        }

        private float weight(Balancer balancer, ModelNode node, String index, int numAdditionalShards) {
            final float weightShard = node.numShards() + numAdditionalShards - balancer.avgShardsPerNode();
            final float weightIndex = node.numShards(index) + numAdditionalShards - balancer.avgShardsPerNode(index);
            return theta0 * weightShard + theta1 * weightIndex;
        }
    }

cluster.routing.allocation.balance.threshold:阈值。当节点间权重差值大于这个值时,才会进行分片的reallocate。默认值为1.0f,增大这个值,将会降低reallocate的敏感度:
 

private static boolean lessThan(float delta, float threshold) {
            /* deltas close to the threshold are "rounded" to the threshold manually
               to prevent floating point problems if the delta is very close to the
               threshold ie. 1.000000002 which can trigger unnecessary balance actions*/
            return delta <= (threshold + 0.001f);
        }

除了上面集群级别设置之外,分片分配还收到基于磁盘的分片分配Disk-based shard allocation和基于awareness的分片分配Shard allocation awareness的影响。

es会考虑磁盘剩余空间的多少,来决定是否分配新的分片到节点或者将分片从节点中迁移到集群中其他节点。如下是相关参数设置:
cluster.routing.allocation.disk.threshold_enabled:设置是否启用基于磁盘的分配策略。默认为true。
cluster.routing.allocation.disk.watermark.low:设置磁盘使用空间的低水线限制。默认值为85%,表示磁盘使用空间达到85%后,除了新建索引的primary shards以及之前从未分配过的shards(unassigned shards),es将不会分配其他shard到此节点。设置为字节值,例如500mb,则表示磁盘剩余空间限制。
cluster.routing.allocation.disk.watermark.high设置磁盘使用空间的高水线限制。默认值为90%,表示磁盘使用空间达到90%后,es将会尝试将分片从此节点迁出。此影响针对所有类型的分片,包括unassigned shards。可以设置为字节值,例如250mb,表示磁盘剩余空间限制。
cluster.routing.allocation.disk.watermark.flood_stage:磁盘使用率的最高限制。默认值为95%,表示当磁盘使用率达到95%后,es将会设置所有在此节点上有分片存储的index为readonly并允许delete的(index.blocks.read_only_allow_delete)。当磁盘空间释放后,被设置为index.blocks.read_only_allow_delete的index,需要通过如下语句重置:
 

PUT /twitter/_settings
{
  "index.blocks.read_only_allow_delete": null
}

需要注意的是,以上三个参数不能混合使用百分比与字节值。要么三个都使用百分比,要么都使用字节值。并且百分比值需要递增,字节值需要递减。
cluster.info.update.interval:设置磁盘空间检查频率。默认为30s。
cluster.routing.allocation.disk.include_relocations:设置评估磁盘使用率时是否考虑正在reallocate中的分片的空间。默认值为true。这会导致磁盘使用率的评估偏高,假设reallocate的分片大小为1G,reallocate过程已完成了50%,那这个评估过程会多出这50%的空间占用。参数设置举例如下:
 

PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.disk.watermark.low": "100gb",
    "cluster.routing.allocation.disk.watermark.high": "50gb",
    "cluster.routing.allocation.disk.watermark.flood_stage": "10gb",
    "cluster.info.update.interval": "1m"
  }
}

基于awareness的分配是考虑了这样的想定:一个elasticsearch集群可能包含了若干服务器,这些服务器可能分布在若干机架或不同地理位置的机房或不同网络区域。基于容灾的考虑,可能会将同个索引的primary、replica分片分布在不同的机架上;或是基于就近获取的考虑,将get请求路由到与coordinator处于同个网络区域的节点。启用shard allocation awareness需要做如下设置:

1,在节点的elasticsearch.yml配置文件中设置节点属性,属性名称与值是任意指定的,假设我的集群中有3个节点,这里指定my_rack_id的属性:
node1:    node.attr.my_rack_id: rack1
node2:    node.attr.my_rack_id: rack1
node3:    node.attr.my_rack_id: rack2

2,在节点的elasticsearch.yml配置文件中,指定cluster.routing.allocation.awareness.attributes:
cluster.routing.allocation.awareness.attributes: my_rack_id
或者通过cluster update api指定:
 

PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.awareness.attributes":"my_rack_id"
  }
}

cluster.routing.allocation.awareness.attributes设置要特别小心,如果设置错误,比如设置了不存在的属性,会导致分片分配错误,新建的索引无法分配分片,已存在的索引replica copy无法分配,导致集群healthy变为yellow甚至red状态。


注意,这个的三个节点中,node1和node2设置了my_rack_id都为rack1,node3只是my_rack_id为rack2。

现在考虑这样一种情况,假设给每个索引设置3个分片,1个replica。那么此时,集群共有6个分片,平均每个节点3个。按照我上面的设置,那么必然node3会存放3个分片的各一个copy,也就是node3上会有3个分片,另外两个节点上随机分布3个节点。此时,整个集群时不平衡的,但是这是为了满足用户的设置。

情况在发展,you know, things going on 。这个时候node3挂掉了,如果其中一个节点丢失,那么此时,node3上的分片会迁移到另外两个节点,而忽略了awareness的容灾要求的设置。这个时候会变成node1,node2平分6个分片的情况。如果需要强制保留node3挂掉之前的效果,需要设置cluster.routing.allocation.awareness.force来让同一个my_rack_id区域的节点上,不会分配一个分片的多余一个copy。既在node3挂掉之后,node1、node2上只会分布所有分片repica group的其中一个copy,而不是所有。此时node1,node2上的copy会全部转变成primary copy,而没有replica copy。这个时候,索引的状态是yellow。如下:
 

PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.awareness.attributes":"my_rack_id",
    "cluster.routing.allocation.awareness.force.rack_id.values":"rack_one,rack_two"
  }
}

同样可以通过shard allocation filter过滤(include或者exclude)分片在节点上的分布,相关的设置参数有下面三个:
cluster.routing.allocation.include.{attribute}:Allocate shards to a node whose {attribute} has at least one of the comma-separated values。将shard分配到至少有一个attribute-value的节点上。{attribute}的值是一个逗号分隔的属性值列表;
cluster.routing.allocation.require.{attribute}:
Only allocate shards to a node whose {attribute} has all of the comma-separated values。将shard分配到拥有所有attribute-values的节点上。
cluster.routing.allocation.exclude.{attribute}:
Do not allocate shards to a node whose {attribute} has any of the comma-separated values。将shard从拥有任何attribute-value的节点上排除掉,移走。需要注意的是,这个并不是强制生效的。同时需要符合其他的设置,例如这里的node1和node2的rack_id为rack_one,node3的rack_id为rack_two,当设置awareness为rack_id时,primary 和replica shard不能都分布在同一个rack_id上。
{attribute}支持自定义属性及下面的内建属性:

_name

Match nodes by node names

_ip

Match nodes by IP addresses (the IP address associated with the hostname)

_host

Match nodes by hostnames

举例如下:
 

PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.exclude._ip": "192.168.2.*","192.168.1.*"
  }
}
PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.include._name": "node1","node2"
  }
}
PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.require.rack_id": "rack_one","rack_two"
  }
}

因为可以动态设置,这一功能通常使用在节点停机时,通过设置cluster.routing.allocation.exclude将分片从此节点移出到其他节点。

其他设置:
cluster.blocks.read_only:Make the whole cluster read only (indices do not accept write operations), metadata is not allowed to be modified (create or delete indices)。使整个集群只读。禁止包括document的CUD操作,以及索引元数据的修改(创建、删除索引);
cluster.blocks.read_only_allow_delete:Identical to cluster.blocks.read_only but allows to delete indices to free up resources。使集群只读,但是可进行删除操作以释放空间。
cluster.max_shards_per_node:Controls the number of shards allowed in the cluster per data node。集群中单个data节点允许的open的分片数量,closed的index所属的shard不计算在内。默认1000。如果集群中data node节点数固定的话,这个值也限定了整个集群中shard的数量,包括primary和replica的shard。在进行create index/restore snapshot/open index时,如果会导致节点上的分片数超过设置的话,会造成操作失败。同时因为更改设置导致分片上存在了多余设置的值,(例如节点上已存在900个shard,此时修改设置为500),会造成不能新建和open索引。
cluster.metadata.*:用户自定义设置。可以设置任何自定义配置和配置值。
cluster.indices.tombstones.size:索引墓碑大小设置,默认值500。静态设置。cluster state中维护了deleted的index的index_name、index_uuid、以及删除时间delete_date_in_millis信息。可通过如下dsl获取:

GET _cluster/state?filter_path=metadata.index-graveyard.tombstones

这个设置用于控制cluster state中维护deleted index的数量。当节点A从集群中离开后,此时集群中进行了删除索引的操作。操作成功后,此时集群中已经没有这个index的任何记录了。此后,节点A再次加入集群,由于es的特点,当节点重新加入集群时会import节点中有的,集群中没有的index,因此可能会re-import这些在节点A离开期间删除掉的索引,可能会抵消掉索引的删除操作。为了对抗这个影响带来的错误影响,cluster state中维护了deleted的索引信息。当集群频繁删除索引时,可调大此设置,维护过多的deleted index会造成cluster state膨胀,需要权衡。

持久化任务(persistent task)分配相关设置:
持久化任务创建后会存储在cluster state中,以保证集群重启后仍然存在。但是task需要分配到具体的node上去执行。
cluster.persistent_tasks.allocation.enable:启用或禁用持久化任务分配。取值为all、none:这个设置不影响已经存在的task,只影响新建或者需要重新分配节点的task(例如节点失去连接,资源不足等)。

  • all - (default) Allows persistent tasks to be assigned to nodes
  • none - No allocations are allowed for any type of persistent task

cluster.persistent_tasks.allocation.recheck_interval:task重新分配检查间隔。当节点失去连接后,节点上的task会自动由master分配到其它节点上执行,这是因为节点离开后,cluster state会变化,此时master是知道哪个节点上的task需要重新分配节点的。但是当节点因为资源不足需要将task分配到其他节点时,就需要master定期进行检查。默认值30s,最小值为10s。

Logger日志相关设置:这个放在日志相关中介绍。

你可能感兴趣的:(elasticsearch)