以下の UniversalClient で Redis Cluster(AWS Elasticache) にアクセスしたところ、 "MOVED 1738 127.0.0.1:6379" みたいなエラーが発生した。 www.pospome.work
MOVED というエラー自体は Redis Cluster のもので、アクセス対象のデータを持っているノードへのリダイレクトらしい。 https://redis.io/topics/cluster-spec
このエラーが発生していた原因は go-redis の NewUniversalClient() のパラメータ設定だった。
NewUniversalClient() は引数に指定するノード数によって、 クライアントが Single Redis 用のものなのか Cluster 用のものなのかが決まる。 具体的に言うとノード数が複数の場合は Cluster になり、1つの場合は Single Redis になる。
// NewUniversalClient returns a new multi client. The type of client returned depends // on the following three conditions: // // 1. if a MasterName is passed a sentinel-backed FailoverClient will be returned // 2. if the number of Addrs is two or more, a ClusterClient will be returned // 3. otherwise, a single-node redis Client will be returned. func NewUniversalClient(opts *UniversalOptions) UniversalClient { if opts.MasterName != "" { return NewFailoverClient(opts.Failover()) } else if len(opts.Addrs) > 1 { return NewClusterClient(opts.Cluster()) } return NewClient(opts.Simple()) }
https://github.com/go-redis/redis/blob/v8.4.0/universal.go#L199
そのため Redis Cluster では以下のようにノードを複数指定することで、Cluster 用のクライアントを生成することになる。
rdb := redis.NewUniversalClient(&redis.UniversalOptions{ Addrs: []string{":7000", ":7001", ":7002", ":7003", ":7004", ":7005"}, })
Single Redis はノードが1つしかないので、"ノードを1つのみ指定する = Single Redis である" というのはたしかにそーだが、
AWS の Elasticache Redis Cluster には "Configuration Endpoint" という単一のエンドポイントがあり、
これを利用すればノードを意識せずに Redis を操作することができる。
https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/Endpoints.html
なので、Elasticache に関しては以下のように Configuration Endpoint のみ指定していたのだが、 これだと NewUniversalClient() で生成されるクライアントは Single Redis 用のものになってしまい、MOVED Error が発生してしまう。
rdb := redis.NewUniversalClient(&redis.UniversalOptions{ Addrs: []string{"configuration_endpoint:1234"}, })
とりあえず以下のように同じ Configuration Endpoint を2つ指定することでエラーは発生しなくなった。
rdb := redis.NewUniversalClient(&redis.UniversalOptions{ Addrs: []string{"configuration_endpoint:1234", "configuration_endpoint:1234"}, })