您好,登錄后才能下訂單哦!
本篇內容介紹了“Swoole webSocket消息服務系統怎么設計”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
用戶消息服務主要有2部分組成,對外使用webSocket長鏈接服務提供給安卓/Ios手機客戶端,web提供服務,對內使用Http服務。
當服務端攜帶Token來訪問請求webSocket服務,進行用戶中心進行權限驗證,如果權限通過,在本地進行信息緩存,返回給請求端,為了防止緩存雪崩(雪崩就是指緩存同一時間到期),用戶訪問峰值是晚間21-24點這個時間段,峰值大概100w/請求,持續4個小時左右,但因為用戶中心的緩存時間為7300s,所以這里的過期時間公式:
$uid = $redis->get($token); $expireTime = 3650 + rand(1, 3000); $uid = OAuth::getUserInfo($token); if (!empty($uid) && intval($uid) > 0) { //存入緩存時間,過期時間小于 7300s $redis->setEx($token, $expireTime, $uid); } if($uid && $uid > 0){ $key = 'token_'.$uid; $redis->setEx($key, $expireTime, $token); }
本地服務的緩存怎么存儲,具體看自己的業務情況,適合自己的就是最好的。
Http服務的安全依賴于服務只針對云服務器內網訪問,主站有服務變更時,異步埋點在功能里,比如有系統消息、評論、站內信等一系列操作的時候,會通過http請求用戶消息服務,設置超時時間,允許丟失部分消息。
1.業務埋點處理
埋點再操作后異步觸發,超時時間2秒,如果失敗再進行一次重試,如果失敗,其實基本就是服務掛了,局域網處理,性能傳輸成本幾乎為0,這個地方相當于消息的生產方。
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) { // 請求失敗再重試一次 usleep(100000); $res = Curl::posturl($url, http_build_query($msg), $this->_headerQArr, 2); } return $res; }
2.消息處理
Swoole有一個缺點就是如果沒有建立websocket服務,就不能實時進行通信,所以這個地方我分兩步處理,根據消息類型進行管理和消息的推送,存入redis list結構的隊列中,使用Crontab,執行定時腳本處理。
設計方案為快慢2條雙隊列結構,快隊列主要處理當前最新的消息,如果用戶超過1天不上線,放入延遲隊列執行,用戶超過超過15天未登錄,消息釋放。
websocket的心跳時間是300s,所以crontab 4min,執行一次,延遲隊列6分鐘執行一次,我們的redis使用的是鏈接池單節點特點,整個服務都在依賴,所以這樣設計的方案。
3.數據存儲
數據使用Mysql存儲,Uid進行分表取模,采用分表的初衷是因為當時已經有300w+的用戶,消息多,所以采用分表設計,所有的操作依賴于uid這個變量,所有的操作都采用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); }); }
在業務中有全體用戶,全體作者,簽約作者等分組的情況,成為統計中的重點和難點,一共分分2步解決。
**第一步,**在http消息接收端專門放置一個消息計數器對用戶單條發送的消息進行計數,只統計針對用戶的消息。
**第二步,**新建一個mysql表,專門用于統計用戶最近查看消息的時間戳,根據用戶最后的查看消息時間來統計群組中的未讀消息數,把兩個結果進行相加,得出用戶未讀消息數和。
表的設計用uid做主鍵,保持用戶的唯一性,使用REPLACE INTO
進行更新,REPLACE INTO
的好處是如果主鍵uid存在,更新時間,如果不存在則新增數據。
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='用戶查看消息最新時間'
“Swoole webSocket消息服務系統怎么設計”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。