消息服务器使用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. PAT 1015 德才论 (25)(代码+思路)

    1015 德才论 (25)(25 分)提问 宋代史学家司马光在<资治通鉴>中有一段著名的"德才论":"是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子, ...

  2. DNA甲基化检测服务

    DNA甲基化检测服务 DNA甲基化是最早发现的基因表观修饰方式之一,真核生物中的甲基化仅发生于胞嘧啶,即在DNA甲基化转移酶(DNMTs)的作用下使CpG二核苷酸5'-端的胞嘧啶转变为5'-甲基胞嘧啶 ...

  3. send发送一次buffer

    发送的字符串后面添加:\r\n 结束标志 否则发送1024或者程序接收默认的字节数 #include <stdio.h> #include <stdlib.h> #includ ...

  4. OSGi 系列(一)之什么是 OSGi :Java 语言的动态模块系统

    OSGi 系列(一)之什么是 OSGi :Java 语言的动态模块系统 OSGi 的核心:模块化.动态.基于 OSGi 就可以模块化的开发 java 应用,模块化的部署 java 应用,还可以动态管理 ...

  5. wcf数据推送

    http://www.cnblogs.com/artech/archive/2007/03/02/661969.html

  6. NSNotificationCenter 注意

    成对出现 意思很简单,NSNotificationCenter消息的接受线程是基于发送消息的线程的.也就是同步的,因此,有时候,你发送的消息可能不在主线程,而大家都知道操作UI必须在主线程,不然会出现 ...

  7. OC调用Swift

    Step by step swift integration for Xcode Objc-based project: Create new *.swift file (in Xcode) or a ...

  8. 2018.09.20 atcoder 1D Reversi(模拟)

    传送门 考虑每次摆石头都会消去最外层的一个连续颜色串. 所以只用统计一下有多少段颜色即可. 代码: #include<bits/stdc++.h> using namespace std; ...

  9. hibernate的一级缓存问题

    1.证明一级缓存的问题 输出结果: 只发出一条查询语句  第二条查询语句没有执行 因为第一条查询语句缓存的存在 2. 移除缓存: 输出结果: 3.一级缓存的快照 就是对一级缓存的数据备份 保证数据库的 ...

  10. android插件化简述

    2015年是Android插件化技术突飞猛进的一年,随着业务的发展各大厂商都碰到了Android Native平台的瓶颈: 从技术上讲,业务逻辑的复杂导致代码量急剧膨胀,各大厂商陆续出到65535方法 ...