ホームページ  >  記事  >  バックエンド開発  >  Redis を使用して PHP に分散ロックを実装する

Redis を使用して PHP に分散ロックを実装する

WBOY
WBOYオリジナル
2023-05-15 15:51:242565ブラウズ

インターネットの急速な発展と Web サイトへのアクセス数の急増に伴い、分散システムの重要性が徐々に顕著になってきました。分散システムでは、同時実行の同期とデータの一貫性の問題が必然的に伴います。分散ロックは、同時実行同期の問題を解決する手段として、分散システムで徐々に広く使用されるようになりました。 PHP では、Redis を使用して分散ロックを実装できます。これについては、この記事で紹介します。

分散ロックとは何ですか?

分散システムでは、複数のマシンが同じタスクを同時に処理する場合、複数のマシンが同じリソース上で同時に動作することを避けるために、リソースをロックする必要があります。分散ロックは、分散システム内の共有リソースをロックするためのメカニズムです。分散ロックでは、次の 2 つの要件を確実にする必要があります:

1. 相互排他性: いつでも 1 つのクライアントだけがロックを保持できます。

2. 再入可能: 同じクライアントが複数回ロックを取得できます。

分散ロックを実装するには、データベースの使用、Zookeeper の使用など、さまざまな方法があります。この記事では、Redis を使用して分散ロックを実装する方法を紹介します。

Redis による分散ロック実装の原理

Redis は、さまざまなデータ構造をサポートする高性能のキー/値ストレージ システムです。 Redis では、SET コマンドを使用して分散ロックを実装できます。その実装原理は次のとおりです:

1. クライアントは SETNX コマンドを Redis に送信します。

2. Redis サーバーは、受信した SETNX コマンドを処理して、指定されたキーが存在するかどうかを確認し、存在しない場合は、キーの値をクライアント ID に設定し、有効期限を設定します。存在する場合は、直接失敗が返されます。

3. クライアントは、Redis から返された結果を受け取り、ロックの取得が成功したかどうかを判断します。成功した場合は、対応する操作を実行します。失敗した場合は、一定時間待機してから、ロックを取得します。リクエストを再度送信してください。

Redis を使用して分散ロックを実装する手順

1. Redis への接続

PHP では、PHPredis 拡張機能を使用して Redis に接続します。拡張機能を使用する前に。具体的なインストール方法については公式ドキュメントを参照してください。

2. ロックの取得

次のようにロックを取得する関数を実装します:

protected function lock($lock_key, $expire_time = 5)
{
    $redis = new Redis();
    $redis->connect('localhost', 6379); // 连接Redis
    $micro_second = 1000000;
    $timeout = 10 * $micro_second; //等待锁超时时间

    while($timeout >= 0)
    {
        $microtime = microtime(true);
        $timeout -= $micro_second;
        $current_lock_time = $microtime + $expire_time + 1; //锁过期时间

        if($redis->setnx($lock_key, $current_lock_time)) //获取锁成功
        {
            $redis->expire($lock_key, $expire_time); //设置过期时间,防止死锁
            return $current_lock_time;
        }

        //检查锁是否过期
        $lock_time = $redis->get($lock_key);
        if($lock_time < $microtime)
        {
            $new_lock_time = $microtime + $expire_time + 1; //设置新的过期时间
            $old_lock_time = $redis->getset($lock_key, $new_lock_time); //获取旧的过期时间并设置新的过期时间
            if($old_lock_time < $microtime) //锁已经过期,获取锁成功
            {
                $redis->expire($lock_key, $expire_time); //设置过期时间,防止死锁
                return $new_lock_time;
            }
        }

        //等待一段时间后再次尝试获取锁
        usleep(10000); //等待10毫秒
    }

    return false;
}

この関数の機能は、指定されたキーのロックを取得することです。取得が成功するとロックが返されます有効期限; 取得が失敗した場合は false を返します。

3. ロックを解放します

ロックの取得に成功して操作が完了した場合でも、一定時間待ってもロックの取得に失敗した場合でも、ロックは解除されます。解放する必要がある。

protected function unlock($lock_key, $current_lock_time)
{
    $redis = new Redis();
    $redis->connect('localhost', 6379); // 连接Redis
    
    $lock_time = $redis->get($lock_key);
    if($lock_time == $current_lock_time) //判断是否为当前持有锁的客户端
        $redis->del($lock_key); //释放锁
}

この関数の機能は、指定されたキーのロックを解放することであり、現在ロックを保持しているクライアントのみがロックを解放できます。

注意事項

1. ロックの有効期限は、実際の状況に応じて合理的に設定する必要があります。ロックの有効期限が短すぎると、ロックが期限切れになったり、頻繁にロックを取得できなくなったりする可能性があり、ロックの有効期限が長すぎると、ロックの有効期限が長すぎてシステムのパフォーマンスに影響を与える可能性があります。

2. 有効期限を設定する場合は、デッドロックが発生しないように注意してください。 1 つのクライアントがロックを取得しても、予期しない終了またはクラッシュによりロックが解放されない場合、他のクライアントがロックを取得することに影響し、デッドロックの問題が発生します。

3. 分散ロックの実装はクライアントの一意の識別子に依存しているため、異なるクライアントは異なる識別子を使用する必要があり、そうしないと、あるクライアントが他のクライアントのロックを解放してしまう可能性があります。 PHP では、クライアントの一意の識別子として PHP_SESSION_ID または IP アドレス/プロセス ID を使用できます。

結論

Redis を使用した分散ロックの実装は、PHP における比較的シンプルで実用的な分散ロック ソリューションです。実際のアプリケーションでは、デッドロックの問題を回避し、システムの安定性と信頼性を確保するために、実際の状況に応じてロックの有効期限を合理的に設定する必要があります。同時に、起こり得る問題を回避するために、クライアントの一意の識別子の一意性を確保することに注意を払う必要があります。

以上がRedis を使用して PHP に分散ロックを実装するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。