リードレプリカを利用するためのRedisライブラリ

こんにちは、WFSでサーバサイドを担当している藤田です。
先日、Redisを扱うための小さなライブラリを公開しましたので、紹介できればと思います。

Master-Slave-Redis
https://github.com/gree/master-slave-redis

これは何か

このライブラリは、Redisがレプリケーション構成を取っているときに、マスタ側へのクエリとリードレプリカ側へのクエリを出し分けられるようにするライブラリです。

もともと、社内には同様の機能を持つライブラリが存在していたのですが、
Cascade(https://github.com/gree/cascade)に影響されている設計で重厚だったり、バグがあったりしていたのと、
PSR-0/PSR-4が無い時代に作られていたりというのがあり、
スクラッチから書き直すことにしました。

目指したこと

  • 機能を少なく
    • Connection Poolingの機能は自分で持たずに、Redisのpconnectに任せる
    • ラッパーではなく、phpredisのインスタンスを直接返す
  • クラウドのマネージドなサービスに対応する
    • 複数のリードレプリカに対して、1つのエンドポイントを通してアクセスする機能が、
      DNSを利用することで実現されているとき、きちんとクエリを分散させられるようにする

DNSの話

DNSの話が急に出てきました。
これはphpredisのpconnectの実装への対応です。

pconnectが呼び出されたとき、プールされているコネクションを使うべきかどうかは、
ホスト名とポート番号のセットから生成したpersistent_idというものを使って識別しています。

https://github.com/phpredis/phpredis/blob/17ddbe76a2918f3d47176e74b14ab28a68a51b54/library.c#L64

よって、ホスト名が複数のIPアドレスを含む場合(ラウンドロビンにせよ、都度都度別のレスポンスになるにせよ)、複数のIPアドレスを使い分けることができません。
本ライブラリでは、毎回ホスト名からIPアドレスを引いて、pconnectにはIPアドレスを渡すことで分散できるようにしました。

使い方

それでは、前置きはこのくらいにしておいて、使い方を説明したいと思います。

getMaster()は、master-host向けのphpredisインスタンス、getSlave()は、slave-host向けのphpredisインスタンスを
それぞれ返します。

この際、slave-hostがラウンドロビンで複数のIPアドレスと紐付けられている場合、getSlave()はアクセスの度、異なるインスタンスを返してきます。
(実装上、マスタ側も同じ事が起こりますが、そういうことは無いと判断して、とくに対応はしていません)

その他、複数のレプリカのエンドポイントがある場合、レプリカが無い場合、ポートが違う場合などの設定について、READMEにまとめてありますのでご参照ください。

おわりに

小さなライブラリなのですが、案外フィットするものが無いということで、今回このライブラリを実装し、公開することになりました。
もし、みなさんのお手伝いになれば幸いです。