前回は、redisをインストールして生でつかってみました。
今回はnode.jsでredisを利用してみたいと思います。
マルチユーザーのサーバーでのプッシュ配信はSocket.IOが定番ですが、
サーバーが増えた時にある問題が生じます。
例えばサーバーを2つに増やして、サーバーAでブロードキャストしても
サーバーBのクライアントでは受信できないのです。
以前の記事で作成したチャットプログラムを例にしてみます。
サーバー側のjs
$ cat /home/appadmin/chat/node/chat.js
var server = require('http').createServer(function(req, res){ res.writeHead(200, {'Content-Type': 'text/html'}); res.end('server connected'); }); server.listen(3001); var io = require('socket.io').listen(server); io.sockets.on('connection', function (socket) { socket.emit('info', { msg: 'welcome' }); socket.on('msg', function (msg) { io.sockets.emit('msg', {msg: msg}); }); socket.on('disconnect', function(){ socket.emit('info', {msg: 'bye'}); }); });
クライアント側のjs
$ cat /home/appadmin/chat/public/assets/js/client.js
$(function(){ var socket = io.connect('http://'+location.hostname+':3001/'); socket.on('connect', function() { $("#log").html($("#log").html() + "<br />" + 'connected'); socket.on('info', function (data) { $("#log").html($("#log").html() + "<br />" + data.msg); }); socket.on('msg', function(data){ $("#log").html($("#log").html() + "<br />" + "<b>" + data.msg + "</b>"); }); $("#send").click(function(){ var msg = $("#msg").val(); if(!msg){ alert("input your message"); return; } socket.emit('msg', msg); }); }); });
画面
$ cat /home/appadmin/chat/public/index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> $(function(){ function load(){ $.getScript("assets/js/client.js"); } $.getScript("http://" + location.hostname + ":3001/socket.io/socket.io.js", function(){ load(); }); }); </script> <title>Node A</title> </head> <body> <input id="msg" type="text" style="width:400px;"></input> <input id="send" type="button" value="send" /></br > <div id="log" style="width:400px;height:400px;overflow:auto;border:1px solid #000000;"></div> </html>
サーバー側のjsをforeverで起動します。
$ forever start chat.js
これをサーバーAとします。
同じ内容を別のサーバーBに配置し、同じようにnodeを起動します。
2つのサーバーにアクセスすると、以下のように同じ画面が表示されます。
サーバーAで「a」と入力します。
サーバー側では接続した全ユーザーに投稿内容をブロードキャストし、ユーザーの画面に「a」が表示されます。
しかし、サーバーBには何も表示されません。
おなじようにサーバーBで、「b」と投稿してもサーバーAに接続した画面にはなにも表示されません。
接続がサーバーAとサーバーBで共有されていないためです。
ここで登場するのがredisです。
Socket.IOではデフォルトで接続情報をローカルメモリに保存しています。
これをMemoryStoreと呼びますが、Socket.IOにはRedisStoreというredisに接続情報を保存するオプションも存在します。
このオプションを選択することで、分散されたnodeサーバーが同じredisサーバーを参照し
各nodeの接続情報を共有することができます。
それではサーバー側のjsを修正してRedisStoreを使ってみます。
接続するredisは前回設定したredisサーバーにします。
var server = require('http').createServer(function(req, res){ res.writeHead(200, {'Content-Type': 'text/html'}); res.end('server connected'); }); server.listen(3001); var io = require('socket.io').listen(server); //RedisStoreを読み込みます var RedisStore = require('socket.io/lib/stores/redis'); //redisサーバーの接続先情報を定義します opts = {host:'10.0.0.200', port:6379}; //storeをRedisStoreにし、redisPub, redisSub, redisClientをredisサーバーに向けます io.set('store', new RedisStore({redisPub:opts, redisSub:opts, redisClient:opts})); io.sockets.on('connection', function (socket) { socket.emit('info', { msg: 'welcome' }); socket.on('msg', function (msg) { io.sockets.emit('msg', {msg: msg}); }); socket.on('disconnect', function(){ socket.emit('info', {msg: 'bye'}); }); });
これで再起動します。
$ forever restart chat.js
再度2つの画面をリロードして、サーバーAの画面に「a」サーバーBの画面に「b」と入力してみます。
おお、両方の画面に「a」「b」が表示されました!
これで台数が増えてもすべてのユーザーが同じ空間でコミュニケーションすることができます。
以上です。