Heim  >  Artikel  >  Backend-Entwicklung  >  Laravel+Redis implementiert einfach die Verarbeitung von Warteschlangen mit hoher Parallelität, die Stresstests bestehen

Laravel+Redis implementiert einfach die Verarbeitung von Warteschlangen mit hoher Parallelität, die Stresstests bestehen

不言
不言Original
2018-07-06 10:37:078688Durchsuche

In diesem Artikel wird hauptsächlich die Verarbeitung von Warteschlangen mit hoher Parallelität vorgestellt, die den Stresstest bestehen. Jetzt kann ich ihn mit Ihnen teilen

Flash-Sale-Event

In allgemeinen Online-Einkaufszentren sind wir oft einigen Geschäftsbedingungen mit hoher Parallelität ausgesetzt, wie z. B. unseren gemeinsamen Flash-Sales und anderen Aktivitäten

In diesen Geschäften sind wir oft Sie müssen einige Anfragen bezüglich der Informationsfilterung und des Produktinventars bearbeiten.

Eine häufige Situation bei Anfragen besteht darin, dass derselbe Benutzer mehrere Anfragen stellt oder böswillige Angriffe sowie wiederholte Käufe einiger Bestellungen enthält.

Bezüglich des Lagerbestands müssen überverkaufte Konditionen berücksichtigt werden.

Simulieren wir eine einfache und nutzbare gleichzeitige Verarbeitung.

Gehe direkt zum Code

Codevorgang

1. Benutzeranfrage simulieren und den Benutzer in die Redis-Warteschlange schreiben

2 Der Benutzer fordert Informationen zur Verarbeitung an (Sie können in diesem Schritt weitere Verarbeitungen durchführen, eine Filterung anfordern, einen Rückkauf bestellen usw.)

3. Der Benutzer gibt eine Bestellung auf (Zahlung usw.) und reduziert den Lagerbestand. Im Folgenden werden zwei Methoden für die Verarbeitung verwendet. Eine davon verwendet die Single-Threaded-Atomic-Operation-Funktion in Redis, um das Programm linear zu betreiben und die Datenkonsistenz aufrechtzuerhalten .

Die andere Möglichkeit besteht darin, Transaktionen für den Betrieb zu verwenden, die je nach Geschäft angepasst werden können. Ich werde sie hier nicht einzeln beschreiben.

Die tatsächliche Geschäftssituation ist komplizierter, liegt aber eher an der Erweiterung grundlegender Ideen.

<?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;;
            //执行其他操作
        }
    }

}

AB-Test

Hier habe ich Apache Bench verwendet, um den Code zu testen

Aufruf

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

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

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

Hier haben wir 1200 Anfragen abgeschlossen, von denen 1199 als fehlgeschlagen markiert wurden. Dies liegt daran, dass Apache Bench den Inhalt der ersten Anforderungsantwort als Benchmark verwendet.

Wenn der Inhalt der nachfolgenden Anforderungsantwort inkonsistent ist, wird er als Fehler markiert Die Länge ist nicht korrekt und kann grundsätzlich ignoriert werden. Die Anfrage wurde tatsächlich abgeschlossen.

Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, er wird für das Studium aller hilfreich sein. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website.

Verwandte Empfehlungen:

Lösung für den Konfigurationsfehler von fastcgi_param in der Nginx-Konfigurationsdatei

Wie WordPress die Funktion wp_head() verwendet

Das obige ist der detaillierte Inhalt vonLaravel+Redis implementiert einfach die Verarbeitung von Warteschlangen mit hoher Parallelität, die Stresstests bestehen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn