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を使うなら第一候補となるパッケージです。