php進程間通信 yoc_續上篇Swoole多進程數據共享的問題

3f1c1241ce88da9c78465c154ff0dd0c.png

原因

進程作為程序執行過程中資源分配的基本單位,擁有獨立的地址空間,同一進程的線程可以共享本進程的全局變量,靜態變量等數據和地址空間,但進程之間資源相互獨立。

由于PHP語言不支持多線程,因此Swoole使用多進程模式,再多進程模式下就存在進程內存隔離,進程間通信與數據共享問題。

swoole中master主進程會創建manager管理進程reactor線程,真正的工作進程為worker進程

manager是創建和管理worker進程,reactor進程測試監聽socket,接受數據任務,發送給worker進程去工作,因此所有業務邏輯最終都是在worker進程中進行,worker進程之間的數據共享與通信必不可少。

swoole中設置選項worker_num啟動的worker進程數,默認設置為CPU核數

例如:

$server = new swoole_server('127.0.0.1',9898);
$server->set(array('worker_num' => 4,   //設置啟動的Worker進程數。
));

如上面說描述,進程存在進程隔離:

$fds = array();
$server->on('connect', function ($server, $fd){echo "connection open: {$fd}n";global $fds;$fds[] = $fd;var_dump($fds);
});

$fds雖然是全局變量,但是只在但前的進程內有效,swoole服務器底層會創建多個worker進程,此處打印出來的只有部分連接的fd

解決方法:

swoole為我們提供了兩種有效的解決方法,都是基于多進程內存型數據庫,代替單進程PHP變量來存儲fd

第一種為:swoole_redis,特點是使用簡單,跟PHP原生的redis用法幾乎一致。

第二種為:swoole_table,這是swoole官方研制的一款內存型數據庫,比redis的可擴展性要強許多,單機器的情況下牛牛推薦大家使用這種方法。

Swoole_Tbale

swoole_redis沒什么好談的,因為redis都是個老活了,用法都一個鳥樣。

下面我們就重點搞下swoole_table的用法。

一波官方說明襲來:

Table一個基于共享內存和鎖實現的超高性能,并發數據結構。用于解決多進程/多線程數據共享和同步加鎖問題。

請謹慎使用數組方式讀寫Table, 建議使用文檔中提供的API來進行操作
數組方式取出的SwooleTableRow對象為一次性對象, 請勿依賴其進行過多操作

優勢

性能強悍,單線程每秒可讀寫200萬次
應用代碼無需加鎖,Table內置行鎖自旋鎖,所有操作均是多線程/多進程安全。用戶層完全不需要考慮數據同步問題。
支持多進程,Table可以用于多進程之間共享數據
使用行鎖,而不是全局鎖,僅當2個進程在同一CPU時間,并發讀取同一條數據才會進行發生搶鎖
Table的內存容量不受PHP的memory_limit控制

官方文檔地址:https://wiki.swoole.com/wiki/page/p-table.html

多進程數據共享的WebSocket例子:

<?php
// +----------------------------------------------------------------------
// 小黃牛blog - Swoole 即時通訊交互處理
// +----------------------------------------------------------------------
// Copyright (c) 2018 https://xiuxian.junphp.com All rights reserved.
// +----------------------------------------------------------------------
// Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// Author: 小黃牛 <1731223728@qq.com>
// +----------------------------------------------------------------------
class Server{/*** 客戶端身份存儲器*/private $_table = []; /*** WS的啟動實例*/private $_ws;/*** host-IP,0.0.0.0表示允許接收所有請求*/private $_host = '0.0.0.0';/*** 端口號*/private $_port = '9502';/*** 最大服務端心跳重連次數*/private $_max  = 3;/*** 強制心跳重連啟動狀態*/private $_status = true;/*** 這是啟動服務端的入口*/public function run() { $this->start_service(); $this->start_table(); $this->start_handshake();$this->start_message();$this->end();}/*** ①啟動websocker服務*/private function start_service() {# 創建websocket服務器對象,監聽0.0.0.0:9502端口$this->_ws = new swoole_websocket_server($this->_host, $this->_port);$this->_ws->set(['worker_num' => 4,// 開4個工作進程]);}/*** ①創建Table服務*/private function start_table() {# 創建最大只能存儲1024個用戶的數據$this->_table = new swoole_table(1024);# 創建字段$this->_table->column('fd', swoole_table::TYPE_INT, 8); // FD$this->_table->column('status', swoole_table::TYPE_INT, 8); // 離線狀態$this->_table->column('heartbeat', swoole_table::TYPE_INT, 8); // 心跳重連數$this->_table->column('user_id', swoole_table::TYPE_STRING, 32); // 會員ID$this->_table->column('user_nice', swoole_table::TYPE_STRING, 32); // 會員名稱$this->_table->create();# 將表附加到ws實例里,方便后續使用$this->_ws->user = $this->_table;}/*** ②監聽WebSocket握手申請*/private function start_handshake() {# 監聽WebSocket連接打開事件$this->_ws->on('open', function ($ws, $request){# 這里可以做些鑒權驗證之類的});}/*** ③監聽客戶端消息發送請求*/private function start_message() {# 監聽WebSocket消息事件$this->_ws->on('message', function ($ws, $frame) {$data    = json_decode($frame->data, true);$user_id = $data['user_id'];# 加入存儲器$this->_ws->user->set($user_id, ['fd'        => $frame->fd, # FD'status'    => 1, # 設置上線狀態'heartbeat' => 0, # 重置心跳重連數'user_id' => $data['user_id'], # 用戶ID'user_nice' => $data['user_nice'], # 用戶昵稱]);# 登錄廣播處理if ($data['code'] == 1) {# 發送廣播上線消息$data['content'] = '【'.$data['user_nice'].'】騎著小黃牛上線啦~!';$this->broadcast($ws, $this->json($data), $user_id);# 心跳重連檢測} else if ($data['code'] == 4) {$this->broadcast($ws, $frame->data, $user_id);$this->timer();# 其他請求} else {# 廣播消息$this->broadcast($ws, $frame->data, $user_id);}});} /*** ④監聽客戶端退出事件*/private function end() {# 這里加入了unset,清除open存儲器,防止存儲器無限增大# 監聽WebSocket連接關閉事件$this->_ws->on('close', function ($ws, $fd) {# 這塊提取用戶信息還有優化空間,實際開發中這樣for會消耗內存$user = null;foreach ($this->_ws->user as $k=>$v) {if ($v['fd'] == $fd) {$user = $v;break;}}# 獲取用戶ID$user_id = $user['user_id'];# 獲取用戶nice$user_nice = $user['user_nice'];# 設置離線狀態$this->_ws->user->set($user_id, ['status'    => 0, # 設置離線狀態]);$data = ['code' => 2,'user_id' => $user_id,'user_nice' => $user_nice,'content' => '【'.$user_nice.'】騎著小掃帚灰溜溜的走了~~!'];# 廣播消息$this->broadcast($ws, $this->json($data));});$this->_ws->start();}/*** 廣播消息* @todo 無* @author 小黃牛* @version v1.0.0.1 + 2018.11.12* @deprecated 暫不棄用* @global 無* @param object $wx 實例* @param string $content 廣播內容* @param string $id 用戶的userid*  @param bool $status 是否做心跳限制 * @return void*/private function broadcast($ws, $content, $id=null, $status=false) {# 向所有人廣播foreach ($this->_ws->user as $k=>$v) {# 不向自己廣播,并且要在線的# 注意,這里一定要有上線狀態的限制,否則假設用戶已經退出,但你的進程還開著,實際上已經關閉,這時候push就會報錯# 只有正常在線的用戶才能接收到廣播# 加入心跳檢測限制if ($k != $id && $v['status'] == 1 && $status == true) {$ws->push($v['fd'], $content);} else if ($v['user_id'] != $id && $v['status'] == 1 && $v['heartbeat'] == 0) {$ws->push($v['fd'], $content);}}}/*** 數組轉json* @todo 無* @author 小黃牛* @version v1.0.0.1 + 2018.11.08* @deprecated 暫不棄用* @global 無* @param array $array 數組* @return json*/private function json($array) {return json_encode($array, JSON_UNESCAPED_UNICODE);}/*** 服務端定時強制心跳檢測* @todo 無* @author 小黃牛* @version v1.0.0.1 + 2018.11.08* @deprecated 暫不棄用* @global 無* @return void*/private function timer() {# 注意強制心跳觸發器不能放在open事件里,因為那時候用戶還沒有提交登錄請求,是還沒有userID的# 還有,強制心跳定時器只能觸發一次,否則會出現生成多個定時器的情況if ($this->_status) {$this->_status = false;/*** ⑤服務端強制心跳檢測* 每隔1分鐘發送1次,如果連續3次強制心跳檢測未通過,服務端將強制斷開連接*/$obj = $this;swoole_timer_tick(60000, function ($timer_id) use (&$obj) {# 廣播消息$obj->broadcast($obj->_ws, $obj->json(['code' => 5]), null, true);# 所有人的心跳次數+1foreach ($this->_ws->user as $k=>$v) {if (empty($v['heartbeat'])) {# 重置心跳次數$this->_ws->user->set($v['user_id'], ['heartbeat' => 0,]);}# 心跳次數累加$this->_ws->user->set($v['user_id'], ['heartbeat' => $v['heartbeat']+1]);# 心跳次數大于等于_max && 在線的 的連接關閉if ($v['heartbeat'] >= $obj->_max && $v['status'] == 1) {$data = $v;# 發送強制掉線廣播$data['code'] = 6;$data['content'] = '【'.$data['user_nice'].'】已被服務端強制下線!';$obj->broadcast($obj->_ws, $obj->json($data), null, true);# 這里不需要unset連接,因為在close事件中,已經將這個連接設置為離線了# 主動關閉連接k$obj->_ws->close($v['fd']);}}});}}
}
$socketServer = new Server();
$socketServer->run();

最后推薦大家可以用下我開源的一個基于Swoole4.5+研發的PHP框架。該框架基于注解實現了很多好玩的功能,很適合新人快速上手Swoole擴展。

SW-X框架-專注高性能便捷開發而生的PHP-SwooleX框架?www.sw-x.cn
6c4bf0fcc8fd93cfe23676097afdd1e1.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/376245.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/376245.shtml
英文地址,請注明出處:http://en.pswp.cn/news/376245.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JavaBean的規范

&#xff08;1&#xff09;JavaBean 類必須是一個公共類&#xff0c;并將其訪問屬性設置為 public &#xff08;2&#xff09;JavaBean 類必須有一個空的構造函數&#xff1a;類中必須有一個不帶參數的公用構造器&#xff0c;此構造器也應該通過調用各個特性的設置方法來設置特…

linux虛擬機ip修改無效

把一個centos虛擬機移動到另一臺電腦的時候&#xff0c;移動前是靜態ip&#xff0c;移動后發現虛擬機的ip不同了。 由于使用的是NAT&#xff0c;于是就修改了虛擬機的配置&#xff0c;發現虛擬機的ip仍然不是配置文件需要的情況。 可以嘗試命令nmcli con show&#xff0c;如果…

驗證(Verification)與確認(Validation)的差別

驗證(Verification)與確認&#xff08;Validation&#xff09;的差別 說法一&#xff1a; &#xff08;2&#xff09;“驗證(Verification)”的涵義 通過提供客觀證據對規定要求已得到滿足的認定。 &#xff08;2&#xff09;“確認&#xff08;Validation&#xff09;”的涵義…

vscode自動格式化不符合eslint_VsCode(Visual Studio Code)格式化代碼符合EsLint

利用Visual Studio Code ESlint插件&#xff0c;實現自動格式化代碼步驟一&#xff1a;安裝ESlint插件>點擊Extensions或者CtrlShiftX>搜索ESlint>install EsLint步驟二: 重啟VsCode&#xff0c; 發現代碼提示報錯&#xff0c;代碼不符合規范步驟三&#xff1a;鼠標ho…

解讀Google分布式鎖服務

背景介紹 在2010年4月&#xff0c;Google的網頁索引更新實現了實時更新&#xff0c;在今年的OSDI大會上&#xff0c;Google首次公布了有關這一技術的論文。 在此之前&#xff0c;Google的索引更新&#xff0c;采用的的批處理的方式(map/reduce)&#xff0c;也就是當增量數據達到…

使用PHPMailer郵件發不出去

遇到了PHPMailer發不出去郵件的問題&#xff0c;在執行smtpConnect()時失敗了&#xff0c;同樣的配置在其他環境就能發送郵件。 最后發現是dns沒有配置&#xff0c;解析不了郵箱服務器的域名&#xff0c;所以沒發出去。。。。 如果其他語言也遇到了這樣的情況&#xff0c;可以…

PHPcurl抓取AJAX異步內容(轉載)

PHPcurl抓取AJAX異步內容其實抓ajax異步內容的頁面和抓普通的頁面區別不大。ajax只不過是做了一次異步的http請求&#xff0c;只要使用firebug類似的工具&#xff0c;找到請求的后端服務url和傳值的參數&#xff0c;然后對該url傳遞參數進行抓取即可。 利用Firebug的網絡工具 …

做自適應網站專業樂云seo_自適應網站方案品牌樂云seo

自適應網站方案品牌樂云seo&#xff0c;做樂云seo網站推廣哪收錄比較穩定&#xff0c;下面小編從以下幾點詳細介紹一下自適應網站方案品牌樂云seo&#xff1a;一、樂云seo做核心關鍵詞首頁排名技術怎么樣&#xff1f;孔祥永seo做核心關鍵詞到首頁的秘訣就是做好原創內容&#x…

boost windows編譯

執行&#xff1a; &#xff08;1&#xff09;bootstrap.bat &#xff08;2&#xff09;b2 -j4 toolsetmsvc-9.0 linkstatic threadingmulti runtime-linkstatic address-model64 stage --stagedir“D:\Code\boost_1_66_0\lib” debug release toolset:msvc-9.0 使用vs2008編…

必應輸入法產品分析

2013年4月&#xff0c;微軟MSN(中國)宣布推出首款整合搜索體驗的中文云輸入法“必應Bing輸入法”&#xff0c;其前身是“英庫拼音輸入法(于2012年8月發布測試版)” 在此&#xff0c;Fruits小組從宏觀的軟件工程角度和微觀的產品實現細節對必應輸入法進行了考察和分析。 &#x…

這是我第一題AC的線段樹

題目簡述&#xff1a; 有N個整數&#xff0c;Q次操作&#xff0c;每次操作為詢問一個區間[a, b]內數的和(0號操作)或者把一個區間內的數全部加上v(1號操作) 線段樹求解即可。 #include <cstdio> #include <algorithm> using std::min; using std::max; #define L(n…

a頻繁連接不上redis_連接不到redis Caused by:..._慕課問答

redis裝在linux虛擬機上&#xff0c;在xshell上可以成功訪問redis&#xff0c;配了密碼拿了老師完整的代碼作測試&#xff0c;就是訪問失敗&#xff0c;不知道哪里出了問題地址端口密碼都沒錯的&#xff0c;求解org.springframework.data.redis.RedisConnectionFailureExceptio…

抓localhost包 - rawcap

抓localhost包的話用wireshark好像有點麻煩&#xff0c;所以用rawcap RawCap官網 RawCap下載連接 直接運行&#xff0c;首先根據需要選擇監聽相應的網卡&#xff0c;然后再填寫抓包文件保存的名字

持續集成交付CICD:Jira 發布流水線

目錄 一、實驗 1.環境 2.GitLab 查看項目 3.Jira 遠程觸發 Jenkins 實現合并 GitLab 分支 4.K8S master節點操作 5.Jira 發布流水線 一、實驗 1.環境 &#xff08;1&#xff09;主機 表1 主機 主機架構版本IP備注master1K8S master節點1.20.6192.168.204.180 jenkins…

計算幾何_多邊形

判定凸多邊形&#xff1a;頂點凹凸性法 連續三個頂點p1,p2,p3。計算p1p2,p2p3的叉乘&#xff0c;階乘大于0&#xff0c;則表示p3點在線段p1和p2的左側&#xff0c;然后依次計算下一個前后所組成向量的階乘&#xff0c;如果在計算時&#xff0c;出現負值&#xff0c;則此多邊形是…

wps完成率怎么設置_WPS表格中如何計算完成率?詳細操作方法看這里!

平時我們在使用像WPS這樣的辦公軟件時&#xff0c;我們經常會使用到其中的Excel表格軟件&#xff0c;來完成日常工作當中所需要完成的各種數據的統計以及錄入等工作。而在我們使用WPS表格來錄入、修改或者是統計某一些數據時&#xff0c;我們往往會因為表格內容的設定需求&…

[原創]WebScarab工具介紹

[原創]WebScarab工具介紹 一 WebScarab介紹 WebScarab是一個用來分析使用HTTP和HTTPS協議的應用程序框架。其原理很簡單&#xff0c;WebScarab可以記錄它檢測到的會話內容&#xff08;請求和應答&#xff09;&#xff0c;并允許使用者可以通過多種形式來查看記錄。WebScarab的設…

段表的作用

表格來自《程序員的自我修養 ——鏈接、裝載與庫》 ELF段名作用.text代碼段&#xff0c;存放執行語句.data數據段&#xff0c;存放初始化的全局變量和局部靜態變量.bss未初始化的全局變量和局部靜態變量.rodata只讀數據段.comment注釋信息段.note.GNU-stack堆棧提示段.debug調…

layoutSubviews總結

ios layout機制相關方法 - (CGSize)sizeThatFits:(CGSize)size- (void)sizeToFit——————- - (void)layoutSubviews- (void)layoutIfNeeded- (void)setNeedsLayout——————– - (void)setNeedsDisplay- (void)drawRectlayoutSubviews在下面情況下會被調用&#xff1a; …

三個彩燈循環點亮程序_近百組彩燈點亮江畔,義渡燈會正式亮燈啦

10月23日晚上&#xff0c;大渡口區義渡古鎮華燈初上。夜幕之下&#xff0c;2020第一屆義渡燈會亮燈儀式在此舉行&#xff0c;來自四川的近百組彩燈將在這里點亮夜空&#xff0c;一直陪伴廣大市民游客至明年元宵節后。當晚6點半&#xff0c;義渡燈會亮燈儀式正式開啟。本次燈會以…