Dark Horse Dianping 02 Coupon Flash Sale (Überverkauft-Problem)

1. Datenbanktabelle

2. So generieren Sie eine weltweit eindeutige ID

2.1 Warum erhöht sich die ID nicht automatisch?

Aus den oben genannten Gründen wird ein globaler ID-Generator verwendet.

2.2 Globaler ID-Generator (unter Verwendung der Auto-Inkrementierungsfunktion von Redis)

Der Zeitstempel ist die Anzahl der Sekunden ab der eingestellten Startzeit.

Die Seriennummer ist der Schlüssel einer Redis-Zeichenfolge, die hauptsächlich aus dem Geschäftsschlüssel + der Tageszeit besteht. Der gespeicherte Redis-Wert ist die Bestellmenge am x Monat x Tag x Jahr, also die Seriennummer (selbststeigend).

Durch Spleißen wird die Bestellnummer gebildet, die die Bestellnummer der aktuellen Bestellung ist.

Der INCR-Befehl ist eine Operation für Zeichenfolgen. Da Redis keinen dedizierten Ganzzahltyp hat, wird der im Schlüssel gespeicherte Wert beim Ausführen des INCR-Befehls als dezimale 64-Bit-Ganzzahl mit Vorzeichen interpretiert. 

package com.example.heima.utils;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

@Component
public class RedisIdWorker {
    //开始时间
    private static final long BEGIN_TIMESTAMP = 1640995200L;
    //序列号位数
    private static final int COUNT_BITS = 32;
    private StringRedisTemplate stringRedisTemplate;
    public RedisIdWorker(StringRedisTemplate stringRedisTemplate){
        this.stringRedisTemplate = stringRedisTemplate;
    }

    //id构成 : 1位符号位 + 31位时间戳 + 32位序列号
    public long nextId(String keyPrefix){
        //1.生成时间戳,当时时间
        LocalDateTime now = LocalDateTime.now();
        long nowSecond = now.toEpochSecond(ZoneOffset.UTC);//时间格式转换
        long timestamp = nowSecond - BEGIN_TIMESTAMP;//计算现在距离开始时间时间差

        //2.生成32位序列号
        //2.1生成订单时间当前日期,精确到天(因为32位最多2^32次方,序列号有上限,不管多久这个key都不变。
        // 所以为了让key随时间变化,加上天数拼接,但是一天很难到达2^32单)
        String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        //2.2自增长(传入的是string会被redis解释成数字类型)
        long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);

        //3,拼接并返回
        return timestamp << 32 | count ;

    }


}

2.2.1 Testen

Analyse der Verwendung und des Prinzips von CountDownLatch - Zhihu (zhihu.com)

//线程池500个线程
    private ExecutorService es = Executors.newFixedThreadPool(500);
    @Test
    void testIdWorker(){
        //CountDownLatch可以使一个或多个线程等待其他线程各自执行完毕后再执行。
        CountDownLatch latch = new CountDownLatch(300);  //构造300的计数器
        //任务
        Runnable task = ()->{
            for(int i=0;i < 100;i++){
                long id =redisIdWorker.nextId("order");
                System.out.println("id = " + id);
            }
            latch.countDown(); //对计数器进行递减1操作,当计数器递减至0时,当前线程会去唤醒阻塞队列里的所有线程。
        };
        long begin = System.currentTimeMillis();
        //300个线程执行任务
        for(int i=0;i < 300;i ++){
            es.submit(task);
        }

        try {
            //等待latch计数器归零再开始执行该线程
            latch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        long end = System.currentTimeMillis();

        System.out.println("time = " + (end-begin) );

    }

Nach der Ausführung wird ein Auftragszähler namens „spleißen“ in Redis geschrieben. 

Erfolgreich generiert

3. Gutscheine hinzufügen

Im Grunde überträgt das Frontend Coupon-JSON-Daten und ruft die Steuerung und den Dienst für die Datenbankverarbeitung auf.

3.1 Tabellenstruktur

Die beiden Tabellen sind durch die Coupon-ID verknüpft

Flash-Sale-Gutschein

 Alle Coupons (einschließlich gewöhnlicher Coupons und Flash-Sale-Coupons)

3.2 Gutscheine hinzufügen

Sie können die Informationen erhalten, indem Sie JSON per Post weiterleiten

4. Implementieren Sie den Coupon-Kaufprozess

Entsprechender Coupon-Kauf-Service-Prozess

5. Lösen Sie das Problem von Multi-Thread-Flash-Verkäufen und Überverkäufen

5.1 Simulieren Sie Mehrbenutzer-Anfragesoftware

Das Video verwendet die JMeter-Software zum Testen der Auslastung. Sie kann die Anzahl der Threads festlegen und gleichzeitig eine große Anzahl von Anforderungen an eine bestimmte URL initiieren, um Mehrbenutzerszenarien zu simulieren.

JMeter-Leistungstests, vollständiges Einführungs-Tutorial – CSDN-Blog

5.2 Überverkaufsproblem

Bevor etwas verkauft wird, wird eine Beurteilung vorgenommen, und die Funktion zum Abziehen des Lagerbestands wird erst aufgerufen, wenn die Beurteilung erfolgreich ist. Wenn der Lagerbestand 1 ist und die beiden Threads erfolgreich feststellen, dass gleichzeitig Lagerbestand vorhanden ist, wird ein Lagerbestand abgezogen Lagerbestand, dann ist der Lagerbestand -1 und es liegt ein Überverkaufsproblem vor. .

5.3 Lösung (Sperren, optimistisches Sperren, pessimistisches Sperren)

Pessimistische Sperren sind traditionelle Sperren und haben große Auswirkungen auf die Effizienz. Daher untersuchen wir, wie optimistische Sperren implementiert werden können.

Beim optimistischen Sperren muss die Versionsnummer anhand von Änderungen ermittelt werden, sodass sie nur auf Aktualisierungen angewendet werden kann. Für Multithread-Abfragen kann nur pessimistisches Sperren verwendet werden.

5.4 Optimistisches Sperren

Beim optimistischen Sperren muss die Versionsnummer anhand von Änderungen ermittelt werden, sodass sie nur auf Aktualisierungen angewendet werden kann. Für Multithread-Abfragen kann nur pessimistisches Sperren verwendet werden.

5.4.1 Versionsnummernmethode

5.4.2CAS-Methode (Inventar als Versionsnummer verwenden, vergleichen und wechseln)

5.5 Optimistische Sperrimplementierung --- CAS-Methode

Fügen Sie vor dem Abzug des Lagerbestands einen Lagerbestand hinzu, um festzustellen, ob er derselbe ist wie zuvor.

Dies bringt jedoch ein neues Problem mit sich: Die Erfolgsquote ist zu niedrig. Wenn 100 Threads gleichzeitig ausgeführt werden, kann nur ein Thread geändert werden, und die anderen werden aufgrund von Versionsänderungen beendet, was zu einer Erhöhung der Fehlerquote führt.

Daher muss nicht beurteilt werden, ob der Lagerbestand mit dem vorherigen im Code übereinstimmt. Solange der Lagerbestand größer als 0 ist, kann er verkauft werden.

5.5 Segmentverriegelung

Da optimistisches Sperren die Fehlerquote erhöht, können segmentierte Sperren verwendet werden, um 100 Gutscheine auf 10 Tische zu verteilen, um die Erfolgsquote zu erhöhen. Benutzer können jeweils zu 10 Tischen gehen, um sie zu holen. Auf diese Weise werden ein Kauf und eine Sperre durchgeführt Es muss nur ein Tisch gesperrt werden, was keinen Einfluss auf den Kauf anderer Tische hat und die Erfolgsquote erheblich verbessert.

Supongo que te gusta

Origin blog.csdn.net/m0_50973548/article/details/134982825
Recomendado
Clasificación