ずっと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試すのは難しく、利用ケースが限られてしまいますね。