Link Search Menu Expand Document Documentation Menu

使用流量回放器

本指南介绍如何在迁移过程中使用流量重放器(Traffic Replayer)将捕获的流量从源集群重放至目标集群。流量重放器允许您验证目标集群是否能以与源集群相同的方式处理请求,并赶上实时流量,以实现平滑迁移。

何时运行流量重放器

部署迁移助手后,流量重放器默认不运行。它应在所有元数据和文档迁移完成后才启动,以确保源集群的最新更改正确反映在目标集群中。

例如,如果快照拍摄后删除了某个文档,在文档迁移完成前启动流量重放器可能导致删除请求在文档添加到目标之前执行。在所有其他迁移过程完成后运行流量重放器,可确保目标集群与源集群保持一致。

配置选项

流量重放器设置在部署迁移助手时配置。请务必为流量重放器设置身份验证模式,以便它能正确地与目标集群通信。

使用流量回放器

要管理流量重放器,请使用 console replay 命令。以下示例展示了可用的命令。

启动流量重放器

以下命令使用部署时指定的选项启动流量重放器

console replay start

启动流量重放器时,您应该收到类似于以下的输出

root@ip-10-0-2-66:~# console replay start
Replayer started successfully.
Service migration-dev-traffic-replayer-default set to 1 desired count. Currently 0 running and 0 pending.

检查流量重放器的状态

使用以下命令显示流量重放器的状态

console replay status

重放将返回以下状态之一

  • Running 显示有多少容器实例正在活动运行。
  • Pending 指示有多少实例正在被预置。
  • Desired 显示应运行的实例总数。

您应该收到类似于以下的输出

root@ip-10-0-2-66:~# console replay status
(<ReplayStatus.STOPPED: 4>, 'Running=0\nPending=0\nDesired=0')

停止流量重放器

以下命令停止流量重放器

console replay stop

您应该收到类似于以下的输出

root@ip-10-0-2-66:~# console replay stop
Replayer stopped successfully.
Service migration-dev-traffic-replayer-default set to 0 desired count. Currently 0 running and 0 pending.

交付保证

流量重放器从 Kafka 检索流量,并在向目标集群发送请求后更新其提交游标。这提供了“至少一次”的交付保证;然而,成功并不总是能得到保证。因此,您应该监控指标和元组输出,或执行外部验证,以确保目标集群按预期运行。

时间缩放

流量重放器以从源头每个连接接收到的相同顺序发送请求。然而,不同连接之间的相对时间不作保证。例如

  • 场景:存在两个连接:一个每分钟发送一次 PUT 请求,另一个每秒发送一次 GET 请求。
  • 行为:流量重放器将保持每个连接内的序列,但不保留连接之间(PUT 和 GET)的相对时间。

假设源集群在 100 毫秒内响应请求(GET 和 PUT)

  • 加速因子为 1 的情况下,目标将体验与源相同的请求速率和空闲周期。
  • 加速因子为 2 的情况下,请求将以两倍的速度发送,GET 请求每 500 毫秒发送一次,PUT 请求每 30 秒发送一次。
  • 加速因子为 10 的情况下,请求将以 10 倍的速度发送,只要目标响应迅速,流量重放器就能保持这个速度。

如果目标无法足够快地响应,流量重放器将等待前一个请求完成后再发送下一个请求。这可能导致延迟并影响全局相对顺序。

转换

在迁移过程中,某些请求可能需要在版本之间进行转换。例如,Elasticsearch 以前支持索引中的多个类型映射,但 OpenSearch 中不再支持。客户端可能需要相应地进行调整,例如将文档拆分为多个索引或转换请求数据。

流量重放器会自动重写主机和身份验证头,但对于更复杂的转换,可以使用 --transformer-config 选项指定自定义转换规则。有关更多信息,请参阅流量重放器 README

转换示例

假设源请求包含一个需要删除并提升其子元素的 tagToExcise 元素,并且 URI 路径包含 extraThingToRemove,也应将其删除。以下 Jolt 脚本处理此转换

[{ "JsonJoltTransformerProvider":
[
  {
    "script": {
      "operation": "shift",
      "spec": {
        "payload": {
          "inlinedJsonBody": {
            "top": {
              "tagToExcise": {
                "*": "payload.inlinedJsonBody.top.&" 
              },
              "*": "payload.inlinedJsonBody.top.&"
            },
            "*": "payload.inlinedJsonBody.&"
          },
          "*": "payload.&"
        },
        "*": "&"
      }
    }
  }, 
 {
   "script": {
     "operation": "modify-overwrite-beta",
     "spec": {
       "URI": "=split('/extraThingToRemove',@(1,&))"
     }
  }
 },
 {
   "script": {
     "operation": "modify-overwrite-beta",
     "spec": {
       "URI": "=join('',@(1,&))"
     }
  }
 }
]
}]

发送到目标集群的最终请求将类似于以下内容

PUT /oldStyleIndex/moreStuff HTTP/1.0
host: testhostname

{"top":{"properties":{"field1":{"type":"text"},"field2":{"type":"keyword"}}}}

您可以使用 --transformer-config-base64 传递 Base64 编码的转换脚本。

结果日志

源捕获的 HTTP 事务以及重新发送到目标集群的 HTTP 事务都记录在 /shared-logs-output/traffic-replayer-default/*/tuples/tuples.log 文件中。/shared-logs-output 目录在包括迁移控制台在内的所有容器之间共享。您可以从迁移控制台使用相同的路径访问这些文件。之前的运行记录也以 gzipped 格式提供。

每个日志条目都是一个以换行符分隔的 JSON 对象,包含有关源请求/响应和目标请求/响应的信息以及其他事务详细信息,例如响应时间。

这些日志包含所有请求的内容,包括授权头和所有 HTTP 消息的内容。请确保对迁移环境的访问受到限制,因为这些日志是确定源集群和目标集群中发生事件的真相来源。源的响应时间是指代理发送请求结束到接收到响应之间的时间量。虽然目标的响应时间以相同方式记录,但请记住捕获代理、流量重放器和目标的位置可能不同,并且这些日志不考虑客户端的位置。

日志条目示例

以下示例日志条目显示了发送到源集群和目标集群的 /_cat/indices?v 请求

{
    "sourceRequest": {
        "Request-URI": "/_cat/indices?v",
        "Method": "GET",
        "HTTP-Version": "HTTP/1.1",
        "Host": "capture-proxy:9200",
        "Authorization": "Basic YWRtaW46YWRtaW4=",
        "User-Agent": "curl/8.5.0",
        "Accept": "*/*",
        "body": ""
    },
    "sourceResponse": {
        "HTTP-Version": {"keepAliveDefault": true},
        "Status-Code": 200,
        "Reason-Phrase": "OK",
        "response_time_ms": 59,
        "content-type": "text/plain; charset=UTF-8",
        "content-length": "214",
        "body": "aGVhbHRoIHN0YXR1cyBpbmRleCAgICAgICB..."
    },
    "targetRequest": {
        "Request-URI": "/_cat/indices?v",
        "Method": "GET",
        "HTTP-Version": "HTTP/1.1",
        "Host": "opensearchtarget",
        "Authorization": "Basic YWRtaW46bXlTdHJvbmdQYXNzd29yZDEyMyE=",
        "User-Agent": "curl/8.5.0",
        "Accept": "*/*",
        "body": ""
    },
    "targetResponses": [{
        "HTTP-Version": {"keepAliveDefault": true},
        "Status-Code": 200,
        "Reason-Phrase": "OK",
        "response_time_ms": 721,
        "content-type": "text/plain; charset=UTF-8",
        "content-length": "484",
        "body": "aGVhbHRoIHN0YXR1cyBpbmRleCAgICAgICB..."
    }],
    "connectionId": "0242acfffe13000a-0000000a-00000005-1eb087a9beb83f3e-a32794b4.0",
    "numRequests": 1,
    "numErrors": 0
}

解码日志内容

HTTP 消息正文的内容经过 Base64 编码,以处理各种类型的流量,包括压缩数据。要以更易读的格式查看日志,请使用控制台库 tuples show。按如下方式运行脚本将在主目录中生成一个 readable-tuples.log 文件

console tuples show --in /shared-logs-output/traffic-replayer-default/d3a4b31e1af4/tuples/tuples.log > readable-tuples.log

readable-tuples.log 应该类似于以下内容

{
    "sourceRequest": {
        "Request-URI": "/_cat/indices?v",
        "Method": "GET",
        "HTTP-Version": "HTTP/1.1",
        "Host": "capture-proxy:9200",
        "Authorization": "Basic YWRtaW46YWRtaW4=",
        "User-Agent": "curl/8.5.0",
        "Accept": "*/*",
        "body": ""
    },
    "sourceResponse": {
        "HTTP-Version": {"keepAliveDefault": true},
        "Status-Code": 200,
        "Reason-Phrase": "OK",
        "response_time_ms": 59,
        "content-type": "text/plain; charset=UTF-8",
        "content-length": "214",
        "body": "health status index       uuid         ..."
    },
    "targetRequest": {
        "Request-URI": "/_cat/indices?v",
        "Method": "GET",
        "HTTP-Version": "HTTP/1.1",
        "Host": "opensearchtarget",
        "Authorization": "Basic YWRtaW46bXlTdHJvbmdQYXNzd29yZDEyMyE=",
        "User-Agent": "curl/8.5.0",
        "Accept": "*/*",
        "body": ""
    },
    "targetResponses": [{
        "HTTP-Version": {"keepAliveDefault": true},
        "Status-Code": 200,
        "Reason-Phrase": "OK",
        "response_time_ms": 721,
        "content-type": "text/plain; charset=UTF-8",
        "content-length": "484",
        "body": "health status index       uuid         ..."
    }],
    "connectionId": "0242acfffe13000a-0000000a-00000005-1eb087a9beb83f3e-a32794b4.0",
    "numRequests": 1,
    "numErrors": 0
}

Amazon CloudWatch 指标和仪表盘

迁移助手会创建一个名为 MigrationAssistant_ReindexFromSnapshot_Dashboard 的 Amazon CloudWatch 仪表盘,以可视化回填过程的健康状况和性能。此仪表盘结合了回填工作器和迁移到 Amazon OpenSearch Service 的指标,提供了对捕获代理和流量重放器组件的性能和健康状况的洞察,包括以下指标:

  • 读取和写入的字节数。
  • 活动连接数。
  • 重放速度乘数。

您可以在部署迁移助手的 AWS 区域的 AWS 管理控制台的 CloudWatch 仪表盘中找到捕获和重放仪表盘。

流量重放器向 Amazon CloudWatch 发送各种 OpenTelemetry 指标,并通过 AWS X-Ray 发送追踪。以下是一些有助于评估迁移性能的有用指标。

sourceStatusCode

此指标跟踪源集群和目标集群的 HTTP 状态代码,并具有 HTTP 动词(例如 GETPOST)和状态代码系列(200-299)的维度。这些维度可以帮助快速识别源和目标之间的差异,例如当 DELETE 200s 变为 4xxGET 4xx 错误变为 5xx 错误时。

lagBetweenSourceAndTargetRequests

此指标显示请求到达源集群和目标集群之间的延迟。当加速因子大于 1 且目标集群能够高效处理请求时,该值应随着重放的进行而减小,表明重放延迟减少。

其他指标

还会报告以下指标:

  • 吞吐量bytesWrittenToTargetbytesReadFromTarget 指示到集群和从集群的吞吐量。
  • 重试次数numRetriedRequests 跟踪由于源和目标之间的状态代码不匹配而重试的请求数量。
  • 事件计数:各种 (*)Count 指标跟踪已完成事件的数量。
  • 持续时间(*)Duration 指标衡量过程中每个步骤的持续时间。
  • 异常(*)ExceptionCount 显示在每个处理阶段遇到的异常数量。

CloudWatch 考量

推送到 CloudWatch 的指标和仪表盘可能会经历大约 5 分钟的可见性延迟。CloudWatch 还会保留更高分辨率的数据,但时间比低分辨率数据短。有关更多信息,请参阅Amazon CloudWatch 概念