ずっとRedis Cluster を使っているものの、ローカル環境を作るのが面倒で数年来避けてきました。 今回 Redis 7.0 の Shared Pub/Sub をしたくなったので、重い腰を上げてローカル環境に Docker Compose で Redis Cluster を構築したメモです。
- tl;dr;
- Redis Cluster を起動する Docker Compose
- Redis Cluster のコマンドを試す
- (余談) StackExchange.Redis の Shared Pub/Sub 対応
- (余談2) Grokzen/docker-redis-cluster は使うのは難しい
tl;dr;
ローカルでも Redis Cluster が組めるのは、ElastiCache for Redis Cluster や MemoryDB が VPC外部からのアクセスが原則制約ある点を踏まえてもうれしいですね。
- 従来めんどくさかった Redis Cluster 構築も Docker Compose で簡単に行えるようになった
- 今後 Redis Cluster で Pub/Sub するなら、Global Pub/Sub から Shared Pub/Sub に変えていきたいところ
gist おいておきます。
https://gist.github.com/guitarrapc/2c6625acfab1c771f1543d917e3a6dd9
Redis Cluster を起動する Docker Compose
次の compose.yaml
を用意して、 docker compose up -d
1 で起動すれば Redis Cluster がローカル環境で触れるようになります。
コツは、 bitnami/redis-cluster
を使うことです。 bitnami の redis イメージは公式に追随しつつ扱いやすいように env 対応されていたりといい感じなのでよいです、おすすめ。
services: redis-node-0: image: docker.io/bitnami/redis-cluster:7.0 environment: - 'REDIS_PASSWORD=bitnami' - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5' redis-node-1: image: docker.io/bitnami/redis-cluster:7.0 environment: - 'REDIS_PASSWORD=bitnami' - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5' redis-node-2: image: docker.io/bitnami/redis-cluster:7.0 environment: - 'REDIS_PASSWORD=bitnami' - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5' redis-node-3: image: docker.io/bitnami/redis-cluster:7.0 environment: - 'REDIS_PASSWORD=bitnami' - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5' redis-node-4: image: docker.io/bitnami/redis-cluster:7.0 environment: - 'REDIS_PASSWORD=bitnami' - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5' redis-node-5: image: docker.io/bitnami/redis-cluster:7.0 depends_on: - redis-node-0 - redis-node-1 - redis-node-2 - redis-node-3 - redis-node-4 environment: - 'REDIS_PASSWORD=bitnami' - 'REDISCLI_AUTH=bitnami' - 'REDIS_CLUSTER_REPLICAS=1' - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5' - 'REDIS_CLUSTER_CREATOR=yes' ports: - 6379:6379 redis: image: bitnami/redis:7.0 environment: - ALLOW_EMPTY_PASSWORD=yes
Redis Cluster のコマンドを試す
Redis 7.0 から、Redisの Pub/Sub にSharded Pub/Subを行うためのコマンド SSUBSCRIBE
、SPUBLISH
が追加されました。従来の グローバルPub/Sub に使う SUBSCRIBE
、PUBLISH
には、Redis Cluster で Pub/Sub するとクラスター内部にメッセージが伝搬するためスケール問題を起こすことが知られています。この問題はShared Pub/Sub で改善されるので、Pub/Sub を使うRedis Cluster も水平スケール可能になります。
ということで、Shard Pub/Sub を先ほどDocker Compose で構築したRedis Cluster で試しましょう。
Pub/Subなので、まずは SSUBSCRIBE します。適当にマスターノードにつなぐと指定したキー sfoo
を管理するシャードにredis-cliが自動的にリダイレクトされます。2
$ docker compose exec redis /bin/bash $ redis-cli -h redis-node-5 -a bitnami -c redis-node-5:6379> ssubscribe sfoo Reading messages... (press Ctrl-C to quit) -> Redirected to slot [13887] located at 172.18.0.3:6379 Reading messages... (press Ctrl-C to quit) 1) "ssubscribe" 2) "sfoo" 3) (integer) 1
別シェルで sfoo
キーに SPUBLISH すると、自動的に同じシャードにリダイレクトされてメッセージが発行されます。
$ docker compose exec redis /bin/bash $ redis-cli -h redis-node-5 -a bitnami -c redis-node-5:6379> spublish sfoo 1 -> Redirected to slot [13887] located at 172.18.0.3:6379 (integer) 1 172.18.0.3:6379> spublish sfoo 2 (integer) 1
すると、先ほど SSUBSCRIBE した側で購読されます。いい感じですね。
1) "smessage" 2) "sfoo" 3) "1" 1) "smessage" 2) "sfoo" 3) "2"
別のキー sbar
にしても同様です。キーを変更してSSUBSCRIBE します。
172.18.0.3:6379> ssubscribe sbar Reading messages... (press Ctrl-C to quit) -> Redirected to slot [2668] located at 172.18.0.2:6379 Reading messages... (press Ctrl-C to quit) 1) "ssubscribe" 2) "sbar" 3) (integer) 1
sbar
キーに SPUBLISH します。
172.18.0.3:6379> spublish sbar hogemoge -> Redirected to slot [2668] located at 172.18.0.2:6379 (integer) 1
意図通り、SSUBSCRIBE している側で購読されます。
1) "smessage" 2) "sbar" 3) "hogemoge"
以前、Redis Cluster にグローバルPub/Sub しかないときにPub/Subを組んだ時はノードを増やしても性能がスケールしなかったのですが、Shared Pub/Sub で改善しそうなので使っていけるか負荷かけたりして判断していきたいです。
ElastiCache for Redis は NLBを介することで外部からアクセスできます。しかし、Shared Pub/Sub はシャード管理しているノードへ接続がリダイレクトされるため、同手法は使えないと予想されます。開発環境の ElastiCache につなげないなら、代わりにローカルでRedis Cluster を使いたくなるでしょうから、今回のDocker Compose 手法が役立つでしょう。3
(余談) StackExchange.Redis の Shared Pub/Sub 対応
C# で Redis を扱う場合、StackExchange.Redis が事実上のデファクトスタンダードです。しかし、Missing Commands in StackExchange.Redis · Issue #2055 · StackExchange/StackExchange.Redis を見ると、SSUBSCRIBE/SPUBLISH のサポートはされていません。実装を探してもまだも見つからないので、使うには自前拡張がいる感じです。
(余談2) Grokzen/docker-redis-cluster は使うのは難しい
Redis Cluster の Docker イメージとしては Grokzen/docker-redis-cluster もあり、これを使うとRedis Cluster が1コンテナで起動してくれます。簡便ではあるものの構成上の副作用として、この Redis Cluster は外部から個別ノードへの接続を考慮しておらず4、同コンテナに exec してローカルホストからつな具必要があります。 コンテナの外から試せないので、適当に LinqPad や VS からRedis Cluster 試すのは難しく、利用ケースが限られてしまいますね。