search
HomePHP FrameworkLaravelDesign of flash kill system

Design of flash kill system

Jun 25, 2019 pm 03:06 PM
Flash kill systemdesign

Design of flash kill system

I have written an article before about the design of the promotion system and mentioned flash sales/direct discounts/juhuasuan, but in actual work, I have never really done a flash sale system, so I made a hypothetical A simple flash sale system was created to “quench the craving”, and the promotional ideas still followed the design of the previous article.

Analysis

A large amount of traffic flows in during the flash sale, and queries are frequently refreshed before the flash sale starts. If a large amount of traffic hits the database instantly, it is very easy to cause the database to collapse. Therefore, the main job of the flash sale is to filter the traffic layer by layer and finally allow as little and as smooth traffic as possible to enter the database.

Usual flash sales involve a large number of users snapping up a small amount of goods. For needs like this, simply caching the inventory can filter a large amount of traffic before actually creating an order.

But but but, it doesn’t seem to be challenging at all! To increase the difficulty a little bit, suppose our flash sale is like grabbing Xiaomi mobile phones, what if 1 million people grab 100,000 mobile phones? Queuing up during Xiaomi rush sales is one method (although the experience is not very good), and our flash sale design will be based on this idea in the future.

When it comes to Xiaomi, I have to say that it made me know what "luck is also a part of strength!"

Front-end current limiting method: random(0, 1) ? axios.post: wait(30, 'All finished!')

The following is an analysis of some code details. In principle, the original business logic should be changed as little as possible.

In addition, there are no advanced gameplay such as service circuit breaker and multi-level caching in the following article, just a relatively simple business design.

Start

The operator adds a variant to the flash sale promotion in the background and sets the flash sale inventory/flash sale discount rate/start time and end time, etc. We can get something like Such data.

// promotion_variant (促销和变体表「sku」的一个中间表)
{
    'id': 1,
    'variant_id': 1,
    'promotion_id': 1,
    'promotion_type': 'snap_up',
    'discount_rate': 0.5,
    'stock': 100, // 秒杀库存
    'sold': 0, // 秒杀销量
    'quantity_limit': 1, // 限购
    'enabled': 1,
    'product_id': 1,
    'rest': {
        variant_name: 'xxx', // 秒杀期间变体名称
        image: 'xxx', // 秒杀期间变体图片
    }
}
The first thing is to cache the promotion information after the flash sale promotion is successfully created

# PromotionVariantObserver.php

public function saved(PromotionVariant $promotionVariant)
{
  if ($promotionVariant->promotion_type === PromotionType::SNAP_UP) {
    $seconds = $promotionVariant->ended_at->getTimestamp() - time();

    \Cache::put(
      "promotion_variants:$promotionVariant->id",
      $promotionVariant,
      $seconds
    );
  }
}
Order placement

Existing order interface, after receiving the variant information , we don’t know which of the current variant list is participating in the promotion. The judgment operation here requires a large number of database query operations.

So here we write a new API for flash sale. When the front end detects that the current variant is in flash sale promotion, it switches to the flash sale ordering API.

Of course, we still use the original order api, and there is no problem in passing a logo on the front end.

One thing that needs explanation is that placing an order is usually divided into two steps

The first step is to "checkout (checkout)" to generate a checkout order. The user can select the address for the checkout order. , coupons, payment methods, etc.

The second step is "confirm". At this time, the order will become confirmed, the inventory will be locked, and the user can make payment. Usually if payment is not made within the stipulated time, the order is canceled and the inventory is unlocked.

So in the first step, users will be filtered and queued to prevent subsequent operations such as selecting addresses and coupons from impacting the database.

# CheckoutController.php

/**
 * @param Request $request
 * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
 * @throws StockException
 */
public function snapUpCheckout(Request $request)
{
    $variantId = $request->input('variant_id');
    $quantity = $request->input('quantity', 1);

    // 加锁防止超卖
    $lock = \Cache::lock('snap_up:' . $variantId, 10);

    try {
        // 未获取锁的消费者将阻塞在这里
        $lock->block(10);

        $promotionVariant = \Cache::get('promotion_variants:' . $variantId);

        if ($promotionVariant->quantity release();

            throw new StockException('库存不足');
        }

        $promotionVariant->quantity -= $quantity;

        $seconds = $promotionVariant->ended_at->getTimestamp() - time();
        \Cache::put(
            "promotion_variants:$promotionVariant->id",
            $promotionVariant,
            $seconds
        );

    } catch (LockTimeoutException $e) {
        throw new StockException('库存不足');

    } finally {
        optional($lock)->release();
    }

    CheckoutOrder::dispatch([
        'user_id' => \Auth::id(),
        'variant_id' => $variantId,
        'quantity' => $quantity
    ]);

    return response('结账订单创建中');
}
You can see that there is no database operation involved in the flash sale checkout api. And the task of creating an order is distributed to the queue through dispatch, and users wait in line for the corresponding time in the order of entering the queue.

The question now is, how to notify the client after the order is successfully created?

Client Notification

The solution here is nothing more than polling or websocket. Here we choose websocket that consumes less server performance and use laravel-echo provided by laravel ( laravel-echo-server ). When the user's flash sale is successful, the front-end and back-end establish a websocket link. After the back-end checkout order is successfully created, the front-end is notified to proceed with the next step.

Backend

The next thing the backend needs to do is to send an "OrderChecked" event to the corresponding channel of the websocket to indicate the checkout after the order in the "CheckoutOrder" Job is successfully created. The order has been created and the user can proceed to the next step.

# Job/CheckoutOrder.php

// ...

public function handle()
{
  // 创建结账订单
  // ...

  // 通知客户端. websocket 编程本身就是以事件为导向的,和 laravel 的 event 非常契合。
  event(new OrderChecked($this->data->user_id));
}

// ...
# Event/OrderChecked.php

class OrderChecked implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    private $userId;

    /**
     * Create a new event instance.
     *
     * @param $userId
     */
    public function __construct($userId)
    {
        $this->userId = $userId;
    }

    /**
     * App.User.{id} 是 laravel 初始化时,默认的私有频道,直接使用即可
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('App.User.' . $this->userId);
    }
}
Assume that the current user ID of the purchase is 1. To summarize, the above code is to push an "OrderChecked" event to the private channel "App.User.1" of websocket.

Front end

The code below is the default project initialized using the vue-cli tool.

// views/products/show.vue

<script>

import Echo from &#39;laravel-echo&#39;
import io from &#39;socket.io-client&#39;
window.io = io

export default {
  name: &#39;App&#39;,
  methods: {
    async snapUpCheckout () {
      try {
        // await post -> snap-up-checkout
        this.toCheckout()
      } catch (error) {
        // 秒杀失败
      }
    },
    toCheckout () {
      // 建立 websocket 连接
      const echo = new Echo({
        broadcaster: &#39;socket.io&#39;,
        host: &#39;http://api.e-commerce.test:6001&#39;,
        auth: {
          headers: {
            Authorization: &#39;Bearer &#39; + this.store.auth.token
          }
        }
      })

      // 监听私有频道 App.User.{id} 的 OrderChecked 事件
      echo.private(&#39;App.User.&#39; + this.store.user.id).listen(&#39;OrderChecked&#39;, (e) => {
        // redirect to checkou page
      })
    }
  }
}
</script>
One thing to note when using laravel-echo is that due to the use of a private channel, laravel-echo will send a post request to the server api

/broadcasting/auth by default for authentication. . However, because the front-end and back-end categories are used instead of blade templates, we cannot easily obtain the csrf token and session to perform some necessary authentication.

So you need to slightly modify the configuration of broadcast and laravel-echo-server

# BroadcastServiceProvider.php

public function boot()
{
  // 将认证路由改为 /api/broadcasting/auth 从而避免 csrf 验证
  // 添加中间件 auth:api (jwt 使用 api.auth) 进行身份验证,避免访问 session ,并使 Auth::user() 生效。
  Broadcast::routes(["prefix" => "api", "middleware" => ["auth:api"]]);

  require base_path('routes/channels.php');
}
// laravel-echo-server.json

// 认证路由添加 api 前缀,与上面的修改对应
"authEndpoint": "/api/broadcasting/auth"
Inventory unlocking

When the "inventory" has been locked for this order, if the user When you disconnect the websocket or leave for a long time, you need to unlock the inventory to prevent meaningless occupation of the inventory.

The inventory here refers to cache inventory, not database inventory. This is because even if the order is successfully created at this time, it is still in checkout status (no address, payment method, etc. have been selected) and is not visible in the personal center. The database inventory will be locked only when the user confirms the order.

So the ideal implementation here is to return the locked inventory of the order after the user disconnects the websocket connection. After the checkout order is created, a delay queue is created to return inventory to orders that have not been operated for a long time.

But, laravel-echo is a broadcast system and does not provide callbacks for client disconnect events. There are some methods to implement client events that laravel listens to, such as adding hooks to laravel-echo-server. Notify laravel, but the implementation of laravel-echo-server needs to be modified. I won’t go into details here. The focus is to provide flash sale ideas.

Summary

Design of flash kill system

The above picture is a logical summary of the flash kill system. At this point, the entire flash sale process is over. Generally speaking, the amount of code is not much and the logic is relatively simple.

As can be seen from the figure, in the entire process, it interacts with mysql only in the queue. Through the current limiting of the queue, it can adapt to the endurance of mysql to the maximum extent. When mysql performance is sufficient, users can consume orders through a large number of queues at the same time, and the user will not be aware of the queuing process at all.

If you have any questions or better ideas, please leave a message for discussion~

For more Laravel-related technical articles, please visit the Laravel Tutorial column to learn!

The above is the detailed content of Design of flash kill system. For more information, please follow other related articles on the PHP Chinese website!

Statement
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
Laravel (PHP) vs. Python: Weighing the Pros and ConsLaravel (PHP) vs. Python: Weighing the Pros and ConsApr 17, 2025 am 12:18 AM

Laravel is suitable for building web applications quickly, while Python is suitable for a wider range of application scenarios. 1.Laravel provides EloquentORM, Blade template engine and Artisan tools to simplify web development. 2. Python is known for its dynamic types, rich standard library and third-party ecosystem, and is suitable for Web development, data science and other fields.

Laravel vs. Python: Comparing Frameworks and LibrariesLaravel vs. Python: Comparing Frameworks and LibrariesApr 17, 2025 am 12:16 AM

Laravel and Python each have their own advantages: Laravel is suitable for quickly building feature-rich web applications, and Python performs well in the fields of data science and general programming. 1.Laravel provides EloquentORM and Blade template engines, suitable for building modern web applications. 2. Python has a rich standard library and third-party library, and Django and Flask frameworks meet different development needs.

Laravel's Purpose: Building Robust and Elegant Web ApplicationsLaravel's Purpose: Building Robust and Elegant Web ApplicationsApr 17, 2025 am 12:13 AM

Laravel is worth choosing because it can make the code structure clear and the development process more artistic. 1) Laravel is based on PHP, follows the MVC architecture, and simplifies web development. 2) Its core functions such as EloquentORM, Artisan tools and Blade templates enhance the elegance and robustness of development. 3) Through routing, controllers, models and views, developers can efficiently build applications. 4) Advanced functions such as queue and event monitoring further improve application performance.

Laravel: Primarily a Backend Framework ExplainedLaravel: Primarily a Backend Framework ExplainedApr 17, 2025 am 12:02 AM

Laravel is not only a back-end framework, but also a complete web development solution. It provides powerful back-end functions, such as routing, database operations, user authentication, etc., and supports front-end development, improving the development efficiency of the entire web application.

Laravel (PHP) vs. Python: Understanding Key DifferencesLaravel (PHP) vs. Python: Understanding Key DifferencesApr 17, 2025 am 12:01 AM

Laravel is suitable for web development, Python is suitable for data science and rapid prototyping. 1.Laravel is based on PHP and provides elegant syntax and rich functions, such as EloquentORM. 2. Python is known for its simplicity, widely used in Web development and data science, and has a rich library ecosystem.

Laravel in Action: Real-World Applications and ExamplesLaravel in Action: Real-World Applications and ExamplesApr 16, 2025 am 12:02 AM

Laravelcanbeeffectivelyusedinreal-worldapplicationsforbuildingscalablewebsolutions.1)ItsimplifiesCRUDoperationsinRESTfulAPIsusingEloquentORM.2)Laravel'secosystem,includingtoolslikeNova,enhancesdevelopment.3)Itaddressesperformancewithcachingsystems,en

Laravel's Primary Function: Backend DevelopmentLaravel's Primary Function: Backend DevelopmentApr 15, 2025 am 12:14 AM

Laravel's core functions in back-end development include routing system, EloquentORM, migration function, cache system and queue system. 1. The routing system simplifies URL mapping and improves code organization and maintenance. 2.EloquentORM provides object-oriented data operations to improve development efficiency. 3. The migration function manages the database structure through version control to ensure consistency. 4. The cache system reduces database queries and improves response speed. 5. The queue system effectively processes large-scale data, avoid blocking user requests, and improve overall performance.

Laravel's Backend Capabilities: Databases, Logic, and MoreLaravel's Backend Capabilities: Databases, Logic, and MoreApr 14, 2025 am 12:04 AM

Laravel performs strongly in back-end development, simplifying database operations through EloquentORM, controllers and service classes handle business logic, and providing queues, events and other functions. 1) EloquentORM maps database tables through the model to simplify query. 2) Business logic is processed in controllers and service classes to improve modularity and maintainability. 3) Other functions such as queue systems help to handle complex needs.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Chat Commands and How to Use Them
1 months agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

EditPlus Chinese cracked version

EditPlus Chinese cracked version

Small size, syntax highlighting, does not support code prompt function

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment