知りたかったこと
- Redisを活用したバックグラウンド処理の管理
結論
下記のフローを理解してると良さそう
- キューにタスクを追加 (lpush):
- バックグラウンドプロセスでタスクをポーリング:
- タスクを処理する関数を呼び出す
また、Redisの基本的な特徴も把握しておくと良い
- RedisはNoSQLデータベース
- インメモリ型
- シングルスレッドで、並列処理をする場合はシャーディング(複数Redis立ち上げる)
背景
- 今仕事で開発中のタスクで処理が重たいので、バックグラウンド処理を行うようにしている。ただ、ローカル環境でのデバックが難しかったので、しっかり理解しようと思った
サンプルコード
ChatGPTが教えてくれたコード
- ディレクトリ構成
project-folder/ ├── docker-compose.yml └── app/ ├── package.json ├── app.js
- docker-compose
version: '3' services: redis: image: "redis:latest" ports: - "6379:6379"
- package.json
バージョンが4系だと以降に記載するコードは動かない
{ "dependencies": { "redis": "^3.1.2" } }
- app.js
const redis = require('redis'); // Redisクライアントの作成 const client = redis.createClient({ host: 'localhost' }); // Docker Composeのサービス名 const someProcess = () => { for ( var i = 0; i < 10; i++ ) { console.log(i) } } // タスクのスケジューリング const scheduleTask = (taskData) => { const taskID = `task:${taskData.id}`; client.hmset(taskID, taskData); client.lpush('task_queue', taskID); }; // タスクの処理 const processTask = (taskID) => { client.hgetall(taskID, (err, taskData) => { if (err) throw err; console.log('Processing task:', taskData); someProcess() setTimeout(() => { const result = 'Task completed successfully'; client.set(`task_result:${taskID}`, result); console.log('Task completed:', result); }, 3000); // 3秒間のタスクをシミュレート }); }; // タスクを処理するループ const processTasksLoop = () => { client.rpop('task_queue', (err, taskID) => { if (err) throw err; if (taskID) { console.log(`taskID ${taskID}`) processTask(taskID); } setTimeout(processTasksLoop, 1000); // 新しいタスクを待つ }); }; // テスト用タスクのスケジューリング scheduleTask({ id: 'task123', param1: 'value1', param2: 'value2' }); scheduleTask({ id: 'task234', param1: 'value2', param2: 'value3' }); scheduleTask({ id: 'task567', param1: 'value3', param2: 'value4' }); // タスクの処理を開始 processTasksLoop();
- 実行結果
ポーリングされる時に関数を挟むと実行できるだな
taskID task:task123 Processing task: { id: 'task123', param1: 'value1', param2: 'value2' } 0 1 2 3 4 5 6 7 8 9 taskID task:task234 Processing task: { id: 'task234', param1: 'value2', param2: 'value3' } 0 1 2 3 4 5 6 7 8 9 taskID task:task567 Processing task: { id: 'task567', param1: 'value3', param2: 'value4' } 0 1 2 3 4 5 6 7 8 9 Task completed: Task completed successfully Task completed: Task completed successfully Task completed: Task completed successfully
Redisのメソッド
- client.set
キューに対して、データをセットするメソッド
- client.hmset(今は非推奨)
ハッシュ(Hash)としてデータを設定するメソッド
- client.lpush
リスト(List)に値を追加z
調べた内容
Redisとは
この記事によると
- データベース
- インメモリキャッシュなのが味噌っぽい
- NoSQL
- NoSQLだが扱える型は決まっているっぽい
- シングルスレッド: 複数のリクエストが来ても、順番に処理される
- シャーディング可能
気になった点
- データベースなのになんで Mysqlとかと同じ感じで出てこないのか?
自分で結論づけたのは、インメモリキャッシュだから、サーバーが落ちると消えるのでMysqlなどとは同じ扱いにならないのではないか?と思った
- シングルスレッドについて
Redisって重い処理をバックグランド処理に使われているイメージなんだけど、 シングルスレッドで実行されているので、都合悪いケースが多いのではないか? と思った。
そこは、マルチスレッドではなく、シャーディングという方法があるらしく、 複数台のredisサーバーを立てて、分散させるっぽい
複数台のサーバーの管理で肝になるのが 「slot」で、idnのようなもので管理している