TL;DR
- Amazon ElastiCache for Redisにおいて利用すべきエンドポイントは、ノードの数やクラスターモードが有効かどうかで異なる
- シングルノードの場合
- ノードのエンドポイント(Endpoint)を読み書きのオペレーションに使う
- PrimaryEndpointでもいい気も
- ノードのエンドポイント(Endpoint)を読み書きのオペレーションに使う
- クラスター構成の場合
- クラスターモードが有効の場合は、ConfigurationEndpointを使う
- クラスターモードが無効の場合は、書き込みにはPrimaryEndpointを、読み込みにはReaderEndpointを使う
Amazon ElastiCache for Redisのドキュメントをさらっと読んでみても、どういう時にどのエンドポイントを使うのかがよくわからなかったので、ちゃんと読み込んでみようかなと。
で、その情報を整理するのが、このエントリの目的です。
Amazon ElastiCache for Redisの構成パターン
TL;DRに書いた、「シングルノードの場合」「クラスタ構成の場合」というのは、以下のページから引っ張ってきたものです(完全に表現が同じというわけではありませんが)。
クラスターという言葉がよくわからなくなるので、用語を確認してみましょう。
なんだかんだで、全部のパターンでクラスターという用語を使うみたいです。
コンソールは、すべての Redis 用 ElastiCache クラスターに対してクラスターという用語を使用します。
この記述を見ていると
- クラスターが単一ノード Redis クラスターの場合。
- クラスターが単一のシャード内 (API および CLI ではノードグループと呼ばれる) のレプリケーションをサポートする Redis (クラスターモードが無効) クラスターである場合。
- クラスターが、1 – 90 のシャード内のレプリケーションをサポートする Redis (クラスターモードが有効) クラスターである場合。
以下で理解すれば良さそうです。
構成 | シャード数 | プライマリノード数 | レプリカノード数 | クラスターモード |
---|---|---|---|---|
シングルノード構成 | 1 | 1 | 0 | 無効 |
レプリケーション構成 | 1 | 1 | N(1〜5) | 無効 |
シャーディング構成 | S(1〜90) | S | S × N(0〜5) | 有効 |
ドキュメントとしては、このあたりを参考に。
レプリケーション: Redis (クラスターモードが無効) と Redis (クラスターモードが有効) の比較
このいずれも、"クラスター"と呼びます。また、どのパターンも1つ以上のシャードを持ちます。
本来のRedisというデータストアのクラスター(Redis Cluster)という用語が指すのは、シャーディング構成の場合のみですね。
まあ、ややこしいです…。
Amazon ElastiCache for Redisの接続エンドポイント
で、このいずれの構成を取るかで、利用するエンドポイントが変わるというのが今回の話です。
ちなみに、エンドポイントというのは
- アドレス
- ポート
で構成されるようです。
以下のドキュメントを見ていると、エンドポイントには4つの種類がありそうです。
Redis (クラスターモードが無効) クラスターのエンドポイントの検索 ((コンソール))
Redis (クラスターモードが有効) クラスターでのエンドポイントの検索 ((コンソール))
- (ノード単位の)Endpoint
- PrimaryEndpoint
- ReaderEndpoint
- ConfigurationEndpoint
使い方は、こんな感じですね。
エンドポイントの種類 | 意味 | 用途 | 使う構成 | クラスターモード |
---|---|---|---|---|
(ノード単位の)Endpoint | Redisノード単位のエンドポイント | Redisノードにアクセスするために使う(読み書き含む) | シングルノード構成 | 無効 |
PrimaryEndpoint | シャードのプライマリーノードのエンドポイント | シャードに対する書き込み操作を行うために使う | レプリケーション構成 | 無効 |
ReaderEndpoint | シャードのレプリカノード群のエンドポイント | シャードに対する読み込み操作を行うために使う | レプリケーション構成 | 無効 |
ConfigurationEndpoint | シャーディング構成全体に対するエンドポイント | シャーディング構成全体に対する読み込み、書き込み操作を行うために使う | シャーディング構成 | 有効 |
※ 後述の確認結果を見ていると、シングルノードでもPrimaryEndpointを使ってもいいんじゃないかという気はします
あと、実はこの他にReadEndpointというものもあり、これはノード単位の読み取りエンドポイントなようです。
これを、シャード内の(複数の)レプリカノードに対してバランシングしてくれるのが、ReaderEndpointということみたいです。
Amazon ElastiCache Redis にリーダーエンドポイントを開始
Amazon ElastiCache を Redis 向けに設定して可用性を高める
ReaderEndpointが出てくるまでは、各ノードのエンドポイントを管理していたってことですね…。
AWSのドキュメント上、「設定エンドポイント」とか「読み込みエンドポイント」とかになっていて、意味がわかりにくい気がします…。AWS CLIの結果と紐付けにくかったりもしますし…。
困ったら、英語版でどう書いてあるか見てみよう、という気分になりました。
では、説明はこんな感じにして、実際に試してみましょう。確認環境は、Terraformで構築することにします。
環境
今回の環境は、こちらです。
$ terraform version
Terraform v0.13.0
+ provider registry.terraform.io/hashicorp/aws v3.2.0
$ aws --version
aws-cli/2.0.40 Python/3.7.3 Linux/4.15.0-112-generic exe/x86_64.ubuntu.18
AWSのクレデンシャルは、環境変数で設定します。
$ export AWS_ACCESS_KEY_ID=...
$ export AWS_SECRET_ACCESS_KEY=...
$ export AWS_DEFAULT_REGION=ap-northeast-1
これから、以下の構成でそれぞれ試していきます。
- シングルノード構成
- レプリケーション構成
- シャーディング構成
Amazon ElastiCache for Redisの、Redis自体のバージョンは5.0.6とします。
確認は、Amazon ElastiCache for Redisと同じサブネット上にAmazon EC2を用意してredis-cli
から行いたいと思います。
こちらは、Amazon Linux 2で構築します。
$ sudo amazon-linux-extras install epel
$ sudo yum install https://rpms.remirepo.net/enterprise/remi-release-7.rpm
$ sudo yum search --showduplicates --enablerepo=remi search redis | grep '^redis-5'
redis-5.0.9-1.el7.remi.x86_64 : A persistent key-value database
$ sudo yum install --enablerepo=remi redis-5.0.9-1.el7.remi.x86_64
少しバージョンが新しいですが、今回はRedis 5.0.9をインストールして、redis-cli
のみを使います。
$ redis-cli -v
redis-cli 5.0.9
シングルノード構成
まずは、シングルノード構成から。
Terraformで、aws_elasticache_replication_group
、aws_elasticache_parameter_group
、aws_elasticache_subnet_group
をこんな感じで用意。
※その他の要素は、最後にまとめて載せます
# Single Node
resource "aws_elasticache_replication_group" "redis" {
replication_group_description = "My ElastiCache for Redis Replication Group"
replication_group_id = "my-redis-replication-group"
engine = "redis"
engine_version = "5.0.6"
node_type = "cache.t3.medium"
port = 6379
parameter_group_name = aws_elasticache_parameter_group.redis_parameter_group.name
security_group_ids = [module.elasticache_for_redis_cluster_sg.this_security_group_id]
subnet_group_name = aws_elasticache_subnet_group.redis_subnet.name
automatic_failover_enabled = false
number_cache_clusters = 1 # Primary Only
}
resource "aws_elasticache_parameter_group" "redis_parameter_group" {
family = "redis5.0"
name = "my-elasticache-for-redis-parameter-group"
parameter {
name = "cluster-enabled"
value = "no"
}
}
resource "aws_elasticache_subnet_group" "redis_subnet" {
name = "my-elasticache-for-redis-subnet-group"
subnet_ids = module.vpc.private_subnets
}
レプリケーショングループのidは、my-redis-replication-group
としています。
ところで、Terraformのaws_elasticache_replication_group
の出力結果としてエンドポイントやノードの情報として得られるのは、PrimaryEndpoint、ConfigurationEndpoint、そしてクラスター内のメンバーのようです。
Resource: aws_elasticache_replication_group / Attributes Reference
というわけで、とりあえずOutputに設定してみます。
output "redis_elasticache_replication_group_primary_endpoint_address" {
value = aws_elasticache_replication_group.redis.primary_endpoint_address
}
output "redis_elasticache_replication_group_configuration_endpoint_address" {
value = aws_elasticache_replication_group.redis.configuration_endpoint_address
}
output "redis_elasticache_replication_group_member_clusters" {
value = aws_elasticache_replication_group.redis.member_clusters
}
得られたのは、こんな感じですね。
Outputs:
redis_elasticache_replication_group_member_clusters = [
"my-redis-replication-group-001",
]
redis_elasticache_replication_group_primary_endpoint_address = my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com
"outputs": {
"redis_elasticache_replication_group_member_clusters": {
"value": [
"my-redis-replication-group-001"
],
"type": [
"set",
"string"
]
},
"redis_elasticache_replication_group_primary_endpoint_address": {
"value": "my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com",
"type": "string"
}
},
ConfigurationEndpointは、クラスターモードが有効でないと得られないようです。
configuration_endpoint_address - The address of the replication group configuration endpoint when cluster mode is enabled.
反対に、PrimaryEndpointはクラスターモードが無効の時に得られるようです。
primary_endpoint_address - (Redis only) The address of the endpoint for the primary node in the replication group, if the cluster mode is disabled.
ここで返ってくるエンドポイントは、アドレスのみのようですね(ポートがない)。
AWS CLIでも確認してみましょう。
$ aws elasticache describe-replication-groups \
--replication-group-id my-redis-replication-group | \
jq '..|.NodeGroups?'
null
[
{
"NodeGroupId": "0001",
"Status": "available",
"PrimaryEndpoint": {
"Address": "my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"ReaderEndpoint": {
"Address": "my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"NodeGroupMembers": [
{
"CacheClusterId": "my-redis-replication-group-001",
"CacheNodeId": "0001",
"ReadEndpoint": {
"Address": "my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"PreferredAvailabilityZone": "ap-northeast-1c",
"CurrentRole": "primary"
}
]
}
]
PrimaryEndpoint、ReaderEndpoint、ReadEndpointはそれぞれ違う値を指していますね。
今回は、どれを使っても同じ値が返ってくるようですが。
$ dig +short my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com
my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com.
10.0.40.66
$ dig +short my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com
my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com.
10.0.40.66
$ dig +short my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com
10.0.40.66
どのアドレスに接続しても、読み書きが可能です。
$ redis-cli -h my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com
my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com:6379> set key1 value1
OK
my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com:6379> get key1
"value1"
my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com:6379>
$ redis-cli -h my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com
my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com:6379> set key2 value2
OK
my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com:6379> get key2
"value2"
$ redis-cli -h my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com
my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com:6379> set key3 value3
OK
my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com:6379> get key3
"value3"
レプリケーションの情報も見てみましょう。ノード単位のエンドポイントで実行していますが、他のエンドポイントを使っても結果は同じです。
$ redis-cli -h my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com info replication
# Replication
role:master
connected_slaves:0
master_replid:5b13bc875ab08515dc6fbfde8060a9334ff6bd6d
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
ところで、今回作成したクラスターのidをAWS CLIで調べてみるとmy-redis-replication-group-001
のようです。
$ aws elasticache describe-cache-clusters | \
jq '..|.CacheClusterId?'
null
"my-redis-replication-group-001"
ノード単位の情報を見てみましょう。
$ aws elasticache describe-cache-clusters \
--cache-cluster-id my-redis-replication-group-001 \
--show-cache-node-info | \
jq '..|.CacheNodes?'
null
[
{
"CacheNodeId": "0001",
"CacheNodeStatus": "available",
"CacheNodeCreateTime": "2020-08-14T13:38:43.098000+00:00",
"Endpoint": {
"Address": "my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"ParameterGroupStatus": "in-sync",
"CustomerAvailabilityZone": "ap-northeast-1c"
}
]
これが、ノード単位のエンドポイントですね。
ちなみに、先ほどのレプリケーショングループの情報からすると、ReadEndpointと同じ値を指しています…。
# aws elasticache describe-replication-groups --replication-group-id my-redis-replication-group
"ReadEndpoint": {
"Address": "my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
# aws elasticache describe-cache-clusters --cache-cluster-id my-redis-replication-group-001 --show-cache-node-info
"Endpoint": {
"Address": "my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
この場合は、AWS CLIでノード単位のエンドポイントを取得した方が無難な感じでしょうかね。
この後のレプリケーション構成の結果を見ていると、PrimaryEndpointを使っていても良さそうな気もしますが。
ところで、TerraformだとReaderEndpointも取得できなさそうです。
Reader endpoint in aws_elasticache_replication_group #10519
はい。
ここで、1度リソースは破棄しておきます。
レプリケーション構成
続いて、レプリケーション構成にしてみます。
resource "aws_elasticache_replication_group" "redis" {
replication_group_description = "My ElastiCache for Redis Replication Group"
replication_group_id = "my-redis-replication-group"
engine = "redis"
engine_version = "5.0.6"
node_type = "cache.t3.medium"
port = 6379
parameter_group_name = aws_elasticache_parameter_group.redis_parameter_group.name
security_group_ids = [module.elasticache_for_redis_cluster_sg.this_security_group_id]
subnet_group_name = aws_elasticache_subnet_group.redis_subnet.name
automatic_failover_enabled = true
number_cache_clusters = 3 # Primary : Replica = 1 : 2
}
resource "aws_elasticache_parameter_group" "redis_parameter_group" {
family = "redis5.0"
name = "my-elasticache-for-redis-parameter-group"
parameter {
name = "cluster-enabled"
value = "no"
}
}
resource "aws_elasticache_subnet_group" "redis_subnet" {
name = "my-elasticache-for-redis-subnet-group"
subnet_ids = module.vpc.private_subnets
}
シングルノードの時とほとんど同じですが、ちょっとだけ差が有ります。
プライマリノードに対して、レプリカノードを2つとしてみました。
number_cache_clusters = 3 # Primary : Replica = 1 : 2
あと、なんとなく自動フェイルオーバーは有効にしています。
automatic_failover_enabled = true
outputは、こんな感じになりました。
Outputs:
redis_elasticache_replication_group_member_clusters = [
"my-redis-replication-group-001",
"my-redis-replication-group-002",
"my-redis-replication-group-003",
]
redis_elasticache_replication_group_primary_endpoint_address = my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com
"outputs": {
"redis_elasticache_replication_group_member_clusters": {
"value": [
"my-redis-replication-group-001",
"my-redis-replication-group-002",
"my-redis-replication-group-003"
],
"type": [
"set",
"string"
]
},
"redis_elasticache_replication_group_primary_endpoint_address": {
"value": "my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com",
"type": "string"
}
},
member_clusters
内の数が増え、primary_endpoint_address
も得られましたが、相変わらずconfiguration_endpoint_address
はありません。
AWS CLIで確認してみます。
$ aws elasticache describe-replication-groups \
--replication-group-id my-redis-replication-group | \
jq '..|.NodeGroups?'
null
[
{
"NodeGroupId": "0001",
"Status": "available",
"PrimaryEndpoint": {
"Address": "my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"ReaderEndpoint": {
"Address": "my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"NodeGroupMembers": [
{
"CacheClusterId": "my-redis-replication-group-001",
"CacheNodeId": "0001",
"ReadEndpoint": {
"Address": "my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"PreferredAvailabilityZone": "ap-northeast-1c",
"CurrentRole": "primary"
},
{
"CacheClusterId": "my-redis-replication-group-002",
"CacheNodeId": "0001",
"ReadEndpoint": {
"Address": "my-redis-replication-group-002.dl12u5.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"PreferredAvailabilityZone": "ap-northeast-1c",
"CurrentRole": "replica"
},
{
"CacheClusterId": "my-redis-replication-group-003",
"CacheNodeId": "0001",
"ReadEndpoint": {
"Address": "my-redis-replication-group-003.dl12u5.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"PreferredAvailabilityZone": "ap-northeast-1a",
"CurrentRole": "replica"
}
]
}
]
今回の構成では、ReadEndpointの数が増えています。ノードが増えているので、当たり前ですが。
EC2内から、dig
で確認してみます。
# PrimaryEndpoint
$ dig +short my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com
my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com.
10.0.40.53
# ReaderEndpoint
$ dig +short my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com
my-redis-replication-group-002.dl12u5.0001.apne1.cache.amazonaws.com.
10.0.40.31
$ dig +short my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com
my-redis-replication-group-003.dl12u5.0001.apne1.cache.amazonaws.com.
10.0.30.200
# ノード単位のReadEndpoint
$ dig +short my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com
10.0.40.53
$ dig +short my-redis-replication-group-002.dl12u5.0001.apne1.cache.amazonaws.com
10.0.40.31
$ dig +short my-redis-replication-group-003.dl12u5.0001.apne1.cache.amazonaws.com
10.0.30.200
それぞれの値は、実ノードのIPアドレスを指しているようです。また、ReaderEndpointに関しては、各レプリカのIPアドレスを返すようですね。
というか、ノードのReadEndpointを指してました…。
$ dig my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com
...
;; ANSWER SECTION:
my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com. 15 IN CNAME my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com.
my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com. 15 IN A 10.0.40.53
$ dig my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com
...
;; ANSWER SECTION:
my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com. 1 IN CNAME my-redis-replication-group-002.dl12u5.0001.apne1.cache.amazonaws.com.
my-redis-replication-group-002.dl12u5.0001.apne1.cache.amazonaws.com. 11 IN A 10.0.40.31
redis-cli
で接続して、確認してみましょう。
# PrimaryEndpoint
$ redis-cli -h my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com
my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com:6379> set key1 value1
OK
my-redis-replication-group.dl12u5.ng.0001.apne1.cache.amazonaws.com:6379> get key1
"value1"
# ReaderEndpoint
$ redis-cli -h my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com
my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com:6379> set key2 value2
(error) READONLY You can't write against a read only replica.
my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com:6379> get key1
"value1"
# ノード単位のReadEndpoint
## Primary
$ redis-cli -h my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com
my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com:6379> set key2 value2
OK
my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com:6379> get key2
"value2"
## Replica
$ redis-cli -h my-redis-replication-group-002.dl12u5.0001.apne1.cache.amazonaws.com
my-redis-replication-group-002.dl12u5.0001.apne1.cache.amazonaws.com:6379> set key3 value3
(error) READONLY You can't write against a read only replica.
my-redis-replication-group-002.dl12u5.0001.apne1.cache.amazonaws.com:6379> get key1
"value1"
my-redis-replication-group-002.dl12u5.0001.apne1.cache.amazonaws.com:6379>
$ redis-cli -h my-redis-replication-group-003.dl12u5.0001.apne1.cache.amazonaws.com
my-redis-replication-group-003.dl12u5.0001.apne1.cache.amazonaws.com:6379> set key3 value3
(error) READONLY You can't write against a read only replica.
my-redis-replication-group-003.dl12u5.0001.apne1.cache.amazonaws.com:6379> get key1
"value1"
レプリケーションの情報も見てみます。
# PrimaryEndpoint
$ redis-cli -h my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com info replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.3.0.243,port=6379,state=online,offset=62865,lag=1
slave1:ip=10.3.2.218,port=6379,state=online,offset=62812,lag=1
master_replid:3acb819b47caa9b0b0d88a10565e5afd87707b75
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:62865
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:62865
# ReaderEndpoint
$ redis-cli -h my-redis-replication-group-ro.dl12u5.ng.0001.apne1.cache.amazonaws.com info replication
# Replication
role:slave
master_host:my-redis-replication-group.dl12u5.0001.internal.apne1.cache.amazonaws.com
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:65426
repl_sync_enabled:1
slave_read_reploff:65426
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:3acb819b47caa9b0b0d88a10565e5afd87707b75
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:65426
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1686
repl_backlog_histlen:63741
# ノード単位のReadEndpoint
## Primary
$ redis-cli -h my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com info replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.3.0.243,port=6379,state=online,offset=67496,lag=1
slave1:ip=10.3.2.218,port=6379,state=online,offset=67496,lag=1
master_replid:3acb819b47caa9b0b0d88a10565e5afd87707b75
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:67496
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:67496
## Replica
$ redis-cli -h my-redis-replication-group-002.dl12u5.0001.apne1.cache.amazonaws.com info replication
# Replication
role:slave
master_host:my-redis-replication-group.dl12u5.0001.internal.apne1.cache.amazonaws.com
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:68093
repl_sync_enabled:1
slave_read_reploff:68093
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:3acb819b47caa9b0b0d88a10565e5afd87707b75
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:68093
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1686
repl_backlog_histlen:66408
$ redis-cli -h my-redis-replication-group-003.dl12u5.0001.apne1.cache.amazonaws.com info replication
# Replication
role:slave
master_host:my-redis-replication-group.dl12u5.0001.internal.apne1.cache.amazonaws.com
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:68902
repl_sync_enabled:1
slave_read_reploff:68902
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:3acb819b47caa9b0b0d88a10565e5afd87707b75
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:68902
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1686
repl_backlog_histlen:67217
ここで、クラスターのidを調べてみます。
$ aws elasticache describe-cache-clusters | \
jq '..|.CacheClusterId?'
null
"my-redis-replication-group-001"
null
null
null
"my-redis-replication-group-002"
null
null
null
"my-redis-replication-group-003"
3つあります…。
それぞれ、ノード単位のエンドポイントも合わせて見てみましょう。
$ aws elasticache describe-cache-clusters \
--cache-cluster-id my-redis-replication-group-001 \
--show-cache-node-info | \
jq '..|.CacheNodes?'
null
[
{
"CacheNodeId": "0001",
"CacheNodeStatus": "available",
"CacheNodeCreateTime": "2020-08-14T15:03:02.292000+00:00",
"Endpoint": {
"Address": "my-redis-replication-group-001.dl12u5.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"ParameterGroupStatus": "in-sync",
"CustomerAvailabilityZone": "ap-northeast-1c"
}
]
$ aws elasticache describe-cache-clusters \
--cache-cluster-id my-redis-replication-group-002 \
--show-cache-node-info | \
jq '..|.CacheNodes?'
null
[
{
"CacheNodeId": "0001",
"CacheNodeStatus": "available",
"CacheNodeCreateTime": "2020-08-14T15:03:02.292000+00:00",
"Endpoint": {
"Address": "my-redis-replication-group-002.dl12u5.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"ParameterGroupStatus": "in-sync",
"CustomerAvailabilityZone": "ap-northeast-1c"
}
]
$ aws elasticache describe-cache-clusters \
--cache-cluster-id my-redis-replication-group-003 \
--show-cache-node-info | \
jq '..|.CacheNodes?'
null
[
{
"CacheNodeId": "0001",
"CacheNodeStatus": "available",
"CacheNodeCreateTime": "2020-08-14T15:03:02.292000+00:00",
"Endpoint": {
"Address": "my-redis-replication-group-003.dl12u5.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"ParameterGroupStatus": "in-sync",
"CustomerAvailabilityZone": "ap-northeast-1a"
}
]
これに関してはシングルノードの時と同様、ノード単位のEndpointは、ノード単位のReadEndpointと同じ値を指していますね。
なるほど。
シャーディング構成
最後は、シャーディング構成です。
resource "aws_elasticache_replication_group" "redis" {
replication_group_description = "My ElastiCache for Redis Replication Group"
replication_group_id = "my-redis-replication-group"
engine = "redis"
engine_version = "5.0.6"
node_type = "cache.t3.medium"
port = 6379
parameter_group_name = aws_elasticache_parameter_group.redis_parameter_group.name
security_group_ids = [module.elasticache_for_redis_cluster_sg.this_security_group_id]
subnet_group_name = aws_elasticache_subnet_group.redis_subnet.name
automatic_failover_enabled = true
cluster_mode {
replicas_per_node_group = 2 # 2 Replica
num_node_groups = 3 # 3 Shard
}
}
resource "aws_elasticache_parameter_group" "redis_parameter_group" {
family = "redis5.0"
name = "my-elasticache-for-redis-parameter-group"
parameter {
name = "cluster-enabled"
value = "yes"
}
}
resource "aws_elasticache_subnet_group" "redis_subnet" {
name = "my-elasticache-for-redis-subnet-group"
subnet_ids = module.vpc.private_subnets
}
今回は、クラスターモード専用の設定が入ります。
cluster_mode {
replicas_per_node_group = 2 # 2 Replica
num_node_groups = 3 # 3 Shard
}
3シャードで、各シャード内には2レプリカ、という構成にしています。
合計9ノードできますね。
あと、パラメーターグループでも、明示的にcluster-enabled
をyes
にしておきました。
resource "aws_elasticache_parameter_group" "redis_parameter_group" {
family = "redis5.0"
name = "my-elasticache-for-redis-parameter-group"
parameter {
name = "cluster-enabled"
value = "yes"
}
}
Outputは、こんな感じに。
Outputs:
redis_elasticache_replication_group_configuration_endpoint_address = my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com
redis_elasticache_replication_group_member_clusters = [
"my-redis-replication-group-0001-001",
"my-redis-replication-group-0001-002",
"my-redis-replication-group-0001-003",
"my-redis-replication-group-0002-001",
"my-redis-replication-group-0002-002",
"my-redis-replication-group-0002-003",
"my-redis-replication-group-0003-001",
"my-redis-replication-group-0003-002",
"my-redis-replication-group-0003-003",
]
9ノードできています。
今回は、configuration_endpoint_address
が入りましたね。代わりに、primary_endpoint_address
がなくなりました。
"outputs": {
"redis_elasticache_replication_group_configuration_endpoint_address": {
"value": "my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com",
"type": "string"
},
"redis_elasticache_replication_group_member_clusters": {
"value": [
"my-redis-replication-group-0001-001",
"my-redis-replication-group-0001-002",
"my-redis-replication-group-0001-003",
"my-redis-replication-group-0002-001",
"my-redis-replication-group-0002-002",
"my-redis-replication-group-0002-003",
"my-redis-replication-group-0003-001",
"my-redis-replication-group-0003-002",
"my-redis-replication-group-0003-003"
],
"type": [
"set",
"string"
]
}
},
AWS CLIで見てみます。
$ aws elasticache describe-replication-groups \
--replication-group-id my-redis-replication-group | \
jq '..|.ConfigurationEndpoint?'
null
{
"Address": "my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com",
"Port": 6379
}
今回の構成では、ConfigurationEndpointが得られるようになります。代わりに、PrimaryEndpointやReaderEndpointは得られなくなります。
ノードの情報も見ておきましょうか。
$ aws elasticache describe-replication-groups \
--replication-group-id my-redis-replication-group | \
jq '..|.NodeGroups?'
null
[
{
"NodeGroupId": "0001",
"Status": "available",
"Slots": "0-5461",
"NodeGroupMembers": [
{
"CacheClusterId": "my-redis-replication-group-0001-001",
"CacheNodeId": "0001",
"PreferredAvailabilityZone": "ap-northeast-1c"
},
{
"CacheClusterId": "my-redis-replication-group-0001-002",
"CacheNodeId": "0001",
"PreferredAvailabilityZone": "ap-northeast-1c"
},
{
"CacheClusterId": "my-redis-replication-group-0001-003",
"CacheNodeId": "0001",
"PreferredAvailabilityZone": "ap-northeast-1a"
}
]
},
{
"NodeGroupId": "0002",
"Status": "available",
"Slots": "5462-10922",
"NodeGroupMembers": [
{
"CacheClusterId": "my-redis-replication-group-0002-001",
"CacheNodeId": "0001",
"PreferredAvailabilityZone": "ap-northeast-1a"
},
{
"CacheClusterId": "my-redis-replication-group-0002-002",
"CacheNodeId": "0001",
"PreferredAvailabilityZone": "ap-northeast-1a"
},
{
"CacheClusterId": "my-redis-replication-group-0002-003",
"CacheNodeId": "0001",
"PreferredAvailabilityZone": "ap-northeast-1c"
}
]
},
{
"NodeGroupId": "0003",
"Status": "available",
"Slots": "10923-16383",
"NodeGroupMembers": [
{
"CacheClusterId": "my-redis-replication-group-0003-001",
"CacheNodeId": "0001",
"PreferredAvailabilityZone": "ap-northeast-1a"
},
{
"CacheClusterId": "my-redis-replication-group-0003-002",
"CacheNodeId": "0001",
"PreferredAvailabilityZone": "ap-northeast-1c"
},
{
"CacheClusterId": "my-redis-replication-group-0003-003",
"CacheNodeId": "0001",
"PreferredAvailabilityZone": "ap-northeast-1c"
}
]
}
]
他のEndpointの情報、まったくなくなりましたね…?
describe-replication-groups / Output
ReadEndpoint -> (structure)
The information required for client programs to connect to a node for read operations. The read endpoint is only applicable on Redis (cluster mode disabled) clusters.
確かに、クラスターモードが無効でないと、ReadEndpointは出力されないみたいですね。
PrimaryEndpointと、ReaderEndpointもなくなりましたけど。
dig
でConfigurationEndpointを見てみましょう。
$ dig my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com
...
;; ANSWER SECTION:
my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com. 15 IN A 10.0.40.137
my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com. 15 IN A 10.0.40.191
my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com. 15 IN A 10.0.30.6
my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com. 15 IN A 10.0.30.42
my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com. 15 IN A 10.0.30.194
my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com. 15 IN A 10.0.30.254
my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com. 15 IN A 10.0.40.12
my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com. 15 IN A 10.0.40.15
my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com. 15 IN A 10.0.40.68
全ノード分を指してる感じがしますね…。
redis-cli
で接続してみましょう。
$ redis-cli -h my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com
my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com:6379> set key1 value1
(error) MOVED 9189 10.0.30.194:6379
データを登録しようとしたら、エラーになりました。
Redis Clusterとして動作しているようなので、-c
オプションが必要ですね。
$ redis-cli -c -h my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com
my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com:6379> set key1 value1
-> Redirected to slot [9189] located at 10.0.30.194:6379
OK
10.0.30.194:6379> get key1
"value1"
10.0.30.194:6379> set key2 value2
-> Redirected to slot [4998] located at 10.0.40.15:6379
OK
10.0.40.15:6379> get key2
"value2"
10.0.40.15:6379> set key3 value3
OK
10.0.40.15:6379> get key3
"value3"
リダイレクトに追従して、動作しました。
クラスタの情報を見てみましょう。
$ redis-cli -h my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com cluster nodes
89260a12e7bf9e0b9598c5897b51a0a2d7502939 10.0.30.6:6379@1122 myself,master - 0 1597420677000 0 connected 10923-16383
35547892f11e00fc59c940892d573fe03ac2788b 10.0.30.194:6379@1122 master - 0 1597420679000 3 connected 5462-10922
4e6acd4049362d8111c00a280625d207f0aac883 10.0.40.12:6379@1122 slave 89260a12e7bf9e0b9598c5897b51a0a2d7502939 0 1597420680967 0 connected
8a478b2499d0ac68ac78fbc40b286ca93354f401 10.0.30.254:6379@1122 slave 1b0582425b6597b194d8c334dc80af1dafa81d0a 0 1597420679000 1 connected
0a00719c18721972bcfd9f70edfc436ff8145a79 10.0.40.191:6379@1122 slave 35547892f11e00fc59c940892d573fe03ac2788b 0 1597420679000 3 connected
1b0582425b6597b194d8c334dc80af1dafa81d0a 10.0.40.15:6379@1122 master - 0 1597420681000 1 connected 0-5461
29dfadb6042b119bd11e03f8a76754a615709288 10.0.30.42:6379@1122 slave 35547892f11e00fc59c940892d573fe03ac2788b 0 1597420679000 3 connected
17196d689a040d3a03c89930065bd5d525b3760b 10.0.40.137:6379@1122 slave 89260a12e7bf9e0b9598c5897b51a0a2d7502939 0 1597420681000 0 connected
71279c2f1b7afed0cab5f8f1f1e9dc86f41fc702 10.0.40.68:6379@1122 slave 1b0582425b6597b194d8c334dc80af1dafa81d0a 0 1597420681970 1 connected
3つのマスターノード、6つのスレーブノードがありますね。
ちなみに、レプリケーションの情報として見ると、こうなります。
$ redis-cli -h my-redis-replication-group.dl12u5.clustercfg.apne1.cache.amazonaws.com info replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.3.2.215,port=6379,state=online,offset=54891,lag=0
slave1:ip=10.3.2.46,port=6379,state=online,offset=54824,lag=1
master_replid:87f1db07458e72bbfac1f59505a7fa20e0249acf
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:54891
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:54891
スレーブは2つですね。ひとつのシャード内で見ているので。
クラスターのidを見てみます。
$ aws elasticache describe-cache-clusters | \
jq '..|.CacheClusterId?'
null
"my-redis-replication-group-0001-001"
null
null
null
"my-redis-replication-group-0001-002"
null
null
null
"my-redis-replication-group-0001-003"
null
null
null
"my-redis-replication-group-0002-001"
null
null
null
"my-redis-replication-group-0002-002"
null
null
null
"my-redis-replication-group-0002-003"
null
null
null
"my-redis-replication-group-0003-001"
null
null
null
"my-redis-replication-group-0003-002"
null
null
null
"my-redis-replication-group-0003-003"
9つありますね…。
ノードの情報も、いくつかピックアップで見てみましょう。
$ aws elasticache describe-cache-clusters \
--cache-cluster-id my-redis-replication-group-0001-001 \
--show-cache-node-info | \
jq '..|.CacheNodes?'
null
[
{
"CacheNodeId": "0001",
"CacheNodeStatus": "available",
"CacheNodeCreateTime": "2020-08-14T15:49:54.669000+00:00",
"Endpoint": {
"Address": "my-redis-replication-group-0001-001.dl12u5.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"ParameterGroupStatus": "in-sync",
"CustomerAvailabilityZone": "ap-northeast-1c"
}
]
$ aws elasticache describe-cache-clusters \
--cache-cluster-id my-redis-replication-group-0001-002 \
--show-cache-node-info | \
jq '..|.CacheNodes?'
null
[
{
"CacheNodeId": "0001",
"CacheNodeStatus": "available",
"CacheNodeCreateTime": "2020-08-14T15:49:54.669000+00:00",
"Endpoint": {
"Address": "my-redis-replication-group-0001-002.dl12u5.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"ParameterGroupStatus": "in-sync",
"CustomerAvailabilityZone": "ap-northeast-1c"
}
]
$ aws elasticache describe-cache-clusters \
--cache-cluster-id my-redis-replication-group-0003-001 \
--show-cache-node-info | \
jq '..|.CacheNodes?'
null
[
{
"CacheNodeId": "0001",
"CacheNodeStatus": "available",
"CacheNodeCreateTime": "2020-08-14T15:49:54.669000+00:00",
"Endpoint": {
"Address": "my-redis-replication-group-0003-001.dl12u5.0001.apne1.cache.amazonaws.com",
"Port": 6379
},
"ParameterGroupStatus": "in-sync",
"CustomerAvailabilityZone": "ap-northeast-1a"
}
]
こうすると、ノード単位のEndpointは得られますね。といっても、この構成の場合はConfigurationEndpointを使うことになるので、ノード単位のEndpointの情報は使わないのでしょうけど。
とりあえず、3つの構成パターンでエンドポイントに関する確認はできました、と。
オマケ
作成した、Terraformの構成ファイル全体です。
Amazon VPCやセキュリティグループについては、Terraformモジュールを利用しています。
シャーディング構成、レプリケーション構成、スタンドアロン構成の3つは、コメントで切り替える感じです。
また、redis-cli
で使っていたEC2は、自作のモジュールで簡単に済ませました(1番最後に書いてるやつです)。
main.tf
terraform {
required_version = "0.13.0"
}
provider "aws" {
version = "3.2.0"
}
module "elasticache_for_redis_cluster_sg" {
source = "terraform-aws-modules/security-group/aws"
version = "3.15.0"
name = "app-with-nginx-rp-service-sg"
vpc_id = module.vpc.vpc_id
ingress_with_cidr_blocks = [
{
from_port = 6379
to_port = 6379
protocol = "tcp"
description = "ElastiCache for Redis Cluster inbound ports"
cidr_blocks = "10.0.30.0/24"
},
{
from_port = 6379
to_port = 6379
protocol = "tcp"
description = "ElastiCache for Redis Cluster inbound ports"
cidr_blocks = "10.0.40.0/24"
}
]
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "2.47.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
azs = ["ap-northeast-1a", "ap-northeast-1c"]
public_subnets = ["10.0.10.0/24", "10.0.20.0/24"]
private_subnets = ["10.0.30.0/24", "10.0.40.0/24"]
map_public_ip_on_launch = true
enable_nat_gateway = true
single_nat_gateway = false
one_nat_gateway_per_az = true
}
# Cluster
resource "aws_elasticache_replication_group" "redis" {
replication_group_description = "My ElastiCache for Redis Replication Group"
replication_group_id = "my-redis-replication-group"
engine = "redis"
engine_version = "5.0.6"
node_type = "cache.t3.medium"
port = 6379
parameter_group_name = aws_elasticache_parameter_group.redis_parameter_group.name
security_group_ids = [module.elasticache_for_redis_cluster_sg.this_security_group_id]
subnet_group_name = aws_elasticache_subnet_group.redis_subnet.name
automatic_failover_enabled = true
cluster_mode {
replicas_per_node_group = 2 # 2 Replica
num_node_groups = 3 # 3 Shard
}
}
resource "aws_elasticache_parameter_group" "redis_parameter_group" {
family = "redis5.0"
name = "my-elasticache-for-redis-parameter-group"
parameter {
name = "cluster-enabled"
value = "yes"
}
}
# Replication
/*
resource "aws_elasticache_replication_group" "redis" {
replication_group_description = "My ElastiCache for Redis Replication Group"
replication_group_id = "my-redis-replication-group"
engine = "redis"
engine_version = "5.0.6"
node_type = "cache.t3.medium"
port = 6379
parameter_group_name = aws_elasticache_parameter_group.redis_parameter_group.name
security_group_ids = [module.elasticache_for_redis_cluster_sg.this_security_group_id]
subnet_group_name = aws_elasticache_subnet_group.redis_subnet.name
automatic_failover_enabled = true
number_cache_clusters = 3 # Primary : Replica = 1 : 2
}
resource "aws_elasticache_parameter_group" "redis_parameter_group" {
family = "redis5.0"
name = "my-elasticache-for-redis-parameter-group"
parameter {
name = "cluster-enabled"
value = "no"
}
}
*/
# Single Node
/*
resource "aws_elasticache_replication_group" "redis" {
replication_group_description = "My ElastiCache for Redis Replication Group"
replication_group_id = "my-redis-replication-group"
engine = "redis"
engine_version = "5.0.6"
node_type = "cache.t3.medium"
port = 6379
parameter_group_name = aws_elasticache_parameter_group.redis_parameter_group.name
security_group_ids = [module.elasticache_for_redis_cluster_sg.this_security_group_id]
subnet_group_name = aws_elasticache_subnet_group.redis_subnet.name
automatic_failover_enabled = false
number_cache_clusters = 1 # Primary Only
}
resource "aws_elasticache_parameter_group" "redis_parameter_group" {
family = "redis5.0"
name = "my-elasticache-for-redis-parameter-group"
parameter {
name = "cluster-enabled"
value = "no"
}
}
*/
resource "aws_elasticache_subnet_group" "redis_subnet" {
name = "my-elasticache-for-redis-subnet-group"
subnet_ids = module.vpc.private_subnets
}
output "redis_elasticache_replication_group_primary_endpoint_address" {
value = aws_elasticache_replication_group.redis.primary_endpoint_address
}
output "redis_elasticache_replication_group_configuration_endpoint_address" {
value = aws_elasticache_replication_group.redis.configuration_endpoint_address
}
output "redis_elasticache_replication_group_member_clusters" {
value = aws_elasticache_replication_group.redis.member_clusters
}
module "client_instance" {
source = "github.com/charon-r13b/ssh-key-less-ec2-instance"
vpc_id = module.vpc.vpc_id
subnet_id = module.vpc.private_subnets[0]
module_creation_iam_role_name = "MyElastiCacheSshKeyLessEc2Role"
module_creation_iam_instance_profile_name = "MyElastiCacheSshKeyLessEc2InstanceProfile"
}