ホームページ  >  記事  >  PHPフレームワーク  >  Swooleで分散ロックを実装する方法

Swooleで分散ロックを実装する方法

PHPz
PHPzオリジナル
2023-06-25 16:45:21954ブラウズ

インターネットとモバイル インターネットの発展に伴い、高同時実行性と分散システムは日常の開発において避けられない問題となっています。この場合、分散ロックは、リソースの競合やデータの不整合などの問題を回避するのに役立つ不可欠なツールになります。この記事では、分散システムにおける同時実行の問題をより適切に解決するために、Swoole に分散ロックを実装する方法を紹介します。

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

分散システムでは、複数のプロセスが共有リソースに同時にアクセスする状況があります。データが破壊されたり、同時実行性の競合が発生したりしないように、これらの共有リソースをロックする必要があります。分散ロックは、分散システムで共有リソースを正しく使用できるように設計されたロック メカニズムです。

分散ロックの実装は比較的複雑であり、一般に次の側面を考慮する必要があります:

  1. 相互排他性: 同時にロックを占有できるのは 1 つのプロセスまたはスレッドのみです。 ;
  2. 再入可能: 同じプロセスまたはスレッドがロックを複数回申請できますが、ロックを解除するときは同じ回数のロック解除操作を実行する必要があります;
  3. デッドロックの防止: 有効期限を設定する必要があります。例外やその他の理由による無限の待機を避けるために、ロックを取得するときに設定する必要があります。
  4. 高可用性: ノード障害、ネットワーク分割などの問題を考慮する必要があります;
  5. パフォーマンス: 高い同時実行性と低遅延の機能を実現する必要があります。

2. Swoole の紹介

Swoole は、PHP 言語用の高性能非同期並列ネットワーク通信エンジンであり、TCP/UDP/HTTP/WebSocket などのさまざまなプロトコルを実装できます。 . サーバー側とクライアント側。 Swoole の機能は次のとおりです:

  1. 高パフォーマンス: サーバーの同時実行機能を大幅に向上できる非同期ノンブロッキング IO モデルの使用;
  2. 組み込みコルーチン: 非同期プログラミングを簡単に実行できます。実装済み、手動でスレッドやプロセスを作成する必要なし;
  3. HTTP/WebSocket サーバー内蔵: Web アプリケーション開発を簡単に実現;
  4. 非同期 MySQL、Redis、ElasticSearch などのカプセル化をサポート一般的なツール。

したがって、Swoole は非常に優れた適応性を備えており、同時実行性が高くパフォーマンスの高い分散システムを構築するために使用できます。

3. Swoole で分散ロックを実装するにはどうすればよいですか?

以下では、Swoole で分散ロックを実装する方法を紹介します。

  1. Redis に基づく分散ロックの実装

Redis はメモリベースのキーと値のデータベースであり、分散システムで最も一般的に使用されるツールの 1 つです。文字列、リスト、セット、順序付きセットなどを含むさまざまなデータ構造をサポートします。その中で、文字列型を使用して分散ロックを実装できます。

Redis を使用して分散ロックを実装する一般的なプロセスは次のとおりです:

(1) Redis 接続プールを通じて Redis 接続オブジェクトを取得します;
(2) SETNX コマンドを使用します排他的、戻り値が 1 の場合、占有が成功したことを意味します;
(3) デッドロックを防ぐために、ロックの有効期限を設定します;
(4) DEL を使用しますロックを解除するコマンドです。

次は具体的な実装コードです:

class RedisLock
{
    private $redis;

    public function __construct($config)
    {
        $this->redis = new Redis();
        $this->redis->connect($config['host'], $config['port'], $config['timeout']);
        if (!empty($config['auth'])) {
            $this->redis->auth($config['auth']);
        }
    }

    public function lock($key, $timeout = 10)
    {
        $startTime = time();
        do {
            $result = $this->redis->setnx($key, time() + $timeout);
            if ($result) {
                return true;
            }
            $lockTime = $this->redis->get($key);
            if ($lockTime && $lockTime < time()) {
                $oldTime = $this->redis->getset($key, time() + $timeout);
                if ($oldTime == $lockTime) {
                    return true;
                }
            }
            usleep(100); // 100毫秒等待
        } while (time() - $startTime < $timeout);
        return false;
    }

    public function unlock($key)
    {
        $this->redis->del($key);
    }
}

上記のコードでは、ロック関数は do-while ループを使用してロックが解放されるのを待ちます。タイムアウトが指定された場合は false を返します。ロックを解除するには、ロック解除関数で DEL コマンドが使用されます。この方法は実装が簡単でオーバーヘッドが低いですが、一定の確率でデッドロックが発生する可能性もあります。

  1. Zookeeper に基づく分散ロックの実装

Zookeeper は、分散システムでのデータ同期と構成管理を実現するために使用できる分散オープン ソース調整システムです。一連の機能。これが提供する一時シーケンシャル ノード (EPHEMERAL_SEQUENTIAL) は、分散ロックを簡単に実装できます。

Zookeeper を使用して分散ロックを実装する一般的なプロセスは次のとおりです:

(1) Zookeeper クライアントを作成し、Zookeeper サーバーに接続します;
(2) createSequential 関数を使用します一時的な Sequential ノードを作成するには;
(3) Zookeeper ですべてのノードを取得し、ノードのシリアル番号で並べ替えます;
(4) 自分のノードのシリアル番号と現在の最小ノードのシリアル番号を比較します。それらが等しい場合、ロックが取得されていることを意味し、それ以外の場合は、自身よりも小さいシーケンス番号を持つ最新のノードをリッスンします;
(5) 自分より小さいシーケンス番号を持つノードが削除されると、現在のノードが削除されます。ノードはイベント通知を受信し、ステップ 4 を繰り返します。

以下は具体的な実装コードです:

class ZookeeperLock
{
    private $zk;
    private $basePath = '/lock';
    private $myNode;

    public function __construct($config)
    {
        $this->zk = new Zookeeper();
        $this->zk->connect($config['host'] . ':' . $config['port']);
        if (isset($config['auth'])) {
            $this->zk->addAuth('digest', $config['auth']);
        }
        if (!$this->zk->exists($this->basePath)) {
            $this->zk->create($this->basePath, null, array(array('perms' => Zookeeper::PERM_ALL, 'scheme' => 'world', 'id' => 'anyone')), null);
        }
    }

    public function lock()
    {
        $this->myNode = $this->zk->create($this->basePath . '/node_', null, array(array('perms' => Zookeeper::PERM_ALL, 'scheme' => 'world', 'id' => 'anyone')), Zookeeper::EPHEMERAL | Zookeeper::SEQUENCE);
        while (true) {
            $children = $this->zk->getChildren($this->basePath);
            sort($children);
            $pos = array_search(basename($this->myNode), $children);
            if ($pos === 0) {
                return true;
            } else {
                $this->zk->exists($this->basePath . '/' . $children[$pos - 1], function ($event_type, $s, $event_data) {
                    $this->unlock();
                });
                usleep(100); // 100毫秒等待
            }
        }
    }

    public function unlock()
    {
        if ($this->myNode) {
            $this->zk->delete($this->myNode);
            $this->myNode = null;
        }
    }
}

上記のコードでは、ロック関数は while ループを使用して、自身のシリアル番号よりも小さいシリアル番号を持つ最新のノードを監視します。が削除された場合は、ロックが取得されたことを意味します。ロック解除関数は、削除関数を使用して現在のノードを削除します。

  1. 概要

この記事では、Swoole で分散ロックを実装する方法を紹介します。Redis と Zookeeper に基づいた 2 つの一般的な実装方法を紹介し、コードを実装します。分散システムでデータの一貫性を確保するための重要な技術的手段として、分散ロックは同時実行性の競合やデータの不整合などの問題を回避するのに役立ちます。分散ロックを実装する場合は、相互排他性、再入性、デッドロック防止、高可用性、パフォーマンスなどの問題を考慮し、実際のアプリケーション シナリオに基づいてさまざまな実装方法を選択する必要があります。

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

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