1

サーバーのコストは最大の支出であるため、すべての人からより多くのものを得たいと考えています。
このサーバーでより多くのスクリプトを実行できるようにするにはどうすればよいでしょうか?

Scrips が行っていること:
1 つのサーバーで 80 の PHP スクリプトを実行し、Gearman を介してそれらにジョブを供給します。
スクリプトは で Web サイトをcURL検索し、 で必要な情報を抽出Zend_Dom_Queryし、DB にデータを保存します。各スクリプトには ca が供給されます。彼らが調べなければならない1000のURL。スクリプトの例を以下に示します。

サーバーの構成
lshw要素: s 出力:

description: Computer
    width: 64 bits
    capabilities: vsyscall64 vsyscall32
  *-core
       description: Motherboard
       physical id: 0
     *-memory
          description: System memory
          physical id: 0
          size: 8191GiB
     *-cpu
          product: Intel(R) Xeon(R) CPU E31230 @ 3.20GHz
          vendor: Intel Corp.
          physical id: 1
          bus info: cpu@0
          width: 64 bits
          capabilities: fpu fpu_exception wp vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp x86-64 constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer xsave avx lahf_lm ida arat epb xsaveopt pln pts tpr_shadow vnmi flexpriority ept vpid

それにもかかわらず、これは V-Server であり、そのサーバーで実行されている唯一の V-Server です。また、16GB のような 8191GB のメモリもありません。

サーバーがどれだけ使い果たされているかを示すために、次topの出力を示します。

top - 14:45:04 up 8 days,  3:10,  1 user,  load average: 72.96, 72.51, 71.82
Tasks: 100 total,  72 running,  28 sleeping,   0 stopped,   0 zombie
Cpu(s): 87.5%us, 12.2%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.3%st
Mem:  8589934588k total,  4349016k used, 8585585572k free,        0k buffers
Swap:        0k total,        0k used,        0k free,   282516k cached

ここにスクリプトの主な構造があることを忘れないでください。

    // Get the Infos on which to crawl on
    $asin = explode(',', $job->workload());
    try {
        $userproducts = new App_Dbservices_U...();
        $konkurrenz = new App_Dbservices_K...();
        $repricingstream = new App_Dbservices_R...();

        $err = 0;
        for ($i = 0; $i < count($asin) - 3; $i = $i + 50) {
            $mh = curl_multi_init();
            $handles = array();
            for ($j = $i; $j < $i + 50; $j++) {
                if ((count($asin) - 3) > $j) {
                    if (isset($asin[$j])) {
                            // create a new single curl handle
                            $ch = curl_init();

                            // setting several options like url, timeout, returntransfer
                            // simulate multithreading by calling the wait.php scipt and sleeping for $rand seconds
                            $url = // URL
                            curl_setopt($ch, CURLOPT_URL, $url);
                            curl_setopt($ch, CURLOPT_HEADER, 0);
                            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                            curl_setopt($ch, CURLOPT_TIMEOUT, 80);

                            // add this handle to the multi handle
                            $erroro[$j] = curl_errno($ch);
                            $errmsg[$j] = curl_error($ch);
                            curl_multi_add_handle($mh, $ch);

                            // put the handles in an array to loop this later on
                            $handles[] = $ch;
                        }
                    }
                }
            }
            // execute the multi handle
            $running = null;
            do {
                curl_multi_exec($mh, $running);
            } while ($running > 0);

            // get the content (if there is any)
            $output = '';
            for ($k = 0; $k < count($handles); $k++) {
                // get the content of the handle
                $output[$k] = curl_multi_getcontent($handles[$k]);
                $_asin[$k]['asin'] = $asin[$j - 50 + $k];
                $_asin[$k]['condition'] = $condition[$j - 50 + $k];
                $_asin[$k]['pId'] = $pId[$j - 50 + $k];

                if ($output[$k] != '')
                {
                    // get the dom of each page
                    $dom = new Zend_Dom_Query($output[$k]);

                    // get the sellerInfos of each page
                    $seller = $dom->query('div.Offer');

                    if (count($seller) > 0) {
                        // get the price out of the string
                        $seller_i = 0;
                        $selfCameOver = false;
                        foreach ($seller as $d2) {
                            if ($seller_i <= 6 OR $selfCameOver === false) {
                                $itemHtml = '';
                                foreach($d2->childNodes as $node) {
                                    $itemHtml .= $node->ownerDocument->saveHTML($node);
                                }
                                $dom = new Zend_Dom_Query($itemHtml);

                                $itemPrice = $dom->query('span.Price');
                                foreach($itemPrice as $ItemPrice)
                        {
                            $_asin[$k]['price_end'][$seller_i] = 0.00;
                            $_asin[$k]['shipping_end'][$seller_i] = 0.00;
                            if (preg_match('/[0-9]++(?>[,.][0-9]+)?+/', $ItemPrice->textContent, $rueckgabe)) {
                                $priceEnd = str_replace(',', '', str_replace('.', '', $rueckgabe[0][0]));
                                $priceLength = strlen($priceEnd);
                                $priceEnd = substr($priceEnd, 0, ($priceLength - 2)) . '.' . substr($priceEnd, ($priceLength - 2), 2);
                                $_asin[$k]['price_end'][$seller_i] = (float)$priceEnd;
                                }
                            }
                        }

                                $shippingPrice = $dom->query('span.ShippingPrice');
                                foreach($shippingPrice as $ShippingPrice)
                                {
                                    preg_match_all('/[0-9]{1,}([\,\. ]?[0-9])*/', $ShippingPrice->textContent, $rueckgabe);
                                    if (isset($rueckgabe[0][0])) {
                                        // ...
                                    }
                                }
                                $_asin[$k]['price_total_end'][$seller_i] = $_asin[$k]['price_end'][$seller_i] + $_asin[$k]['shipping_end'][$seller_i];

                                $conditionTag = $dom->query('.Condition');

                                foreach($conditionTag as $ConditionTag)
                                {
                                    $_asin[$k]['main_con'][$seller_i]= 0;
                                    $_asin[$k]['sub_con'][$seller_i] = 0;
                                    $conditionValue = explode(' - ', $ConditionTag->textContent);
                                    if(isset($conditionValue[0])){
                                        // ...
                                    }
                                    if(isset($conditionValue[1])) {
                                        // ...
                                    }
                                }

                                $ratingItem = $dom->query('.Rating');
                                $_asin[$k]['bewertung_end'][$seller_i] = -1;
                                $_asin[$k]['stars_end'][$seller_i] = -1;
                                foreach($ratingItem as $RatingItem)
                                {
                                    echo $RatingItem->textContent; // 99% positiv ... 12 Monaten ... 11.719 Bewertungen ...
                                    // I want to get 99 (which is stars ) and 11719 (which is bewertungen )
                                    preg_match_all('/[0-9]{1,}([\,\. ]?[0-9])*/', preg_replace('/,/', '.', $RatingItem->textContent), $rueckgabe);
                                    if (isset($rueckgabe[0]) AND count($rueckgabe[0]) > 0) {
                                        $_asin[$k]['bewertung_end'][$seller_i] = (int)str_replace('.', '', $rueckgabe[0][count($rueckgabe[0]) - 1]);
                                        $_asin[$k]['stars_end'][$seller_i] = $rueckgabe[0][0];
                                    }
                                }

                                $sellerType = $dom->query('.Name img');
                                $_asin[$k]['merchant_end'][$seller_i] = "N/A";
                                $_asin[$k]['name_end'][$seller_i] = "N/A";
                                $_asin[$k]['img_end'][$seller_i] = "N/A";
                                $_asin[$k]['konk_type'][$seller_i] = 'ERROR';
                                if(count($sellerType) == 1)
                                {
                                    foreach($sellerType as $SellerType)
                                    {
                                        $imgAltText = $SellerType->getAttribute('alt');
                                        $a = explode('.', $imgAltText);
                                        // ...
                                    }
                                }
                                elseif(count($sellerType) == 0)
                                {
                                    $_asin[$k]['img_end'][$seller_i] = 'NO_IMG';
                                    $_asin[$k]['konk_type'][$seller_i] = 'WO_IMG';

                                    $sellerName = $dom->query('.Name b');
                                    foreach($sellerName as $SellerName)
                                    {
                                        $_asin[$k]['name_end'][$seller_i] = $SellerName->textContent;
                                    }

                                    $sellerMerchant = $dom->query('.Name a');
                                    foreach($sellerMerchant as $SellerMerchant)
                                    {
                                        $_asin[$k]['merchant_end'][$seller_i] = str_replace('=', '', substr($SellerMerchant->getAttribute('href'), -14));
                                    }
                                }

                                unset($rueckgabe);
                            }
                            $seller_i++;
                        }
                    }
                }
                // remove the handle from the multi handle
                curl_multi_remove_handle($mh, $handles[$k]);
            }
            // Update Price ...

            // Update Shipping ... 

            // Update Conc ...

            unset($_asin);
            // close the multi curl handle to free system resources
            curl_multi_close($mh);
        }
    } catch (Exception $e) {
        $error = new Repricing_Dbservices_Error();
        $error->setError($id, $e->getMessage(), $e->getLine(), $e->getFile());
    }

また、価格更新のスクリプト (他の update-statements も同様に見えます)

$this->db->beginTransaction();
        try {
            for ($i = 0; $i < count($asin); $i++) {
                if (isset($asin[$i]['price_total_end'])) {
                    if (count($asin[$i]['price_total_end']) > 1) {
                        if ($asin[$i]['price_total_end'][0] > 0) {
                            $this->db->query("UPDATE u... SET lowest_price = ? , last_lowest_price_update = ? WHERE id = ?", array(
                                    $asin[$i]['price_total_end'][1],
                                    date("Y-m-d H:i:s", time()),
                                    $asin[$i]['pId']
                                ));
                        }
                    } elseif (count($asin[$i]['price_total_end']) == 1) {
                        if ($asin[$i]['price_total_end'][0] >= 0) {
                            $this->db->query("UPDATE u... SET lowest_price = ? , last_lowest_price_update = ? WHERE id = ?", array(
                                -1,
                                date("Y-m-d H:i:s", time()),
                                $asin[$i]['pId']
                            ));
                        }
                    }
                }
            }
            $this->db->commit();
        } catch (Exception $e) {
            $this->db->rollBack();
            echo $e->getMessage();
        }
        $this->db->closeConnection();

スクリプトに大きなパフォーマンス リークがありますか? 他の言語や他の手法を使用する必要がありますか? すべての提案は高く評価されています。

4

3 に答える 3

1

これらの種類の行はすべて置き換えることができます。

preg_match_all('/[0-9]{1,}([\,\. ]?[0-9])*/', $ItemPrice->textContent, $rueckgabe);
if (isset($rueckgabe[0])) {
    // ...
}

に:

if (preg_match('/([0-9]++)(?>[.,]([0-9]++))?+/', $ItemPrice->textContent, $rueckgabe)) {
    unset($rueckgabe[0]);
    $priceEnd = sprintf("%01.2f", implode('.', $rueckgabe));
    $_asin[$k]['price_end'][$seller_i] = $priceEnd;
}

すべての for ループを foreach に置き換える必要があります ( countRaymondN が気付くので、on each ループを回避します)。例:

それ以外の:

for ($k = 0; $k < count($handles); $k++) {

あなたが書く:

foreach($handles as $k=>$handle) {
  // you can replace $handles[$k] by $handle

現在の日時を変換して "Ymd H:i:s" にフォーマットすることは、mySQL ステートメントで直接同じことができるため、あまり役に立ちませんNOW()

于 2013-08-10T20:24:53.307 に答える
0

for ループでカウント関数を使用しないでください。これにより、CPU サイクルが節約されます。

しかし、使用します。

$m = count($array) - 1;
for ($i = 0 ; $i < $m ; $i++) {}

新しいPHPバージョンは、はるかに優れたパフォーマンスを発揮できる可能性があります。

于 2013-08-10T20:27:15.410 に答える
0

ここで最も注目すべき点は、データをシャーディングしすぎていることです。負荷平均が CPU の数よりも高い場合、OS はジョブが CPU を解放するのを待つのではなく、ジョブの先取りを開始します。その結果、全体的なスループットが大幅に低下します。あなたは単一のCPUを持っているようです-単一のコアで実行されているこのようなCPUにバインドされたシステムの場合、最適な動作を与えるプロセスを確認するために2、4、8、および16のプロセスを試します(コードをその逆ではなく、ハードウェア)。

次の問題は、zend フレームワークが非常に CPU とメモリを消費することです。Zend は飾り気のない PHPよりも4 倍遅いです。

ここのループには多くのインライン化されたコードがあります - インライン化はパフォーマンスを向上させますが、プロファイラーから有用なデータを取得することをより困難にします - したがって、Zend を使わずに並行処理を減らした後の私の次のステップは、コードを関数に構造化し、プロファイリングします。

于 2013-08-10T23:30:14.203 に答える