2013-02-20 25 views
1

我正在用Webhostingpad託管一個網站,而且我遇到了一個問題。隨着我的主頁加載,我目前正在對一個php腳本進行8次併發ajax調用,該腳本返回用於主頁的內容。 8個Ajax調用正在調用一個名爲run.php的文件。這個文件的工作就是調用一個名爲amazon的類的函數,該函數在另一個名爲amazon.php的文件中定義。Web服務器CPU /內存資源LImited由於多個Ajax調用PHP腳本

這是通過ajax調用8次的URL。 8個調用之間的唯一區別是查詢字符串:

http://my-domain.com/run.php?f=getItemsById&arg=id:B0043OYFKU,B001JKTTVQ,B004Y9D90Q,B003S516XO,B002XQ1YTK,B003V265QW,B00121UVU0,B004EDYQUE,B000P22TIY,B000E7WHLY

正如你所看到的,我傳遞函數名稱在url中的「F」參數。

的run.php文件看起來是這樣的:

require_once('amazon.php'); 

$function_name = $_REQUEST['f']; 
$arg_parameter = $_REQUEST['arg']; 

$arg_tmp = explode(";", $arg_parameter); 
$arg_array = array(); 
foreach($arg_tmp as $key_value_pair){ 
    $exploded = explode(':', $key_value_pair); 
    $key = $exploded[0]; 
    $value = $exploded[1]; 
    $arg_array[$key] = $value; 
} 

$amazon = new amazon(); 
echo $amazon->$function_name($arg_array); 

正如你可以看到,該文件只是要求從amazon.php功能和呼應的結果,所以我可以在的回調使用ajax函數。

下面是從amazon.php關於getItemsById()功能的相關代碼:

class amazon { 

    private $url; 
    private $accessKey = 'AKIAISJ2OHTBA888311SD'; 
    private $secretAccessKey = 'RM8EG61w3dLwjymtAEVdfsdiesd883711lskdf'; 

    function __construct(){ 
     $this->url = 'http://webservices.amazon.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId=' . $this->accessKey . '&AssociateTag=global-18&Version=2011-08-01'; 
    } 

    public function getItemsById($args = array()){ 

     $itemIds = $args['id']; 

     $url = $this->url; 
     $url .= '&Operation=ItemLookup'; 
     $url .= '&ItemId=' . $itemIds; 
     $url .= '&ResponseGroup=Images,Small,Offers,VariationSummary,EditorialReview'; 

     $signedUrl = $this->amazonSign($url, $this->secretAccessKey); 
     $returned_xml = file_get_contents($signedUrl); 
     return $returned_xml; 

    } 
} 

正如你可以在上面看到,這個功能是呼籲amazon.com的API一個網址,並使用PHP的file_get_contents()函數返回的XML。我的問題是,一些對run.php的ajax調用已成功執行,而另一些正在獲取HTTP 500內部服務器錯誤。當我在本地服務器上運行它時,它工作正常。當我在辦公室的開發服務器上運行它時,它工作正常。但是,我始終在Webhostingpad服務器上看到此問題。某些ajax調用會返回HTTP 500錯誤。

我已經講過Webhostingpad支持,他們向我提供的唯一見解是我超出了我的CPU /內存資源限制。來自服務器的錯誤日誌似乎證實:

[星期二2月19日21時36分39秒2013] [錯誤] [客戶68.174.126.115](12)不能 分配內存:無法創建子過程中:/ opt/suphp/sbin目錄/ suphp爲/home/my-server/public_html/my-domain.com/run.php,引用者 : http://my-domain.com/

我對社會問題是,如果你有什麼在這裏突出顯然是內存密集?我覺得我所做的並不是出於行動準則,所以我試圖弄清楚我是否應該專注於優化我的腳本,或者我應該只是尋找其他託管提供商。

+1

一個共享服務器上的太多站點是我的猜測。 – 2013-02-20 04:12:29

+0

呼叫必須是併發的嗎?或者你可以簡單地執行第一個AJAX調用,等待它完成,將本地數據存儲在數據結構中,執行第二次調用,漂洗並重復?執行Ajax調用的瀏覽器中的對象會在您完成後讓您知道。 – kermit 2013-02-20 04:29:41

+0

謝謝@kermit。我以前有ajax調用同步工作(我知道這是不好意思,這就是爲什麼我改變了它),但基本上模仿了你描述一個調用只會發生在另一個完成後的相同行爲。主要問題在於,在同時進行所有8個調用並使用延遲對象在全部完成時採取行動時,速度顯着較慢。 – flyingL123 2013-02-20 04:40:29

回答

0

如果同步執行AJAX請求不是一個選項,您仍然可以對PHP腳本的內存消耗做些事情。目前,PHP腳本在將內存回傳給客戶端之前,會將內存中從亞馬遜返回的整個XML內存。如果XML很大並且同時執行8次,則內存不足並不奇怪。

一個解決方案是使用cURL請求amazon並使用cURL選項CURLOPT_WRITEFUNCTION將結果回顯給客戶端。這樣,你可以讓amazon.php腳本將結果XML流式傳輸到客戶端,並且它不會佔用太多的內存。

例子亞馬遜。php代碼:

<? 
function writeCallback($handle, $data) 
{ 
    echo $data;  
    ob_flush(); 
    flush(); 
    return strlen($data); 
} 

$ch = curl_init(); 

curl_setopt($ch, CURLOPT_URL, 'http://webservices.amazon.com/onca/xml'); 
curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'writeCallback'); 

ob_start(); // start output buffer 
curl_exec($ch); // commence streaming 
+0

非常感謝Matthijs的建議。我只是想確保我完全理解這裏發生的事情,因爲我已經按照您的建議實施了它,並且就我收到的內存錯誤而言,它沒有什麼差別。是否有一個原因,你使用回調函數回聲數據,而不是使用選項'CURLOPT_RETURNTRANSFER',並設置curl_exec的輸出等於一個變量。另外,爲什麼回調函數返回'strlen($ data)'?基本上,我試圖理解這應該如何工作,因爲目前它沒有改變。 – flyingL123 2013-02-21 04:50:26

+0

這樣做的主要原因是**流**從亞馬遜收到的數據,而不是一次性把它們全部存入內存。如果您檢查CURLOPT_WRITEFUNCTION和CURLOPT_RETURNTRANSFER的文檔,您將看到CURLOPT_WRITEFUNCTION允許您這樣做。 – 2013-02-22 08:18:14

+0

所有這一切的一個重要部分是,您不會在writeCallback中緩衝數據,因爲這會破壞目的。您必須將每個數據片段無緩衝地發送出去。可能需要在每個回聲後調用'ob_flush()'。我已經更新了上面的代碼以反映這一點。 但是,這可能仍然無法正常工作,因爲即使您的PHP腳本沒有,您的web服務器也可能會緩衝輸出。例如,在啓用Apaches mod_deflate時可能會發生這種情況。 – 2013-02-22 08:31:53

相關問題