TerraformでDMSレプリケーションインスタンスを自動構築する(検証エラーを検知する編)

# はじめに
DMS記事第3弾。

DMSの検証タスクは、なぜか検証エラー数のメトリクスが標準では累計でしか提供されていない。
これでは、バリデーションエラー検知時に都度アラームを上げるということができなくて困るではないか。
というわけで、今回はDMSと言いつつ、CloudWatchメトリクスを駆使してアラームを上げてみようという話。

DMSのインスタンスやタスクについては、以下の過去記事をベースに作っているため、こちらを使って構築していただきたい。
- [基本編](https://qiita.com/neruneruo/items/d327e2e0bf504c4c8c43)
- [ロギング編](https://qiita.com/neruneruo/items/04fb2c45cfcbe92801ef)

# 検証タスクを使うための設定
検証タスクを有効にするには、タスクの設定に以下の部分を追加しておく。
```EnableValidation: true```により、検証が実行されるようになる。各パラメータの詳細は[公式のユーザーガイド](https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/CHAP_Tasks.CustomizingTasks.TaskSettings.DataValidation.html)を読んでおこう。

```JSON
  "ValidationSettings": {
    "EnableValidation": true,
    "ValidationMode": "ROW_LEVEL",
    "ThreadCount": 5,
    "FailureMaxCount": 10000,
    "TableFailureMaxCount": 1000,
    "HandleCollationDiff": false,
    "ValidationOnly": false,
    "RecordFailureDelayInMinutes": 1,
    "RecordFailureDelayLimitInMinutes": 0,
    "RecordSuspendDelayInMinutes": 30,
    "SkipLobColumns": false,
    "ValidationPartialLobSize": 0,
    "ValidationQueryCdcDelaySeconds": 0,
    "PartitionSize": 10000,
    "MaxKeyColumnSize": 8096
  }
```

# メトリクスを作る
上述した通り、標準のメトリクスでは検証タスクの累計しか確認することができない。
以下のようにメトリクスを定義してあげよう。

```HCL
resource "aws_cloudwatch_metric_alarm" "dms_validation_error" {
  alarm_name        = local.cloudwatch_alarm_validation_error_name
  alarm_description = "Metric monitor for DMS CDC Validation Error"

  metric_query {
    id          = "m1"
    return_data = false

    metric {
      namespace   = "AWS/DMS"
      metric_name = "ValidationFailedOverallCount"

      dimensions = {
        "ReplicationInstanceIdentifier" = aws_dms_replication_instance.example.replication_instance_id
        "ReplicationTaskIdentifier"     = element(split(":", aws_dms_replication_task.example.replication_task_arn), 6)
      }

      period = 60
      stat   = "Maximum"
    }
  }

  metric_query {
    id          = "e1"
    return_data = true

    label      = "DMSValidationFailedCount"
    expression = "DIFF(m1)"
  }

  datapoints_to_alarm = "1"
  evaluation_periods  = "1"
  comparison_operator = "GreaterThanOrEqualToThreshold"
  threshold           = "1"
  treat_missing_data  = "notBreaching"
}
```

最初の```metric_query```で標準提供される、検証エラーの累計値を引っ張ってくる。
これ自体を監視するわけではないため、```return_data = false```にして、```id```で名前をつける。

次の```metric_query```で、```expression = "DIFF(m1)"```として、```id = "m1"```のクエリの結果の前回差を取るようにする。
※この辺りの詳細は、CloudWatchのMetric Mathに関する[公式のユーザガイド](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/using-metric-math.html)を参照しよう。

なお、```ReplicationTaskIdentifier```で変な指揮を使っているのは、現状、DMSのタスクのIdentifierは、Terraformの標準の属性で提供されていないためだ。取得が面倒なので、将来的には対応してもらいたい……。

# メトリクスを表示する
これでメトリクスを表示すると、以下のようになる。

![キャプチャ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/6d937450-5351-49b9-4a00-3d73dfa34447.png)

検証タスクを再起動すると、一度マイナスになってしまうようだ。
また、前の値との差であるため、次の周期では一気にこれまでの検証エラーの累積値が出てしまう。こうなってしまうのは仕方がないか……。

これで、新規に検証エラーを発生させると、以下のようにアラームが上がり、次の周期では収まる。
これで、検証エラーを検知する都度エラーを発生させることが可能になった！

![キャプチャ2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/9b767f17-d27e-fb63-d807-d4039ef0cdc1.png)

# メトリクスの見た目にこだわるなら
Metric Mathを駆使すれば以下のようにすることでメトリクスの誤検知を減らすことができる。

```diff_HCL
  metric_query {
    id          = "e1"
    return_data = true

    label      = "DMSValidationFailedCount"
-   expression = "DIFF(m1)"
+   expression = "IF(DIFF(m1)<0,0,IF(DIFF(m1)==m1&&m1!=1,0,DIFF(m1)))"
  }
```

最初の条件式で停止後最初に0以下で表示されるものを除外し、次の条件式で、今までの累計値と同じになるものを除外する。
ただし、初回の検知で累積値と検知した値が同じになってしまったときにアラームが上がらないということがないようにしている。
これとて、初回で同時に2件以上まとめて検知する場合にうまく動作しないが……。

ともあれ、これで以下のように検知をできるようになった！

![キャプチャ3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/738edbe7-5490-5869-5fc7-2cdd09b4ffbf.png)