異步任務推送的實踐

目錄

  • 初識Swoole
  • 異步進程介紹
  • 傳統推送業務邏輯
  • 異步任務推送邏輯
  • 效率對比

初識Swoole

Swoole是PHP一個擴展,但和其餘擴展只提供接口、函數不一樣,Swoole從新定義PHP,接管並從新處理數據,將處理好的數據返回給PHP,支持百萬TCP鏈接,同時支持異步/同步/協程等功能php

Swoole採用多進程架構模型,比多線程架構更方便,不存在線程安全問題,缺點是進程與進程通訊沒有線程方便,另外PHP-FPM,Nginx採用的也是多進程模型,學習起來仍是容易接受。git

異步Worker進程介紹

異步Worker進程是Swoole提供的一個非阻塞進程,投遞一個異步任務到異步進程,執行完畢當即返回,異步進程能夠繼續處理新請求,進程間沒有加鎖爭搶,性能異常優良。利用以上特性,能夠用來處理耗時較長的事務。github

傳統推送業務邏輯

傳統推送經過設置自動執行,或者手動執行讀取運營後臺設定數據,寫入隊列(可選),接着將數據推給第三方,第三方將推送結果告知程序,這個告知的過程一般以對方網絡穩定決定了推送效率,推送短板也在這塊。sql

異步任務進程推送邏輯


異步任務運用在從隊列讀取數據過程當中,開啓多個進程讀取數據,接着發送數據給第三方,只要開啓合適數量的進程,推送速度極快。數據庫

下面介紹用到技術

  • EasySwoole框架
  • Redis隊列
  • 定時器
  • Task進程

話很少說,擼起代碼就是幹數組

一、註冊定時器,寫入任務安全

if ($workerId == 0) {
    Timer::Loop(1 * 1000, function () {
        PushLogic::addQueue();
    });
}
<?php
namespace App\Logic;

use App\Logic\Queue;

class PushLogic
{
    const REDIS_KEY = 'push_list';
    public static function addQueue($task)
    {
        Queue::push(self::REDIS_KEY, $task);
    }
}

二、註冊定時器 獲取任務swoole

if ($workerId == 1) {
    Timer::Loop(5 * 1000, function () {
        $share = ShareMemory::getInstance();
        // 啓用16個異步Task進程
        if ($share->get(Sys::PUSH_TASK_NUM) < 16) {
            AsyncTaskManager::getInstance()->add(PushTask::class);
        }
    });
}

三、封裝異步執行邏輯網絡

<?php
namespace App\Logic;

use App\Logic\Queue;

class PushLogic
{
    conse REDIS_KEY = 'push_list';
    public static function handle($task)
    {
            // 進程數據隔離 文件鎖 記錄異步Task進程數量
            $share = ShareMemory::getInstance();
            $share->startTransaction();
            $key = Sys::PUSH_TASK_NUM;
            $share->set($key, $share->get($key) + 1);
            $share->commit();
            while (true) {
                $task = Queue::pop(self::REDIS_KEY);
                // 調用GCM或APNS邏輯
                Gcm::send($task);
            }
            $share->startTransaction();
            $share->set($key, $share->get($key) - 1);
            $share->commit();
    }
}

至此主要功能已處理完畢,具體推送結果能夠根據實際狀況存入Redis、Swoole內存表、數據庫
注:推送結果不要存在全局變量或者靜態變量,由於不一樣進程內存隔離多線程

效率對比

  • 系統:CenOS release 5.11
  • CPU: 4核
  • 內存:32G
  • PHP:7.1
  • 總終端數量:1百萬
  • 單次任務終端數量:1千
傳統推送耗時:30分鐘
異步多任務:3分鐘
舒適提示
  • EasySwoole框架是常駐內存,鏈接數據庫須要採用斷線重連,不然會出現MySQL server has gone away,能夠參考這裏的使用方法PHP-MySQLi-Database-Class
  • 獲取任務時,應避免全部異步任務進程處於忙的狀態。
  • 代碼不要出現sleep/usleep等睡眠函數,會使進程陷入睡眠阻塞。
  • 禁用exit/die,致使進程退出。
  • 全局變量、靜態變量、須要自行銷燬,特別要注意array類型的值,必要時清理大數組,防止內存溢出。
相關文章
相關標籤/搜索