Home > Backend Development > PHP Tutorial > laravel+Redis simply implements high-concurrency processing of queues that pass stress testing

laravel+Redis simply implements high-concurrency processing of queues that pass stress testing

不言
Release: 2023-04-02 16:26:01
Original
8727 people have browsed it

This article mainly introduces the high concurrency processing of laravel Redis's simple implementation of queue passing the stress test. It has a certain reference value. Now I share it with you. Friends in need can refer to it

flash sale activity

In general online malls, we are often exposed to some highly concurrent business conditions, such as our common flash sales and other activities.

In these businesses, we often need to process some request information Filtering and product inventory issues.

A common situation in requests is that the same user issues multiple requests or contains malicious attacks, as well as the repurchase of some orders.

In terms of inventory, you need to consider the situation of oversold.

Let’s simulate a simple and available concurrent processing.

Go directly to the code

Code process

1. Simulate user request and write the user into the redis queue

2. Take out one from the user Request information for processing (you can do more processing in this step, request filtering, order repurchase, etc.)

3. The user places an order (payment, etc.) to reduce inventory. Two methods are used for processing below. One uses the single-threaded atomic operation feature in Redis to make the program operate linearly and maintain data consistency.

The other is to use transactions for operations, which can be adjusted according to the business. I will not describe them one by one here.

The actual business situation is more complicated, but it is more due to the expansion of basic ideas.

<?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(&#39;user_list&#39;);     ///取出一个用户     ///     ///一些对请求的处理     ///
        if (!is_null($num)) {       ///将需要秒杀的商品放入队列中
            $this->AddGoodToRedis(1);       ///需要注意的是我们如果写的是秒杀活动的话,需要做进一步的处理,例如设置商品队列的缓存等方式,这里就实现了       ///下订单减库存
            $this->GetGood(1,$num);
        }
    }

    public function DoLog($log) {
        file_put_contents("test.txt", $log . &#39;\r\n&#39;, FILE_APPEND);
    }

    /**
     * 重点在于Redis中存储数据的单线程的原子性,!!!无论多少请求同时执行这个方法,依然是依次执行的!!!!!
     * 这种方式性能较高,并且确保了对数据库的单一操作,但容错率极低,一旦出现未可预知的错误会导致数据混乱;
     */
    public function GetGood($id,$user_id) {
        $good = \App\Goods::find($id);
        if (is_null($good)) {
            $this->DoLog("商品不存在");
            return &#39;error&#39;;
        }

        ///去除一个库存
        $num = Redis::lpop(&#39;good_list&#39;);
        ///判断取出库存是否成功
        if (!$num) {
            $this->DoLog("取出库存失败");
            return &#39;error&#39;;
        } else {
            ///创建订单
            $order = new \App\Order();
            $order->good_id = $good->good_id;
            $order->user_id = $user_id;
            $order->save();

            $ok = DB::table(&#39;Goods&#39;)
                    ->where(&#39;good_id&#39;, $good->good_id)
                    ->decrement(&#39;good_left&#39;, $num);
            if (!$ok) {
                $this->DoLog("库存减少失败");
                return;
            }
            echo &#39;下单成功&#39;;
        }
    }

    public function AddUserToRedis() {
        $user_count = 1000;
        for ($i = 0; $i < $user_count; $i++) {
            try {
                Redis::lpush(&#39;user_list&#39;, rand(1, 10000));
            } catch (Exception $e) {
                echo $e->getMessage();
            }
        }
        $user_num = Redis::llen(&#39;user_list&#39;);
        dd($user_num);
    }

    public function AddGoodToRedis($id) {

        $good = \App\Goods::find($id);
        if ($good == null) {
            $this->DoLog("商品不存在");
            return;
        }

        ///获取当前redis中的库存。
        $left = Redis::llen(&#39;good_list&#39;);
        ///获取到当前实际存在的库存,库存减去Redis中剩余的数量。
        $count = $good->good_left - $left;
        //        dd($good->good_left);
        ///将实际库存添加到Redis中
        for ($i = 0; $i < $count; $i++) {
            Redis::lpush(&#39;good_list&#39;, 1);
        }
        echo Redis::llen(&#39;good_list&#39;);
    }

    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([&#39;goods_id&#39; => $id])->sharedLock()->first();
            //对商品表进行加锁(悲观锁)
            if ($good->good_left) {
                $ok = DB::table(&#39;Goods&#39;)
                        ->where(&#39;good_id&#39;, $good->good_id)
                        ->decrement(&#39;good_left&#39;, $num);
                if ($ok) {
                    // 提交事务
                    DB::commit();
                    echo&#39;下单成功&#39;;
                } else {
                    $this->DoLog("库存减少失败");
                }
            } else {
                $this->DoLog("库存剩余为空");
            }
            DB::rollBack();
            return &#39;error&#39;;
        } catch (Exception $e) {
            // 出错回滚数据
            DB::rollBack();
            return &#39;error&#39;;
            //执行其他操作
        }
    }

}
Copy after login

AB test

Here I used apache bench to test the code

Calling the code in

AddUserToRedis()
方法将一堆请求用户放进redis队列中
先看库存
Copy after login

这里设置了一千个库存
开始压力测试
Copy after login

向我们的程序发起1200个请求,并发量为200
Copy after login

Here we completed 1200 requests, of which 1199 were marked as failed. This is because apache bench will use the content of the first request response as the benchmark.

If the content of subsequent request responses is inconsistent, it will be marked as a failure. If you see that the number of marks in length is not correct, it can basically be ignored. We The request was actually completed.

The above is the entire content of this article. I hope it will be helpful to everyone's study. For more related content, please pay attention to the PHP Chinese website!

Related recommendations:

Solution to the configuration error of fastcgi_param in the nginx configuration file

How to use the wp_head() function in wordpress

The above is the detailed content of laravel+Redis simply implements high-concurrency processing of queues that pass stress testing. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template