Swoole webSocket消息服務(wù)系統(tǒng)方案設(shè)計(jì)詳解
概述
基于Swoole的websocket服務(wù),計(jì)劃整合3篇進(jìn)行技術(shù)整理,該服務(wù)主要有2個(gè)核心業(yè)務(wù),用戶消息服務(wù)(消息計(jì)數(shù)統(tǒng)計(jì))和 客服IM消息系統(tǒng)服務(wù),這篇先說用戶消息服務(wù)是怎么設(shè)計(jì)實(shí)現(xiàn)的。
實(shí)現(xiàn)方案
用戶消息服務(wù)主要有2部分組成,對(duì)外使用webSocket長(zhǎng)鏈接服務(wù)提供給安卓/Ios手機(jī)客戶端,web提供服務(wù),對(duì)內(nèi)使用Http服務(wù)。
鑒權(quán)和緩存周期設(shè)置
當(dāng)服務(wù)端攜帶Token來訪問請(qǐng)求webSocket服務(wù),進(jìn)行用戶中心進(jìn)行權(quán)限驗(yàn)證,如果權(quán)限通過,在本地進(jìn)行信息緩存,返回給請(qǐng)求端,為了防止緩存雪崩(雪崩就是指緩存同一時(shí)間到期),用戶訪問峰值是晚間21-24點(diǎn)這個(gè)時(shí)間段,峰值大概100w/請(qǐng)求,持續(xù)4個(gè)小時(shí)左右,但因?yàn)橛脩糁行牡木彺鏁r(shí)間為7300s,所以這里的過期時(shí)間公式:
$uid = $redis->get($token); $expireTime = 3650 + rand(1, 3000); $uid = OAuth::getUserInfo($token); if (!empty($uid) && intval($uid) > 0) { //存入緩存時(shí)間,過期時(shí)間小于 7300s $redis->setEx($token, $expireTime, $uid); } if($uid && $uid > 0){ $key = 'token_'.$uid; $redis->setEx($key, $expireTime, $token); }
本地服務(wù)的緩存怎么存儲(chǔ),具體看自己的業(yè)務(wù)情況,適合自己的就是最好的。
Http服務(wù)
Http服務(wù)的安全依賴于服務(wù)只針對(duì)云服務(wù)器內(nèi)網(wǎng)訪問,主站有服務(wù)變更時(shí),異步埋點(diǎn)在功能里,比如有系統(tǒng)消息、評(píng)論、站內(nèi)信等一系列操作的時(shí)候,會(huì)通過http請(qǐng)求用戶消息服務(wù),設(shè)置超時(shí)時(shí)間,允許丟失部分消息。
1.業(yè)務(wù)埋點(diǎn)處理
埋點(diǎn)再操作后異步觸發(fā),超時(shí)時(shí)間2秒,如果失敗再進(jìn)行一次重試,如果失敗,其實(shí)基本就是服務(wù)掛了,局域網(wǎng)處理,性能傳輸成本幾乎為0,這個(gè)地方相當(dāng)于消息的生產(chǎn)方。
public function swooleComment($uid, $data) { $url = $this->swooleUrl . "/api/comment/message"; $commentUid = empty($data['comment_uid']) ? 0 : $data['comment_uid']; $msg = [ "uid" => $uid, "msg" => json_encode(['comment_uid' => $commentUid]) ]; $res = Curl::posturl($url, http_build_query($msg), $this->_headerQArr, 2); if ($res === false) { // 請(qǐng)求失敗再重試一次 usleep(100000); $res = Curl::posturl($url, http_build_query($msg), $this->_headerQArr, 2); } return $res; }
2.消息處理
Swoole有一個(gè)缺點(diǎn)就是如果沒有建立websocket服務(wù),就不能實(shí)時(shí)進(jìn)行通信,所以這個(gè)地方我分兩步處理,根據(jù)消息類型進(jìn)行管理和消息的推送,存入redis list結(jié)構(gòu)的隊(duì)列中,使用Crontab,執(zhí)行定時(shí)腳本處理。
設(shè)計(jì)方案為快慢2條雙隊(duì)列結(jié)構(gòu),快隊(duì)列主要處理當(dāng)前最新的消息,如果用戶超過1天不上線,放入延遲隊(duì)列執(zhí)行,用戶超過超過15天未登錄,消息釋放。
websocket的心跳時(shí)間是300s,所以crontab 4min,執(zhí)行一次,延遲隊(duì)列6分鐘執(zhí)行一次,我們的redis使用的是鏈接池單節(jié)點(diǎn)特點(diǎn),整個(gè)服務(wù)都在依賴,所以這樣設(shè)計(jì)的方案。
3.數(shù)據(jù)存儲(chǔ)
數(shù)據(jù)使用Mysql存儲(chǔ),Uid進(jìn)行分表取模,采用分表的初衷是因?yàn)楫?dāng)時(shí)已經(jīng)有300w+的用戶,消息多,所以采用分表設(shè)計(jì),所有的操作依賴于uid這個(gè)變量,所有的操作都采用TaskManager異步操作,以保證最大的性能。
protected function _getTableName(int $uid): string { $tableIndex = intval($uid % 128); return 'user_push_msg_' . $tableIndex; }
protected function addAsyncMysql( array $pushMsg, int $uid): ?bool { $tableName = $this->_getTableName($uid); if (empty($pushMsg) || empty($tableName) || empty($uid)) return false; TaskManager::getInstance()->async(function () use ($pushMsg, $tableName) { DbManager::getInstance()->invoke(function (ClientInterface $client) use ($pushMsg, $tableName) { $model = PushMsgModel::invoke($client, $pushMsg); $model->tableName($tableName)->save(); }, self::MYSQL_CONN_NAME); }); }
用戶消息數(shù)統(tǒng)計(jì)
在業(yè)務(wù)中有全體用戶,全體作者,簽約作者等分組的情況,成為統(tǒng)計(jì)中的重點(diǎn)和難點(diǎn),一共分分2步解決。
**第一步,**在http消息接收端專門放置一個(gè)消息計(jì)數(shù)器對(duì)用戶單條發(fā)送的消息進(jìn)行計(jì)數(shù),只統(tǒng)計(jì)針對(duì)用戶的消息。
**第二步,**新建一個(gè)mysql表,專門用于統(tǒng)計(jì)用戶最近查看消息的時(shí)間戳,根據(jù)用戶最后的查看消息時(shí)間來統(tǒng)計(jì)群組中的未讀消息數(shù),把兩個(gè)結(jié)果進(jìn)行相加,得出用戶未讀消息數(shù)和。
表的設(shè)計(jì)用uid做主鍵,保持用戶的唯一性,使用REPLACE INTO
進(jìn)行更新,REPLACE INTO
的好處是如果主鍵uid存在,更新時(shí)間,如果不存在則新增數(shù)據(jù)。
CREATE TABLE `table` ( `uid` int(10) unsigned NOT NULL DEFAULT '0', `unixtime` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用戶查看消息最新時(shí)間'
以上就是Swoole webSocket消息服務(wù)系統(tǒng)方案設(shè)計(jì)詳解的詳細(xì)內(nèi)容,更多關(guān)于Swoole webSocket消息服務(wù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
php教程之魔術(shù)方法的使用示例(php魔術(shù)函數(shù))
這篇文章主要介紹了php的魔術(shù)方法的使用示例(php魔術(shù)函數(shù)),需要的朋友可以參考下2014-02-02ThinkPHP3.2.3框架郵件發(fā)送功能圖文實(shí)例詳解
這篇文章主要介紹了ThinkPHP3.2.3框架郵件發(fā)送功能,結(jié)合圖文與實(shí)例形式詳細(xì)分析了基于thinkPHP框架進(jìn)行郵件發(fā)送的相關(guān)原理、配置及操作技巧,需要的朋友可以參考下2019-04-04PHP實(shí)現(xiàn)用戶異地登錄提醒功能的方法【基于thinkPHP框架】
這篇文章主要介紹了PHP實(shí)現(xiàn)用戶異地登錄提醒功能的方法,基于thinkPHP框架結(jié)合用戶session實(shí)現(xiàn)異地登陸的判定功能,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2018-03-03淺談PHP檢查數(shù)組中是否存在某個(gè)值 in_array 函數(shù)
下面小編就為大家?guī)硪黄獪\談PHP檢查數(shù)組中是否存在某個(gè)值 in_array 函數(shù)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-06-06php中通過curl模擬登陸discuz論壇的實(shí)現(xiàn)代碼
PHP支持的由Daniel Stenberg創(chuàng)建的libcurl庫(kù)允許你與各種的服務(wù)器使用各種類型的協(xié)議進(jìn)行連接和通訊。libcurl目前支持http、https、ftp、 gopher、telnet、dict、file和ldap協(xié)議2012-02-02thinkPHP批量刪除的實(shí)現(xiàn)方法分析
這篇文章主要介紹了thinkPHP批量刪除的實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了thinkPHP實(shí)現(xiàn)批量刪除數(shù)據(jù)的數(shù)據(jù)庫(kù)及模板操作相關(guān)技巧,需要的朋友可以參考下2016-11-11你可能不知道PHP get_meta_tags()函數(shù)
這篇文章主要介紹了你可能不知道PHP get_meta_tags()函數(shù),比較實(shí)用的一個(gè)函數(shù)了,小編也是第一次看到它,需要的朋友可以參考下2014-05-05