redis の使い方

A modern, high performance Redis client

v5.11.08.2M/週MITORM / DB
AI生成コンテンツ

この記事はAIによって生成されました。内容の正確性は保証されません。最新の情報は公式ドキュメントをご確認ください。

redis(Node-Redis)の使い方完全ガイド

一言でいうと

redisは、Node.js向けの公式高性能Redisクライアントです。すべてのRedisコマンドをネイティブにサポートし、TypeScript型定義、Pub/Sub、トランザクション、クラスター対応など、本番運用に必要な機能を網羅しています。

どんな時に使う?

  • セッション管理・キャッシュ層の構築 — Webアプリケーションのレスポンス高速化のため、DBクエリ結果やセッション情報をRedisに格納する
  • リアルタイム通信のメッセージブローカー — Pub/Sub機能を使って、マイクロサービス間のイベント配信やチャット機能を実装する
  • ジョブキュー・レートリミッターの基盤 — Redisのアトミック操作やTTLを活用して、バックグラウンドジョブの管理やAPIレートリミットを実装する

インストール

Redisサーバーの起動(Docker):

docker run -p 6379:6379 -d redis:8.0-rc1

パッケージのインストール:

# npm
npm install redis

# yarn
yarn add redis

# pnpm
pnpm add redis

補足: redisパッケージは、@redis/client@redis/json@redis/search@redis/bloom@redis/time-seriesを含むオールインワンパッケージです。特定のモジュールだけが必要な場合は、個別パッケージをインストールすることも可能です。

基本的な使い方

最もシンプルな接続・読み書きのパターンです。

import { createClient } from "redis";

// クライアントの作成と接続
const client = await createClient()
  .on("error", (err) => console.error("Redis Client Error", err))
  .connect();

// 値の書き込み
await client.set("user:1:name", "田中太郎");

// 値の読み取り
const name = await client.get("user:1:name");
console.log(name); // "田中太郎"

// TTL付きで書き込み(10秒後に自動削除)
await client.set("session:abc123", JSON.stringify({ userId: 1 }), {
  EX: 10,
});

// 接続の破棄
client.destroy();

接続先の指定

// URL形式で接続先を指定
const client = createClient({
  url: "redis://alice:foobared@awesome.redis.server:6380",
});

// 個別パラメータで指定
const client2 = createClient({
  socket: {
    host: "redis.example.com",
    port: 6380,
    tls: true,
  },
  username: "alice",
  password: "foobared",
});

接続状態の確認

// コマンド送信可能な状態か
console.log(client.isReady); // true / false

// ソケットが開いているか(再接続中はtrueだがisReadyはfalse)
console.log(client.isOpen); // true / false

よく使うAPI

1. set / get — 文字列の読み書き

最も基本的なKey-Value操作です。

// 基本的なset/get
await client.set("key", "value");
const value = await client.get("key"); // "value"

// オプション付きset
await client.set("key", "value", {
  EX: 60,    // 有効期限(秒)
  NX: true,  // キーが存在しない場合のみセット
});

// NXはロック実装にも使える
const acquired = await client.set("lock:resource", "owner-id", {
  EX: 30,
  NX: true,
});
if (acquired) {
  console.log("ロック取得成功");
}

2. hSet / hGetAll — ハッシュ操作

オブジェクト的なデータ構造を扱う場合に使います。

// ハッシュへの書き込み
await client.hSet("user:100", {
  name: "佐藤花子",
  email: "hanako@example.com",
  age: "30",
});

// 特定フィールドの取得
const email = await client.hGet("user:100", "email");
console.log(email); // "hanako@example.com"

// 全フィールドの取得(オブジェクトとして返る)
const user = await client.hGetAll("user:100");
console.log(user);
// { name: "佐藤花子", email: "hanako@example.com", age: "30" }

// 全バリューのみ取得
const values = await client.hVals("user:100");
console.log(values); // ["佐藤花子", "hanako@example.com", "30"]

3. multi / exec — トランザクション

複数コマンドをアトミックに実行します。

await client.set("balance:A", "1000");
await client.set("balance:B", "500");

// 送金処理をトランザクションで実行
const results = await client
  .multi()
  .decrBy("balance:A", 200)
  .incrBy("balance:B", 200)
  .get("balance:A")
  .get("balance:B")
  .exec();

console.log(results);
// [800, 700, "800", "700"]

// watchによる楽観的ロック
await client.watch("balance:A");
const currentBalance = await client.get("balance:A");

if (Number(currentBalance) >= 200) {
  // watch対象のキーが他から変更されるとトランザクションは中断される
  await client
    .multi()
    .decrBy("balance:A", 200)
    .incrBy("balance:B", 200)
    .exec();
}

4. scanIterator — キーの安全な走査

KEYS *はブロッキングするため本番では使えません。代わりにscanIteratorを使います。

// キーの走査
for await (const key of client.scanIterator({
  MATCH: "user:*",
  COUNT: 100,
})) {
  const value = await client.get(key);
  console.log(`${key}: ${value}`);
}

// ハッシュのフィールド走査
for await (const { field, value } of client.hScanIterator("user:100")) {
  console.log(`${field} = ${value}`);
}

// セットのメンバー走査
for await (const member of client.sScanIterator("tags")) {
  console.log(member);
}

// ソート済みセットの走査
for await (const { score, value } of client.zScanIterator("ranking")) {
  console.log(`${value}: ${score}点`);
}

5. sendCommand — 未サポートコマンドの実行

ライブラリがまだ対応していないコマンドや、カスタムモジュールのコマンドを直接実行できます。

// 任意のRedisコマンドを文字列配列で送信
const result = await client.sendCommand(["SET", "key", "value", "NX"]);
console.log(result); // "OK"

const hashData = await client.sendCommand(["HGETALL", "user:100"]);
console.log(hashData); // ["name", "佐藤花子", "email", "hanako@example.com", ...]

// CLIENT INFO の例
const info = await client.sendCommand(["CLIENT", "INFO"]);
console.log(info);

補足: コネクションプール(v5の新機能)

v5ではRedisClientPoolが独立したクラスとして提供されています。ブロッキングコマンドや高並行処理に適しています。

import { createClientPool } from "redis";

const pool = await createClientPool()
  .on("error", (err) => console.error(err))
  .connect();

// プールから自動的にコネクションが割り当てられる
await pool.ping();
await pool.set("key", "value");

pool.destroy();

類似パッケージとの比較

特徴redis (node-redis)ioredis
メンテナRedis公式個人(luin)→ 現在はメンテナンス縮小
TypeScriptネイティブ対応型定義あり(@types/ioredis不要)
クラスター対応
Sentinel対応
Pub/Sub
Lua スクリプト✅(より直感的なAPI)
Redis Stack モジュール✅(JSON, Search, Bloom等)❌(sendCommandで対応)
コネクションプール✅(v5でcreateClientPool❌(外部ライブラリが必要)
パフォーマンス高い高い
コミュニティ規模非常に大きい大きい

選定の目安:

  • Redis Stack(JSON、Search等)を使うなら → redis一択
  • 公式サポートの安心感を重視するなら → redis
  • 既存プロジェクトでioredisを使っていて問題がないなら → 無理に移行する必要はない

注意点・Tips

1. エラーハンドリングは必ず設定する

errorイベントをハンドルしないと、接続エラー時にプロセスがクラッシュします。

const client = createClient()
  .on("error", (err) => console.error("Redis Error:", err))
  .on("reconnecting", () => console.log("Redis reconnecting..."));

await client.connect();

2. destroy()disconnect() の違い

// 未送信のコマンドを待ってから切断
await client.disconnect();

// 即座に切断(未送信コマンドは破棄される)
client.destroy();

グレースフルシャットダウンにはdisconnect()を使いましょう。

3. Redisの値はすべて文字列

Redisは基本的に文字列を扱います。数値やオブジェクトを格納する場合は明示的に変換が必要です。

// ❌ オブジェクトをそのまま渡すとエラーまたは意図しない結果に
// await client.set("data", { foo: "bar" });

// ✅ JSON.stringifyで文字列化
await client.set("data", JSON.stringify({ foo: "bar" }));
const data = JSON.parse((await client.get("data"))!);

4. Buffer対応が必要な場合

バイナリデータを扱う場合はwithTypeMappingを使います。

import { createClient, RESP_TYPES } from "redis";

const client = createClient().withTypeMapping({
  [RESP_TYPES.BLOB_STRING]: Buffer,
});
await client.connect();

await client.set("binary", Buffer.from([0x00, 0x01, 0x02]));
const buf = await client.get("binary"); // Buffer

5. 本番環境ではKEYSコマンドを使わない

KEYS *はすべてのキーを走査するためO(N)でブロッキングします。必ずscanIteratorを使ってください。

6. v4からv5への移行ポイント

⚠️ この情報はバージョン5.x系に基づいています。

  • Isolation Poolは廃止され、createClientPoolに置き換わりました
  • commandOptions({ isolated: true })の代わりにプールを使用してください

まとめ

redis(node-redis)は、Redis公式が提供するNode.js向けクライアントで、すべてのRedisコマンドとRedis Stackモジュールをネイティブにサポートしています。v5ではコネクションプールが独立クラスとして整備され、高並行処理がより扱いやすくなりました。TypeScriptとの親和性も高く、新規プロジェクトでRedisを使うなら第一候補となるパッケージです。