Elasticsearch & AWS S3 备份

我们的系统中大部分都是时序数据,一些数据被清洗后,过期的数据意义已经不大,但是保不齐哪天需要重新清洗或者查阅历史,所以准备将 Indices 的内容备份在 AWS S3 当中。

虽然我们采用 Elastic Cloud 的服务,他每 30 分钟会自动全盘用 Elastic 自己的 S3 系统备份一次,但是他只保留最近 48 小时左右的数据,并且他做的是整个 ES 系统的全量备份。这个备份的目标更像一个灾备的状态,而不是我们需要的历史数据备份。所以我们准备从 Elastic Cloud 每天备份过期数据到自己的 AWS S3 当中。

基本概念

使用 Elasticsearch Snapshot 时需要有一些基本概念澄清,他不是拿指定的 Indices 文件做个压缩包丢在 S3 完事,他是有控制的。

snapshot 结构

Elasticsearch 的 snapshot 是由其自身控制的,整个系统保持了一个如下的从下到上的控制结构,他们具备包含关系:

snapshot --> repository --> single snapshot --> indices

  • snapshot
    这里将 snapshot 单独列出,是因为在 Elasticsearch 中 snapshot 独占性工作的,他更像是一个管道,任何一个 repository 在工作的时候是排他的,虽然他并不阻止 indices 的写入。
  • repository
    这个仓库应该是一组 snapshot 备份的集合,也可以认为是一个目标的选择。在一个 Elasticsearch 系统中你可以根据自己的意愿设定不同的 Repository,在我们使用的 Elastic Cloud 服务中,官方会自动提供一个他们 30 分钟自动全量备份的 Repository。
GET _snapshot/_all
{
  "found-snapshots": {
    "type": "s3",
    "settings": {
      "bucket": "PRIVATE-UUID",
      "base_path": "snapshots/PRIVATE-UUID",
      "server_side_encryption": "true",
      "region": "us-west-2",
      "compress": "true"
    }
  }
}
  • Single snapshot
    这个指的是在 Repository 中我们进行的每个备份内容,他更像一个集合,包含了这次 snapshot 中所有的 Indices。
  • Indices
    在一个 snapshot 当中,可以包含多个 Indices 文件内容。他可以在执行 snapshot 的时候用 pattern 识别,也可以一个一个的指定。

S3 插件

如果要想让 Elasticsearch 备份到 S3 当中需要单独安装一个插件 S3 Repository Plugin,在我们使用的 Elastic Cloud 当中这个插件已经默认安装了。我们并不知道安装中是否会遇到什么阻碍。

Snapshot 配置

在 Elasticsearch 中进行 snapshot 操作官方文档已经说得非常清楚了,整体结构和控制并不复杂。

Repository

在正常执行 _snapshot 以前,需要先建立好自己的 Repository。具体操作可以参考 S3 Repository Plugin 完成 S3 的配置操作。

其中 AWS 的账户口令控制不必非要写在系统的 YAML 配置文件中,直接在创建 Repository 的设定用起来会更加灵活。获取 Repository 的时候,系统会自动屏蔽账户信息部分。

AWS IAM

这个稍微复杂一点,也可能是我们对 AWS IAM 并不熟悉。按照 Elastic 官方给出的 Recommanded S3 Permissions 直接配置即可。

这里他需要获取到 AWS S3 Bucket 的列表权限,因为他会放置自己的一些控制文件进入,并且还需要进行比对操作。

如果你需要备份不同的 ES 系统到一个 AWS S3 Bucket 一定要分配到不同的目录当中,因为 Elasticsearch 的那些控制文件会导致他们之间冲突。这里可以参考这个 S3 Permissions 的说明中后面一个 IAM 配置说明即可。

snapshot 操作

当 Repository 做好后,就可以直接执行 _snapshot 操作了。具体的操作方法可以参考 Snapshot and Restore 部分的说明了。指令比 _search 不知道简单多少倍 🙄

如果你执行的时候,其他的 snapshot 正在执行,你会得到一个 503: Service Unavailable 的错误信息。这就是上面说的 snapshot 执行的独占性,哪怕不同的 repository 之间也不能并行。

S3 中文件的作用

Elasticsearch 在 S3 中创建 snapshot 的时候,会形成一些辅助文件,帮他管理 snapshot 内容。

最坑爹是 Elasticsearch 并不在自己的 Indices 当中创建备份信息,而是将所有这些信息都放在了 S3 当中。当然熟悉后也明白,这么做的好处是,可以让另一个 ES 系统通过同样的 Repository 配置读取这些 S3 中的内容。

文件目录结构

下面是我们专门保存 Elasticsearch Snapshot 的 S3 Bucket 中的文件结构,"-" 表示这是一个文件,"+" 表示这是一个目录。

S3 Bucket
+ Directory for each ES
  - incompatible-snapshots
  - index-A
  - index-B
  - index.latest
  - meta-SNAPUUID.dat
  - snap-SNAPUUID.dat
  + NO NAMED DIR
    + indices
      + INDEXUUID
        - meta-SNAPUUID.dat
        + 0
          - __*
          - index-0
          - snap-SNAPUUID.dat

其中目录的情况如下,对于那些文件后面专门说。

  • Directory for each ES
    我们有多个 ES 系统,他们的内容全部备份在一个 AWS S3 当中,所以我们每个 ES 系统在这个 S3 Bucket 中有一个独立的目录保存所有的 snapshot。
  • NO NAMED DIR
    这是一个没有显性名称的目录,我猜官方的意思就是“别动这里”,后面的实验证明,确实别动这里,动了麻烦会有点大。
  • indices & INDEXUUID
    就是一个固定目录,里面装的是所有备份了的 Index,每个 Index 在备份的时候,系统会重新定义一个 UUID 标记这个 Index。这里不用 Index 本身的 UUID 应该是考虑到在其他的 ES 系统恢复时不造成混乱。
  • 0
    这也是一个固定的目录,本来以为多个分片会有多个目录,但是我们实验系统中多个主分片的 Index 在这里也是一个目录。
    大家可以验一下,如果有错误请指正。要不设定这么一级目录实在想不明白 Elastic 的研发是怎么考虑的。

UUID 的使用

在 snapshot 执行的时候,他会给每个 snapshot 生成一个 UUID,我们叫他 SNAPUUID。

在 S3 文件系统说明中会在每个 meta-* & snap-* 的部分使用这个 SNAPUUID 生成相关文件。这些文件都是二进制文件,应该是内部的一些 mapping 内容。

并且他会给每个被 snapshot 的 Index 文件生成一个 UUID,我们叫他 INDEXUUID。虽然在 ES 系统中,每个 Index 都有自己的 UUID,但是在这里保存的时候,snapshot 并没有复制这个 UUID,而是给每个 Index 起了新的 UUID。这样的方式应该可以有效的防止冲突问题。

这些 INDEXUUID 在 <indices> 目录中标记了每个独立的 Index,其中保存这个 Index 所有数据内容。这些 UUID 都在 <index-A> & <index-B> 中有重要作用,稍后再说。

数据文件

在 <indices.INDEXUUID.0> 目录当中,所有这个 Index 的数据文件都在这里了。数据文件采用 "__" 开头,后面使用 [0-9, a-z] 进行顺序编号。在我们的系统中单个文件好像被限制在 1GB 大小,如果一个 "__" 数据文件超过这个限制,会形成类似 "__1q.part0" & "__1q.part1" 这样的分片文件。

这些数据文件的数目多少应该跟 Index 在系统中的 Segment 数量有关系,但是并不是 Segment 有多少这里就有多少。我们并没有通过实验查出来其中的关联关系。

这里单独谈数据文件是因为我们鸡贼了一下,后面再说。

控制文件

在根目录中有几个控制文件:

  • incompatible-snapshots
    这个文件的作用应该是处理冲突问题的,我们并没有针对的做实验看这个内容,我们的系统中他一直都是空的 JSON 文件。
  • meta-SNAPUUID.dat & snap-SNAPUUID.dat
    这两个文件是成对出现的,他们都是二进制文件,并不知道他们保存了什么内容。但是在 snapshot 执行后,meta-SNAPUUID.dat 文件会先创建,而当 snapshot 执行完毕后,对应的 snap-SNAPUUID.dat 文件才会创建。

根目录 index* 文件

这些文件比较重要,着重做说明。

index-A & index-B

这里的 A & B 只是个标记,您的系统中可能叫做 index-18 & index-19。这个 index- 开头的文件在系统中会一直保持有两个。

他保存了一次 snapshot 操作开始执行时的 S3 当中 snapshot 的情况,和执行后的 snapshot 情况。这些文件是 JSON 文件,有兴趣完全可以打开看看。

{
  "snapshots": [
    {
      "name": "snap-2017-10-14",
      "uuid": "ilVKxRUxRxyJRmfnps6HDA",
      "state": 1
    },
    {
      "name": "snap-2017-10-18",
      "uuid": "T4rGaActS6-dJW6Pz6KGHA",
      "state": 1
    }
  ],
  "indices": {
    "metric-2017-10-24": {
      "id": "1smmvcuATkuy-hokdARDPw",
      "snapshots": [
        "nhFg0A3QT4yHOAhzDMY_3w"
      ]
    },
    "metric-2017-10-25": {
      "id": "pjFu2jmKSNGpp1L-W55iHw",
      "snapshots": [
        "sFtZ2JGRTqmWzK3wH9vVlg"
      ]
    }
  }
}

我们的这个文件比较长,我摘取了其中一段,上下并不能对应,不好意思。

这个文件的结构很清晰,两个部分:snapshots & indices,其中包含了所有的 S3 中刚才提到的 UUID 内容。

后面谈到数据出现问题恢复的时候,就靠这里的 UUID 来解决问题了。

index.latest

这是用文本文件存储的 64bits 数字,他说明当前上面的 index-* 文件后面的最新编号应该是什么。

通过修改这个文件中的编号,然后自己仿造一个 index-XX 文件后,完全可以让 ES 系统只读取你希望他看到的 snapshot 或者 indices 记录内容。后面文件损坏后的恢复中会用到这个文件。

AWS S3 存储格式选择

AWS S3 提供了 4 中存储文件的类型:

类型 Remark
Standard 标准的文件存储
Standard_IA 不频繁调用的文件存储,价格比 Standard 便宜 50% OFF
Glacier 存档文件,必须手动恢复才能调用,价格比 Standard 便宜 75% OFF
Reduced_Redundancy 可靠性降低的存储,读取速度也会慢一点,但是价格比 Standard 贵一点点,我都怀疑是不是我眼花了,实在不明白他存在的意义 😓

他们具体的价格可以参考 AWS S3 存储类别 而对于 Reduced Redundancy Price 是单列的。有懂得朋友给解释解释 Reduced Redundancy 的类型工作目标到底是啥?存在即合理吗,我实在想不明白。

S3 操作

在 AWS S3 的控制台操作文件转换的时候,可以设定 Standard / Standard_IA (SIA) / Reduced_Redundancy (RRS) 为文件转换目标格式。而针对 Glacier 格式,只能通过 “生存周期” 控制中指定创建天数后进行转换。

不明白 AWS 这样的设定意义是什么,不过系统控制台操作有这么个限制。大家别说在控制台找不到转换为 Glacier 的位置。

服务端压缩与加密

在设定 Repository 的时候,建议设定 "compress": "true" 选项。我们的数据内容大概压缩的比例是 43% OFF 的状态。

AWS S3 存储和执行命令收钱 CPU 又不收钱,让他服务端去压缩去吧。这个存储容量大概省一半银子。

而对于加密选项我们没有测试,看过说明应该会使用到一些证书的配置。我们采用独立的 S3 Bucket 进行访问权限限制来进行一定的安全限制,就没有添加这个加密选项,省的其他 ES 从 S3 恢复数据时给自己找麻烦。

多省点银子 😄

我们的系统选择了 Standard_IA 模式存储。 "storage_class": "standard_ia"

Standard_IA 模式有两个限制:

  • 不足 128KB 的文件按照 128KB 计算容量;
  • 每个文件收费时间颗粒度为 30天,就是说如果你只存了一个小时也按照 30 天收费;

我们的每个 Index 文件大概在 10GB - 20GB 左右。统计了一下一个 Index 一共有 119 个文件,小于 128KB 的只有 46 个,容量有 9.1MB。这个状态怎么算都是用 SIA 模式更便宜。并且在数据备份后,应该从 S3 恢复到 ES 系统的频率会比较低,所以我们选择了 Standard_IA 模式,来降低存储的成本。50% OFF 哦 :-)

并且针对所有存储的文件我们设定创建 390 天后,自动转换为 Glacier 模式,再省 50% 银子。因为 SIA 模式 30 天的限制,365 天肯定是亏的 😀

但是在转换 Glacier 模式的时候,请注意要添加一个 "__" 前缀的模式匹配。

  • 数据文件都是 __ 开头的,这些大容量文件转换后也就完成了主要的成本节约;
  • 如果不限制这个文件意味着 meta-* & snap-* 文件也会被转换,就会影响一些指令的执行,后面会有介绍;

前前后后在 AWS S3 的存储中,这一系列的操作可以节省大概 85% OFF 的成本。下面是我们的 Repository 的设定,供参考:

{
  "my-repository": {
    "type": "s3",
    "settings": {
      "bucket": "MY-BUCKET",
      "endpoint": "s3-us-west-2.amazonaws.com",
      "protocol": "http",
      "server_side_encryption": "false",
      "storage_class": "standard_ia",
      "max_retries": "3",
      "readonly": "false",
      "compress": "true",
      "base_path": "ES-DIRECTORY/"
    }
  }
}

传输速率

在我们测试的过程中,同一个 AWS Region 传送的速率在 90Mbps - 40Mbps 之间,不知道是否因为虽然同一个 Region 而不同的账户会导致速率下降。因为 Elastic Cloud 自己做的全量备份,明显速度比这个快很多。大家可以通过这个速度预估自己的 snapshot 执行的时间长度。

并且,在备份的过程中,我们发现有时候一个 snapshot 中的不同 Index 是同时并行发送的,而有时候是串行同步的。感觉上应该是如果 Index 有 Replicas 那么就可以并行,否则串行,这个没有特别认真的核对过。我们对现在的速度已经很满意了。毕竟一个 snapshot 是 10 秒执行完还是 10分钟执行完,没太多人关心 😄

传输异常情况

操作过程中我们发生过一次卡死在指定位置不动,一个十来分钟的 snapshot,我们等了超过一个小时。并不知道这个问题出现在哪里。

这时候,我们通过 DELETE 这个正在操作的 snapshot 内容,中断了这个操作。但是,在后一次的操作过程中有点奇怪,不过我们再也模拟不出这种卡死情况,就只剩一个奇怪的感觉了。后面 snapshot & restore 的所有过程中,并没有发现有什么不对的地方。

Snapshot 操作监控

我们通过 AWS Lambda 启动 Elasticsearch Snapshot 后,2 个小时添加了一个 Elasticsearch Watcher 程序用于检查备份是否完成。

监控通过 GET _snapshot/my-repository/_all 获取所有 snapshot 的列表,然后根据 <snapshots.snapshot> 这个位置的内容判断是否存在指定的 snapshot。若有,则判断 <snapshots.state> 位置的内容,如果正在备份中会标记 "IN_PROGRESS",如果已经完成会标记 "SUCCESS"。

我们整体备份过程中没有发现出现其他的错误状态,哪位大虾碰到过给个范例,万分感谢。

个别文件类型不对

有些 snapshot 生成的文件,应该是 Elasticsearch 自己控制的,他们并不受你指定的存储类型限制。默认这些文件都是 standard 格式的。

  • incompatible-snapshots
  • index-A
  • index-B
  • index.latest
  • indices.INDEXUUID.0.index-0

上面这些文件不管你怎么搞,都会是 standard 格式。

文件损坏和修复

AWS S3 从来没有保证自己 100% 的文件可靠性。当一些文件出现问题的时候,需要进行一些修复才能正常使用 _snap 的相关指令内容。

当然我们关心这个是希望降低存储成本,定期会将文件转换为 Glacier 格式,这种格式将导致系统会认为这个文件不存在了。

当一些文件出现问题时,我们将遇到如下的一些问题。

对状态指令的影响

在执行相关指令的时候大概经历了如下的过程:

  • GET _snapshot/my-repository/_all
    • 得到 S3 index.latest 文件内的编号
    • 得到 S3 index-XX 文件内的内容
    • 检查文件标记中每个 UUID 对应的 meta-* & snap-* 文件内容
    • 给出结果
      也就是只要保证 <index.latest> <index-A> <index-B> <meta-SNAPUUID.dat> <snap-SNAPUUID.dat> 文件是完整的,这个指令不会出现问题。
      同样对于 GET _snapshot/my-repository/snap-YYYY-MM-DD 这样的指令也不会出现问题。
  • GET _snapshot/my-repository/snap-YYYY-MM-DD/_status
    • 同上面指令的过程;
    • 获取 indices.INDEXUUID 目录中的 <meta-SNAPUUID.dat> <0.snap-SNAPUUID.dat> 文件内容
    • 给出结果
      也就是需要一个 snapshot 备份的具体内容时,两对 meta-* 和 snap-* 文件都要是正常的。

如果这些文件出现问题,就会得到一个 500: no_such_file_exception 的错误信息。这时候除非恢复这些关联的文件,则 DELETE 指令和 _restore 指令都无法执行。

对 restore 的影响

  • POST _snapshot/my-repository/snap-YYYY-MM-DD/_restore
    • 执行上面类似的过程;
    • 在对应的几个 INDEXUUID 目录的 0 目录中获取每个数据文件;

若其中个别文件出现问题,则会给出一个 503: concurrent_snapshot_execution_exception 的错误信息。请注意,在进行 _restore 操作的时候,建议设置 "ignore_unavailable": false 参数,避免出现无法恢复而得到一个正确结果的假象。

这时执行 DELETE _snapshot/my-repository/snap-YYYY-MM-DD 指令一样会得到 503: concurrent_snapshot_execution_exception 的错误信息。

必须对 AWS S3 上的控制文件进行修复后,才能继续执行这些实际的操作指令。

修复

当这些文件有问题的时候,只能屏蔽指定的 Index 文件或者指定的 snapshot 了。

就跟前面说的一样,这时需要打开根目录中的 <index-B> 文件,编辑其中的内容。将出现问题的内容删除即可,当然如果是跳过 snapshot,需要改 snapshot & indices 两个部分的内容。

在修改的时候,就需要通过 UUID 对应目录结构中的内容和 <index-B> 中的内容处理了。当然,你也可以创建一个新的 <index-XX> 文件,然后修改 <index.latest> 文件指向他,来进行这个恢复。这样如果不行,起码还有个回退的机会。😀

当然还有一个更加保险一些的方案,就是当接收到一个 snapshot 后,可以将根目录的 <meta-SNAPUUID> <snap-SNAPUUID> <indices.INDEXUUID> 这些文件弄个 ZIP 包,在备份到另外一个 AWS S3 区域当中。不过这个花费就不仅仅是存储了,还有传输等各种费用问题。也可以利用 AWS Glacier 的独立控制台生成这些内容,他跟 AWS S3 上的限定日期转换为 Glacier 是不同的。这个部分我们没有这么高的要求,就没有详细看了。

如果有损坏文件的备份,只要将其恢复到指定位置中,受影响的 snapshot 指令立刻就可以执行了。在 Elasticsearch 内部没有保存对应信息的好处就在这里了,如果他保存了一个什么状态机,那就等着哭吧。

Snapshot 指令的一些说明

官方在 Snapshot and Restore 已经介绍的非常详细了。一般就这些指令:

  • POST _snapshot/my-repository/snap-YYYY-MM-DD
    异步指令,可以通过添加 ?wait_for_completion=true 参数让他变成同步的,不过建议采用异步方式,不然一般都会超时,可以启动后采用 GET _snapshot/my-repository/snap-YYYY-MM-DD 或者 GET _snapshot/my-repository/_status 进行执行状态的监控。
  • POST _snapshot/my-repository/snap-YYYY-MM-DD/_restore
    异步指令,恢复的过程中 Elasticsearch 会有短暂的红色报警。
  • DELETE _snapshot/my-repository/snap-YYYY-MM-DD
    同步指令,而且删除速度很快,也用于 snapshot 备份过程中中断当前备份操作使用。

相关参考

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

推荐阅读更多精彩内容