redis の同時実行の問題
私は長い間 redis をキャッシュとして使用してきましたが、Redis は単一のプロセスとして実行され、コマンドが次々に実行されます。同時実行性の問題は発生しないだろうと思っていましたが、今日関連情報を見て初めて気づきました。
具体的な問題の例
名前が myNum であると仮定したキーがあり、その中にアラビア数字が格納されているとします。現在の値は 1 です。myNum 上で複数の接続が動作している場合、同時実行性の問題が発生します。 linkA と linkB の 2 つの接続があるとします。両方の接続が次の操作を実行し、myNum の値 1 を取り出して保存し直し、次の相互作用を確認します:
linkA get myNum => 1linkB get myNum => 1linkA set muNum => 2linkB set myNum => 2
操作を実行した後の結果おそらく 2 ですが、これは私たちが予想していた 3 とは一致しません。
具体的な例を見てみましょう:
<?phprequire "vendor/autoload.php";$client = new Predis\Client([ 'scheme' => 'tcp', 'host' => '127.0.0.1', 'port' => 6379,]);for ($i = 0; $i < 1000; $i++) { $num = intval($client->get("name")); $num = $num + 1; $client->setex("name", $num, 10080); usleep(10000);}
name の初期値を 0 に設定し、2 つの端末を使用して上記のプログラムを同時に実行します。name の最終値は異なる場合があります。 2000 ですが、< ;2000 という値は、上記の同時実行性の問題が存在することを証明しています。これを解決するにはどうすればよいでしょうか?
redis のトランザクション
redis にもトランザクションがありますが、このトランザクションは mysql ほど完璧ではなく、一貫性と分離性を保証するだけであり、アトミック性は満たしていません。 . 性別と耐久性。
redis トランザクションは multi、execcommands
アトミック性を使用します。redis は、途中で実行がある場合でも、トランザクション内のすべてのコマンドを実行します。失敗してもロールバックはありません。 Kill シグナル、ホストのダウンタイムなどによりトランザクションの実行が失敗し、redis は再試行またはロールバックしません。
永続性、redis トランザクションの永続性は、redis で使用される永続性モードに依存しますが、残念ながら、さまざまな永続性モードは永続的ではありません。
分離、redis は単一プロセスです。トランザクションの開始後、exec コマンドが検出されるまで現在の接続のすべてのコマンドが実行され、その後、他の接続のコマンドが処理されます。
一貫性、この文書を読んだ後、これは非常にばかげていると思いますが、それは正しいようです。
redis のトランザクションはアトミック性をサポートしていないため、上記の問題は解決できません。
もちろん、redis には、この問題を解決できる watch コマンドもあります。次の例を参照して、キーに対して watch を実行し、トランザクションを実行します。watch の存在により、 , 彼はキー a を監視します。 a が修復されると、後続のトランザクションは実行に失敗します。これにより、複数の接続が同時に行われ、すべての a が監視されます。正常に実行できるのは 1 つだけで、他のものは失敗を返します。
127.0.0.1:6379> set a 1OK127.0.0.1:6379> watch aOK127.0.0.1:6379> multi OK127.0.0.1:6379> incr aQUEUED127.0.0.1:6379> exec1) (integer) 2 127.0.0.1:6379> get a"2"
失敗の例。最後から、test の値が他の接続によって変更されたことがわかります:
127.0.0.1:6379> set test 1OK127.0.0.1:6379> watch testOK127.0.0.1:6379> multiOK127.0.0.1:6379> incrby test 11QUEUED127.0.0.1:6379> exec(nil) 127.0.0.1:6379> get test"100"
問題の解決方法
redis コマンドはアトミックなので、値がアラビア数字の場合は、get および set コマンドを incr または incrby に変更してこの問題を解決できます。次のコードにより、2 つの端末を同時に実行できるようになります。結果は、2000 年を予想しました。
<?phprequire "vendor/autoload.php";$client = new Predis\Client([ 'scheme' => 'tcp', 'host' => '127.0.0.1', 'port' => 6379,]);for ($i = 0; $i < 1000; $i++) { $client->incr("name"); $client->expire("name", 10800); usleep(10000);}
これは確かに実現可能であり、その効果は悪くありません。これは例です
<?phprequire "vendor/autoload.php";$client = new Predis\Client([ 'scheme' => 'tcp', 'host' => '127.0.0.1', 'port' => 6379,]);class RedisLock{ public $objRedis = null; public $timeout = 3; /** * @desc 设置redis实例 * * @param obj object | redis实例 */ public function __construct($obj) { $this->objRedis = $obj; } /** * @desc 获取锁键名 */ public function getLockCacheKey($key) { return "lock_{$key}"; } /** * @desc 获取锁 * * @param key string | 要上锁的键名 * @param timeout int | 上锁时间 */ public function getLock($key, $timeout = NULL) { $timeout = $timeout ? $timeout : $this->timeout; $lockCacheKey = $this->getLockCacheKey($key); $expireAt = time() + $timeout; $isGet = (bool)$this->objRedis->setnx($lockCacheKey, $expireAt); if ($isGet) { return $expireAt; } while (1) { usleep(10); $time = time(); $oldExpire = $this->objRedis->get($lockCacheKey); if ($oldExpire >= $time) { continue; } $newExpire = $time + $timeout; $expireAt = $this->objRedis->getset($lockCacheKey, $newExpire); if ($oldExpire != $expireAt) { continue; } $isGet = $newExpire; break; } return $isGet; } /** * @desc 释放锁 * * @param key string | 加锁的字段 * @param newExpire int | 加锁的截止时间 * * @return bool | 是否释放成功 */ public function releaseLock($key, $newExpire) { $lockCacheKey = $this->getLockCacheKey($key); if ($newExpire >= time()) { return $this->objRedis->del($lockCacheKey); } return true; } }$start_time = microtime(true);$lock = new RedisLock($client);$key = "name";for ($i = 0; $i < 10000; $i++) { $newExpire = $lock->getLock($key); $num = $client->get($key); $num++; $client->set($key, $num); $lock->releaseLock($key, $newExpire);}$end_time = microtime(true);echo "花费时间 : ". ($end_time - $start_time) . "\n";
shell php setnx.php & php setnx.php& を実行すると、最終的に結果:
$ 花费时间 : 4.3004920482635 [2] + 72356 done php setnx.php# root @ ritoyan-virtual-pc in ~/PHP/redis-high-concurrency [20:23:41] $ 花费时间 : 4.4319710731506 [1] + 72355 done php setnx.php
同様に 1w 回ループし、usleep を削除し、incr を使用して直接増加します。これには約 2 秒かかります。
インカム取得時に usleep をキャンセルすると、時間が減らないどころか増加してしまうため、処理が無駄なループをしないように適切な usleep 設定を行う必要があります。
まとめ
簡単にまとめると、実際、redis は単一プロセスであり、コマンドがどれだけ実行されても 1 つずつ実行されるため、同時実行性の問題は発生しません。これを使用すると、get と set のペアなど、同時実行の問題が発生する可能性があります。
以上がRedis の最大同時実行数はどれくらいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

Redisのコア関数は、高性能のメモリ内データストレージおよび処理システムです。 1)高速データアクセス:Redisはデータをメモリに保存し、マイクロ秒レベルの読み取り速度と書き込み速度を提供します。 2)豊富なデータ構造:文字列、リスト、コレクションなどをサポートし、さまざまなアプリケーションシナリオに適応します。 3)永続性:RDBとAOFを介してディスクにデータを持続します。 4)サブスクリプションを公開:メッセージキューまたはリアルタイム通信システムで使用できます。

Redisは、次のようなさまざまなデータ構造をサポートしています。1。文字列、単一価値データの保存に適しています。 2。キューやスタックに適したリスト。 3.非重複データの保存に使用されるセット。 4。ランキングリストと優先キューに適した注文セット。 5。オブジェクトまたは構造化されたデータの保存に適したハッシュテーブル。

Redisカウンターは、Redisキー価値ペアストレージを使用して、カウンターキーの作成、カウントの増加、カウントの減少、カウントのリセット、およびカウントの取得など、カウント操作を実装するメカニズムです。 Redisカウンターの利点には、高速速度、高い並行性、耐久性、シンプルさと使いやすさが含まれます。ユーザーアクセスカウント、リアルタイムメトリック追跡、ゲームのスコアとランキング、注文処理などのシナリオで使用できます。

Redisコマンドラインツール(Redis-Cli)を使用して、次の手順を使用してRedisを管理および操作します。サーバーに接続し、アドレスとポートを指定します。コマンド名とパラメーターを使用して、コマンドをサーバーに送信します。ヘルプコマンドを使用して、特定のコマンドのヘルプ情報を表示します。 QUITコマンドを使用して、コマンドラインツールを終了します。

Redisクラスターモードは、シャードを介してRedisインスタンスを複数のサーバーに展開し、スケーラビリティと可用性を向上させます。構造の手順は次のとおりです。異なるポートで奇妙なRedisインスタンスを作成します。 3つのセンチネルインスタンスを作成し、Redisインスタンスを監視し、フェールオーバーを監視します。 Sentinel構成ファイルを構成し、Redisインスタンス情報とフェールオーバー設定の監視を追加します。 Redisインスタンス構成ファイルを構成し、クラスターモードを有効にし、クラスター情報ファイルパスを指定します。各Redisインスタンスの情報を含むnodes.confファイルを作成します。クラスターを起動し、CREATEコマンドを実行してクラスターを作成し、レプリカの数を指定します。クラスターにログインしてクラスター情報コマンドを実行して、クラスターステータスを確認します。作る

Redisのキューを読むには、キュー名を取得し、LPOPコマンドを使用して要素を読み、空のキューを処理する必要があります。特定の手順は次のとおりです。キュー名を取得します:「キュー:キュー」などの「キュー:」のプレフィックスで名前を付けます。 LPOPコマンドを使用します。キューのヘッドから要素を排出し、LPOP Queue:My-Queueなどの値を返します。空のキューの処理:キューが空の場合、LPOPはnilを返し、要素を読む前にキューが存在するかどうかを確認できます。

RedisクラスターでのZsetの使用:Zsetは、要素をスコアに関連付ける順序付けられたコレクションです。シャード戦略:a。ハッシュシャーディング:ZSTキーに従ってハッシュ値を分配します。 b。範囲シャード:要素スコアに従って範囲に分割し、各範囲を異なるノードに割り当てます。操作の読み取りと書き込み:a。読み取り操作:ZSetキーが現在のノードのシャードに属している場合、ローカルで処理されます。それ以外の場合は、対応するシャードにルーティングされます。 b。書き込み操作:Zsetキーを保持しているシャードに常にルーティングされます。

Redisデータをクリアする方法:Flushallコマンドを使用して、すべての重要な値をクリアします。 FlushDBコマンドを使用して、現在選択されているデータベースのキー値をクリアします。 [選択]を使用してデータベースを切り替え、FlushDBを使用して複数のデータベースをクリアします。 DELコマンドを使用して、特定のキーを削除します。 Redis-CLIツールを使用してデータをクリアします。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SecLists
SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

DVWA
Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、

ドリームウィーバー CS6
ビジュアル Web 開発ツール

WebStorm Mac版
便利なJavaScript開発ツール
