【swoole4.0】分布式广播实现

2019年4月29日 329点热度 0人点赞 0条评论

源起

群里的一个提问

图片


问题

这是一个比较典型的场景,当用户发展到一定程度后,单机的支撑能力是有上限的,这个时候必需用多台机器进行水平扩展了,那针对长连接这种有状态的情况下,就必需面临以下2个问题?

  1. 怎么分配用户到哪台机器上?

  2. 同一房间的用户被分配到不同机器上,如何广播和相互通讯


万变不离其宗,我们先看单机的场景下如何处理


单机的广播场景


如果要进行全局广播,那非常easy, 可以用swoole内置的方法:

foreach($server->connections as $fd)
{
$server->send($fd, "hello");
}

echo "当前服务器共有 ".count($server->connections). " 个连接\n";

(PS: 广播可以放到task进程,避免堵塞worker进程)


这个只是所有的广播,如果我想做组播怎么办?


单机组播

以聊天室为例,广播就相当于整个系统是一个大聊天室,但实际情况往往是需要多个聊天室,相互之间不影响,对某一个聊天室进行广播,称之为组播,那需要怎么做呢?
实现想来也非常简单,这个时候,我们可以引入redis,以房间Id做为key,创建一个list,进入该房间时,用户加入到这个list中,退出房间时,从list删除, 相关伪代码如下:

图片

单机场景下,服务非常简单,就一个websocket server外加一个redis
时序图基本如下:

图片

OK,现在我们回到最开始提到的问题,当一台机器变成N台机器之后,怎么办?

分配用户到哪台机器上?

这时,建议专门把登录服务提出来,这是一个http服务,用户登录成功之后,除了返回token之外,还返回一台聊天服务器的ip和端口,原因有:

  1. 登录服务无状态,可以水平扩展

  2. 返回哪台服务器的ip和端口就可以做很多灵活的策略,通常有以下

    1. 随机

    2. 轮询

    3. 跟据对应的服务器的负载状态

    4. ====

  3. 聊天服务器也可以水平扩展了

这里面还有一个关键的一步:
把用户的uid 和 对应的服务器ip/port 关系绑定,这有助于我们知道用户在哪台机器上


Proxy

除了要把登录服务单独拎出来,还需要一个proxy,专于来处理各服务之间的通信和redis的交互

如我们进入房间的操作,退出房间,都通过这个proxy把数据存放在redis里


聊天室广播

聊天服务器的核心代码如下:

图片

proxy的关键代码如下:

图片

通过引入中间的proxy层,可以很方便的进行server之间的转发,不管同一个房间的用户分散到哪,通过redis都能找到对应的关系

大致的思路如上,当然做好一个分布式聊天室的细节还非常多,有何问题,随时交流, 希望能给大家带来帮助。

----------伟大的分割线-----------


PHP饭米粒(phpfamily) 由一群靠谱的人建立,愿为PHPer带来一些值得细细品味的精神食粮!


饭米粒只发原创或授权发表的文章,不转载网上的文章


所发的文章,均可找到原作者进行沟通。


也希望各位多多打赏(算作稿费给文章作者),更希望大家多多投搞。


投稿请联系:


[email protected]


本文由 桶哥 授权 饭米粒 发布,转载请注明本来源信息和以下的二维码(长按可识别二维码关注)

图片

36180【swoole4.0】分布式广播实现

这个人很懒,什么都没留下

文章评论