消息服务器使用socket,为避免服务器过载,单台只允许500个socket连接,当一台不够的时候,扩充消息服务器是必然,问题来了,如何让链接在不同消息服务器上的用户可以实现消息发送呢?

要实现消息互通就必须要让这些消息服务器本身能互通,想了两个方式,一种是消息服务器之间交叉链接,另一种是增加一个特殊的消息服务器,这个消息服务器不对外开放,只负责消息转发和推送。

下列测试不考虑防火墙等。仅测试可行性和效率。

测试环境

  • 消息服务器
    192.168.0.201 9501
    192.168.0.202 9501
  • 转发服务器
    192.168.0.203 9501
  • 公共缓存
    Redis 192.168.0.231 6379
  • 软件环境
    centos 6.5 mini swoole php

流程图

  • 整个流程图如下:

  • 流程图说明:
    client1可向client2或者其他client发送消息,并接收其他client发送的消息.

    Redis中保存client连接的信息,给每个用户分配唯一的key,包括链接的哪台服务器,转发服务器定时检测消息服务器,如消息服务器挂掉,由转发服务器清理掉Redis已经挂掉的所有链接。

  • 完整的流程:

    1.Client1Client2发送一条消息

    2.Socket1接收到消息,根据key从Redis取出Client2的连接信息,连接在本机,直接推送给Client2,流程结束。

    3.如果连接不在本机,把消息推送到转发服务器,由转发服务器把该消息推送给连接所在消息服务器,消息服务器接收消息,推送给Client2

    4.消息发送结束。

编码实现

  • Socket
    在socket1上创建一个server.php,内容如下:

      <?php //服务端
    $serv = new swoole_server("0.0.0.0", 9501); //redis
    $redis = new \Redis();
    $redis->connect("192.168.0.231", 6379); //client
    $proxy = new swoole_client(SWOOLE_TCP | SWOOLE_KEEP);
    $proxy->connect("192.168.0.203", 9501); $serv->on('start', function($serv) {
    echo "Service:Start...";
    });
    $serv->on('connect', function ($serv, $fd) { });
    $serv->on('receive', function ($serv, $fd, $from_id, $data) {
    global $redis; $data = (array) json_decode($data);
    $cmd = $data['cmd']; switch ($cmd) { case "login"://登陆
    //保存连接信息
    $save = array(
    'fd' => $fd,
    'socket_ip' => "192.168.0.201"
    );
    $redis->set($data['name'], serialize($save));
    break; case "chat":
    $recv = unserialize($redis->get($data['recv']));
    if ($recv['socket_ip'] != "192.168.0.201") {
    //需要转发
    $data['cmd'] = 'forward';
    $data['recv_ip'] = $recv['socket_ip'];
    $serv->task(json_encode($data));
    } else {
    //直接发送
    $serv->send($recv['fd'], "{$data['send']}给您发了消息:{$data['content']}");
    }
    break; case "forward"://接收转发消息
    $recv = unserialize($redis->get($data['recv']));
    $serv->send($recv['fd'], "{$data['send']}给您发了消息:{$data['content']}"); break;
    }
    //$serv->send($fd, 'Swoole: ' . $data);
    });
    $serv->on('task', function ($serv, $task_id, $from_id, $data) {
    global $proxy;
    $proxy->send($data);
    }); $serv->on('finish', function ($serv, $task_id, $data) { });
    $serv->on('close', function ($serv, $fd) {
    echo "Client: Close.\n";
    }); $serv->set(array('task_worker_num' => 4)); $serv->start();

    在socket2上只需把ip变更一下即可。192.168.0.201变更为192.168.0.202.

  • Proxy
    在转发服务器上建立脚本proxy.php,内容如下:

     $serv = new swoole_server("0.0.0.0", 9501); //服务端
    $serv->on('start', function($serv) {
    echo "Service:Start...";
    });
    $serv->on('connect', function ($serv, $fd) { });
    $serv->on('receive', function ($serv, $fd, $from_id, $data) {
    global $redis;
    $serv->task($data);
    });
    $serv->on('task', function ($serv, $task_id, $from_id, $data) {
    $forward = (array) json_decode($data);
    $client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC); $client->connect($forward['recv_ip'], 9501);
    unset($forward['recv_ip']);
    $client->send(json_encode($forward));
    $client->close();
    }); $serv->on('finish', function ($serv, $task_id, $data) { });
    $serv->on('close', function ($serv, $fd) {
    echo "Client: Close.\n";
    }); $serv->set(array('task_worker_num' => 4)); $serv->start();

测试

注意开启顺序

1.开启转发服务器php proxy.php

2.分别开启socket服务器php server.php

可以在转发服务器上看到两个消息服务器已经连接
3.开始测试,分别打开两个telnet,连接两个消息服务器,发送消息测试:
登陆

发送消息测试

消息成功接收。

基于强大的swoole扩展,让php高效的实现这些成为可能,目前消息服务器到转发服务器是长连接,转发服务器到消息服务器是短连接,存在性能瓶颈,也浪费了连接资源。下一步改造成长连接,消息服务器的client使用异步。

基于SWOOLE的分布式SOCKET消息服务器架构的更多相关文章

  1. 手撸基于swoole 的分布式框架 实现分布式调用(20)讲

    最近看的一个swoole的课程,前段时间被邀请的参与的这个课程 比较有特点跟一定的深度,swoole的实战教程一直也不多,结合swoole构建一个新型框架,最后讲解如何实现分布式RPC的调用. 内容听 ...

  2. 【原】用PHP搭建基于swoole扩展的socket服务(附PHP扩展的安装步骤及Linux/shell在线手册)

    最近公司的一项目中,需要用PHP搭建一个socket服务. 本来PHP是不适合做服务的,因为和第三方合作,需要采用高效而稳定的TCP协议进行数据通信.经过多次尝试,最终选择了开源的PHP扩展:swoo ...

  3. 基于Redis的分布式锁真的安全吗?

    说明: 我前段时间写了一篇用consul实现分布式锁,感觉理解的也不是很好,直到我看到了这2篇写分布式锁的讨论,真的是很佩服作者严谨的态度, 把这种分布式锁研究的这么透彻,作者这种技术态度真的值得我好 ...

  4. 基于Redis的分布式锁到底安全吗(下)?

    2017-02-24 自从我写完这个话题的上半部分之后,就感觉头脑中出现了许多细小的声音,久久挥之不去.它们就像是在为了一些鸡毛蒜皮的小事而相互争吵个不停.的确,有关分布式的话题就是这样,琐碎异常,而 ...

  5. java分布式通信系统(J2EE分布式服务器架构)

    一.序言 近几个月一直从事一个分布式异步通信系统,今天就整理并blog一下. 这是一个全国性的通信平台,对性能,海量数据,容错性以及扩展性有非常高的要求,所以在系统的架构上就不能简单的采用集中式.简单 ...

  6. 【分布式事务】基于RocketMQ搭建生产级消息集群?

    导读 目前很多互联网公司的系统都在朝着微服务化.分布式化系统的方向在演进,这带来了很多好处,也带来了一些棘手的问题,其中最棘手的莫过于数据一致性问题了.早期我们的软件功能都在一个进程中,数据的一致性可 ...

  7. GPS部标监控平台的架构设计(十一)-基于Memcached的分布式Gps监控平台

    部标gps监控平台的架构,随着平台接入的车辆越来越多,架构也面临越来越大的负载挑战,我们当然希望软件尽可能的优化并能够接入更多的车辆,减少在硬件上的投资.但是当车辆增多到某一个临界点的时候,仍然要面临 ...

  8. 高扩展的基于NIO的服务器架构

    当你考虑写一个扩展性良好的基于Java的服务器时,相信你会毫不犹豫地使用Java的NIO包.为了确保你的服务器能够健壮.稳定地运行,你可能会花大量的时间阅读博客和教程来了解线程同步的NIO selec ...

  9. 基于libevent, libuv和android Looper不断演进socket编程 - 走向架构师之路 - 博客频道 - CSDN.NET

    基于libevent, libuv和android Looper不断演进socket编程 - 走向架构师之路 - 博客频道 - CSDN.NET 基于libevent, libuv和android L ...

随机推荐

  1. JavaScript修改注册表

    JavaScript修改注册表 2009-04-14 11:22:13|  分类: JS相关 |  标签: |字号大中小 订阅     注册表有关安全设置项的说明: 注册表路径: HKEY_CURRE ...

  2. 【JDBC&Dbutils】JDBC&JDBC连接池&DBUtils使用方法(重要)

    -----------------------JDBC---------- 0.      db.properties文件 driver=com.mysql.jdbc.Driver url=jdbc: ...

  3. 2018.09.17 atcoder Digit Sum(数论)

    传送门 数论好题啊. 首先对于b<=sqrt(n)b<=sqrt(n)b<=sqrt(n)的情况直接枚举b判断一下就行了. 下面谈一谈如何解决b>sqrt(n)b>sqr ...

  4. SPI通信协议(SPI总线)学习

    1.什么是SPI? SPI是串行外设接口(Serial Peripheral Interface)的缩写.是 Motorola 公司推出的一 种同步串行接口技术,是一种高速的,全双工,同步的通信总线. ...

  5. b4和tncl_extract_UNCL_new

    # -*- coding:utf-8 -*- import re ''' 适应新版本 注意: 1)17A文件改完后缀后,需要转为UTF-8无BOM格式,才能正确处理. 2)fr = open(file ...

  6. hB

    function Coef = LowPassHb(Fs,Fpass,Apass,n) % -- Fs sample frequency % -- Fpass % -- Apass(dB) % -- ...

  7. cxf-rs 、spring 和 swagger 环境配置切换【github 有项目】

    环境切换的目的是 准生产和生产环境切换时,只修改一个文件就可以达到效果 在spring bean 文件中 配置: <bean class="cn.zno.common.context. ...

  8. SPATIALINDEX_LIBRARY Cmake

    https://libspatialindex.org/ QGIS:https://github.com/qgis/QGIS/blob/master/cmake/FindSpatialindex.cm ...

  9. TCP/IP模型的一个简单解释

    TCP/IP模型是互联网的基础. 想要理解互联网,就必须理解这个模型.但是,它不好懂,我就从来没有搞懂过. 前几天,BetterExplained上有一篇文章,很通俗地解释了这个模型.我读后有一种恍然 ...

  10. [program]编程习惯总结(2015_11_25)

    1. 前端页面不要的数据,那么后端就不要发送到前端: 如:我们根据各个大洲来建立了一个个大洲的讨论区,但是在发表讨论页面.我们却希望用户去选择与当前帖子相关的国家标签. 那么,我们只需要在后台使用国家 ...