关于elasticsearch:ES数据扩容与索引设计

3次阅读

共计 4653 个字符,预计需要花费 12 分钟才能阅读完成。

数据扩容

当存储达到下限的时候,就须要思考扩容,个别有两种状况:

  1. 单分片的数据量达到了下限(文档数量下限 2^31 或者容量下限 50GB)
  2. 单节点数据容量超载,存储吃紧

第 1 种状况,需思考减少分片的数量,减小单个分片的数据存储量。
第 2 种状况,须要减少新节点,减小单节点上的数据量,缓解单节点数据容量吃紧的压力。当有新的节点退出集群,Elasticsearch 会主动挪动分片,且在分片挪动过程中,所有的索引搜寻申请均在失常运行。

Elasticsearch 在索引创立时须要指定分片数量,分片的数量一旦确定,就不能进行批改了,因为分片的数量是文档路由算法的计算元素:

shard = hash(routing) % number_of_primary_shards

所以,在索引创立之初,就须要依据业务理论状况,对分片的数量做一个预调配。提前预调配适合的分片数量。

海量分片

分片的预调配不是随便的,海量的分片数量给未来的扩容带来肯定的便当,然而会有大量的没有实际意义的分片存在,而每个分片也是有肯定的老本的:

  • 一个分片的底层即为一个 Lucene 索引,会耗费肯定文件句柄、内存、以及 CPU 运行。
  • 每一个搜寻申请都须要命中索引中的每一个分片,海量的分片性能比拟差。

所以要防止海量分片,应该依据业务倒退状况,对数据量做评估,来预调配更适合的分片数量。

容量评估

1 个分片太少而 1000 个又太多,那么怎么晓得须要多少分片?这是一个不好答复的问题。因为切实有太多相干的因素:应用的硬件、文档的大小和复杂度、文档的索引剖析形式、运行的查问类型、执行的聚合以及数据模型等。

单分片的容量评估:

  1. 基于筹备用于生产环境的硬件创立一个领有单个节点的集群。
  2. 创立一个和筹备用于生产环境雷同配置和分析器的索引,并设置只有一个分片无正本。
  3. 索引理论的文档(或者尽可能靠近理论)。
  4. 运行理论的查问和聚合(或者尽可能靠近理论)。

复制实在环境的应用形式并将数据全副压缩到单个分片上直到它“挂掉”。
“挂掉”的定义:申请无响应或者超出忍受。这样就能够定义好了单个分片的适合容量大小。

通常将 50GB 作为分片下限,但还是有必要进行理论场景评估,评估是为了找到一个界线,理论场景中,可能数据量未触达 50GB 下限,然而过了界线就曾经不太可能满足疾速响应速度需要了。

数据总量(GB)的评估:
通过下面单分片容量的评估能够计算出绝对精确的单个文档占用多大存储空间,而后依照业务将来某个阶段倒退的预期,评估进去总的文档数据量,计算出来数据总量(GB):
数据总量(GB)= 单文档存储空间 x 文档数据量

分片数量确定:
分片数 = 数据总量(GB)/ 单分片的容量
另外,联合每 1GB 内存对应最多 20 个分片

磁盘空间(GB)的评估:
磁盘空间(BG)= 数据总量(GB)x(正本数量 + 1)x 1.2

数据节点数量评估:
数据节点数量 = 向上取整(磁盘空间(GB)/ 单节点的数据量(GB))+ 1

扩容分类

减少分片

当分片容量快要达到下限,容量达到下限 50GB,或者文档数量达到下限,报错:number of documents in the index can not exceed 2147483519。就须要扩充分片数量以减小单个分片内的数据量。

大规模风行论坛都是从小论坛起步的,随着工夫的推移,论坛的数据量激增到超过了以后分片的下限,就须要扩增分片数量。

扩增分片的步骤:
第一步、为论坛创立一个新的索引 baking_new,并为其调配正当的分片数,能够满足以后和将来肯定预期的数据增长:

PUT /baking_new
{
  "settings": {"number_of_shards": 10}
}

第二步、将旧索引中的数据迁徙到新的索引 baking_new 中,能够通过 scroll 查问和 bulk API 来实现,当迁徙实现时,能够更新索引别名指向那个新的索引:

POST /_aliases
{
  "actions": [{ "remove": { "alias": "baking", "index": "baking_old"}},
    {"add":    { "alias": "baking", "index": "baking_new"}}
  ]
}

更新索引别名的操作是原子性的,就像在拨动一个开关。应用程序还是在与 baking API 交互并且对于它曾经指向 baking_new 索引毫无感知。

减少容量

数据节点上磁盘容量吃紧的时候,Elasticsearch 会有一些体现,例如:数据不能写入,不能查问最新的数据等。这背地可能是触发 Elasticsearch 的爱护机制:

  • ES cluster.routing.allocation.disk.watermark.low:管制磁盘应用的低水位线(watermark)默认值 85%,超过后,Elasticsearch 不会再为该节点调配分片;
  • ES cluster.routing.allocation.disk.watermark.high:管制高水位线,默认值 90%,超过后,将尝试将分片重定位到其余节点;
  • ES cluster.routing.allocation.disk.watermark.flood_stage:管制洪泛水位线。默认值 95%,超过后,Elasticsearch 集群将强制将所有索引都标记为只读。如需解除只读,只能手动将 index.blocks.read_only_allow_delete 改成 false。

磁盘的扩容绝对比拟容易,个别能够通过上面两种计划解决:减少磁盘容量或者减少数据节点。

索引设计

基于时序的数据

时序数据的特点:文档数量增长迅速,通常随工夫减速;文档简直不会更新,根本以最近文档为搜寻指标;随着时间推移,旧文档逐步失去价值。典型的时序数据如:日志。

应答时序数据的索引设计个别依照工夫范畴索引数据,比方:按年的索引 (logs_2022) 或按月的索引 (logs_2022-06)。如果数据量比拟大,甚至能够思考按天索引 (logs_2022_06_29)。

依照工夫范畴索引数据,能够比拟不便的在须要的时候进行分片调整,依照数据增长状况调整索引工夫范畴来适应以后需要。删除旧数据也非常简略:只须要删除旧的索引即可。

依照工夫范畴索引数据,索引的数量就不止一个,Elasticsearch 提供的别名,能够实现通明地在索引间切换。例如:当创立索引时,能够将 logs_current 指向以后索引来接管新的日志事件,当检索时,将 last_3_months 指向所有最近三个月的索引:

POST /_aliases
{
  "actions": [{ "add":    { "alias": "logs_current",  "index": "logs_2021-10"}}, 
    {"remove": { "alias": "logs_current",  "index": "logs_2021-09"}}, 
    {"add":    { "alias": "last_3_months", "index": "logs_2021-10"}}, 
    {"remove": { "alias": "last_3_months", "index": "logs_2021-07"}}  
  ]
}

最新的索引是 10 月,将 logs_current 由 9 月切换至 10 月。将 10 月增加到 last_3_months 并删掉 7 月。利用中应用的索引别名,这种变动对利用没有任何影响。

基于时序数据的索引创立应该是主动进行的,零碎主动创立索引就须要指定满足需要的 settings 设置和 mapping 定义。
索引模板能够用于管制何种设置(settings)该当被利用于新创建的索引:

PUT /_template/my_logs 
{
  "template": "logs_*", 
  "order":    1, 
  "settings": {"number_of_shards": 1},
  "mappings": {
    "_default_": { 
      "_all": {"enabled": false}
    }
  }
}

这个模板指定了所有名字以 logs- 为起始的索引的默认设置,不管它是手动还是主动创立的。

基于用户的数据

比拟典型的基于用户的数据:用户邮件。用户领有本人的邮箱,各用户的邮件数量有差别,一些用户有着比其用户更多的邮件数据,一些用户可能有比其余用户更多的搜寻次数。这种对索引的分片和正本数量以及应用状况的差异化需要,适宜应用“一个用户一个索引”的模式。每个用户只在本人的索引上进行读写,即便有查看所有用户邮件数据的场景,也能够通过搜寻所有用户的索引实现。

应用共享索引

一个例子可能是为一些拥仅有几千个邮箱账户的论坛提供搜寻服务。一些论坛可能有微小的流量,但大多数都很小。将一个有着单个分片的索引用于一个小规模论坛曾经是足够的了 —— 一个分片能够承载很多个论坛的数据。

这种场景,能够为这些小论坛应用一个大的共享的索引,将论坛标识索引进一个字段并且将它用作一个过滤器:

PUT /forums
{
  "settings": {"number_of_shards": 10},
  "mappings": {
    "post": {
      "properties": {
        "forum_id": { 
          "type":  "string",
          "index": "not_analyzed"
        }
      }
    }
  }
}

PUT /forums/post/1
{
  "forum_id": "baking", 
  "title":    "Easy recipe for ginger nuts",
  ...
}

当对单个论坛进行搜寻,能够把 forum_id 用作一个过滤器来针对单个论坛进行搜寻。这个过滤器能够排除索引中绝大部分的数据(属于其它论坛的数据),缓存(节点级别的缓存,节点上的所有分片共享此缓存,是 Lucene 层面的实现。缓存的是某个 filter 子查问语句在一个 segment 上的查问后果)会保障疾速的响应:

GET /forums/post/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {"title": "ginger nuts"}
      },
      "filter": {
        "term": {
          "forum_id": {"baking"}
        }
      }
    }
  }
}

能够进一步优化,将来自于同一个论坛的帖子能够简略地包容于单个分片,这样能够进步查问性能。依照文档的路由公式,能够将文档调配到一个指定分片:

shard = hash(routing) % number_of_primary_shards

routing 的值默认为文档的 _id,但能够笼罩它并且提供自定义的路由值,例如 forum_id。所有有着雷同 routing 值的文档都将被存储于雷同的分片:

PUT /forums/post/1?routing=baking 
{
  "forum_id": "baking", 
  "title":    "Easy recipe for ginger nuts",
  ...
}

搜寻一个指定论坛的帖子时,能够传递雷同的 routing 值来保障搜寻申请仅在存有咱们文档的分片上执行:

GET /forums/post/_search?routing=baking 
{
  "query": {
    "bool": {
      "must": {
        "match": {"title": "ginger nuts"}
      },
      "filter": {
        "term": { 
          "forum_id": {"baking"}
        }
      }
    }
  }
}

参考

https://www.elastic.co/cn/blo…
https://www.elastic.co/guide/…
https://www.elastic.co/guide/…
https://www.elastic.co/guide/…

正文完
 0