dポイントプレゼントキャンペーン実施中!

ローカルのシステムでデータベースからCSVファイルを作成して、公開用WEBサーバへFTPアップロード。その後CSVファイルをWEB用データベースに登録する処理を開発しているんのですが、開発用WEBサーバでは正常に完了するのですが、本番用WEBサーバで行うと最初の数万件は登録できているのですが、途中でエラーというか真っ白になって処理がSTOPしてしまいます。
開発、本番用共に同じPHPのファイルを使用しており、データベース構成も同じです。
【相違点】
開発(正常):PHP4.4.2(Apacheモジュールにて動作)
本番(異常):PHP4.4.1(CGI動作)
エラーとなるのも、CSVのファイルの容量によって違います。
ちなみにFTPでのアップロードは開発・運用供正常にできています。
どなたかご教授お願いします。

A 回答 (5件)

がるです。


んと…ちと長くなりますのでご覚悟を(笑

#2さんのおっしゃっている「メモリ」問題の可能性も考えてはいるのですが、今回の件はいわゆる「タイムアウト系かなぁ」お思ってますので、その観点から。

まず「htaccessでは」とのお話しですが…すみませんちょっとこのあたりは。
Timeoutディレクティブなのは把握しているのですが…元々、普段は .htaccess自体を、性能の観点からoffにしているので、あまり詳しくなくて。
もし設定される場合、例えば
Timeout 7200
とかにしておくと、大分よいかと思います。数値の単位は秒です(通常、最近は300が多いのですが…レンタルサーバですと30とかで切ってるかもしれません)。
ただ、.htaccessでTimeoutディレクティブが有効になるかどうかはちとわからないです。

> 10000件ごとに取り込み状況を出力するように変更したのですが、的を外れていますか?
残念ながら。
ちと厳密に書くと。
Apacheのプロセスは、CGI(今回ですとPHPプログラム)を起動します。で、そのプログラムのstdout(標準出力)が完全にcloseし、プログラムが終了した時点で初めて出力を行うのが通常なので。
結局のところ、プログラムが動いている最中は、今まで試した限りでは、「別プロセスにforkした場合」を含め、すべてNGでした。
ですので、ある程度以上の作業であれば、どうしても「裏側で別途処理」という流れになることが多いです。
なので、cronで、という流れになるのですが。

あとは…行数制限をかけてしまうのが、恐らくは現実解なのではないか、と思います。

あまり役に立つ情報でなく大変に恐縮ですが。
    • good
    • 0
この回答へのお礼

お礼が遅くなってしまい申し訳ありませんでした。
アドバイスありがとうございました。
Timeoutディレクティブは.htaccessでは無理でした。
結局、抽出する件数を指定してFTPアップロード→WEBサーバ側で取込後
また抽出といった処理に変更しました。
この方法だと、処理に時間がかかりますが正常に動作しました。
同時にWEBサーバの容量の問題も解決できました。

お礼日時:2006/12/26 09:25

#2です。



error_logはapacheのerror_logではなくて、phpのerror_logの事だったのですが、設定されていないとの事なので情報は得られないとの事了解致しました。

#1氏がforkで駄目だった経験がお有りとの事で、これから私が説明する手法ーもforkの様なものなのでやはり駄目かもしれませんが一つ。
(尚、今思い付いたので検証はしておりません)

CSVを読み込んでDBに保存するスクリプトを処理単位で3分割します。
a.ブラウザから処理開始のトリガーを引く為だけのスクリプト。
b.単純にCSVを読み込んでDBを更新するだけのスクリプト。
c.bの処理が終了しているかどうかを確認するだけのスクリプト。

まず、ブラウザからaが呼び出されたら、まずは処理開始のフラグを立てます。(ファイルでも良いし、DBに専用のテーブルを用意しても良い)
続けて system() を使ってbを呼び出しますが、その際のパラメータストリングの末尾に "&" を付けます。
具体的には system("/usr/bin/php -q bのスクリプトパス &"); とします。
これでbは常駐扱いとされて直ぐに処理が戻ってくる筈なので、取り合えずブラウザには「更新処理中です」等と出力して終了します。

bは処理が終わったらaが立てた処理中フラグを降ろします。

cは呼び出される都度にaが立てた処理中フラグを確認し、立っていれば「処理中です」と出力して終了。降りていれば「完了しました」を出力して終了します。

このcをaの処理が終わった時に出力されるHTMLのヘッダにmetaタグのrefresh定義を利用して10秒程度の間隔で何度も呼び出す様にします。
c自信も結果を出力する際に、まだフラグが立っていたら同じくmetaタグを仕込みます。(つまり自分を再度呼び出す様に仕掛けます)

頭の中ではイケそうな気もしますが、いかんせん検証していませんので駄目元という事で簡便してください。
    • good
    • 0
この回答へのお礼

アドバイスどうもありがとうございました。
結果的に無事動作するようになりました。
NINJA104さんの処理については今後の参考にさせていただきます。

お礼日時:2006/12/26 09:30

がるです。


なるほど状況は概ね。

PHPでどれだけの設定をしようとも、最終的には「Apacheの設定次第で切られてしまう」というのが、この場合直接的な回答になろうかと思います。
もうちょっと詳細に書くと。
「CSVを処理している最中にApacheの設定している接続時間を超えた場合にその時点で"処理が片付かない"エラーでApache自身が異常終了として処理してしまう」ため。またファイルサイズによって違うのは「ファイルサイズによってCSV処理時間が異なるため」になります。
Apacheの、通常httpd.confと呼ばれる設定ファイルの中に、接続時間への設定などがあるので。

で、解決策ですが。
httpd.confの設定を長くするのが一つ。下策ですがとりあえず楽ですが、やはりどこかで同じ事象に悩まされます。
CSVファイルが「一定サイズ以上にならない」のであればある程度逃げれるのですが。
上策は「つくりを変える」事。具体的には
・CSVのupload
・CSVの処理
を別々に行います。CSVの処理は、cronあたりでバッチにするほうがよろしいかと。
この方法の場合、どんだけのファイルサイズがあろうとも、基本的には問題なく動きます。
ただ、画面遷移など色々変更がはいるでしょうから、多分大変です。

何かの参考にでもなれば幸いです。
    • good
    • 0
この回答へのお礼

がるさんアドバイスありがとうございます。
Apacheの設定ですが、htaccessではできない項目なんでしょうか?
あと処理の流れはローカルのシステム内でCSV生成後FTPアップロード。
そのあとheader関数でWEBサーバ内のCSV取り込み処理のファイルへアクセス。
そのまま取り込みを行っています。
がるさんが言われている「つくりを変える」と言う内容はこういうことではダメということでしょうか?
cronのバッチ処理は公開用のサーバが対応していません。
いろいろと調べまして、10000件ごとに取り込み状況を出力するように変更したのですが、的を外れていますか?
確かIEの接続時間の関係でこういう処理をすればタイムアウトにならないという情報が検索して見つかったので試してみました。
開発用では200万件のデータの取り込みは正常にできました。
ちなみに開発用のWEBサーバもレンタルサーバです。
もし、ご回答いただければ嬉しいです。

お礼日時:2006/12/21 02:25

error_logには何が出力されていますか?


私の経験ではメモリが足りなくなった場合に、ブラウザに同じ挙動(真っ白)が返った時がありました。
その場合、php.iniの利用するメモリ上限値設定を見直して余裕を持たせるか、またはメモリを無駄に消費しない様にコードを自力で最適化(必要ではなくなった変数をせっせとunset()する等)して対策を取るかのどちらかですね。

この回答への補足

apacheのerror_logには
「Premature end of script headers:ファイル名・・・」
とありました。
調べてみたのですが、どこかにエラーがありますとしかわかりませんでした。
ちなみに本番用はレンタルサーバになります。
memory_limitは本番、開発共に同じ値(項目なし)です。
CGI版とApacheモジュール版ってちがうのでしょうか?

補足日時:2006/12/20 21:04
    • good
    • 0

がると申します。


拝見している限りですと「処理に時間が掛かっているから途中でタイムアウトしている」、ごく普通というか真っ当な挙動だと思うのですが。
ご質問は「タイムアウトしないためには」でよろしいでしょうか?

この回答への補足

すいません。
説明不足でした。
set_time_limit(0);を指定しています。
にも関わらず本番環境及び開発環境(CGI動作)では
途中で止まってしまいます。

補足日時:2006/12/20 20:16
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!