這兩天老大給了個需求想把商城熱點數據同步到redis緩存。咱們項目使用的是swoft框架,因此我就想到用框架的Crontab定時器。可是在測試的時候發現把Table的size設置爲1024時(實際上設置爲任何大小都同樣,貼上swoole的解釋)發現內存溢出了html
普及一下Table(來自swoole文檔):
Table底層是創建在共享內存之上的HashTable數據結構。$size最大行數,決定了HashTable的總行數。因爲Table是在共享內存之上,因此沒法動態擴容。這個$size必須在建立前設置好。
$size參數指定表格的最大行數,若是$size不是爲2的N次方,如102四、8192,65536等,底層會自動調整爲接近的一個數字,若是小於1024則默認成1024,即1024是最小值
先把框架任務投遞流程走一下:redis
注:在定時器這塊使用到兩個Table 一個是originTable用於存儲任務的(Task)實例。另外一個是runTimeTable 存儲任務隊列實例,通俗地說就是存須要執行的任務實例
再看看任務執行流程,任務的執行就很簡單了數組
從新梳理一下咱們邏輯
當咱們新建執行一個任務的時候,系統每秒鐘都回去更新執行一個每一個任務中的隊列數。
代碼以下:
緩存
經過代碼咱們可以發現每一分鐘他都會往runTimeTable 中添加60個任務隊列
可是當咱們getExecTasks獲取將要執行的任務隊裏的時候是根據當前的時候是否等於執行時間而標誌狀態的
那麼如今就會出現一個問題。當前時間往任務隊裏中添加數據的時候 他把前面執行過的任務隊列再次添加進runTimeTable 中
舉個栗子:
假如我有個異步任務Sync,其中有個每秒執行一次的方法cronTask,
如今時間是2019-03-22 10:01:20 如今往更新runTimeTable 的時候 他會往裏面添加60的任務隊列key分別會是
MD5(" ".'Sync'.'cronTask'.'01'.'00')
MD5(" ".'Sync'.'cronTask'.'01'.'01')
MD5(" ".'Sync'.'cronTask'.'01'.'02')
MD5(" ".'Sync'.'cronTask'.'01'.'03')
MD5(" ".'Sync'.'cronTask'.'01'.'04')
...
MD5(" ".'Sync'.'cronTask'.'01'.'59')swoole
當時間到下一秒(是2019-03-22 10:01:21)的時候後 依然會往更新runTimeTable數據 key值爲
MD5(" ".'Sync'.'cronTask'.'01'.'00')
MD5(" ".'Sync'.'cronTask'.'01'.'01')
MD5(" ".'Sync'.'cronTask'.'01'.'02')
MD5(" ".'Sync'.'cronTask'.'01'.'03')
MD5(" ".'Sync'.'cronTask'.'01'.'04')
...
MD5(" ".'Sync'.'cronTask'.'01'.'59')數據結構
那麼咱們能夠很明確地看出來在2019-03-22 10:01:21秒前的數據都是沒用的了 。這些數據永遠不會被消費,也不會被刪除。所以一段時間後會出現內存溢出的狀況。
因此解決方法是在清理消費數據的時候把過時數據也同時清理
把cleanRunTimeTable中的框架
if ($value['runStatus'] === self::FINISH) {
改成異步
$currentTime = time(); if ($value['runStatus'] === self::FINISH || $value['sec'] < $currentTime) {
本文爲本人學習過程記錄。若是有哪些地方描述不當望各位大佬指出。
點我閱讀原文學習