タイムアウト問題によるサーバー処理の困難

このQ&Aのポイント
  • 一日のログ数が10万を超えた辺りから集計処理がタイムアウトしてしまい、集計ができなくなってしまいました。
  • ループを多用して重い処理になっているため、タイムアウトせずに動かす方法を模索しています。
  • 現在の環境で応急処置を行いたいが、タイムアウト時にはエラーメッセージが表示されず、ページが表示されなくなってしまっています。
回答を見る
  • ベストアンサー

現在、レンタルサーバ(コアサーバー)上でPHP5とmysqlでサイトへ

現在、レンタルサーバ(コアサーバー)上でPHP5とmysqlでサイトへのアクセス数とサイト上の複数のリンク先へのクリック数のログを取得し、一日一回それらを一つのテーブルへ集計し、レポート表示させるプログラムを作成しました。 一日のログが少なかった頃は問題なく動いていたのですが、一日のログ数が10万を超えた辺りから集計処理がタイムアウトしてしまい、集計ができなくなってしまいました。 下記のようなイメージで集計プログラムとして動かしています。 ループ数は25,000回位です。 ループ中にはmysqlからの読み込みと書き込み処理を含んでおります。 $i = "0"; do{//サイト数だけループ $cat_i = "0"; do{//カテゴリ数だけループ $carrier = "0"; do{ $cl_i = "1"; do{ }while($cl_i < 21);    $carrier = $carrier + 1;          }while($carrier < 3); $cat_i = $cat_i + 1; }while($cat_i < $rows_cat); $i = $i + 1; }while($i < $rows_clsite); PHPを触り始めて日が浅いもので、ループを多用して重い処理になっているのはわかっております…。 コードの書き方自体もなっていないと思いますが、タイムアウトせずに動かせなく困っておりまして、アドバイスを頂ければと思っております。 PHP・ブラウザのタイムアウト対策は、 set_time_limit(0); ob_end_clean(); echo str_pad('',256); flush(); sleep(1); としており、上記で暫くは処理時間を伸ばすことができておりました。 また、phpがapachユーザー?として動く為、apachのタイムアウトに引っかかるのではと、コアサーバーのサイトに記載されていた、CGI版PHPとして動かす方法(.htaccessに記載する方法)でも試してみたのですが、結果は変わりませんでした。 しかし、本当にCGI版として動いているのか確信はありません。。 試行錯誤の上、上記のループの$iの部分を1回終了毎にブラウザに戻し、metaのRefreshで15秒開け次の処理を行わせたり、$iのループ毎に手動でPOSTにて送信し、細切れにして処理をさせているのですが、細切れにした処理だけでもタイムアウトになったりならなかったりを繰り返しております。 上記の方法では、ブラウザのタイムアウト対策をしているだけではと思いつつも、原因がどこにあるのか思い当たらない為、どう対処していいのかさえわからない状況となっております。。 単純に、apachのタイムアウトに引っかかっているのか、負荷が大きいためなんらかのサーバの制限に引っかかっているのか等、考えられる原因やその原因を一つ一つ切り捨てていけるような方法等がありましたら、ご意見お願いできればと思います。 自前のサーバの準備も進めておりますが、暫く時間がかかってしまいそうですので、現在の環境で応急処置できればと思っております。 タイムアウト時はphpなどのエラーメッセージは出ず、IEの「このページは表示できません。」というメッセージが表示されております。 乱文にて申し訳ありませんが、お知恵をお貸し頂けますと大変幸いでございます。 宜しくお願い致します。

  • PHP
  • 回答数6
  • ありがとう数10

質問者が選んだベストアンサー

  • ベストアンサー
  • yuuki0229
  • ベストアンサー率70% (33/47)
回答No.5

execの使い方は合ってますが、どうやら制限によって難しそうですね。 そこまで制限してるならサーバー移行が良いかも知れません。 と言いつつ、一つ思いついたので書いておきます。 「実行時刻(時)の2時間前~1時間前のログのみを対象として集計する」というスクリプトを1時間に1回実行します。 2010/2/20 0:00~1:00のログは同日2時に集計 2010/2/20 1:00~2:00のログは同日3時に集計・・・ 保存先のDBでそのような分割実行でも集計できるテーブルになってる必要がありますが、計算量は24分の1になるはずなのでしばらくは大丈夫だと思います。 #実際には引数でいつの分を集計するか指定できたほうが良いですが

watchout
質問者

お礼

execの件、確認頂きまして有難うございました。 その後いろいろと試行錯誤し、毎時間cornから処理プログラムを起動させ、一度タイムアウトまで処理を行い、1時間後はタイムアウトまでに処理されたログの集計を飛ばして、続きから処理させるようにしました。 毎時間、途中から集計処理をさせることで、全ての処理を完了するところまでいくことができました。 体感で15~30分でタイムアウトになってしまうようですので、前日の処理は日が昇る前には完了することができ、一応理想としていた処理の形とすることができました。 ただし、処理完了後も同じ処理が毎時間走ってしまいますので、集計処理用のログテーブルを作成し、前日の処理が終了したら集計処理完了ログを作成し、完了ログがあった場合は処理を中止するという仕組みにすれば、サーバーへの負荷も軽減できると思いますので、構築しようと思っております。 正直cornも正常に走っているか、深く追求しておりませんでしたので、cornを追求するきっかけを与えて頂いたyuuki0229様に感謝しております。 linuxでのサーバー構築を前倒しにして、自前サーバーにて安定した運用ができるようにしていきたいと思っております。 linuxの方もいろいろと勉強する点が多々ありますが、いろいろとお知恵をお貸し頂きまして有難うございました。

その他の回答 (5)

  • bm_hiro
  • ベストアンサー率51% (200/388)
回答No.6

解決策でもなく回避策でもなく、 俺なら こうするかなって言う妄想レベルの話ですので、聞き流しでお願いします。 ローカルにXAMPP入れて、ローカルからネット上にデータを取りに行って、集計したら、ネット上に戻してやる感じでやれば、多分 タイムアウトしません。 ただ、データの量的に なんか問題がある気もします。 ちなみに、俺は 最初に自分でブラウザからトリガー引いた後は、8時間以上 放置して、データをネットから自動で拾い続けさせていた事があります。

watchout
質問者

お礼

いろいろと策をお考え頂きまして有難うございました。 ANo,5のお礼に記載させて頂いた方法にて、処理を完了するところまで持っていくことができました。 XAMPPは一度触ったことがある程度でbm_hiro様の様に、難しい連動をさせるのには、知識不足かもしれません。。 本当にいろいろとお力をお貸し頂きまして、感謝しております。 有難うございました!

noname#243182
noname#243182
回答No.4

CLI版のPHPは「/usr/bin/php5cli」で利用することが出来そうです。 しかし、CORESERVERではジョブの最大実行時間が3分間に制限されているようで、これはCGI版やモジュール版の300秒よりさらに短い設定値ですね。 CLI版のPHP自体は「max_execution_time」が0で無制限となりますが、制限により3分で強制終了するのであれば、CLI版であってもタイムアウトしてしまいますので、当方のアドバイスは無意味でした。この線は捨ててください。

参考URL:
http://www.coreserver.jp/help/index.php/limitation/
watchout
質問者

お礼

わざわざお調べ頂きまして、有難うございました。 このような負荷制限があると、やはりサーバを移した方が賢明なのでしょうか…。 サーバー移行も含めて、いろいろと考えてみることにします。 有難うございました!

  • yuuki0229
  • ベストアンサー率70% (33/47)
回答No.3

Apache側のタイムアウト設定に依存してそうです。 Web上でやる場合、 exec("/usr/bin/php heavy_script.php > /dev/null 2>&1 &"); のようにバックグラウンドでスクリプトを実行すればひとまずApacheのタイムアウトは気にしなくてよくなります。 そして1日1回実行とのことですが手動でしょうか? Cronから1日1回、PHPを実行すれば元々Apache関係なく処理できます。 ループのアルゴリズムに無駄があるかどうかは挙げられたコードでは判断できませんでした。

watchout
質問者

お礼

ご回答有難うございます。 exec関数について、使ったことがないので調べてみましたが、使い方が今ひとつ掴めません。 重い処理のスクリプト(c_batch.php)を、同じ階層に作成したexec.phpを頂いたご回答を元に下記のように記載し、exec.phpへブラウザからアクセスしたのですが、処理がされていない様です。。 ↓exec.php <?php echo exec("/usr/bin/php ".dirname(__FILE__)."c_batch.php > /dev/null 2>&1 &"); ?> 勉強不足の為、ご回答頂いた内容と全く違うことをしているかもしれません。 その際は申し訳ありません。 また、cornから…という処理方法が本来行いたい方法でした。 しかし、$iの処理回数が74回あるうち、58回終了後、処理がとまってしまってしまい、処理が中途半端で終わってしまってしまうのです。。 Apachのタイムアウトが関係ないとなると、他の原因はどのようなことが考えられますでしょうか? できれば、cornにて午前4時頃に自動で処理を完了させてしまいたいので、重ねてのご質問になってしまい申し訳ありませんが、お力をお貸し頂ければと思います。 exec関数に関しては、理解が浅い状況ですので、引き続き理解を深めるよう勉強していきたいと思っております。 アドバイス有難うございました。

  • bm_hiro
  • ベストアンサー率51% (200/388)
回答No.2

環境が違うので参考にならないかもしれませんが、一応 そちらと同じ方法でタイムアウト防止させていて、1~2時間程度なら 問題なく動いてます。 それ以上、時間のかかることをしたことがないだけで、それ以上でも動くものと思われます。 ただ、俺の環境はXAMPPでローカルの自分のPCの中にあるテキストファイルを読み出して、解析して、DBに叩き込むだけなので、負荷は常識の範囲内だと思います。 なので、参考にはならないかもしれません。 俺も どっかから コピペしてきた奴なんですけど、そちらと同じようにして使ってます。 // タイムアウト防止処理 set_time_limit(0); // 実行時間を制限しない ob_end_clean(); // 出力をバッファリングしない(==日本語自動変換もしない) print str_pad('',256); // IEのために256バイト空文字出力 ただ、他にも 超うろ覚えで 別のと記憶違いしてる気がしないでもないんですけど、 php.ini とか httpd.conf も いじったような気もします。 ほんと、役に立たない回答で すみません。

watchout
質問者

お礼

有難うございます。 おそらく環境の違いか何かでタイムアウトする時間が違うのかもしれません。 解決に向けて頑張ってみます。 有難うございました。

noname#243182
noname#243182
回答No.1

おそらくCGI版と同じ場所に、CLI版のPHPが用意されています。バッチ処理にはこれを利用すると便利です。 ロジックの見直しなどは、ローカルで行うことをお勧めします。

参考URL:
http://www.php.net/manual/ja/features.commandline.php
watchout
質問者

お礼

有難うございます。 CLI版のPHPの導入をできるよう勉強してみます。 正直CLI版を簡単に導入して、処理を復旧できるレベルではなさそうですが…。

関連するQ&A

  • PHPとMySQLで100万件のデータを登録

    PHPとMySQLで100万件のデータを登録する方法に困っております。 1.PHPで100万回ループして数字をランダムで取得し一意の数字を配列に格納。 ⇒データ量が多すぎてタイムアウトしてしまいます。いい方法はありますか? while($i<1000000){ $h = sprintf("%07d",mt_rand(1,1000000)); if(!array_search($h,$val)){      array_push($val,$h);      $i++; } } 2.またデータベースはMySQLを使用しようかと考えていますが、一気に登録する方法など効率のいいやり方はありますでしょうか?

    • ベストアンサー
    • PHP
  • PHPのループ数限界値について

    PHPのループ数限界値について 宜しくお願い致します。PHP 5.1.6を使用しております。 PHPのforやwhileのループ処理について、限界のループ数というのは存在するのでしょうか? 今作っているプログラムで、約15,000項目の配列と約10,000項目の配列で2重のループ処理しています。 この場合のループ数は15,000×10,000=150,000,000回の繰り返し回数となってしまいます。 しかも、この配列数は今後も増える可能性が高いです。 ループの限界値が何回なのか、教えてください。

    • ベストアンサー
    • PHP
  • 学校の授業で困っていることがあります。PHP+MySQLでショッピング

    学校の授業で困っていることがあります。PHP+MySQLでショッピングサイトを構築しているのですが、カートの在庫処理の部分で疑問が発生しました。 私たちのショッピングサイトは、カートに商品を追加した時点で、DBの在庫テーブルの販売数を増やし、在庫数に即時に反映させたいと考えています。 しかし、ブラウザを閉じた時やセッションタイムアウト時、ログアウト時に確定していないカートの商品については販売数を元に戻したいのです。 ログアウト時は明示的に行えると思うのですが、セッションタイムアウト時、ブラウザを閉じた時の処理はどのようにすればいいのですか? そのようなイベントを取得するメソッドや方法はないのでしょうか? 参考サイトや方法を教えてください!

    • ベストアンサー
    • PHP
  • リクエストの待ち時間が期待通りになりません。

    リクエストの待ち時間が期待通りになりません。 5秒以内にリクエストが行われた場合は、ループとスリープで待たせて、ログに記録されているタイムから5秒以上経過した時点で、新たにログにタイムを記録させたいと思っています。 複数人で同時アクセスもありますので、ループ内で常に最新のファイルを読み込む必要がある?ので、 以下のように書いてみましたが、5秒以内にリクエストした場合、通常は1秒待てば処理が終わるはずなのですが、ループが途中で終わらずに20秒待たされ、$flag==0のまま終わります。 適当な知識しかなくて恥ずかしいですが、どこか間違えている場所があればご指摘くださると幸いです。 my $logfile = "request.dat"; my $time = time; my $i = 0; my $flag=0; while ($i < 20) { $i++; open(IN, "< $logfile"); my ($request_time) = <IN>; close (IN); if($time < $request_time+5) { sleep(1); } else { $flag=1; last; } } if($flag==0){&error;} else { open(OUT,">$logfile"); print OUT $time; close(OUT); }

    • ベストアンサー
    • Perl
  • PHP プログラム ループ処理

    プログラム初心者です、ループ処理についてうまい解決方法が思い浮かばず相談させて頂きます。 ループ処理において、ループ内で変数を定義するのに違う名前を指定するにはどのような方法があるのでしょうか 例えばwhileの場合 $i =0; while($i<10){ $hoge = $i; $i++ } この$hogeを2順目には$hoge1、3順目には$hoge2と言うように増やしたり一定の法則に乗っ取って変数名を変更するにはどのように書けばいいのでしょうか。 どなたかご教授頂ければと存じます、宜しくお願い致します。

    • ベストアンサー
    • PHP
  • 3件目以降出力されないので4件目から出力したい

    <!--ループ1--> <?php $wp_query = new WP_Query(); $args = array( 'post_type' => "post", //投稿タイプ設定 ); $wp_query->query($my_posts); if ($wp_query->have_posts()) : $i = 0; $i <= 10; while ($wp_query->have_posts()) : $wp_query->the_post(); ?> <?php /**** ▼1件分の投稿内容HTML ****/ ?> <?php $i++; ?> <?php if ($i >= 3) break; ?> <?php endwhile; ?> <?php endif; ?> <!--//ループ1--> <!--ループ2--> <?php $wp_query = new WP_Query(); $args = array( 'post_type' => "post", //投稿タイプ設定 ); $wp_query->query($my_posts); if ($wp_query->have_posts()) : while ($wp_query->have_posts()) : $i<=4; //iが4より小さい時は、while内のループ処理を実施する $i>3;break; //iが3より大きい時は、while文を・強制終了する $wp_query->the_post(); ?> <?php /**** ▼1件分の投稿内容HTML ****/ ?> <?php $i++; ?> <?php endwhile; ?> <?php endif; ?> <!--//ループ2--> 変数 i の値が 0 から → $i = 0 10 未満の間は、 → $i <= 10 i の値を1づつ加算しながら → i++ 以下の命令文を実行する。 continue; echo $i; //以降の処理をスキップして、次のループ処理を行う。 0から3まででbreakして, $i<=4; //iが4より小さい時は、while内のループ処理を実施する $i>3;break; //iが3より大きい時は、while文を強制終了する 3件で出力を止めたんですが、4件目から出力されません

    • ベストアンサー
    • PHP
  • do~while文がよくわかりません

    今参考書で勉強しているのですが、do~while文がよくわかりません 。コードは下記のようになります。どうして前の処理結果が足されていくのか理解できません。こんな馬鹿にどうかわかりやすくご教授していただけないでしょうか!? <?php $s = $i = 0; do{ ++$i; $s += $i; }while($i < 10); print "1 から $i までの和は $s"; ?>

    • ベストアンサー
    • PHP
  • PHPコーディング 訓練が出来る媒体

    最近、PHPプログラミングの教室に通っています。 今までプログラム言語を習ったkとがないので、簡単なプログラムを ブラウザに表示させるのも、まったく訳が分かりません。 特に今やっている、ループ処理(for, while)が理解できません。 授業は、「~をfor/while文を使って画面に表示させなさい」のような 感じです。 変数が2個出てくる時点で、脳みそグチャグチャです。 練習するしかないと思いますが、初心者のループ処理を詳しく書かれていて、 レベルアップにつながる練習問題が記載されている書籍、またはwebを教えてください。

    • ベストアンサー
    • PHP
  • C言語/プログラミング

    1 1 2 2 3 3 このように同じ数字になったら同じ処理をループさせる方法(do whileを使って)を教えてください。

  • whileで最後のループを判別するには?

    環境:php5 Q. DBから取得した値をwhileでループさせたとき、最後のループを取得するにはどうしたらいいのでしょうか? 現状ではループさせる数を最初に取得して、whileさせているときに$i++でカウントさせながら、合計の数とイコールになったときに最後と判断させていますが、もっとスマートに記述する方法などはあるのでしょうか? smartyだとlastで取得できるみたいですけど。 ご教授いただけると幸いです。

    • 締切済み
    • PHP

専門家に質問してみよう