Elasticsearch数据分片分析

399 阅读7分钟

数据分片

单节点磁盘存储容量和带宽都是有限制的,要想支持水平扩展,就必须对数据进行分片存储。Elasticsearch的索引由多个分片组成,每个分片可以拥有多个副本。这些分片和副本通过一定的规则分布在不同的节点和磁盘上,以提高集群系统的存储能力和并发处理能力。

可以通过/_cat/indices api查看索引分片健康状态。索引health栏,三种颜色表示索引分片的三种状态:

  • 绿色:正常
  • 黄色:至少一个副本分片不可用
  • 红色:至少一个主分片不可用
GET /_cat/indices

health status index               uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   shakespeare         x0Vw3PZnRWa5-UWi-8xLhw   3   3     111396            0       56mb         18.6mb
green  open   logstash-2015.05.20 b2x-eBAeSOCWs2wCEPdr0g   1   1       4750            0       26mb           13mb
yellow open   user                jSTPcrNjSia7vWR0FpYy4Q   3   3          0            0      1.9kb           675b
yellow open   account             4lsRXuRvSTauO-O-SiHAJw   3   3       1000            0      1.1mb          413kb
green  open   logstash-2015.05.18 iXPiDOU5S5Ou9arVZLk7DQ   1   1       4631            0     25.3mb         12.6mb
green  open   logstash-2015.05.19 pOESFgzvTVunpRkX_EjlOA   1   1       4624            0     25.6mb         12.8mb

高并发

高并发场景下,大量并发请求打到协调节点上,协调节点会将这些请求负载均衡转发到集群中各个主副分片所在节点,充分利用每个节点每个磁盘的带宽,提高的集群吞吐量和响应速度。

很显然副本分片越多,集群吞吐能力就越高,集群的搜索性能也会越快。但是写入数据的时候,各个副本分片数据传输的系统开销就会越大。

image.png

高可用

副本为集群提供了高可用特性,当集群中某个节点宕机时,集群中其它副本会自动成为主分片继续提供服务。所以主副分片不能全部位于同一个节点上,否则就失去故障转移的作用。

image.png

当节点重新恢复后,之前的主分片变成副本分片。

image.png

集群级分片分配

分片分配发生在集群恢复的初始阶段、副本分配、rebalance时、以及节点加入或退出集群时。集群中的master节点主要职责之一就是决定如何分配分片,以及应该在何时去移动分片以重新平稳集群。

Elasticsearch提供了很多配置项来控制分片分配过程。

集群级别配置

cluster.routing.allocation.enable

  • all:允许allocation所有类型的分片
  • primaries:仅允许allocation主分片
  • new_primaries:仅允许allocation新索引的主分片
  • none:不允许allocation

分片rebalance配置

cluster.routing.rebalance.enable

  • all:允许rebalance所有类型的分片
  • primaries:仅允许rebalance主分片
  • replicas:仅允许rebalance副本分片
  • none:不允许rebalance

cluster.routing.allocation.allow_rebalance

  • always:总是允许rebalance
  • indices_primares_active:仅当集群中的所有主分片都被分配时
  • indices_all_active:(默认)仅当集群中的所有分片(主和副本)都被分配时。

分配感知

下面模拟一下机架感知,一个三个节点的集群,在每个节点上的elasticsearch.yml文件添加配置:

cluster.routing.allocation.awareness.attributes: rack_id

这个配置表示rack_id属性会作为分片分配感知条件。如果我们将node-1设置为rack1

node.attr.rack_id: rack1

node-2和node-3设置为rack2.

node.attr.rack_id: rack2

上面的配置模拟三个节点分处于两个机架场景:

image.png

此时如果索引为一个主分片一个副本,其分配如下图所示,主分片在rack2上,rack1上分配一个副本分片。 image.png

如果索引为两个主分片,每个主分片一个副本,其分配如下图所示,主分片在rack2,rack1上分配两个副本分片。 image.png

如果索引为三个主分片,每个主分片一个副本,其分配如下图所示,主分片在rack2,rack1上分配三个副本分片。 image.png

由此可以看出分片分配器会保证主分片和副本分片不会位于同一个机架上,如果某个机架停电、断网或出现其它故障,别一个机架的分片仍然能持续提供服务。

强制感知

为了防止某个节点负载过重,可以设置cluster.routing.allocation.awareness.force,以便在另一个位置的节点可用之前不分配副本。

同上配置,三个节点,两个机架。

image.png

如果停掉node-1,分片会被重新分配到rack2的节点node-2和node-3上。 image.png

此时可以设置如下,这样集群不会重新分片,直到node-1节点重新恢复,恢复原有分片。

cluster.routing.allocation.awareness.force.rack_id.values: rack1,rack2

image.png

集群级别分片过虑

分片分配过滤器可以基于自定义节点属性或内置的_name、_host_ip、_publish_ip、_ip、_host、_id和_tier属性。

集群级分片分配过滤最常见的应用场景是节点删除时。为了在关闭节点之前将分片移出节点,你可以创建一个过滤器,根据节点的IP地址排除该节点:

PUT _cluster/settings
{
  "persistent" : {
    "cluster.routing.allocation.exclude._ip" : "10.0.0.1"
  }
}

以下配置项都可以是逗号分隔的集合配置。

  • cluster.routing.allocation.include.{attribute}:分配至包含集合中任一属性的节点上。
  • cluster.routing.allocation.require.{attribute}:仅分配包含集合中全部属性的节点
  • cluster.routing.allocation.exclude.{attribute}:不分配包含集合中任一属性值的节点

索引级分片分配

分片分配过滤

控制将哪些分片分配给哪些节点。 以下配置项都可以是逗号分隔的集合配置。

  • cluster.routing.allocation.include.{attribute}:分配至包含集合中任一属性的节点上。
  • cluster.routing.allocation.require.{attribute}:仅分配包含集合中全部属性的节点
  • cluster.routing.allocation.exclude.{attribute}:不分配包含集合中任一属性值的节点

索引分配设置支持以下内置属性:

  • _name:根据节点名称匹配节点
  • _host_ip:根据主机IP地址(与主机名相关联的IP)匹配节点
  • _publish_ip:根据发布IP地址匹配节点
  • _ip:匹配_host_ip或_publish_ip
  • _host:根据主机名匹配节点
  • _id:根据节点id匹配节点
  • _tier:根据节点的数据层(冷热分层)角色匹配节点。

延迟分配

当一个节点下线退出集群时,主节点会进行分片分配调度。

  • 将一个分片副本提升为主分片,以替换节点上的所有主分片
  • 在集群中分配分片副本以替换丢失的副本
  • 在集群剩余节点上rebalance所有分片

这些操作用来尽快恢复分片数量以保障集群不会受数据丢失的影响。但这些重组分片的操作会给集群带来较大负荷,很多时候丢失的节点都会在较短的时间内恢复,所以这些额外的开销并不是必要的。

由于节点离开而未分配的副本碎片的分配可以通过 index.unassigned.node_left.delayed_timeout动态设置来延迟,该设置默认值为1m。

PUT _all/_settings
{
  "settings": {
    "index.unassigned.node_left.delayed_timeout": "5m"
  }
}

有了这个机制,假设节点A下线,此时主节点仍然会提升副本分片成为主分片以接替节点A上的主分片,但是节点A上其它副本分片不会立即重新分配,而记录为未分配状态,集群状态为黄色,因为有未分配的副本分片。如果节点A在到期时间之前重新上线,那丢失的副本会立即重新分配到节点A.

每个节点的分片总数

集群级分片分配器试图将单个索引的分片分散到尽可能多的节点上。但根据的分片和索引的数量以及它们的大小,可能并不总是能够均匀地分布。这个时候可以对节点上分片总数进行限制,从而使得分片尽可能均匀分布。

以下动态设置允许指定每个节点允许的单个索引的分片总数的限制:

index.routing.allocation.total_shards_per_node

将分配给单个节点的分片(副本和主)的最大数量。默认为无限制。

你也可以限制一个节点可以拥有的分片数量,而不管索引是什么:

cluster.routing.allocation.total_shards_per_node

分配给每个节点的主分片和副本分片的最大数量。默认为-1(无限)。

数据层分配:

可以使用索引级别的_tier_preference设置来控制将索引分配到哪个数据层。

index.routing.allocation.include._tier_preference

此设置对应于数据节点角色:

  • data_content
  • data_hot
  • data_warm
  • data_cold
  • data_frozen

比如如下设置,分片分配器会优先向data_hot层节点分配,如果没有满足条件的节点,则尝试分配至data_warm层的节点,最后由data_cold层节点进行兜底。

{
     "index.routing.allocation.include._tier_preference": "data_hot,data_warm,data_cold" 
}

关于分片分配更多细节参考官网:

集群级分片分配:www.elastic.co/guide/en/el…

索引级分片分配:www.elastic.co/guide/en/el…