28

PHP 的redis扩展是阻塞式 IO ,使用订阅/发布模式时,会导致整个进程进入阻塞。因此必须使用Swoole\Redis异步客户端来实现。

实例代码

$server = new swoole_websocket_server("0.0.0.0", 9501);

$server->on('workerStart', function ($server, $workerId) {
    $client = new swoole_redis;
    $client->on('message', function (swoole_redis $client, $result) use ($server) {
        if ($result[0] == 'message') {
            foreach($server->connections as $fd) {
                $server->push($fd, $result[1]);
            }
        }
    });
    $client->connect('127.0.0.1', 6379, function (swoole_redis $client, $result) {
        $client->subscribe('msg_0');
    });
});

$server->on('open', function ($server, $request) {

});

$server->on('message', function (swoole_websocket_server $server, $frame) {
    $server->push($frame->fd, "hello");
});

$server->on('close', function ($serv, $fd) {

});

$server->start();

实现过程

  • 在进程启动(onWorkerStart)时创建了Swoole\Redis客户端,连接到Redis服务器

  • 连接成功后,订阅msg_0主题的消息

  • 当有新的message时,Swoole\Redis会触发onMessage事件回调

  • 在这个回调函数中使用$server->connections遍历服务器所有的连接,发送消息


如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的

25 条评论
daydaygo · 2017年10月26日

最后使用 process 解决的, 用一个单独的 process 来跑 redis sub

+1 回复

0

用process来sub redis的可有源代码?另外看到很多人通过给worker编号,保证只有一个worker来订阅了redis,这样是不是就限制了吞吐量呢?

zouliming · 2018年01月08日
0

@zouliming swoole 有2种worker, worker 配合 server, task 配置耗时任务投递, 不适合 pub/sub 这样的场景, 使用 Process 职责分明, 是最佳实践. 代码的话看你如何实现, 原生看 swoole wiki 就好了, 其他开源的框架都封装有自己的实现, 直接用就行, 比如 swoft

daydaygo · 2018年01月08日
0

@daydaygo 谢谢回复。不过你好像没有回答我的问题,也可能是没有看懂我的问题吧。swoft的源码看了,可惜没找到process订阅redis这块。

zouliming · 2018年01月08日
jdxia · 2017年09月04日

?,希望swoole越来越好

回复

facades · 2017年09月05日

这个类哪里来呀swoole_redis

回复

0

参考这个链接来编译安装 Swoole
https://www.swoole.com/wiki/p...

Yian · 2017年10月07日
daydaygo · 2017年09月09日

有 2 点疑问:

  1. 这里相当于把消息广播给每个 server, 然后 server 广播给了每个连接, 如果只想把消息广播给某个单独的连接呢?
  2. https://wiki.swoole.com/wiki/... 这个 wiki 中讲到多个进程不要公用一个连接, 所以在 workStart 回调中初始化, 这样的话, 这里是不是每个 worker 进程都会起一个 swoole_redis 来监听, 导致消息被重复广播?

回复

0

像文中的代码那样把 Redis 的 on message 放在 Swoole 的 on workerStart 里,我这里每个页面会收到 8 条重复消息,然后我把 Redis 的 on message 放在 Swoole 的 on open 后就不会出现重复广播了...
初学 Swoole,还在慢慢摸索中...

Yian · 2017年10月07日
0

@Yian 我按文中的写法,每个页面都会收到8条重复的消息。按你修改了就不会重复广播了,请问您已经找到原因了吗?

qqlcbb · 2017年10月26日
0

@qqlcbb 可以去了解一下 swoole 的进程模型, onWorkerStart 是绑定到 worker 进程上, onOpen 是绑定到 master 进程开启上

daydaygo · 2017年11月02日
jlzan1314 · 2017年11月28日

帮每个worker 订阅 编个号,发布订阅的时候,发给2个订阅不就解决重复的问题了

回复

zouliming · 2018年01月08日

韩总,demo中的实例代码,会订阅多次。如果只想订阅一次,应该如何写更好呢?

回复

0

可以new个swoole_process做订阅,然后server->addProcess 挂进去

易拉罐 · 2018年07月20日
since888 · 2018年12月22日

麻烦问下,之前这代码跑起来没问题,现在重装后,启动时候提示不能使用 new swoole_redis; 只让使用协程的new SwooleCoroutineRedis();
是啥情况

回复

1

报错内容 SwooleRedis::__construct(): async APIs will be removed in Swoole-v4.3.0, you should be using the coroutine APIs instead

since888 · 2018年12月22日
0

@since888 同样问题解决了吗?

羊爸爸 · 1月10日
0

@羊爸爸 新版本不支持这个,所以,吧版本降到1.8+就行

since888 · 1月10日
he_xd · 2月20日

请问一下我在 open 事件的时候能获取到userinfo, 然后需要根据其中的userid 去redis 查找 userid_messages 这样名称的队列,在哪里实现监听redis 队列的数据变动?workerstart 的时候没有userid

回复

载入中...