AWS ElastiCache Redis のクラスターモード無効の挙動確認と Terraform 設定

# 1. 概要
* AWS ElastiCache Redis の クラスターモード無効 で次の挙動を把握したい
 * エンドポイント
 * レプリカノードのスケールアウト/イン
 * マルチAZ
 * ノードのスペックアップ/ダウン
 * フェイルオーバー
* Terraform の設定の理解や、実行手順を確認したい

# 2. 検証するElastiCacheの構成
* ElastiCache のサブネットグループは次の３つのAZを選択
 * ap-northeast-1a
 * ap-northeast-1c
 * ap-northeast-1d

* Redis の クラスターモードは「無効 (disabled)」を選択
 * 小中規模のサービスで利用することを想定しているため

# 3. クラスターモードが無効の場合の機能や注意点

* レプリカノードのスケールアウト(追加)、スケールイン(削除) が可能
* ノードタイプのスケールアップ、スケールダウンが可能
* データのパーティション化は無い
* シャードは１つ
* 作成可能なリードレプリカ数は 0〜5 ノード
* マルチAZはデフォルトでオン
* スナップショット(バックアップ)可能
* 復元可能
* Redisのすべてのバージョンで利用可能
* エンジンバージョンのアップブレードは、[制限あるが可能](https://docs.aws.amazon.com/ja_jp/AmazonElastiCache/latest/red-ug/VersionManagement.html)
 * Redis エンジンバージョン 5.0.5 以降では、[最小限のダウンタイムでクラスターバージョンをアップグレード](https://docs.aws.amazon.com/ja_jp/AmazonElastiCache/latest/red-ug/AutoFailover.html)できる

**【補足】[Redis (クラスターモードが無効) と Redis (クラスターモードが有効) の比較](https://docs.aws.amazon.com/ja_jp/AmazonElastiCache/latest/red-ug/Replication.Redis-RedisCluster.html)**

* クラスターモードが無効(disabled) と クラスターモードが有効(enabled) の構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/79a2385d-f28c-6684-cad7-b1bc3ce3d286.png)

* クラスターモードが無効(disabled)
 * ノードグループは１つで、そのグループ内のクラスターは常に 1 個のシャードと最大 5 個のリードレプリカノードを持つ構成（MySQLのレプレケーション構成に近い）。
 * プライマリノードに問題が生じたときは、レプリカノードが昇格する (フェイルオーバー)。

* クラスターモードが有効(enabled)
 * ノードグループは複数で、それぞれのグループ内のクラスターは 1 ～ 5 個のリードレプリカノードのある最大 90 個のシャードを持つクラスター。
 * プライマリノードの冗長構成が可能。
 * データセットが大規模な場合や、ピーク需要時のアクセスのボトルネックを減らしたい場合は、クラスタモード「有効」を使うべし。

# 5. クラスターモード無効 の構成を Terraform で作成する方法
* Redisクラスターモードが無効の構成を作成する方法は２通りある。<br/>今回は、単に number_cache_clusters を直接調整する方法とする。

【参考】[Resource: aws_elasticache_replication_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_replication_group)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/f9a0f5e2-a7ed-f431-147f-ad3685a489c2.png)

# 6. 単一のプライマリノードを作成する

* 目的の構成
 * プライマリノード ０⇒１個 (書き取り/読み取り)

## 6.1. terraform サンプル

```terraform:sample.tf
resource "aws_elasticache_replication_group" "test-nishimura" {
  replication_group_id          = "test-nishimura"
  replication_group_description = "test-nishimura"
  node_type                     = "cache.t3.small"
  number_cache_clusters         = "1"
  automatic_failover_enabled    = "false"
  engine                        = "redis"
  engine_version                = "5.0.6"
  port                          = 6379
  parameter_group_name          = "test-nishimura"
  maintenance_window            = "mon:21:30-mon:22:30"
  security_group_ids = [
    "sg-*****************"
  ]
  subnet_group_name        = "test-nishimura"
  snapshot_retention_limit = 7
  snapshot_window          = "20:00-21:00"
  apply_immediately        = "true"
}
```

* <font color="red">number_cache_clusters = 1</font>
 * プライマリノード１個
* <font color="red">automatic_failover_enabled    = "false"</font>
 * ノードが１個の場合は「false」 とする。
 * 「true」とした場合、terraform apply時に次のようなエラーとなる

```
Error: Error creating Elasticache Replication Group: InvalidParameterCombination: When using automatic failover, there must be at least 2 cache clusters in the replication group.	
	status code: 400, request id: ********-****-****-****-************
```


* <font color="red">apply_immediately        = "true"</font>
 * いま時点では必要ないが、あとあと レプリカノードをすべて削除する時に automatic_failover_enabled の設定を即時に反映させるために必要なので、設定を入れておく。

* availability_zones は不要
 * 本家の [Resource: aws_elasticache_replication_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_replication_group) のサンプルにはあるが、以降も不要。
 * サブネットグループで選択した AZ (ap-northeast-1a, ap-northeast-1c, ap-northeast-1d) が暗黙で利用される。
 * 逆に、availability_zones を設定すると何かと問題がでるので、レプリカノード作成時も設定はしない。

**【補足】availability_zones**

* プライマリノード１個の場合に availability_zones を設定すると terraform apply時に 次のようなエラーとなるので、そもそも availability_zones は設定できない。

```
Error: Error creating Elasticache Replication Group: InvalidParameterValue: When specifying preferred availability zones, the number of cache clusters must be specified and must match the number of preferred availability zones.	
	status code: 400, request id: ********-****-****-****-************
```
* プライマリノード１個を作成するときに availability_zones は設定できないが、レプリカノードを作成するときは availability_zones を設定できる。後から availability_zones 設定を追加した場合は次のように <font color="red">forces replacement</font> となるため、エンドポイントの変更はないが、プライマリノードを含む全てのノードが作り直されてしまう（データが飛ぶ）。

```
  availability_zones = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]	
	      + availability_zones = [
	          + "ap-northeast-1a",
	          + "ap-northeast-1c",
	          + "ap-northeast-1d",
	        ] # forces replacement
```

## 6.2. 作成されたクラスター/ノードの情報
* クラスター
 * ノードの数: １個のノード
 * マルチAZ: disabled
 * 自動フェイルオーバー: disabled
![20201027-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/287cdda5-58ac-d289-8707-0cd72123d052.png)

* ノード
 * primaryノードが ap-northeast-1d に作られた
![20201027-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/e890bea1-0b7c-9976-ef75-80cd429d0f6d.png)


* エンドポイント
 * プライマリエンドポイント: test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379<br />
⇒ プライマリノード test-nishimura-001.※※※※※※.0001.apne1.cache.amazonaws.com
<p />
 * リーダーエンドポイント: test-nishimura<font color="red">-ro</font>.※※※※※※ .ng.0001.apne1.cache.amazonaws.com:6379<br />
⇒ プライマリノード test-nishimura-001.※※※※※※.0001.apne1.cache.amazonaws.com

# 7. レプリカノードを１個作成する

* 目的の構成
 * プライマリノード １個 (書き取り)
 * レプリカノード ０⇒１個 (読み取り)

## 7.1. terraform サンプル

```terraform:sample.tf
resource "aws_elasticache_replication_group" "test-nishimura" {
  replication_group_id          = "test-nishimura"
  replication_group_description = "test-nishimura"
  node_type                     = "cache.t3.small"
  number_cache_clusters         = "2"
  automatic_failover_enabled    = "true"
  engine                        = "redis"
  engine_version                = "5.0.6"
  port                          = 6379
  parameter_group_name          = "test-nishimura"
  maintenance_window            = "mon:21:30-mon:22:30"
  security_group_ids = [
    "sg-*****************"
  ]
  subnet_group_name        = "test-nishimura"
  snapshot_retention_limit = 7
  snapshot_window          = "20:00-21:00"
  apply_immediately        = "true"
}
```

* <font color="red">number_cache_clusters = 2</font>
 * プライマリノード１個
 * レプリカノード１個
* <font color="red">automatic_failover_enabled    = "true"</font>
 * 自動フェイルオーバーを有効にする 

**【補足】[automatic_failover_enabled] (https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_replication_group)**

* 既存のプライマリに障害が発生した場合に、読み取り専用レプリカを読み取り/書き込みプライマリに自動的に昇格させるかどうかを指定します。
 * trueの場合、このレプリケーショングループに対してマルチAZが有効になります。
 * falseの場合、このレプリケーショングループのマルチAZは無効になります。

## 7.2. 作成されたクラスター/ノードの情報

* クラスター
 * ノードの数: <font color="red">２</font>個のノード
 * マルチAZ: disabled<br />※この「disabled」表示、多分クラスターモード無効の場合は関係なさそう(暗黙でマルチAZはデフォルトがオンになっているので）。
 * 自動フェイルオーバー: <font color="red">enabled</font>
![20201027-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/d80a4112-e7fb-01cf-4d51-c95601a2b3c3.png)

* ノード
 * replicaノードが ap-northeast-1c に作られた
 * primaryノードは ap-northeast-1d にあるので、マルチAZ になった
![20201027-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/9b6b1266-a0a8-d880-4233-58ead72cba87.png)

* エンドポイント
 * プライマリエンドポイント: test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379<br />
⇒ プライマリノード test-nishimura-001.※※※※※※.0001.apne1.cache.amazonaws.com
<p />
 * リーダーエンドポイント: test-nishimura<font color="red">-ro</font>.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379<br />
⇒ <font color="red">レプリカノード</font> test-nishimura-<font color="red">002</font>.※※※※※※.0001.apne1.cache.amazonaws.com

**【補足】リーダーエンドポイントにデータを格納しようとするとエラーになる**

```
$ curl -s telnet://test-nishimura-ro.******.ng.0001.apne1.cache.amazonaws.com:6379
set test1 aaaa
-READONLY You can't write against a read only replica.
```

# 8. レプリカノードを5個にする

* 目的の構成
 * プライマリノード １個 (書き取り)
 * レプリカノード １⇒５個 (読み取り)

## 8.1. terraform サンプル

```terraform:sample.tf
resource "aws_elasticache_replication_group" "test-nishimura" {
  replication_group_id          = "test-nishimura"
  replication_group_description = "test-nishimura"
  node_type                     = "cache.t3.small"
  number_cache_clusters         = "6"
  automatic_failover_enabled    = "true"
  engine                        = "redis"
  engine_version                = "5.0.6"
  port                          = 6379
  parameter_group_name          = "test-nishimura"
  maintenance_window            = "mon:21:30-mon:22:30"
  security_group_ids = [
    "sg-*****************"
  ]
  subnet_group_name        = "test-nishimura"
  snapshot_retention_limit = 7
  snapshot_window          = "20:00-21:00"
  apply_immediately        = "true"
}
```

* <font color="red">number_cache_clusters = 6</font>
 * プライマリノード１個
 * レプリカノード５個

## 8.2. 作成されたノードの情報

* ノード
 * AZの偏りはあるけど、３つのAZに配置された
![20201027-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/90109b72-4447-0bcb-5910-6bf6ff06caa5.png)

* エンドポイント
 * プライマリエンドポイント: test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379<br />
⇒ プライマリノード test-nishimura-001.※※※※※※.0001.apne1.cache.amazonaws.com
<p />
 * リーダーエンドポイント: test-nishimura<font color="red">-ro</font>.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379<br />
⇒ <font color="red">レプリカノード</font> test-nishimura-<font color="red">002</font>.※※※※※※.0001.apne1.cache.amazonaws.com<br />⇒ <font color="red">レプリカノード</font> test-nishimura-<font color="red">003</font>.※※※※※※.0001.apne1.cache.amazonaws.com<br />⇒ <font color="red">レプリカノード</font> test-nishimura-<font color="red">004</font>.※※※※※※.0001.apne1.cache.amazonaws.com<br />⇒ <font color="red">レプリカノード</font> test-nishimura-<font color="red">005</font>.※※※※※※.0001.apne1.cache.amazonaws.com<br />⇒ <font color="red">レプリカノード</font> test-nishimura-<font color="red">006</font>.※※※※※※.0001.apne1.cache.amazonaws.com<br />

# 9. レプリカノードを6個にしてみる

* 目的の構成
 * プライマリノード １個 (書き取り)
 * レプリカノード ５⇒６個 (読み取り)

## 9.1. terraform 設定
* <font color="red">number_cache_clusters = 7</font>
 * プライマリノード１個
 * レプリカノード６個

## 9.2. terraform apply 実行
* 次のエラーが出た<br />
* やはり、<font color="red">作成可能なリードレプリカ数は 0〜5 ノード</font>だった

```
Error: error creating Elasticache Cache Cluster (adding replica): InvalidReplicationGroupState: Specified replication group test-nishimura has already met the number of read replicas allowed.
	status code: 400, request id: ********-****-****-****-************
```

# 10. レプリカノードを減らす

* 目的の構成
 * プライマリノード１ 個 (書き取り)
 * レプリカノード ５⇒２個 (読み取り)

## 10.1. terraform サンプル

```terraform:sample.tf
resource "aws_elasticache_replication_group" "test-nishimura" {
  replication_group_id          = "test-nishimura"
  replication_group_description = "test-nishimura"
  node_type                     = "cache.t3.small"
  number_cache_clusters         = "3"
  automatic_failover_enabled    = "true"
  engine                        = "redis"
  engine_version                = "5.0.6"
  port                          = 6379
  parameter_group_name          = "test-nishimura"
  maintenance_window            = "mon:21:30-mon:22:30"
  security_group_ids = [
    "sg-*****************"
  ]
  subnet_group_name        = "test-nishimura"
  snapshot_retention_limit = 7
  snapshot_window          = "20:00-21:00"
  apply_immediately        = "true"
}
```

* <font color="red">number_cache_clusters</font> =５ ⇒ <font color="red">3</font>
 * プライマリノード １個
 * レプリカノード ２個

## 10.2. 作成されたノードの情報

* 後から追加されたノードが先に削除されているので、LIFO 方式っぽい
* ノードが３つになっても、３つのAZに分散配置されている
![20201027-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/c90b6ab6-222c-59f2-a192-23fa6f6e1498.png)


# 11. レプリカノードをすべて削除して、プライマリノード１個だけにする

* 目的の構成
 * プライマリノード１個 (書き取り/読み取り)
 * レプリカノード ２⇒０個

* 実施手順<br />※複数レプリカノードがある状態からすべてのレプリカノードを削除して、プライマリノード１個だけに変更する
 * まずは、automatic_failover_enabled を false にして terraform apply
 * その後で、number_cache_clusters = 1 にして terraform apply

## 11.1. terraform サンプル その１

まずは automatic_failover_enabled を false にして terraform apply する

```sample.tf
resource "aws_elasticache_replication_group" "test-nishimura" {
  replication_group_id          = "test-nishimura"
  replication_group_description = "test-nishimura"
  node_type                     = "cache.t3.small"
  number_cache_clusters         = "3"
  automatic_failover_enabled    = "false"
  engine                        = "redis"
  engine_version                = "5.0.6"
  port                          = 6379
  parameter_group_name          = "test-nishimura"
  maintenance_window            = "mon:21:30-mon:22:30"
  security_group_ids = [
    "sg-*****************"
  ]
  subnet_group_name        = "test-nishimura"
  snapshot_retention_limit = 7
  snapshot_window          = "20:00-21:00"
  apply_immediately        = "true"
}
```
* <font color="red">automatic_failover_enabled</font> = true ⇒ <font color="red">false</font>

## 11.2. terraform サンプル その２

その１を terraform apply した後に number_cache_clusters を３から１へ減らす

```sample.tf
resource "aws_elasticache_replication_group" "test-nishimura" {
  replication_group_id          = "test-nishimura"
  replication_group_description = "test-nishimura"
  node_type                     = "cache.t3.small"
  number_cache_clusters         = "1"
  automatic_failover_enabled    = "false"
  engine                        = "redis"
  engine_version                = "5.0.6"
  port                          = 6379
  parameter_group_name          = "test-nishimura"
  maintenance_window            = "mon:21:30-mon:22:30"
  security_group_ids = [
    "sg-*****************"
  ]
  subnet_group_name        = "test-nishimura"
  snapshot_retention_limit = 7
  snapshot_window          = "20:00-21:00"
  apply_immediately        = "true"
}
```
* <font color="red">number_cache_clusters</font> = 3 ⇒ <font color="red">1</font>
 * プライマリノード １個
 * レプリカノード ０個


**【補足】最後のレプリカノードを削除するときの terraform エラー例**

* automatic_failover_enabled = true のままで number_cache_clusters = 3 を 1 に変更して terraform apply すると、次のエラーが出て最後のレプリカノード(test-nishimura-002)が削除されない。

```
Error: error deleting Elasticache Cache Cluster (test-nishimura-002) (removing replica): InvalidCacheClusterState: Cannot delete the cache cluster because it is the only read replica for replication group test-nishimura which has autofailover enabled or pending. You can disable autofailover and then delete this cache cluster. Alternatively, to delete the entire replication group, use DeleteReplicationGroup.
	status code: 400, request id: ********-****-****-****-************
```

* automatic_failover_enabled の true ⇒ false 変更と、number_cache_clusters の３⇒1 変更を同時に設定して terraform apply しても、次のエラーが出て最後のレプリカノード(test-nishimura-002)が削除されない。

```
Error: error deleting Elasticache Cache Cluster (test-nishimura-002) (removing replica): InvalidCacheClusterState: Cannot delete the cache cluster because it is the only read replica for replication group test-nishimura which has autofailover enabled or pending. You can disable autofailover and then delete this cache cluster. Alternatively, to delete the entire replication group, use DeleteReplicationGroup.
	status code: 400, request id: ********-****-****-****-************
```

# 12. ノードのタイプ変更(スペックアップ)

* 実施内容
 * プライマリノード１個 (書き取り)<br />⇒ cache.t3.small から cache.t3.medium へスペックアップ
<p />
 * レプリカノード２個 (読み取り)<br />⇒ cache.t3.small から cache.t3.medium へスペックアップ

## 12.1. ノードタイプ変更前の構成

* クラスター
 * ノードのタイプ: cache.t3.small 
![20201028-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/b8743897-5bc1-df14-e66f-42481b15588a.png)


* ノード
 * ノードは３個
![20201028-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/27837cc3-acf1-4d3a-4d8a-845dc318d940.png)

* エンドポイント

 * プライマリエンドポイント: test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379<br />
⇒ プライマリノード test-nishimura-001.※※※※※※.0001.apne1.cache.amazonaws.com
<p />
 * リーダーエンドポイント: test-nishimura-ro.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379<br />
⇒ レプリカノード test-nishimura-002.※※※※※※.0001.apne1.cache.amazonaws.com<br />⇒ レプリカノード test-nishimura-003.※※※※※※.0001.apne1.cache.amazonaws.com<br />


## 12.2. 事前設定

* タイプ変更前後でデータが消えないかどうかの確認のため、事前にデータを格納しておく

```
$ curl -s telnet://test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379
set A A
+OK
set B B
+OK
set C C
+OK
^C
```

* タイプ変更中にデータが書き込めるか確認するため、１秒おきにプライマリエンドポイントに接続してデータをsetするスクリプトを動かす

```bash:set.sh
#!/bin/sh
LANG=C
for i in {1..2000}
do
  date
  echo key$i
  echo "$i" | redis-cli -h test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com -x set key$i
  sleep 1
done
```

* タイプ変更中にデータが読み込めるか確認するため、１秒おきにリーダーエンドポイントに接続してデータをgetするスクリプトを動かす

```bash:get.sh
#!/bin/sh
LANG=C1
for i in {1..2000}
do
  date
  echo key$i
  redis-cli -h test-nishimura-ro.※※※※※※.ng.0001.apne1.cache.amazonaws.com get key$i
  sleep 1
done
```

## 12.3. terraform サンプル

```terraform:sample.tf
resource "aws_elasticache_replication_group" "test-nishimura" {
  replication_group_id          = "test-nishimura"
  replication_group_description = "test-nishimura"
  node_type                     = "cache.t3.medium"
  number_cache_clusters         = "3"
  automatic_failover_enabled    = "true"
  engine                        = "redis"
  engine_version                = "5.0.6"
  port                          = 6379
  parameter_group_name          = "test-nishimura"
  maintenance_window            = "mon:21:30-mon:22:30"
  security_group_ids = [
    "sg-*****************"
  ]
  subnet_group_name        = "test-nishimura"
  snapshot_retention_limit = 7
  snapshot_window          = "20:00-21:00"
  apply_immediately        = "true"
}
```
* <font color="red">node_type</font> = cache.t3.small ⇒ <font color="red">cache.t3.medium</font>

## 12.4. タイプ変更実施
* 実施手順
 * まず、set.sh を走らせる
 * そのあと get.sh を走らせる
 * それから terraform apply を実行する

* modifying
 * クラスター
![20201028-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/bc87f486-1d66-5b97-247e-f0453d21df2c.png)
 * ノード
![20201028-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/9c42bed7-c975-90d3-1328-ecb70148b6e5.png)

## 12.5. ノードタイプ変更 完了後の確認

* terraform apply
 * 23分31秒で完了 

```
〜
aws_elasticache_replication_group.test-nishimura: Still modifying... [id=test-nishimura, 23m21s elapsed]
aws_elasticache_replication_group.test-nishimura: Still modifying... [id=test-nishimura, 23m31s elapsed]
aws_elasticache_replication_group.test-nishimura: Modifications complete after 23m35s [id=test-nishimura]
```


* イベントログ
 * 17時59分18秒〜18時22分22秒
![20201028-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/9ae9963c-cbfa-2e6c-245d-ba3fd5ca6bae.png)

* クラスター
 * ノードのタイプ: cache.t3.medium
![20201028-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/bfcbbaf4-0012-0a10-82d7-4d9c3eb814fb.png)

* ノード
 * ノード名とロールに変更はないので、ノードタイプ変更 によってレプリカノードがプリマリノードに昇格するなどのフェイルオーバーは発生しない
 * 作成日の変更はないので、ノードが作り直されることはない
 * すべてのノードが同じスペックになるので、例えば、プライマリノードだけレプリカノードよりも高いスペックのインスタンスタイプにすることはできない
![20201028-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/b66c3436-b229-1658-5eb2-59b48237e17f.png)

* エンドポイント
 * 変更なし
 
* 事前に格納したデータの確認
 * リーダーエンドポイントへgetして生存確認

```
$ curl -s telnet://test-nishimura-ro.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379
get A
$1
A
get B
$1
B
get C
$1
C
^C
```

* データをsetするスクリプト
 * 開始から終了まで毎秒止まることなく プライマリエンドポイントへ接続して set した
 * ４〜５回同じ検証を試しけど、すべての検証において set が止まることはなかった

```
$ sh set.sh
Wed Oct 28 08:58:29 UTC 2020
key1
OK
Wed Oct 28 08:58:30 UTC 2020
key2
OK
Wed Oct 28 08:58:31 UTC 2020
key3
・
・
・
Wed Oct 28 09:22:35 UTC 2020
key1432
OK
Wed Oct 28 09:22:36 UTC 2020
key1433
OK
^C
```

* データをgetするスクリプト
 * 途中、１回 リーダーエンドポインへの接続が数分切れた
 * ４〜５回同じ検証を試しけど、すべての検証において１、２回 get が数分切れた

```
$ sh get.sh
・
・
Wed Oct 28 09:06:14 UTC 2020
key456
"456\n"
Wed Oct 28 09:06:15 UTC 2020
key457
Could not connect to Redis at test-nishimura-ro.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379: Connection timed out
Wed Oct 28 09:08:25 UTC 2020
key458
"458\n"
Wed Oct 28 09:08:26 UTC 2020
key459
"459\n"
・
・
```


# 13. フェイルオーバー (レプリカノードをプライマリノードへ昇格)

* 実施内容
 * プライマリノード１個 (書き取り)<br />⇒ 手動でフェイルオーバーを実施
 <p />
 * レプリカノード２個 (読み取り)<br />⇒ 自動でどちらかがプライマリノードへ昇格


## 13.1. ノードタイプ変更前の構成

* ノード
 * ノードは３個
 * 今回はきれいに３つのAZに配置された
![20201029-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/fb163db8-7398-324f-f173-38e65e66451a.png)


* エンドポイント

 * プライマリエンドポイント: test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379<br />
⇒ プライマリノード test-nishimura-001.※※※※※※.0001.apne1.cache.amazonaws.com
<p /><p />
 * リーダーエンドポイント: test-nishimura-ro.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379<br />
⇒ レプリカノード test-nishimura-002.※※※※※※.0001.apne1.cache.amazonaws.com<br />⇒ レプリカノード test-nishimura-003.※※※※※※.0001.apne1.cache.amazonaws.com<br />



## 13.2. 事前設定

* フェイルオーバー前後でデータが消えないかどうかの確認のため、事前にデータを格納しておく

```
$ curl -s telnet://test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379
set A A
+OK
set B B
+OK
set C C
+OK
^C
```

* フェイルオーバー中にデータが書き込めるか確認するため、１秒おきにプライマリエンドポイントに接続してデータをsetするスクリプトを動かす

* タイプ変更中にデータが読み込めるか確認するため、１秒おきにリーダーエンドポイントに接続してデータをgetするスクリプトを動かす


## 13.3. プライマリノードのフェイルオーバーを実施
* 実施手順
 * まず、set.sh を走らせる
 * そのあと get.sh を走らせる
 * それから 手動で AWSマネジメントコンソールからプライマリノードのフェイルオーバーを実行する

* プライマリノードをフェイルオーバー
![20201029-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/213e5c7d-ccba-064b-a4ad-c5eb213db43d.png)
![20201029-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/f912dbe4-f6d8-3526-8b75-188d83427e36.png)

## 13.4. ノードタイプ変更 完了後の確認

* イベントログ
 * 14時57分03秒〜15時02分29秒
 * フェイルオーバー自体は、14時57分03秒〜14時57分47秒 で完了して、クラスターのスタータスは available になった。
![20201029-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/72212d04-ecf7-8a9e-aea3-9e60d3fbfd04.png)

* ノード
 * レプリカノードだった 001 が プライマリノード へ昇格した
 * プライマリノードだった 001 が レプリカノード へ降格した
![20201029-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/c78d8e13-9810-0b27-2012-05357b59bd58.png)

* エンドポイント
 * プライマリエンドポイント: test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379<br />
⇒ プライマリノード test-nishimura-<font color="red">003</font>.※※※※※※.0001.apne1.cache.amazonaws.com
<p /><p />
 * リーダーエンドポイント: test-nishimura-ro.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379<br />
⇒ レプリカノード test-nishimura-002.※※※※※※.0001.apne1.cache.amazonaws.com<br />⇒ レプリカノード test-nishimura-<font color="red">001</font>.※※※※※※.0001.apne1.cache.amazonaws.com<br />

 
* 事前に格納したデータの確認
 * リーダーエンドポイントへgetして生存確認

```
$ curl -s telnet://test-nishimura-ro.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379
get A
$1
A
get B
$1
B
get C
$1
C
^C
```


* データをsetするスクリプト
 * ６秒ほど プライマリエンドポイント へ接続できなくなった

```
$ sh set.sh
・
・
Thu Oct 29 05:57:21 UTC 2020
key49
OK
Thu Oct 29 05:57:22 UTC 2020
key50
OK
Thu Oct 29 05:57:23 UTC 2020
key51
Could not connect to Redis at test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379: Connection refused
Thu Oct 29 05:57:24 UTC 2020
key52
Could not connect to Redis at test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379: Connection refused
Thu Oct 29 05:57:25 UTC 2020
key53
Could not connect to Redis at test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379: Connection refused
Thu Oct 29 05:57:26 UTC 2020
key54
Could not connect to Redis at test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379: Connection refused
Thu Oct 29 05:57:27 UTC 2020
key55
Could not connect to Redis at test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379: Connection refused
Thu Oct 29 05:57:28 UTC 2020
key56
Could not connect to Redis at test-nishimura.※※※※※※.ng.0001.apne1.cache.amazonaws.com:6379: Connection refused
Thu Oct 29 05:57:29 UTC 2020
key57
^CThu Oct 29 05:58:10 UTC 2020
key58
OK
・
・
```
* データをgetするスクリプト
 * 開始から終了まで毎秒止まることなく リーダーエンドポインへ接続して get した

# 14. まとめ
* エンドポイント
 * リーダーエンドポイントは積極的に使ったほうがよい
 * 特に、スケールアウト/イン や フェイルオーバー する場合は必須

* レプリカノードのスケールアウト/イン
 * Auroraのレプリカ作成/削除するみたいな感じで、サービス中でも特に気にせず実行できる<br />
※Auroraの場合は一度に大量のレプリカを作成するとプライマリに負荷がかかっちゃうけど
 * レプリカノードをすべて削除する場合は、terraform の実行手順に注意

* マルチAZ
 * デフォルトでオンになっている
 * サブネットグループで選択したAZに配置される
 * サブネットグループは３つのAZで作ったほうが良い

* ノードのスペックアップ/ダウン
 * すべてのノードが同一のタイプになる
 * タイプ変更にかかる時間は20分 (ノードが３個で、cache.t3.small から cache.t3.medium の場合)
 * タイプ変更中は、書き込みはできる
 * タイプ変更中は、読み込みが数回、数分間できなくなる
 * これであれば、メンテ入れなくても深夜のアクセスが少ない時間帯にできそうな感じ
	
* フェイルオーバー
 * レプリカノードの昇格は数秒で終わる
 * フェイルオーバー中は、書き込みが数秒できなくなる
 * フェイルオーバー中は、読み込みはできる