現在の位置: ホーム> 最新記事一覧> APCU_CAS関数を使用して、キャッシュレース条件を回避する方法

APCU_CAS関数を使用して、キャッシュレース条件を回避する方法

gitbox 2025-05-29

キャッシュレースの条件とは何ですか?

複数のプロセスまたはスレッドがキャッシュミスを読み取り、同時にキャッシュを書き留めようとすると、複数のプロセスが同じスロークエリまたは複雑な計算を同時に実行して、リソースの無駄をもたらす可能性があります。この状況は、キャッシュレース条件と呼ばれます。

例えば:

 if (!apcu_exists('my_cache_key')) {
    $data = get_data_from_db(); // 複雑なクエリ
    apcu_store('my_cache_key', $data);
}
echo apcu_fetch('my_cache_key');

高い並行性環境では、複数のリクエストでは、キャッシュが同時に存在しないことがわかり、データベースクエリが同時に実行され、パフォーマンスの問題が発生します。


APCU_CAS関数の紹介

APCU_CASのフルネームは「比較とスワップ」です。これは、キャッシュ値が期待値と等しいかどうかを比較するために使用される原子操作であり、等しい場合、新しい値に置き換えられます。この操作は、キャッシュを同時に変更するための複数のリクエストによって引き起こされる競合の問題を回避できます。

関数プロトタイプ:

 bool apcu_cas(string $key, mixed $old, mixed $new)
  • $キー:キャッシュキー

  • $ old :予想される古い値

  • $ new :交換する新しい値

  • Trueを返すということは、交換が成功することを意味し、 Falseは古い値が一致しないことを意味し、交換は失敗します。


人種の状況を避けるためにAPCU_CASを使用する方法は?

「ロック」フラグを設定して、Mutex Accessキャッシュを実装します。具体的なアイデア:

  1. キャッシュを読み、存在する場合は直接返します。

  2. キャッシュが存在しない場合は、「ロック」フラグを設定して、キャッシュが生成されていることを示してみてください。

  3. 「ロック」の設定は失敗し、他のプロセスがすでにキャッシュを生成している、待っている、または再試行していることを示しています。

  4. 設定が成功したら、遅いクエリを実行してデータを生成します。

  5. データをキャッシュに書き込み、「ロック」フラグをリリースします。

  6. データを返します。


サンプルコードのデモンストレーション

function getCacheData() {
    $cacheKey = 'my_cache_key';
    $lockKey = 'my_cache_key_lock';

    // 1. 最初にキャッシュを読んでみてください
    $data = apcu_fetch($cacheKey, $success);
    if ($success) {
        return $data;
    }

    // 2. 合格してみてくださいapcu_casロックを設定します,複数の要求が同時にキャッシュを生成するのを防ぎます
    // 先尝试ロックを設定します标志位为false(初期ステータス)
    apcu_add($lockKey, false);

    // 予想されるロックはですfalse,に変更してみてくださいtrue(ロック)
    if (!apcu_cas($lockKey, false, true)) {
        // 他のリクエストがロックされていることを示します,キャッシュの生成を待ちます
        // シンプルにすることができますsleepまたは、ループで待ちます
        usleep(100000); // 待って100ミリ秒
        return getCacheData(); // 再帰的に試してみてください
    }

    // 3. ロックを取得します,スロークエリを実行します
    $data = get_data_from_db();

    // 4. キャッシュを書きます
    apcu_store($cacheKey, $data);

    // 5. ロックを解放します(ロックを設定します为false)
    apcu_store($lockKey, false);

    return $data;
}

function get_data_from_db() {
    // スロークエリをシミュレートします
    sleep(1);
    return ['time' => time(), 'data' => 'sample'];
}

上記のコードでは、 APCU_CASは「ロック」のアトミックスイッチングを保証し、複数のリクエストを回避すると同時にスロークエリを実行し、キャッシュ競争を回避します。


まとめ

  • キャッシングレースの条件は、高い並行性キャッシュシナリオで一般的な問題です。

  • APCU_CASは、原子動作を実装するための強力なツールであり、効率的なロックメカニズムを実現できます。

  • 「ロック」メカニズムにより、1つの要求のみがスロークエリを実行してキャッシュを書き込むことができることが保証され、他のリクエストが待機または再試行できることが保証されます。

  • この方法は、スタンドアロン環境でのAPCUキャッシュに適しており、分散環境ではより複雑なロックソリューションを考慮することができます。

APCU_CASの使用を習得すると、PHPキャッシュメカニズムがより堅牢で効率的になり、キャッシュの故障によって引き起こされるパフォーマンスのボトルネックを大幅に回避できます。


<Code> <?PHP関数getCacheData(){$ cachekey = 'my_cache_key'; $ lockkey = 'my_cache_key_lock';
 $data = apcu_fetch($cacheKey, $success);
if ($success) {
    return $data;
}

apcu_add($lockKey, false);

if (!apcu_cas($lockKey, false, true)) {
    usleep(100000);
    return getCacheData();
}

$data = get_data_from_db();

apcu_store($cacheKey, $data);

apcu_store($lockKey, false);

return $data;

}

関数get_data_from_db(){
睡眠(1);
['time' => time()、 'data' => 'sample']を返します。
}
?>
</code>