前回は、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」が表示されました!
これで台数が増えてもすべてのユーザーが同じ空間でコミュニケーションすることができます。
以上です。

