Redis sub/pub 和 php/nodejs

Posted

技术标签:

【中文标题】Redis sub/pub 和 php/nodejs【英文标题】:Redis sub/pub and php/nodejs 【发布时间】:2011-10-17 00:10:52 【问题描述】:

开始使用 redis 作为 sub/pub 系统来显示来自 mysql db 的结果的新项目。因此,如果有更新,我想将这些更新从 mysql 发布到我的网页。我的问题是,哪个选项会更好?

选项 1: 我应该通过 nodejs 和 socket.io 完成所有这些吗?意思是创建一个连接到redis的nodejs脚本,订阅我需要收听的频道,在nodejs中使用mysql查询数据库以获取更新,如果更新发布mysql行然后在通过socket.io连接到nodejs的html中获取新数据并对其进行处理以显示结果?

选项 2: 有一个 php 脚本查询 mysql 并使用 redis-php 客户端向频道发布任何更新?不知道这里还需要设置什么。我还需要让 nodejs 参与这个选项吗?

或者我只是基于这一切的运作方式?底线是我想通过 mysql 数据库向使用 redis sub/pub 功能的用户显示结果。

【问题讨论】:

您为什么打算在架构中添加额外的层?我的意思是在你的应用中使用 nodejs、socket.io 和 redis 有什么具体原因吗? @Sukumar 我的项目包含需要实时更新的列表。在阅读了 redis sub/pub 系统之后,它似乎更适合资源明智和实时需求,而不是使用带有 ajax 的客户端脚本从数据库获取更新。 NodeJS 可以处理大量连接并且可以执行多项任务。 Socket.io 作为连接 nodejs 服务器的简单方法。就像我说的可能是错的,这就是我发帖的原因。 【参考方案1】:

选项 3

当您从 PHP 更新 MySQL 时,您通过 redis publish 命令将这些更改发布到 node.js(在变异数据库时从 PHP 发布)。由于 Redis 的订阅,我可以从 node.js 实时收到这些更改。然后我会通过 socket.io 将它们广播给感兴趣的用户。例如,您可以将publish 引导至mysql。以下面的 SQL 语句 => INSERT INTO comments (1, "Hello World") 为例。其中1 类似于用户ID,Hello World 类似于评论。我可能不会将 SQL 语句发布到该通道,而是使用 JSON 代替,我可以轻松地从 javascript(JSON.stringify / JSON.parse) 和 PHP(json_encode / json_decode) 使用它。

更新

您不会运行 cron-job,因为这会破坏 Redis 发布订阅的目的。以我访问您的网站为例,该网站是http://localhosts 的博客。我在http://localhost.com/a.php 阅读了一篇文章。在网站下方,您提供了一个表单,我可以使用该表单对那篇文章发表评论:

a.php

<html>
<head>
    <title>Interesting blog post</title>
</head>
<body>
    <div id="article">This is interesting</div>

    <div id="comments">
        <div class="comment">
            <div class="from">Alfred Said at 22:34</div>
            <div class="message">Hello World</div>
        </div>
    </div>

    <form action="post.php" method="post">
        <label for="name">Your name</label><br />
        <input type="name" id="name" name="name" /><br />

        <label for="message">Your Message:</label><br />
        <textarea id="message" name="message"></textarea>

        <input type="submit" />
    </form>


    <script src='jquery.min.js'></script>
    <script src='http://localhost:8888/socket.io/socket.io.js'></script>
    <script type="text/javascript">
        $(document).ready(function () 
                var socket = io.connect('http://localhost:8888');

                socket.on('message', function (json) 
                    var obj = $.parseJSON(json);
                    alert('in here: ' + obj.name);
                );
        );
    </script>
</body>
</html>

我提交了具有动作属性http://localhost/postcomment.php 的表单。但这是重要的部分!在post.php,您检索我发布的数据并使用INSERT INTO comments (1, "Hello World") 将其插入MySQL。当这种突变发生时,您还需要通知 node.js 进程,该进程不断地监听频道mysql

post.php:

<?php

$_POST  = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);

require("./Predis.php");
$redis = new Predis\Client();
$obj = array(
    'name'      => $_POST['name'],
    'message'   => $_POST['message']
);

$json = json_encode($obj);
$redis->publish("mysql", $json);

echo $json;

post.php 需要predis。

带有 node_redis 的节点代码如下所示:

var redis       = require('redis'),
    subscriber  = redis.createClient(),
    express     = require('express'),
    store       = new express.session.MemoryStore(),
    app         = express.createServer(
        express.bodyParser(),
        express.static(__dirname + '/public'),
        express.cookieParser(),
        express.session( secret: 'htuayreve', store: store))
    sio         = require('socket.io');

app.listen(8888, '127.0.0.1',  function () 
    var addr = app.address();
    console.log('app listening on http://' + addr.address + ':' + addr.port);
);

var io = sio.listen(app);

io.configure(function () 
    io.set('log level', 1); // reduce logging
);

io.sockets.on('connection', function (socket) 
    socket.join('mysql');   
    socket.on('disconnect', function () 
    );
);

subscriber.on('message', function (channel, json) 
    // this will always retrieve messages posted to mysql
    io.sockets.in('mysql').json.send(json);
);

subscriber.subscribe('mysql');

此示例依赖于以下包,您可以通过 npm 安装这些包

npm install socket.io
npm install redis
npm install express

当我发布post.php 表单时,我也会将这些更改发布到redis。这部分很重要!多亏了 Redis 的 pubsub,node.js 进程总是会收到这些更改。每次当 php 脚本改变数据库时,您应该使用 publish 将这些更改发布到 Redis。

PS:希望这很清楚。也许稍后当我有空时,我可能会更新一些小sn-p...

【讨论】:

对于更新mysql的php脚本,如何连续运行呢?通过 cron 作业?如果是这样,那不是违背了使用 nodejs 的目的吗? 更新的答案,还包括一个小例子!希望现在很清楚您不需要 cronjobs,只需使用 Redis 的 pubsub。 好的,我想我明白了。我相信我遇到的问题是整个客户端更新过程。一直认为我必须每隔这么多秒查询一次数据库以获取更新,而只有在客户端发生操作时才应该更新它。 IE添加cmets,删除cmets,编辑cmets。习惯了客户端做所有的工作。 node.js 是一个在整个上下文中始终运行且可用的进程(每个请求都知道另一个请求),而每个 PHP 进程是分开的(每个请求对其他请求一无所知) )。这就是你应该把头绕起来的东西。 Redis 是一个非常快速的高级键值存储,它也有 pubsub。 Redis 使用普通套接字。这意味着它不使用 HTTP。我喜欢使用 Redis 的 pubsub 通过套接字以非常快速的方式与 PHP 通信。将更改实时发送到我们需要 socket.io 的所有浏览器。我希望这一切都清楚。

以上是关于Redis sub/pub 和 php/nodejs的主要内容,如果未能解决你的问题,请参考以下文章

2-redis的pub/sub发布订阅

Redis

Inplayable技术分享

Inplayable技术分享

Inplayable技术分享

Inplayable技术分享