消息服务器使用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. 设计神器 - 摹客设计系统上线了 | 晒出你的设计规范,赢iPad Pro!

    在国内,设计规范也许还是个不太常用的概念,但是如果你正好有参与互联网公司的产品设计,你应该早就已经体会到设计规范的重要性了.UI设计师总是要花费大量的时间和精力向开发描述一大堆设计细节,但是产品最后呈 ...

  2. JavaScript 代码小片段

    1.获取对象 obj 的所有属性(自有属性和继承属性),保存到数组 lst 中 //获取对象obj的所有属性(自有属性和继承属性),保存到数组lst 中 var lst = []; function ...

  3. css3新增功能

    CSS3新增功能 1 CSS3选择器详解 1.1 基础选择器 通配选择器* 元素选择器E ID选择器#id CLASS选择器.class 群组选择器select1,selectN 1.2 层次选择器 ...

  4. 2018.08.21 NOIP模拟 unlock(模拟+找规律)

    unlock 描述 经济危机席卷全球,L国也收到冲击,大量人员失业. 然而,作为L国的风云人物,X找到了自己的新工作.从下周开始,X将成为一个酒店的助理锁匠,当然,他得先向部门领导展示他的开锁能力. ...

  5. hdu-1150(二分图+匈牙利算法)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1150 思路:题目中给出两个机器A,B:给出k个任务,每个任务可以由A的x状态或者B的y状态来完成. 完 ...

  6. WebService测试工具介绍及下载

    1 LoadRunner  LoadRunner,是一种预测系统行为和性能的负载测试工具.通过以模拟上千万用户实施并发负载及实时性能监测的方式来确认和查找问 题,LoadRunner能够对整个企业架构 ...

  7. C#基础:在using中创建对象

    在using中创建的对象的类必须是实现了IDispose接口的类,示例代码如下: static void Main(string[] args) { Method(); Console.WriteLi ...

  8. [笔记]python

    配置python apt install python2.7 python3 apt install python-bs4 python3-bs4 apt install virtualenv apt ...

  9. 批量远程执行shell命令工具

    使用示例(使用了默认用户root,和默认端口号22): ./mooon_ssh --h=192.168.4.1,192.168.4.2 -P=password -c='cat /etc/hosts' ...

  10. SQL server经验分享:SQLSERVER 被标记为“可疑”的数据库处理方法

    --MyDB为修复的数据名USE MASTER GO SP_CONFIGURE 'ALLOW UPDATES',1 RECONFIGURE WITH OVERRIDE GO ALTER DATABAS ...