2019年11月29日 星期五

使用 cloudflare workers 來代替 php 存取第三方 API ,解決 process 被卡住的問題

最可恨的事情就是,cpu 沒有 100% ,系統就掛了。

本站大部份的頁面,php 平均處理時間大多是 50ms 以下,有快取的則在 10 ms 以下。但是當 php 要存取第三方 api 時, api 的回應常到高達 1~5 秒,所有的 php process 就會被卡住。假設 php process 上限是 5 個,有時候高峰(spike) 來了,一次來個 10 個需要存取 api 的 request,但是當所有 php process 都在用來等待後方 api 的時候,同時間其它應該可以快速回執行完的 request 都會被 queue 住了。

php 往後方存取 api 並不是很 cpu 耗資源,但一個 process 的成本卻很高,可能記憶體就要30~50MB。所以沒辦法將 php process 的上限數設到很高很高。

還有一個簡單的解法,就是把需要存取 API 的部份改成 ajax ,然後透過 nginx proxy 來實作。nginx proxy 可以容納的 connections 就可以很高了,如果你有設定好的話。當然如果 nginx proxy 可以解決,請直接左轉離開吧!但本站考量 SEO 的關係,沒辦法這麼做。

既然 php process 不善長等待這件事,我們就把等待這件事交給 serverless 來去處理。

假設 php 程式在執行的過程中,會執行到某一段程式,並從後端存取資料。

function _fetch($url)
{
// php curling .....
return $html;
}

php 部份只需要加個幾行而已。

function _fetch($url)
{
if(isset($_GET['workers_proxy_get']))
die($url);
if(isset($_GET['workers_proxy_response']))
return $_POST['html'];
// php curling .....
return $html;
}

接下來是 workers 的部份,如下
https://gist.github.com/girvan/2ee69ba0f1887aaab1dc8663240ca73c

然後再到 cloudflare 把這一類的 request 導到 workers 即可。記得 pattern 要設定好,不要所有的 request 都這麼玩。

眼尖的人會發現,php 部份其實是會重複執行到,但問題解決了。