この記事では、laravel Redisのストレステストを通過するキューの簡単な実装の高同時処理を中心に紹介します。一定の参考値があります。共有します。必要な友人は参考にしてください。
一般的なオンライン モールでは、一般的なフラッシュ セールやその他の活動など、高度に並行したビジネス状況にさらされることがよくあります。一部のリクエスト情報 フィルタリングと製品在庫の問題。
リクエストでよくある状況は、同じユーザーが複数のリクエストを発行したり、悪意のある攻撃が含まれたり、一部の注文を再購入したりすることです。
在庫に関しては、売れすぎの状況を考慮する必要があります。
シンプルで利用可能な同時処理をシミュレートしてみましょう。
コードに直接移動します
コード プロセス
2. から 1 つを取り出しますユーザー 処理する情報を要求します (このステップでは、フィルタリング要求、再購入注文など、さらに多くの処理を行うことができます)
3. ユーザーは、在庫を減らすために注文 (支払いなど) を行います。以下の処理には 2 つの方法が使用されます
1 つは、Redis のシングルスレッド アトミック操作機能を使用して、プログラムを線形に動作させ、データの一貫性を維持します。もう 1 つは、業務に応じて調整できるトランザクションを使用した運用です。ここでは 1 つずつ説明しません。
実際のビジネス状況はさらに複雑ですが、それは基本的な考え方の拡張によるものです。<?php namespace App\Http\Controllers\SecKill; use App\Http\Controllers\Controller; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Redis; class SecKillControllers extends Controller { public function SecKillTest() { ///在此之前我们已经将一千过用户写入了redis中了 $num = Redis::lpop('user_list'); ///取出一个用户 /// ///一些对请求的处理 /// if (!is_null($num)) { ///将需要秒杀的商品放入队列中 $this->AddGoodToRedis(1); ///需要注意的是我们如果写的是秒杀活动的话,需要做进一步的处理,例如设置商品队列的缓存等方式,这里就实现了 ///下订单减库存 $this->GetGood(1,$num); } } public function DoLog($log) { file_put_contents("test.txt", $log . '\r\n', FILE_APPEND); } /** * 重点在于Redis中存储数据的单线程的原子性,!!!无论多少请求同时执行这个方法,依然是依次执行的!!!!! * 这种方式性能较高,并且确保了对数据库的单一操作,但容错率极低,一旦出现未可预知的错误会导致数据混乱; */ public function GetGood($id,$user_id) { $good = \App\Goods::find($id); if (is_null($good)) { $this->DoLog("商品不存在"); return 'error'; } ///去除一个库存 $num = Redis::lpop('good_list'); ///判断取出库存是否成功 if (!$num) { $this->DoLog("取出库存失败"); return 'error'; } else { ///创建订单 $order = new \App\Order(); $order->good_id = $good->good_id; $order->user_id = $user_id; $order->save(); $ok = DB::table('Goods') ->where('good_id', $good->good_id) ->decrement('good_left', $num); if (!$ok) { $this->DoLog("库存减少失败"); return; } echo '下单成功'; } } public function AddUserToRedis() { $user_count = 1000; for ($i = 0; $i < $user_count; $i++) { try { Redis::lpush('user_list', rand(1, 10000)); } catch (Exception $e) { echo $e->getMessage(); } } $user_num = Redis::llen('user_list'); dd($user_num); } public function AddGoodToRedis($id) { $good = \App\Goods::find($id); if ($good == null) { $this->DoLog("商品不存在"); return; } ///获取当前redis中的库存。 $left = Redis::llen('good_list'); ///获取到当前实际存在的库存,库存减去Redis中剩余的数量。 $count = $good->good_left - $left; // dd($good->good_left); ///将实际库存添加到Redis中 for ($i = 0; $i < $count; $i++) { Redis::lpush('good_list', 1); } echo Redis::llen('good_list'); } public function getGood4Mysql($id) { DB::beginTransaction(); ///开启事务对库存以及下单进行处理 try { ///创建订单 $order = new \App\Order(); $order->good_id = $good->good_id; $order->user_id = rand(1, 1000); $order->save(); $good = DB::table("goods")->where(['goods_id' => $id])->sharedLock()->first(); //对商品表进行加锁(悲观锁) if ($good->good_left) { $ok = DB::table('Goods') ->where('good_id', $good->good_id) ->decrement('good_left', $num); if ($ok) { // 提交事务 DB::commit(); echo'下单成功'; } else { $this->DoLog("库存减少失败"); } } else { $this->DoLog("库存剩余为空"); } DB::rollBack(); return 'error'; } catch (Exception $e) { // 出错回滚数据 DB::rollBack(); return 'error'; //执行其他操作 } } }AB テストここでは、Apache ベンチを使用してコードをテストしましたコードを
AddUserToRedis() 方法将一堆请求用户放进redis队列中 先看库存
这里设置了一千个库存 开始压力测试
向我们的程序发起1200个请求,并发量为200
ここでは 1200 件のリクエストを完了し、そのうち 1199 件が失敗としてマークされました。これは、Apache ベンチが最初のリクエスト応答の内容をベンチマークとして使用するためです。
後続のリクエスト応答の内容が矛盾している場合、失敗としてマークされます。マークの数が表示された場合は、失敗としてマークされます。長さが正しくありませんが、基本的には無視してかまいません。リクエストは実際に完了しました。 上記がこの記事の全内容です。皆様の学習に少しでもお役に立てれば幸いです。その他の関連コンテンツについては、PHP 中国語 Web サイトをご覧ください。 関連する推奨事項:nginx 設定ファイルの fastcgi_param の設定エラーの解決策
以上がlaravel+Redis はストレステストに合格したキューの高同時実行処理を実装するだけですの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。