程式碼備份錄—— 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/Lib/Gateway.php
GatewayWorker/vendor/workerman/gateway-worker/src/Gateway.php
GatewayWorker/vendor/workerman/gateway-worker/src/Lib/Gateway.php
以上3個檔案因為是部署在第一臺,所以$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/Lib/Gateway.php
GatewayWorker/vendor/workerman/gateway-worker/src/Gateway.php
GatewayWorker/vendor/workerman/gateway-worker/src/Lib/Gateway.php
以上3個檔案部署在第二臺,所以$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 協議》,轉載必須註明作者和本文連結