yutaponのブログ

javascript界隈の興味あるネタを備忘録的に残しておく場所

node.jsでRedisを使ってみる【実践編】

久しぶりの更新。
node.js + Redisでチャット作ろうとして挫折してました。orz

作ったもの

githubに置いておきました。
yussk/mychat · GitHub

動かし方

cloneして、redis起動して、依存モジュールをインストールすれば動きます。

$ git clone git@github.com:yussk/mychat.git  // forkしてからcloneでもいいかもしれません
...

$ redis-server  // redis起動。別ウインドウでやるのがおすすめ
...

$ cd mychat
$ npm install  // package.jsonから依存モジュールを持ってくる
$ node app.js  // チャット起動

これでブラウザを立ちあげて localhost:3000 にアクセスするとチャットできます。



使った技術とか

express3 + ejs

express2 + ejs のときはデフォルトでレイアウト機能をサポートしてたのに
express3になってから削除されたみたい。なぜ削除したし。
それで少し困ったけど express-partials ってモジュールを入れて解決しました。
publicclass/express-partials · GitHub

socket.io

チャットといえばリアルタイム。そんなことから使ってみたけど難しかった。
基本はonでイベントを購読して、emitでイベントを発火させるっていう
よくあるオブザーバパターンだけれど、socket.ioの仕様は奥深い。
Socket.IO: the cross-browser WebSocket for realtime apps.

Redis

もともとnode.jsとredisの相性はいいのはわかってましたが、
socket.ioとの相性も良かったんですね。
Redisで保持しているセッションデータをsocket.ioのコネクションでも
参照できるのは助かりました。
Redis



チャットの設計

どんなチャットを作るかをまず決めないといけませんでした。
研修の時にチャット作ったので、それをリファクタしつつ書くことにしました。

チャットの流れは以下の通りです。

  1. 名前を入力してログイン(パスワード認証は無し)
  2. チャット部屋を選択または新しい部屋を作成する(部屋名の入力あり)
  3. 部屋の中で発言する
  4. 部屋から退室すると 2 の画面に戻る(部屋に誰もいなかったら部屋を削除する)
  5. ログアウトして 1 に戻る

パスワード認証はないので、ログアウトは実質名前を変えたい時に使うくらいです。


Redisのキー設計

KVSのキー設計って未だに慣れません。
RDMSに親しんでいたら発想の転換が必要ですね。

  • global:room:id

文字列型。値はインクリメントされる数値。
部屋名のハッシュを作る時に利用します。ハッシュを作る時に
このglobal:room:idを含めることで部屋名の重複が合ったとしても
一意の部屋を作ることができます。

  • rooms

リスト型。値はroomId:roomNameという形式。
部屋のリストです。roomIdはglobal:room:idと入力された部屋名を
md5でハッシュした文字列になります。
これでどんなに長い部屋名を入力しても32文字に丸められます。
roomNameは入力された部屋名になります。

  • room:name

ハッシュ型。field: roomId, value: roomName
roomsは部屋のリストを管理しているため、値にroomIdとroomNameが混在してます。
こちらのroom:nameはroomNameを管理しているハッシュなので、
roomIdがわかれば日本語の部屋名を取得出来ます。

  • room:roomId:message

リスト型。値はJSONでname, message, date, timeを持つ。
部屋の中で発言されたメッセージを管理します。
キーのroomIdの部分にはハッシュ化された部屋IDが入ります。
e.g. "room:647df86355c1d46b4db50011875fe82e:message"


おわりに

一通り書いてみて、全体のアーキテクチャ設計をもっとうまく出来るようになりたいと思いました。
とりあえずRESTのことをよく知らないのでオライリー本でも買ってみます。

チャットの大枠ができたのでこれをBackbone.jsで書き直したいところです。
その前に、息抜きでGrunt.jsとかやりたいですね。