workman分散式部署遇到的bug以及修復方式

wavebossy6666發表於2020-11-02

程式碼備份錄—— workman 分散式部署遇到的問題,以及解決方式

我的目標

狀況
現在手裡是有2臺伺服器,並且已經是藉助阿里雲的slb負債均衡轉發請求的,當然這個負債均衡在此處並沒有用到,因為它主要是監聽43380埠用。我並沒有去監聽tcp 我的內容
這個案例回頭想想還是比較簡單的

主要實現商家後端登入保持線上後,若有人下單,給它推送一個mp3指令(播放mp3)

伺服器情況

伺服器A :公網IP 66.66.66.61  內網IP192.168.0.1
伺服器B :公網IP 99.99.99.91  內網IP192.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能操作播放)
2new 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 

官網指導的部署方式

workman官方部署指導方式

本作品採用《CC 協議》,轉載必須註明作者和本文連結
朝著夢,踏平坎坷

相關文章