workman分布式部署遇到的bug以及修复方式
代码备份录—— workman 分布式部署遇到的问题,以及解决方式
我的目标
状况
现在手里是有2台服务器,并且已经是借助阿里云的slb负债均衡转发请求的,当然这个负债均衡在此处并没有用到,因为它主要是监听433 和 80端口用。我并没有去监听tcp 我的内容
这个案例回头想想还是比较简单的
主要实现商家后端登入保持在线后,若有人下单,给它推送一个mp3指令(播放mp3)
服务器情况
服务器A :公网IP 66.66.66.61 内网IP:192.168.0.1
服务器B :公网IP 99.99.99.91 内网IP:192.168.0.2
服务端配置 - 服务器A
内容来自:start_register.php
<?php
use \Workerman\Worker;
use \GatewayWorker\Register;
require_once __DIR__ . '/../../vendor/autoload.php';
// register 服务必须是text协议
$register = new Register('text://0.0.0.0:1238');
// 如果不是在根目录启动,则运行runAll方法
if(!defined('GLOBAL_START'))
{
Worker::runAll();
}
---分割线---
内容来自:start_gateway.php
<?php
use \Workerman\Worker;
use \GatewayWorker\Gateway;
use \Workerman\Autoloader;
require_once __DIR__ . '/../../vendor/autoload.php';
// gateway 进程
$gateway = new Gateway("Websocket://0.0.0.0:7373");
$gateway->name = 'gateway';// 设置名称,方便status时查看
$gateway->count = 4;// 设置进程数,gateway进程数建议与cpu核数相同
$gateway->lanIp = '192.168.0.1'; // 分布式部署时请设置成内网ip(非127.0.0.1)此处做演示用,需填写真实的服务器内网ip
$gateway->startPort = 2310;// 不可被其他项目占用端口,2300-2303 , 2310-2313, 必须1236,1238端口不能重复,不能2个项目都用1236端口,可以全部替换其他端口!同时startPort不能冲突
$gateway->pingInterval = 10;// 心跳间隔
$gateway->pingData = '{"type":"ping"}';// 心跳数据
$gateway->registerAddress = '192.168.0.1:1238';// 服务注册地址
if(!defined('GLOBAL_START'))
{
Worker::runAll();
}
---分割线---
内容来自:start_businessworker.php
<?php
use \Workerman\Worker;
use \GatewayWorker\BusinessWorker;
use \Workerman\Autoloader;
require_once __DIR__ . '/../../vendor/autoload.php';
$worker = new BusinessWorker();// bussinessWorker 进程
$worker->name = 'businessWorker';// worker名称
$worker->count = 4;// bussinessWorker进程数量
$worker->registerAddress = '192.168.0.1:1238';// 服务注册地址
// 如果不是在根目录启动,则运行runAll方法
if(!defined('GLOBAL_START'))
{
Worker::runAll();
}
注:框架其他文件
GatewayWorker/vendor/workerman/gateway-worker/src/Gateway.php
GatewayWorker/vendor/workerman/gateway-worker/src/Lib/Gateway.php
以上2个文件因为是部署在第一台,所以$registerAddress中的可以ip可以是127.0.0.1,但端口要修改为自己注册的端口:1238 【即:start_register.php 文件中填写的端口】
服务端配置 - 服务器B
内容来自:start_register.php 【此文件内所有内容全部注释,因为register需要统一一个】
<?php
// 就当全部删除了
---分割线---
内容来自:start_gateway.php 【此文件,和服务器A不同的地方在内网ip lanIp】
<?php
use \Workerman\Worker;
use \GatewayWorker\Gateway;
use \Workerman\Autoloader;
require_once __DIR__ . '/../../vendor/autoload.php';
// gateway 进程
$gateway = new Gateway("Websocket://0.0.0.0:7373");
$gateway->name = 'gateway';// 设置名称,方便status时查看
$gateway->count = 4;// 设置进程数,gateway进程数建议与cpu核数相同
$gateway->lanIp = '192.168.0.2'; // 分布式部署时请设置成内网ip(非127.0.0.1)此处做演示用,需填写真实的服务器内网ip
$gateway->startPort = 2310;// 不可被其他项目占用端口,2300-2303 , 2310-2313, 必须1236,1238端口不能重复,不能2个项目都用1236端口,可以全部替换其他端口!同时startPort不能冲突
$gateway->pingInterval = 10;// 心跳间隔
$gateway->pingData = '{"type":"ping"}';// 心跳数据
$gateway->registerAddress = '192.168.0.1:1238';// 服务注册地址
if(!defined('GLOBAL_START'))
{
Worker::runAll();
}
---分割线---
内容来自:start_businessworker.php 【此文件无改动】
<?php
use \Workerman\Worker;
use \GatewayWorker\BusinessWorker;
use \Workerman\Autoloader;
require_once __DIR__ . '/../../vendor/autoload.php';
$worker = new BusinessWorker();// bussinessWorker 进程
$worker->name = 'businessWorker';// worker名称
$worker->count = 4;// bussinessWorker进程数量
$worker->registerAddress = '192.168.0.1:1238';// 服务注册地址
// 如果不是在根目录启动,则运行runAll方法
if(!defined('GLOBAL_START'))
{
Worker::runAll();
}
注:框架其他文件
GatewayWorker/vendor/workerman/gateway-worker/src/Gateway.php
GatewayWorker/vendor/workerman/gateway-worker/src/Lib/Gateway.php
以上2个文件部署在第二台,所以$registerAddress中的可以ip要改为是192.168.0.1 (register的内网地址,不能是127.0.0.1),端口还是:1238 【即:第一台start_register.php 文件中填写的端口】
域名绑定
添加记录
1、domain.com ==正常解析到第一台ip==> 66.66.66.61
客户端绑定
代码说明
1、一个看不见的mp3 标签(通过jq播放,需要当前页面有点击事件,否则会报错,但由于后台登入的时候,就已经触发了点击,所有下方的jq能操作播放)
2、new ws协议,进入websocket握手环节 -> 成功则会逐步在控制台打印
启动ws链接
onopen
{"type":"init","client_id":"c0a8a0cc090800000007"}
收到workman返回的client_id,准备绑定laravel
开始绑定client_id
绑定成功 [Array(1)]
<div style="display: none">
<audio src="/mp3/xxxx.mp3" controls="controls" preload="auto" id="mp3" ></audio>
</div>
<script type="text/javascript">
var ws;
var client_id ;
function connect() {
// 此处的domain.com 是指向register的那台服务器(上方服务器有记录)
ws = new WebSocket("ws://domain.com:7373");
ws.onopen = onopen;
ws.onmessage = onmessage;
ws.onclose = function() {
console.log("连接关闭,定时重连");
connect();
};
ws.onerror = function() {
console.log("出现错误");
};
}
function onmessage(e) {
console.log("服务端推送",e.data);
var data = JSON.parse(e.data);
client_id = data['client_id'];
switch(data['type']){
// 绑定 client_id
case 'init':
// 客户端ID绑定
console.log("收到workman返回的client_id,准备绑定laravel");
loginInit(data);
break;
// 服务端 ping 客户端
case 'ping':
ws.send('{"type":"ping"}');
break;
case 'mp3':
mp3Bf();
break;
}
}
function loginInit(data) {
$.ajax({
url:"api/wss/bindUid",
type: "post",
data:{
id:"business",//"{{$user}}",
type:"business",
client_id:data['client_id']
},
cache:false,
dataType: "json",
beforeSend:function(XMLHttpRequest){
console.log("开始绑定client_id");
},
success:function(pay){
console.log("绑定成功",pay);
},
error: function (XMLHttpRequest,ex) {
}
});
}
function onopen() {
}
function mp3Bf(){
var mp3 = document.getElementById('mp3');
mp3.play();
}
setTimeout(function () {
console.log("启动ws连接");
connect();
},1000);
</script>
遇到的问题,放在最后
1、阿里云服务器内的iptables和firewalld要关掉
若遇到 GatewayConnection Error : 1 ,connect fail xxxx 表示两台电脑并不互通,尝试执行命令测试是否还会出现 worker给的回复也是没法互通
systemctl stop iptables # 停止防火墙
systemctl stop firewalld # 停止firewalld规则
如果确定不会出现,可以直接禁用(直接使用阿里云的安全组吧)
systemctl disable firewalld # 禁用firewalld规则
2、 stream_socket_client(): unable to connect to tcp://127.0.0.1:1238 这个是第二台服务器框架文件中,没有修改为第一台内网的IP导致
心得
有了这次经验后,准备再优化成wss协议,即ws +ssl 提供小程序做websocket
官网指导的部署方式
本作品采用《CC 协议》,转载必须注明作者和本文链接