前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Elasticsearch 存算分离技术浅析与最佳实践

Elasticsearch 存算分离技术浅析与最佳实践

原创
作者头像
岳涛
修改2023-07-14 10:42:43
2.4K9
修改2023-07-14 10:42:43
举报
文章被收录于专栏:大数据生态大数据生态

说明

本文描述问题及解决方法同样适用于 腾讯云 Elasticsearch Service(ES)

另外使用到:对象存储(Cloud Object Storage,COS)

环境配置

Elasticsearch 版本:7.14.2

背景

ES作为大数据技术栈的一员,也是当下比较流行的搜索引擎,不过随着数据量日益增长,存储成本也变得越来越高昂。比如像有些客户比较重要的日志场景,或者电商数据等,这些数据可能都需要长期保留。那么这时候存储降本的方案就显得尤为重要,今天就和大家分享一下ES的存算分离方案。

一、快照备份原理浅析

ES的存算分离技术实现,是基于快照备份的功能,在快照的基础之上增加了可搜索的能力。在介绍可搜索快照之前,我们简单复习一下ES快照的基本知识。

  • ES 的底层使用了 Lucene,ES 快照实际上是对 Lucene 文件的一次备份;
  • ES 快照包含了当前时间点需要快照索引相关的全部文件,快照支持全量/增量(差异)恢复;
  • 增量快照只存储增量和差异的部分,重叠部分会直接引用历史快照的文件;
  • 快照删除时仅删除没有被任何快照引用的文件。

1. 全量备份

首次快照备份为全量备份,这里我们将快照名称记为 “快照A”。

与快照 A 关联的文件列表为:1、2、3、4。

2. 增量 / 差异备份

然后我们对ES中的数据做了一些修改,导致Lucene文件发生了一些变化。由于Lucene索引段文件的特性,只会新增和删除而不会修改,因此此时的Lucene中文件可能如下图所示。然后进行第二次快照,我们将快照名称记为 “快照 B”。

与快照 B 关联的文件列表为:2、3、4、5。

3. 删除历史快照

最后我们删除了快照 A。

与快照 A 关联的文件是:1、2、3、4;

与快照 B 关联的文件是:2、3、4、5;

所以删除快照 A时,只有文件 1 可以被删除。

Q&A

1、删除历史快照会对增量快照造成影响吗?

答:不会,以上快照逻辑为例,删除历史快照只会清理不被任何快照关联的文件,每个完整的快照都能还原当时的全量数据。

2、恢复完整数据的时候要如何恢复?需要从第一个快照开始一个一个恢复吗?

答:不需要,只需恢复指定时间点的快照即可,因为每个快照都保留了那个时间点的全量数据。

二、可搜索快照技术概述

  • 支持搜索存储在快照中的近乎无限量的冷冻数据(如一年甚至更长)
  • 冷数据存储在 COS 中,成本大幅缩减。
  • 冷冻数据初次查询频率不高,接受较长查询时延。查过的数据通过 cache 提供与热数据一致的查询速度。

DataTier 模型

工作原理

全量挂载(Fully mounted index)

全量挂载就是将快照中索引的数据在 ES 集群节点上全量保留一份,当搜索全量挂载的可搜索快照索引时,搜索原理和性能和普通索引相差不大。相比普通索引的优势在于,当其中一个分片出现损坏时,可搜索快照索引会自动从快照中拉取数据在其他节点上进行恢复,尤其是在集群中没有副本的情况下,普通模式是集群直接 red,如果需要恢复,则必须手动从快照中进行恢复,在恢复前还需要先将该red的索引删除,而通过 mount 挂载下来的索引,则自动从快照中恢复损坏的分片。

部分挂载(Partially mounted index)

部分挂载并不将快照中的索引数据mount到集群节点上,而是只将索引的元数据信息保存以索引和分片的形式保留在节点上。部分挂载的分片只会分配在 Frozen 层。因此集群中 Frozen 层节点不存储快照数据,只存储索引分片的元数据信息,原始数据存储在COS 的快照仓库中。

如下 API 样例所示,其中 storage 就是索引的挂载类型:full_copy 是全量挂载,而 shared_cache 则为部分挂载。

代码语言:json
复制
POST _snapshot/ss_repository/ss_daemonyue/_mount?wait_for_completion=true&storage=full_copy
{
  "index": "daemonyue-2023.06.01-000001", 
  "renamed_index": "daemonyue-2023.06.01-000001_from_cos", 
  "index_settings": { 
    "index.number_of_replicas": 0
  },
  "ignore_index_settings": [ "index.refresh_interval" ] 
}
代码语言:json
复制
POST _snapshot/ss_repository/ss_daemonyue/_mount?wait_for_completion=true&storage=shared_cache
{
  "index": "daemonyue-2023.06.01-000001", 
  "renamed_index": "daemonyue-2023.06.01-000001_from_cos", 
  "index_settings": { 
    "index.number_of_replicas": 0
  },
  "ignore_index_settings": [ "index.refresh_interval" ] 
}
  • 查询部分挂载的可搜索快照索引会从快照中进行拉取并加载在 Frozen 层节点本地缓存中,下次查询类似数据时可以直接从本地返回。
  • 如果集群中没有配置专用 Frozen 节点,则必须在节点的配置文件中配置 xpack.searchable.snapshot.shared_cache.size参数来设置每个节点中需要为共享缓存保留的存储空间。

Frozen 节点上的数据查询速度比全量挂载或普通索引慢很多,为了解决这个问题,Elasticsearch 提供了 Async Search(异步搜索)API,该 API 在执行时不会立即返回查询结果,而是返回一个请求 ID,随后异步准备数据。当数据准备就绪后,可以通过请求 ID 获取相应的数据。

代码语言:json
复制
POST sale*/_async_search?size=0
{
  "sort": [
    { "date": { "order": "asc" } }
  ],
  "aggs": {
    "sale_date": {
      "date_histogram": { 
        "field": "date",
        "calendar_interval": "1d"
      }
    }
  }
}

GET _async_search/status/{id} # 获取异步搜索的状态
GET _async_search/{id}        # 获取异步搜索的执行结果
DELETE _async_search/{id}     # 删除异步搜索

三、可搜索快照最佳实践

下面我们将演示可搜索快照实现的整条链路:

1)我们模拟业务持续向集群中写入数据,新生索引默认分布在热节点。索引配置了 rollover,在达到一定时间或一定大小后开始在热节点中滚动;

2)滚动完成后 7 天,开始迁移到冷节点上,并且执行 COS 备份;

3)备份完成后全量挂载(full_copy)到集群中,并删除集群中冷节点的索引;

4)全量挂载后 30 天,再将索引转为部分挂载(shared_cache),索引分片最终分配在冻结层。

注册快照仓库

首先我们使用腾讯云 COS 作为 ES 的快照仓库,仓库的名称为 ss_repository,同时指定了仓库路径为 searchable-snapshot。

仓库请求的完整API:

代码语言:json
复制
POST _snapshot/ss_repository
{
  "type": "cos", 
  "settings": { 
    "app_id": "1253240642",
    "access_key_id": "XXXXXn46uTmrhHdkbDm7C3f1XxxxXXxxxxxx",
    "access_key_secret": "XXXXXFAtMYWFjxveGmIekaXxxxXxXXXx",
    "bucket": "es-cos-dy",
    "region": "ap-guangzhou",
    "compress": true,
    "chunk_size": "500mb",
    "base_path": "searchable-snapshot"
  }
}

配置索引生命周期

配置ILM的目的是为了实现索引生命周期的自动化,其中包括:

  • 索引热阶段 / 索引滚动
  • 索引数据降冷 / 可搜索快照 fully mount
  • 可搜索快照 partial mount

下面的索引生命周期(ILM)API中,我们分别定义了索引的 hot / cold / frozen 三个阶段。

  • Hot 阶段为索引热数据阶段,也是索引滚动的阶段;
  • Cold 阶段和传统降冷有一定区别,冷数据是先备份到 COS 快照里,然后再将快照的数据全量挂载到本地;
  • Frozen 阶段与 cold 阶段类似,同样是将快照挂载到本地,区别是 frozen 没有直接挂载数据,而是只将索引的元数据相关信息保存在 frozen 层。
代码语言:json
复制
PUT _ilm/policy/ilm-ss
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_age": "1d",
            "max_primary_shard_size": "10gb"
           },
           "set_priority": {
             "priority": 100
           }
         }
       },
       "cold": {
         "min_age": "7d",
         "actions": {
           "searchable_snapshot": {
             "snapshot_repository": "ss_repository",
             "force_merge_index": true
           },
           "set_priority": {
             "priority": 0
           },
           "allocate": {
             "number_of_replicas": 0
           }
         }
       },
       "frozen": {
         "min_age": "30d",
         "actions": {
           "searchable_snapshot": {
             "snapshot_repository": "ss_repository",
             "force_merge_index": true
           }
         }
       }
     }
   }
}

可视化配置索引生命周期(热阶段)

除了API,kibana 也提供可视化配置 ILM。下面展示的为热阶段(滚动阶段)的ILM策略。

我们关闭了默推荐的滚动策略,并且希望数据在写入的过程,当分片大小达到 20gb 或者当索引存在的时间达到 1 天时,索引发生滚动,生成一个新的索引,这样就可以控制单个索引的数据规模在一个可控范围内。

可视化配置索引生命周期(冷阶段)

在冷阶段我们开启了全量挂载( full mount ),选择了前面创建好的快照仓库,定义了冷阶段的触发时间,并调整了冷阶段的索引副本为 0。该阶段会将数据先备份到 COS 仓库,然后将快照索引全量挂载到冷节点并切换别名,最后删除热索引。

可视化配置索引生命周期(冷冻阶段)

冷冻阶段只需配置快照仓库和触发时间即可,该阶段会将快照索引部分挂载到冷冻层并切换别名,然后删除冷索引。

值得注意的是,部分挂载( partial mount)只会先保存索引的元数据相关信息,当查询冷冻数据时,ES会从快照中读取数据返回给客户端,并将查询缓存保存在冷冻层,用于加速查询。ES 有缓存淘汰策略,会定期清理不经常查询的缓存数据以释放空间。

配置索引模板

ILM配置完成之后,还需要配置索引模板。

模版名称为 ss_template,在索引模版中定义了匹配模式为 "ss-*" 开头的索引,并指定刚才我们创建好的 ILM 策略(ilm-ss)以及索引 rollover 的别名(ss)。

另外还配置了分片分配策略( data_hot ),索引的刷新落盘间隔(30s),索引的分片数量(3),以及索引的副本数(1)。

代码语言:json
复制
PUT _template/ss_template
{
  "order": 100,
  "index_patterns": [
    "ss-*"
  ],
  "settings": {
    "index": {
      "lifecycle": {
        "name": "ilm-ss",
        "rollover_alias": "ss"
      },
      "routing": {
        "allocation": {
          "include": {
            "_tier_preference": "data_hot"
          }
        }
      },
      "refresh_interval": "30s",
      "number_of_shards": "3",
      "number_of_replicas": "1"
    }
  }
}

可视化配置索引模板

索引模板也可以通过 kibana 可视化配置:

创建初始索引

ILM 和 索引模板配置完成之后,我们就可以创建初始索引了,使用 <now+8h> 可以在索引名称里加上日期。索引创建完成后索引名称上包含了当前的日期,且后缀从标准的 rollover 000001 开始,索引的分片为3,副本为1。

代码语言:json
复制
PUT <ss-{now+8h}-000001>
{
  "aliases": {
    "ss": {
      "is_write_index": true
    }
  }
}

模拟业务写入(热阶段)

索引有 7 个字段,分别为:

  • @timestamp
  • name
  • age
  • gender
  • address
  • job
  • description

模拟业务写入(冷阶段)

当热数据达到 rollover 条件之后,滚动后的历史索引会进入下一个阶段:cold / full mount。

这个阶段会先将热数据进行快照,当快照完成之后,ES会新建一个 restored- 开头的冷索引,并将快照全量挂载在这个索引上,然后删除热索引。整个过程采用的是别名替换的方式,做到业务的平滑切换无感知。

冷数据层数据如下,full mount 冷数据阶段会自动生成前缀为 restored- 的冷索引。

模拟业务写入(冷冻阶段)

当热数据达到 cold 条件之后,降冷后的历史索引会进入下一个阶段:frozen / partial mount。

下面为索引进入到冷冻状态的展示,partial mount 冷冻阶段会自动生成前缀为 partial- 的冷索引。

数据查询

热阶段 -> 冷阶段 -> 冷冻阶段,我们走完了索引 ILM 的一生。

接下来我们使用 DSL 查询语句来对数据进行检索,分别比较一下热数据和冷冻数据的查询性能。

我们以下面这条 DSL 为例,分别对热索引和冷冻索引进行查询,并做一个简单的count聚合。

代码语言:json
复制
POST ss-2023.06.09-000010/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "Joanne Smith"
          }
        },
        {
          "range": {
            "age": {
              "gte": 37
            }
          }
        },
        {
          "match": {
            "gender": "male"
          }
        },
        {
          "match": {
            "job": "Ship broker"
          }
        }
      ],
      "should": [
        {
          "match": {
            "address": "4985 Patterson Streets"
          }
        },
        {
          "match": {
            "description": "Government question white list"
          }
        }
      ]
    }
  },
  "_source": [
    "name",
    "age",
    "gender",
    "job",
    "description"
  ],
  "aggs": {
    "name_counts": {
      "terms": {
        "field": "name"
      }
    }
  }
}

热数据查询

热数据查询耗时为 547ms

冷冻数据查询

冷冻数据查询耗时为 2733ms

通过前面的 DSL 查询测试,可以看出热数据和冷冻数据的性能差距还是比较大的。主要的差距在于构建缓存的时间,当冷冻数据完成缓存构建之后,可以和热节点一样提供毫秒级查询。

我们也可以使用 kibana discover 来对数据进行检索,可以更直观的展示数据。

四、可搜索快照常见问题

Q&A

1、如何区分普通索引和可搜索快照索引?

答:使用 ILM 实现的可搜索快照,可以通过索引名称区分,前缀为 restored- 的索引为冷快照索引,前缀为 partial- 的索引为冷冻快照索引。

2、如果冷冻数据发生频繁查询,frozen 节点的磁盘会不会不够存储?

答:可搜索快照的缓存策略有自动淘汰机制,当缓存区空间不足时,会淘汰最近最少使用的缓存,另外可搜索快照的缓存状态也支持手动查看以及手动清理。

3、如果节点因为 OOM 或者机器宕机等原因发生重启,服务重新上线后,可搜索快照需要人工干预重新挂载吗?

答:节点重启上线后,可搜索快照也会像普通索引一样正常恢复,无需人工干预。

4、可搜索快照冷冻层的存储介质会影响查询效率吗?

答:对于冷冻层的磁盘,推荐使用 SSD,可以加速查询。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 说明
  • 环境配置
  • 背景
  • 一、快照备份原理浅析
    • 1. 全量备份
      • 2. 增量 / 差异备份
        • 3. 删除历史快照
          • Q&A
          • 二、可搜索快照技术概述
            • DataTier 模型
              • 工作原理
                • 全量挂载(Fully mounted index)
                • 部分挂载(Partially mounted index)
            • 三、可搜索快照最佳实践
              • 注册快照仓库
                • 配置索引生命周期
                  • 配置索引模板
                    • 创建初始索引
                      • 模拟业务写入(热阶段)
                        • 模拟业务写入(冷阶段)
                          • 模拟业务写入(冷冻阶段)
                            • 数据查询
                              • 热数据查询
                              • 冷冻数据查询
                          • 四、可搜索快照常见问题
                            • Q&A
                            相关产品与服务
                            Elasticsearch Service
                            腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档