1

新しいアイテムをキャッシュする必要があるときに、キャッシュ内の最も古いエントリを消去することになっている Web サイトで使用するスクリプトを作成しました。私のウェブサイトは非常に大きく、500,000 枚の写真が掲載されており、キャッシュ スペースは 2 GB に設定されています。

これらの機能が問題の原因です。

function cache_tofile($fullf, $c)
{
    error_reporting(0);
    if(strpos($fullf, "/") === FALSE)
    {
        $fullf = "./".$fullf;
    }
    $lp = strrpos($fullf, "/");
    $fp = substr($fullf, $lp + 1);
    $dp = substr($fullf, 0, $lp);
    $sz = strlen($c);
    cache_space_make($sz);
    mkdir($dp, 0755, true);
    cache_space_make($sz);
    if(!file_exists($fullf))
    {
        $h = @fopen($fullf, "w");
        if(flock($h, LOCK_EX))
        {
            ftruncate($h, 0);
            rewind($h);
            $tmo = 1000;
            $cc = 1;
            $i = fputs($h, $c);
            while($i < strlen($c) || $tmo-- > 1)
            {
                $c = substr($c, $i);
                $i = fwrite($h, $c);
            }
            flock($h, LOCK_UN);
            fclose($h);
        }
    }
    error_reporting(7);
}

function cache_space_make($sz)
{
    $ct = 0;
    $cf = cachefolder();
    clearstatcache();
    $fi = shell_exec("df -i ".$cf." | tail -1 | awk -F\" \" '{print \$4}'");
    if($fi < 1)
    {
        return;
    }
    if(($old = disk_free_space($cf)) === false)
    {
        return;
    }
    while($old < $sz)
    {
        $ct++;
        if($ct > 10000)
        {
            error_log("Deleted over 10,000 files. Is disk screwed up?");
            break;
        }
        $fi = shell_exec("rm \$(find ".$cf."cache -type f -printf '%T+ %p\n' | sort | head -1 | awk -F\" \" '{print \$2}');");
        clearstatcache();
        $old = disk_free_space($cf);
    }
}

cachefolder()を付加した正しいフォルダ名を返す関数です/

関数が実行されると、apache の CPU 使用率は 95% から 100% の間であり、その間、サーバー上の他のサービスへのアクセスは非常に遅くなります。また、キャッシュ ディスクの使用率が 100% であり、キャッシュをクリアするまで低下しないことに気付きました。期待していたのは、90%くらいかな。

私が cache_tofile 関数でやろうとしているのは、フォルダを作成するためにディスク領域を解放してから、キャッシュファイルを作成するためにディスク領域を解放しようとすることです。cache_space_make 関数は、解放するディスク領域の量を表す 1 つのパラメーターを取ります。

その関数では、システム コールを使用して、キャッシュ全体のディレクトリ ツリーで最も古いファイルを見つけようとしましたが、それを行うためのネイティブ php 関数を見つけることができませんでした。

キャッシュ ファイルの形式は次のとおりです。

/cacherootfolder/requestedurl

たとえば、両方の関数からhttp://www.example.com/abc/defを要求した場合、作成されるはずのフォルダーは abc であり、ファイルは def であるため、システム内のファイル全体は次のようになります。

/cacherootfolder/abc/def

http://www.example.com/111/222をリクエストすると、フォルダ 111 が作成され、ファイル 222 が作成されます。

/cacherootfolder/111/222

どちらの場合も、各ファイルには、URL に基づいてユーザーが要求したものと同じコンテンツが含まれています。(例: /cacherootfolder/111/222 には、 http://www.example.com/111/222からソースを表示したときに表示されるものと同じコンテンツが含まれています)

キャッシュ システムの目的は、すべての Web ページを最適な速度で配信することです。

私の質問は、キャッシュがいっぱいになったときにシステムがロックアップしないようにするにはどうすればよいかということです。私が提供したものよりも使用できるより良いコードはありますか?

4

1 に答える 1

1

||コード内の を に置き換えることから始めますが&&、これはおそらく意図されたものです。
現在、ループは常に少なくとも 1000 回実行されます。1000 回後に試行を停止する意図があったことを願っています。

また、 と を削除しftruncateますrewindPHPマニュアルから
(強調鉱山):fopen

'w' 書き込み専用です。ファイルポインタをファイルの先頭に置き、ファイルの             長さをゼロに切り詰め
ます。ファイルが存在しない場合は、作成してみてください。

したがって、あなたtruncateと同様に、あなたは冗長rewindです。

次に、 を確認しますshell_exec
ループの外側にあるものはあまりボトルネックには見えませんが、ループの内側にあるものは...
そのキャッシュ フォルダーに 1'000'000 個のファイルがあるとしましょう。
findどれだけ時間がかかっても、すべてのリストを喜んで表示します。
次に、そのリストを並べ替えます。
そして、そのリストの 999,999 エントリをトイレに流して、最初のエントリだけを保持します。
次にawk、私があまり気にしないことをいくつか行ってから、ファイルを削除します。
次の反復では、999'999 個のファイルを処理するだけで済み、そのうち999'998 個だけを破棄します。
私がどこに行くのか分かりますか?
いずれにせよ、シェル スクリプトを呼び出すのは単純な利便性の悪い習慣だと考えていますが、実行する場合は、少なくともできるだけ効率的に実行してください。なしで実行し、結果のリストを変数に格納して、それを繰り返します
。 完全に放棄し、代わりに PHP で対応するルーチンをプログラムする方が良いかもしれませんが(とはマシン コードであり、同じタスクを実行するために PHP で記述されたコードよりも高速であると主張する人もいるかもしれませんがその IO リダイレクト)。shell_exechead -1
shell_execfindrm

それをすべて実行してから、パフォーマンスがどれだけ悪いかを確認してください。
それでも結果が受け入れられない場合は、それらの関数の特定の部分に必要な時間を測定するコードを追加するか (ヒント: )、 XDebugmicrotime(true)などのプロファイラーを使用して、ほとんどの時間がどこに費やされているかを正確に確認することをお勧めします。

また、なぜそのブロックのエラー報告をオフにしたのですか? 私には疑わしい以上に見えます。

$ccちょっとしたおまけとして、どこにも使用していないので、取り除くことができます.

于 2015-07-29T18:58:23.623 に答える