基于SWOOLE的分布式SOCKET消息服务器架构
消息服务器使用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.
Client1
给Client2
发送一条消息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消息服务器架构的更多相关文章
- 手撸基于swoole 的分布式框架 实现分布式调用(20)讲
最近看的一个swoole的课程,前段时间被邀请的参与的这个课程 比较有特点跟一定的深度,swoole的实战教程一直也不多,结合swoole构建一个新型框架,最后讲解如何实现分布式RPC的调用. 内容听 ...
- 【原】用PHP搭建基于swoole扩展的socket服务(附PHP扩展的安装步骤及Linux/shell在线手册)
最近公司的一项目中,需要用PHP搭建一个socket服务. 本来PHP是不适合做服务的,因为和第三方合作,需要采用高效而稳定的TCP协议进行数据通信.经过多次尝试,最终选择了开源的PHP扩展:swoo ...
- 基于Redis的分布式锁真的安全吗?
说明: 我前段时间写了一篇用consul实现分布式锁,感觉理解的也不是很好,直到我看到了这2篇写分布式锁的讨论,真的是很佩服作者严谨的态度, 把这种分布式锁研究的这么透彻,作者这种技术态度真的值得我好 ...
- 基于Redis的分布式锁到底安全吗(下)?
2017-02-24 自从我写完这个话题的上半部分之后,就感觉头脑中出现了许多细小的声音,久久挥之不去.它们就像是在为了一些鸡毛蒜皮的小事而相互争吵个不停.的确,有关分布式的话题就是这样,琐碎异常,而 ...
- java分布式通信系统(J2EE分布式服务器架构)
一.序言 近几个月一直从事一个分布式异步通信系统,今天就整理并blog一下. 这是一个全国性的通信平台,对性能,海量数据,容错性以及扩展性有非常高的要求,所以在系统的架构上就不能简单的采用集中式.简单 ...
- 【分布式事务】基于RocketMQ搭建生产级消息集群?
导读 目前很多互联网公司的系统都在朝着微服务化.分布式化系统的方向在演进,这带来了很多好处,也带来了一些棘手的问题,其中最棘手的莫过于数据一致性问题了.早期我们的软件功能都在一个进程中,数据的一致性可 ...
- GPS部标监控平台的架构设计(十一)-基于Memcached的分布式Gps监控平台
部标gps监控平台的架构,随着平台接入的车辆越来越多,架构也面临越来越大的负载挑战,我们当然希望软件尽可能的优化并能够接入更多的车辆,减少在硬件上的投资.但是当车辆增多到某一个临界点的时候,仍然要面临 ...
- 高扩展的基于NIO的服务器架构
当你考虑写一个扩展性良好的基于Java的服务器时,相信你会毫不犹豫地使用Java的NIO包.为了确保你的服务器能够健壮.稳定地运行,你可能会花大量的时间阅读博客和教程来了解线程同步的NIO selec ...
- 基于libevent, libuv和android Looper不断演进socket编程 - 走向架构师之路 - 博客频道 - CSDN.NET
基于libevent, libuv和android Looper不断演进socket编程 - 走向架构师之路 - 博客频道 - CSDN.NET 基于libevent, libuv和android L ...
随机推荐
- PAT 1015 德才论 (25)(代码+思路)
1015 德才论 (25)(25 分)提问 宋代史学家司马光在<资治通鉴>中有一段著名的"德才论":"是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子, ...
- DNA甲基化检测服务
DNA甲基化检测服务 DNA甲基化是最早发现的基因表观修饰方式之一,真核生物中的甲基化仅发生于胞嘧啶,即在DNA甲基化转移酶(DNMTs)的作用下使CpG二核苷酸5'-端的胞嘧啶转变为5'-甲基胞嘧啶 ...
- send发送一次buffer
发送的字符串后面添加:\r\n 结束标志 否则发送1024或者程序接收默认的字节数 #include <stdio.h> #include <stdlib.h> #includ ...
- OSGi 系列(一)之什么是 OSGi :Java 语言的动态模块系统
OSGi 系列(一)之什么是 OSGi :Java 语言的动态模块系统 OSGi 的核心:模块化.动态.基于 OSGi 就可以模块化的开发 java 应用,模块化的部署 java 应用,还可以动态管理 ...
- wcf数据推送
http://www.cnblogs.com/artech/archive/2007/03/02/661969.html
- NSNotificationCenter 注意
成对出现 意思很简单,NSNotificationCenter消息的接受线程是基于发送消息的线程的.也就是同步的,因此,有时候,你发送的消息可能不在主线程,而大家都知道操作UI必须在主线程,不然会出现 ...
- OC调用Swift
Step by step swift integration for Xcode Objc-based project: Create new *.swift file (in Xcode) or a ...
- 2018.09.20 atcoder 1D Reversi(模拟)
传送门 考虑每次摆石头都会消去最外层的一个连续颜色串. 所以只用统计一下有多少段颜色即可. 代码: #include<bits/stdc++.h> using namespace std; ...
- hibernate的一级缓存问题
1.证明一级缓存的问题 输出结果: 只发出一条查询语句 第二条查询语句没有执行 因为第一条查询语句缓存的存在 2. 移除缓存: 输出结果: 3.一级缓存的快照 就是对一级缓存的数据备份 保证数据库的 ...
- android插件化简述
2015年是Android插件化技术突飞猛进的一年,随着业务的发展各大厂商都碰到了Android Native平台的瓶颈: 从技术上讲,业务逻辑的复杂导致代码量急剧膨胀,各大厂商陆续出到65535方法 ...