tech.guitarrapc.cóm

Technical updates

Docker ComposeでローカルマシンにRedisClusterを構築する

ずっとRedis Clusterを使っているものの、ローカル環境を作るのが面倒で数年来避けてきました。 今回Redis 7.0のShared Pub/Subをしたくなったので、重い腰を上げてローカル環境にDocker Composeで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を行うためのコマンド SSUBSCRIBESPUBLISHが追加されました。従来のグローバルPub/Subに使うSUBSCRIBEPUBLISHには、Redis ClusterでPub/Subするとクラスター内部にメッセージが伝搬するためスケール問題を起こすことが知られています。この問題はShared Pub/Subで改善されるので、Pub/Subを使うRedis Clusterも水平スケール可能になります。

Shard Pub/SubをDocker Composeで構築したRedis Clusterにて試しましょう。

see: Redis 7 の Sharded Pub/Sub まとめ - Qiita

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のサポートはされていません。実装を探してもまだも見つからないので、使うには自前拡張がいる感じです。

image

(余談2) Grokzen/docker-Redis-cluster は使うのは難しい

Redis ClusterのDockerイメージとしてはGrokzen/docker-redis-clusterもあり、これを使うとRedis Clusterが1コンテナで起動してくれます。簡便ではあるものの構成上の副作用として、このRedis Clusterは外部から個別ノードへの接続を考慮しておらず4、同コンテナにexecしてローカルホストからつな具必要があります。 コンテナの外から試せないので、適当にLinqPadやVSからRedis Cluster試すのは難しく、利用ケースが限られてしまいますね。


  1. あるいはdocker-compose up -d
  2. ElastiCacheならクラスターエンドポイントにつなげば同じことができます。
  3. できればDocker Compose使わずもっと楽に起動したい気持ちがあります。現時点ではいい方法が思いつかないので仕方ない。
  4. 127.0.0.1にすべてのノードが起動、通信しあっているので外部からノードにアクセスできない。