LoginSignup
7
2

More than 3 years have passed since last update.

Node.jsで ioredis を用いて Redis Clusterを取り扱う

Last updated at Posted at 2020-05-10

最近でNode.jsで Redis Clusterを触る機会があったのですが
意外とRedis Cluster × Node.jsの日本語記事が無かったため、備忘録を兼ねて記事に起こしておきます。

今回利用するパッケージはこちら。
GitHub - luin/ioredis: 🚀A robust, performance-focused and full-featured Redis client for Node.js.

typescriptを使う場合は 一緒に型もimportしておきましょう。

npm i ioredis
npm i -D @types/ioredis

Constructor

cluster形式の場合は利用する nodeを配列形式で指定する必要があります。
他に何もOptionを指定する必要が無いのであれば、基本この設定だけで良いです。

const driver: IORedis.Cluster = new IORedis.Cluster([
   { port: 6380, host: '127.0.0.1'},
   { port: 6381, host: '127.0.0.1'},
]);

redisOptions

おそらく一番触る必要が出てくる箇所。
名前の通り Redisに対するオプションを設定します。
例えばパスワードが必要な場合は以下のように redisOptionで指定することが出来ます。

const driver: IORedis.Cluster = new IORedis.Cluster([],
      redisOptions: {
        password: config.password
      }
);

設定できるオプションはAPI - ioredis / new Redis([port], [host], [options]で確認でき、
今回は個人的に使う機会がありそうな項目を列挙しておきます。

オプション名 デフォルト値 詳細
db 0 使用するデータベースインデックス
password null パスワード
dropBufferSupport FALSE バッファサポートの削除を有効化,。巨大な配列の応答を処理するときに有効にするとパフォーマンスが向上するらしい(未検証)
enableReadyCheck TRUE Redisのサーバーステータスを確認してからコマンドを送信する
connectTimeout 10000 初期接続中にタイムアウトが発生するまでのミリ秒
tls null TLS接続のサポート (https://github.com/luin/ioredis#tls-options)
readOnly FALSE 読み取り専用

その他のオプション

redisOption以外にも幾つか指定できるオプションがあるため、こちらも記載。
こちらも同様にAPI - ioredis / new Cluster(startupNodes, options) に設定項目が載っています。

一応 使いそうなものをピックアップしています。

オプション名 デフォルト値 詳細
clusterRetryStrategy ノードに到達できない場合に呼び出されるcallback。 returnした数値分待機して再接続を試みる
scaleReads master 読み取り対象のnodeを指定する。指定可能なのは master, slave, all のいずれか
maxRedirections 16 ターゲット nodeからエラー(MOVED, CLUSTERDOWN等)が返った場合に他のnodeにリダイレクトする回数
retryDelayOnFailover 100 ターゲット nodeが切断されている場合に指定秒後にコマンドを再送信する
const driver: IORedis.Cluster = new IORedis.Cluster([],
      redisOptions: {},
      retryDelayOnFailover: 50
);

ただ、redisOptionsと違って こちらを指定するケースは殆どなさそうです。

Command

基本Commandを中心に。
特に難しくありませんが、writeに関しては書き込む際の型に注意が必要です。

read

await redis.get('key');

write

await redis.set('key', 'value');

expire を指定する場合は 以下のように EX と 有効期限(秒)を指定します。

redis.set('key', 'value', 'EX', 10);

注意点としては Object型をvalueとしてセットすると [Object object]という形で保存されてしまうため、
Object型を保存するときは JSON.stringifyで文字型に変換して入れるようにしましょう。

delete

await this.redis.del('key');

keys

正規表現マッチで取得する。
getでは 未ヒット時は nullが返りますが、こちらは空配列が返ります。

await this.redis.keys('regExp');

Event

Redisへの接続状態に合わせてイベントがトリガーされます。
発火されるイベントは以下の通り。

イベント 詳細
connect Redisサーバーへの接続が確立した時
ready コマンドを受付が可能な時(enableReadyCheck で trueを確認できた時)
error 接続中にエラーが発生した時
close Redisサーバー接続が閉じた時
reconnecting 再接続が行われた時
end Redisサーバーとの接続が閉じた時

発火したイベントは以下のようにすることでハンドリングできます。

this.redis.on('connect', () => {
  console.log('trigger connect');
});

その他 Tips

自分が実際に対応した細々とした内容です。

master nodeへの負荷を低減したい

ioredisでは基本的に commandは全て masterへ送信されます。
そのため、 masterの cpu消費が激しくパフォーマンスが低下する問題を引き起こす可能性があります。

そこでコンストラクタのオプション scaleReadで read commandの向き先を slaveに変更します。

const driver: IORedis.Cluster = new IORedis.Cluster([],
      redisOptions: {},
      scaleReads: 'slave' 
);

これで read commandは slaveに向くので masterへの負荷は軽減されます。
ただし、レプリケーション遅延により、master, slave間でデータの差分が発生する可能性があるので注意が必要です。

writeするデータを圧縮したい

例えば api cacheなどで大量のデータを Redisに書き込む場合に幾つかの問題が発生することが予想されます。

  • ネットワーク帯域を圧迫して帯域詰まりを起こす
  • レイテンシが悪化する
  • Redisの容量を圧迫する

これらの問題に対する一つの解決策としてデータを圧縮するという方法がありますが、
ioredisはデータを圧縮しないため圧縮機構を自前で用意する必要があります。

圧縮・解凍するライブラリは幾つかありますが 今回は高速が売りの lz-string を使っていきます
GitHub - pieroxy/lz-string: LZ-based compression algorithm for JavaScript

npm i lz-string
npm i -D @types/lz-string
import * as IORedis from 'ioredis';
import {compress, decompress} from 'lz-string'

//
// 省略
//

/**
 * 読み込み
 * @param {string} key
 */
async function get(key: string): Promise<string | null> {
  const buf: string | null = await redis.get(key);
  if (buf == null) return null;

  return decompress(buf);
}

/**
 * 書き込み
 * @param {string} key
 * @param {string} value
 * @param {number} expireSec
 */
async function set(key: string, value: string, expireSec: number): Promise<void> {
  await redis.set(key, compress(value), 'EX', expireSec);
}

注意点としては 圧縮・解凍はCPUを消費する処理のため、パフォーマンスが低下する可能性があります。
なので導入する場合はCPUの消費を計測してリソースの再調整をする必要があります。

※レイテンシが悪化する問題に対してはデータサイズによっては逆効果だったするため、
計測して判断する必要があります。

参考

Redis Cluster自体の仕組みについて (非常にわかりやすかったです)
https://qiita.com/keitatata/items/44678ad472e61a4606c5

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2