recherche
Maisoncadre phpLaravelConception du système Flash Kill

Conception du système Flash Kill

Jun 25, 2019 pm 03:06 PM
秒杀系统设计

Conception du système Flash Kill

J'ai déjà écrit un article sur la conception du système de promotion et mentionné les ventes flash/remises directes/juhuasuan, mais dans le travail réel, je n'ai jamais vraiment fait de système de vente flash, donc J'ai fait une hypothèse. Un simple système de vente flash a été créé pour « étancher l'envie », et les idées promotionnelles suivaient toujours la conception de l'article précédent.

Analyse

Une grande quantité de trafic afflue pendant la vente flash. La requête est fréquemment actualisée avant le début de la vente flash. Si une grande quantité de trafic atteint instantanément la base de données, c'est très. facile de provoquer l'effondrement de la base de données. Par conséquent, le travail principal de la vente flash est de filtrer le trafic couche par couche et enfin de permettre au trafic le moins et doux possible d'entrer dans la base de données.

Les ventes flash habituelles impliquent qu'un grand nombre d'utilisateurs s'emparent d'une petite quantité de marchandises. Pour des besoins comme celui-ci, la simple mise en cache de l'inventaire peut filtrer une grande quantité de trafic avant de créer une commande.

Mais mais mais, cela ne semble pas du tout être un défi ! Pour augmenter un peu la difficulté, supposons que notre vente flash soit comme s'emparer de téléphones portables Xiaomi, et si 1 million de personnes s'emparaient de 100 000 téléphones portables ? Faire la queue pendant les ventes urgentes de Xiaomi est une méthode (même si l'expérience n'est pas très bonne), et la conception de notre vente flash sera basée sur cette idée à l'avenir.

En ce qui concerne Xiaomi, je dois dire que cela m'a fait comprendre que « la chance fait aussi partie de la force ! »

Méthode de limitation de courant frontale : aléatoire ( 0, 1) ? axios.post : wait(30, 'Tout est terminé !')

Commençons par l'analyse de certains détails du code. En principe, la logique métier d'origine devrait être modifiée le moins possible. que possible. De plus, il n'y a pas de gameplay avancé tel qu'un disjoncteur de service ou une mise en cache multi-niveaux dans l'article suivant, il s'agit simplement d'une conception commerciale relativement simple.

Démarrer

L'opérateur ajoute une variante à la promotion de la vente flash en arrière-plan et définit l'inventaire de la vente flash/le taux de remise de la vente flash/l'heure de début et l'heure de fin, etc. peut obtenir quelque chose comme de telles données.

// 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', // 秒杀期间变体图片
    }
}

La première chose est de mettre en cache les informations de promotion une fois la promotion de vente flash créée avec succès

# 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
    );
  }
}

Passer une commande

L'interface de commande existante, après avoir reçu les informations de variante , nous ne savons pas laquelle des listes de variantes actuelles participe à la promotion. L'opération de jugement nécessite ici un grand nombre d'opérations de requête de base de données.

Nous écrivons donc ici une nouvelle API pour la vente flash. Lorsque le front-end détecte que la variante actuelle est en promotion de vente flash, il passe à l'API de commande de vente flash.

Bien sûr, nous utilisons toujours l'API de commande d'origine, et il n'y a aucun problème à passer un logo sur le front-end.

Un point qui nécessite une explication est que le passage d'une commande est généralement divisé en deux étapes

La première étape consiste à "passer à la caisse" pour générer une commande de paiement. adresse pour la commande, coupons, modes de paiement, etc.

La deuxième étape est "confirmer". A ce moment, la commande sera confirmée, l'inventaire sera verrouillé et l'utilisateur pourra effectuer le paiement. Généralement si le paiement n'est pas effectué dans le délai imparti, la commande est annulée et l'inventaire est débloqué.

Ainsi, dans un premier temps, les utilisateurs seront filtrés et mis en file d'attente pour empêcher les opérations ultérieures telles que la sélection d'adresses et de coupons d'avoir un impact sur la base de données.

# 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('结账订单创建中');
}

Vous pouvez voir qu'aucune opération de base de données n'est impliquée dans l'API de paiement de la vente flash. Et la tâche de création d'une commande est répartie dans la file d'attente via la répartition, et les utilisateurs font la queue pendant le temps correspondant dans l'ordre d'entrée dans la file d'attente.

La question est maintenant de savoir comment informer le client une fois la commande créée avec succès ?

Notification client

La solution ici n'est rien de plus qu'un sondage ou un websocket. Ici, nous choisissons un websocket qui consomme moins de performances du serveur et utilisons laravel-echo fourni par laravel ( laravel-echo-server ). Lorsque la vente flash de l'utilisateur réussit, le front-end et le back-end établissent un lien websocket. Une fois la commande de paiement back-end créée avec succès, le front-end est informé de passer à l'étape suivante.

Backend

La prochaine chose que le backend doit faire est d'envoyer un événement "OrderChecked" au canal correspondant du websocket pour indiquer que la commande est effectuée après que la commande dans le travail "CheckoutOrder" soit créé avec succès. La commande a été créée et l'utilisateur peut passer à l'étape suivante.

# 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);
    }
}

Supposons que l'ID utilisateur qui se précipite actuellement pour acheter est 1. Pour résumer, le code ci-dessus consiste à transmettre un événement "OrderChecked" au canal privé "App.User.1" de websocket.

Front end

Le code ci-dessous est le projet par défaut initialisé à l'aide de l'outil vue-cli.

// 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>

Une chose à noter lors de l'utilisation de laravel-echo est qu'en raison de l'utilisation d'un canal privé, laravel-echo enverra une demande de publication à l'API du serveur /broadcasting/auth par défaut pour l'authentification. Cependant, étant donné que les catégories front-end et back-end sont utilisées à la place des modèles de lame, nous ne pouvons pas facilement obtenir le jeton csrf et la session pour effectuer certaines authentifications nécessaires.

La configuration de la diffusion et de laravel-echo-server doit donc être légèrement modifiée

# 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"

Déverrouillage de l'inventaire

Lorsque "l'inventaire" a été verrouillé pour cette commande, si l'utilisateur Lorsque vous déconnectez le websocket ou que vous partez pendant une longue période, vous devez déverrouiller l'inventaire pour éviter une occupation inutile de l'inventaire.

L'inventaire ici fait référence à l'inventaire du cache, et non à l'inventaire de la base de données. En effet, à ce moment, même si la commande est créée avec succès, elle est toujours en statut de paiement (aucune adresse, aucun mode de paiement, etc. n'a été sélectionné) et n'est pas visible dans l'espace personnel. L'inventaire de la base de données ne sera verrouillé que lorsque l'utilisateur confirmera la commande.

La mise en œuvre idéale ici est donc de renvoyer l'inventaire verrouillé pour cette commande après que l'utilisateur a déconnecté la connexion Websocket. Une fois la commande de paiement créée, une file d'attente différée est créée pour renvoyer le stock aux commandes qui n'ont pas été traitées depuis longtemps.

Mais laravel-echo est un système de diffusion et ne fournit pas de rappels pour les événements de déconnexion client. Il existe certaines méthodes pour implémenter les événements client que laravel écoute, comme l'ajout de hooks à laravel-echo-server Notify. laravel, mais l'implémentation de laravel-echo-server doit être modifiée. Je n'entrerai pas dans les détails ici. L'objectif est de fournir des idées de vente flash.

Résumé

Conception du système Flash Kill

L'image ci-dessus est le résumé logique du système Flash Kill. À ce stade, tout le processus de vente flash est terminé. De manière générale, la quantité de code n'est pas grande et la logique est relativement simple.

Comme le montre la figure, dans l'ensemble du processus, ce n'est que dans la file d'attente qu'il interagira avec MySQL Grâce à la limitation actuelle de la file d'attente, il peut s'adapter à l'endurance de MySQL. l'étendue maximale. Lorsque les performances de MySQL sont suffisantes, les utilisateurs peuvent consommer des commandes via un grand nombre de files d'attente en même temps, et l'utilisateur ne sera pas du tout conscient du processus de mise en file d'attente.

Si vous avez des questions ou de meilleures idées, veuillez laisser un message pour discussion~

Pour plus d'articles techniques liés à Laravel, veuillez visiter la colonne Tutoriel Laravel pour apprendre !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Développement complet avec Laravel: Gestion des API et Logic FrontendDéveloppement complet avec Laravel: Gestion des API et Logic FrontendApr 28, 2025 am 12:22 AM

Dans le développement de Laravel complet, les méthodes efficaces pour gérer les API et la logique frontale comprennent: 1) l'utilisation des contrôleurs Restful et des API de gestion du routage des ressources; 2) Traitement de la logique frontale via les modèles de lame et Vue.js ou réagir; 3) Optimiser les performances via le versioning et la pagination de l'API; 4) Maintenir la séparation de la logique back-end et frontal pour assurer la maintenabilité et l'évolutivité.

Perdu dans la traduction: nuances culturelles et malentendus dans les équipes distribuéesPerdu dans la traduction: nuances culturelles et malentendus dans les équipes distribuéesApr 28, 2025 am 12:22 AM

TOTACKLECULURALIDRICACIESInSISTRIBITEDTEAMS, FOSTERANENVIRONMENTMEMENTEBRATING DIFFERENCES, BEMINDFULOF COMMUNICATION, ANDUSETOOLSFORCLARITY.1) ImplementCulturArexchangeSessionStosharestories ettradition.2)

Mesurer la connexion: analyse et informations pour l'efficacité de la communication à distanceMesurer la connexion: analyse et informations pour l'efficacité de la communication à distanceApr 28, 2025 am 12:16 AM

Tassesstheefficacitéofremotecommunication, focuson: 1) EngagementMetricsLikeMessagefrequencyAndRresponsetime, 2) SentimentAnalystogaugeemotionaltone, 3) se réunir à la Communication de la Communication et 4) NetworkAnalystoundComunsicationPa

Risques de sécurité dans les équipes distribuées: protéger les données dans un monde éloignéRisques de sécurité dans les équipes distribuées: protéger les données dans un monde éloignéApr 28, 2025 am 12:11 AM

TOPROTECTSENSITIVEDATAINDistributedTeams, ImplementAmulti-FacetedApproach: 1) Useend-to-EntentementForsEcureCommunication, 2) ApplyRole-BasedAccessControl (RBAC) TomanagePerMissions, 3) EncryptDataatrestwithKemberSools, and4) Fosterasecurecust

Au-delà de l'e-mail: explorer les plateformes de communication modernes pour une collaboration à distanceAu-delà de l'e-mail: explorer les plateformes de communication modernes pour une collaboration à distanceApr 28, 2025 am 12:03 AM

Non, envoyez un e-mail à la plate-forme moderne, des équipes Microsoft, un zoom, un asana, une communication et une communication en temps-temps et une gestion de projet et une gestion de la gestion de projet et un intérêt intérimaire.

Édition de documents collaboratifs: rationalisation du flux de travail dans les équipes distribuéesÉdition de documents collaboratifs: rationalisation du flux de travail dans les équipes distribuéesApr 27, 2025 am 12:21 AM

L'édition de documents collaborative est un outil efficace pour les équipes distribuées afin d'optimiser leurs workflows. Il améliore la communication et les progrès du projet grâce à des boucles de collaboration et de rétroaction en temps réel, et les outils communs incluent Google Docs, Microsoft Teams et Notion. Faites attention à des défis tels que le contrôle des versions et la courbe d'apprentissage lorsque vous l'utilisez.

Combien de temps la version Laravel précédente sera-t-elle prise en charge?Combien de temps la version Laravel précédente sera-t-elle prise en charge?Apr 27, 2025 am 12:17 AM

ThepreviousVersionofLaraveLissupported withbugfixesforsixmonthsandSecurityFixesForoneyEarfteranEwmaJorversion'srelease.Croite-compritsThisSupporttimelineScricialForPlanningUpgrades, assurant la mise en place de la stabilité et la mise en place des éléments et les économies de lamence, et la stabilité et la conduite de la rémunération et la santé

Tirer parti des fonctionnalités de Laravel pour le développement du frontend et du backendTirer parti des fonctionnalités de Laravel pour le développement du frontend et du backendApr 27, 2025 am 12:16 AM

LaravelCanBeefectively UsedForBothFronttendandBackendDevelopment.1) Backend: Utilizelaravel'SeloventormforsImpplifiedDatabaseInteractions.2) Frontend: LefetherBlatemplateForCleanhtmland Integratevue.jsfordynamicsPas, STANDSEANSHEST-BACKENDINTEG.

See all articles

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Outils chauds

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

mPDF

mPDF

mPDF est une bibliothèque PHP qui peut générer des fichiers PDF à partir de HTML encodé en UTF-8. L'auteur original, Ian Back, a écrit mPDF pour générer des fichiers PDF « à la volée » depuis son site Web et gérer différentes langues. Il est plus lent et produit des fichiers plus volumineux lors de l'utilisation de polices Unicode que les scripts originaux comme HTML2FPDF, mais prend en charge les styles CSS, etc. et présente de nombreuses améliorations. Prend en charge presque toutes les langues, y compris RTL (arabe et hébreu) ​​et CJK (chinois, japonais et coréen). Prend en charge les éléments imbriqués au niveau du bloc (tels que P, DIV),

DVWA

DVWA

Damn Vulnerable Web App (DVWA) est une application Web PHP/MySQL très vulnérable. Ses principaux objectifs sont d'aider les professionnels de la sécurité à tester leurs compétences et leurs outils dans un environnement juridique, d'aider les développeurs Web à mieux comprendre le processus de sécurisation des applications Web et d'aider les enseignants/étudiants à enseigner/apprendre dans un environnement de classe. Application Web sécurité. L'objectif de DVWA est de mettre en pratique certaines des vulnérabilités Web les plus courantes via une interface simple et directe, avec différents degrés de difficulté. Veuillez noter que ce logiciel

Adaptateur de serveur SAP NetWeaver pour Eclipse

Adaptateur de serveur SAP NetWeaver pour Eclipse

Intégrez Eclipse au serveur d'applications SAP NetWeaver.

VSCode Windows 64 bits Télécharger

VSCode Windows 64 bits Télécharger

Un éditeur IDE gratuit et puissant lancé par Microsoft