使用Node.js中的ioredis库处理Redis Cluster

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

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

如果使用TypeScript的话,让我们一起导入类型吧。

npm i ioredis
npm i -D @types/ioredis

构造函数

如果是以cluster形式来使用的话,需要用数组形式指定要使用的node。如果不需要指定任何其他选项,那么基本上只需进行这个设置即可。

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

Redis选项

可能性最大的触及点可能会是以下命名方法。它是用来设置与 Redis 相关的选项。例如,如果需要密码,可以通过 redisOption 进行指定。

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

在可設定的選項中,可以通過API – ioredis / new Redis([port], [host], [options]來確認,這裡將列出我覺得可能會用到的項目。

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

其他选项

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

我挑选了一些可能会用到的物品。

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

然而,与redisOptions不同,很少有情况需要指定此选项。

命令

以基本的的Command为中心。
尤其是在写入(write)时需要注意写入的数据类型。

阅读

await redis.get('key');

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

如果要指定 expire ,则如下所示指定为 EX 和有效期(秒)。

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

请注意,如果将Object类型设置为value,则会以[Object object]的形式保存,因此在保存Object类型时,请确保使用JSON.stringify将其转换为字符串并放入。

删除

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

钥匙

使用正则表达式匹配进行提取。
当没有匹配时,使用”get” 会返回 null,而这里将返回一个空数组。

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

事件

根据与Redis的连接状态相对应,将触发事件。
触发的事件如下。

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

可以通过以下方式来处理发生异常的事件。

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

其他的技巧

这是我实际处理过的细节内容。

我想要减轻主节点的负载。

基本上,在ioredis中,所有的命令都会发送到主节点。
因此,可能会导致主节点的CPU消耗过大,进而降低性能。

因此,通过构造函数选项scaleRead,将读取命令的目标更改为从设备。

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

这样一来,read命令就会指向从库,减轻了主库的负担。
但是需要注意的是,由于复制延迟的存在,主库和从库之间可能会发生数据差异。

我想压缩要写入的数据。

使用API缓存等将大量数据写入Redis时,预计会出现一些问题。

    • ネットワーク帯域を圧迫して帯域詰まりを起こす

 

    • レイテンシが悪化する

 

    Redisの容量を圧迫する

有一个解决这些问题的方法是通过压缩数据,但是 ioredis 不会压缩数据,因此需要自己准备压缩机制。

虽然有几个可以进行压缩和解压缩的库可供选择,但这次我们将使用速度快的 lz-string 库。在 GitHub 上可找到:pieroxy/lz-string:用于 JavaScript 的基于 LZ 的压缩算法。

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的工作原理非常清晰易懂。

广告
将在 10 秒后关闭
bannerAds