Heim > Datenbank > Redis > Hauptteil

Lösen Sie das Problem des überverkauften Redis-Bestands

coldplay.xixi
Freigeben: 2021-03-18 11:20:02
nach vorne
2859 Leute haben es durchsucht

Lösen Sie das Problem des überverkauften Redis-Bestands

Verwenden Sie MQ zwischen dem Produkt und dem Bestellservice.

Wenn sich der Bestand des Produktservices ändert, wird der Bestellservice über MQ über die Bestandsänderung benachrichtigt.

Ursprünglicher Synchronisierungsprozess

  1. Produktinformationen abfragen (Produktservice aufrufen)
  2. Gesamtpreis berechnen (Bestelldetails generieren)
  3. Bestand vom Produktservice abziehen (Produktservice anrufen)
  4. Lagerhaltung bestellen (Bestellung generieren)
// 原始的MySQL同步流程// 判断此代金券是否加入抢购SeckillVouchers seckillVouchers = seckillVouchersMapper.selectVoucher(voucherId);AssertUtil.isTrue(seckillVouchers == null, "该代金券并未有抢购活动");// 判断是否有效AssertUtil.isTrue(seckillVouchers.getIsValid() == 0, "该活动已结束");// 插入数据库seckillVouchersMapper.save(seckillVouchers);
Nach dem Login kopieren

Empfehlung (kostenlos): redis

Lagerbestand direkt abziehen, wenn eine Bestellung generiert wird. Es ist relativ einfach, aber es gibt

Probleme kann dazu führen, dass viele Bestellungen den Produktbestand ohne Zahlung abziehen. Dazu ist ein Hintergrundskript erforderlich, um den Bestand von Bestellungen freizugeben, die über einen bestimmten Zeitraum nicht bezahlt wurden, die Bestellung zu stornieren, den Lagerbestand sofort abzuziehen und die Differenz auszugeben

1. 3-stufiger Produktservice, Betriebsdatenbank für Produktdienstleistungen, 2-stufiger und 4-stufiger Bestellservice und Datenbank für Betriebsauftragsservices.
  • Vermeiden Sie den Zugriff auf die Datenbank verschiedener Dienste. Grundsätzlich kann derselbe Dienst nur die Datenbank seines eigenen Dienstes betreiben.

MQ-Asynchronisierung

Erwägen Sie zunächst, nur Schritt 4 asynchron zu machen.

Analyse

2 und 4 sind alle Vorgänge auf der Datenbank. Es besteht keine Notwendigkeit, auf Schritt 4 zu warten. Dem Benutzer wird unmittelbar nach dem Erfolg der Schritte 1, 2 und 3 eine Rückmeldung gegeben.

Danach wird die Bestellung asynchron über den Nachrichtenbenachrichtigungsdienst aufgegeben. Wenn die asynchrone Auftragserteilung in Schritt 4 fehlschlägt, versuchen Sie, die Bestellung erneut zu generieren.

Nachdem die Bestellung erstellt wurde, befindet sie sich im Warteschlangenstatus und der Dienst veröffentlicht dann ein Ereignis Bestellung erstellt in der Nachrichtenwarteschlange.

Das heißt, der Bestelldienst sendet Nachrichten an die Außenwelt: Ich erstelle eine Bestellung, die von MQ an den Dienst weitergeleitet wird, der die Nachricht abonniert.

Wenn der Produktservice die Nachricht zur Auftragserstellung erhält, Es wird die Abzugsinventaroperation ausgeführt. Beachten Sie, dass der Bestandsabzug aufgrund einiger Faktoren höherer Gewalt fehlschlagen kann. Unabhängig von Erfolg oder Misserfolg sendet der Produktservice eine Bestandsabzugsnachricht an MQ, und der Inhalt der Nachricht ist das Ergebnis des Bestandsabzugs.
Der Bestellservice abonniert das Ergebnis des Lagerabzugs. Nach Erhalt der Nachricht:
Order Created 到消息队列中。
即订单服务向外界发送消息:我创建了一个订单,由MQ 转发给订阅该消息的服务。

如果商品服务收到创建订单消息之后执行扣库存操作。注意,这里可能因为某些不可抗因素导致扣库存失败,无论成功与否,商品服务都会发送一个扣库存消息到 MQ,消息内容即扣库存的结果。
订单服务会订阅扣库存的结果,接收到该消息后:

  • 如果扣库存成功,将订单的状态改为已确认,即下单成功
  • 如果扣库存失败,将订单的状态改为已取消,即下单失败

欲实现上述模型要求,需可靠的消息投递。服务发出的消息,一定会被MQ收到。

  • 用户体验的变化
    前端配合排队中等界面。

商品/订单服务都变成异步化,适合秒杀类场景,当流量不大时,并不太适合。

异步设计

  1. 库存在Redis中保存
  2. 收到请求Redis判断是否库存充足 ,减掉Redis中库存
  3. 订单服务创建订单写入数据库,并发送消息

当订单支付成功后,会有一个出库过程,既然有这个过程,就有可能出库失败。
库存有两部分:

  • 缓存redis层
  • 数据库mysql层
  1. 当客服新增5个库存,则缓存redis和数据库mysql层都需增加5个库存,使用分布式事务的最终一致性来满足:库存要么全加,要么全不加。
  2. 当订单生成时,需要扣除库存,先扣redis库存,如果扣除成功,则生成订单进行支付,这个过程不扣除mysql库存
  3. 当redis库存扣完,该产品就无法下单了,下单就会失败,就把外层的给挡住了。
  4. 在第2步扣除redis库存成功后,生成订单,进行支付,支付成功,返回我的订单中心, 会发现有一个出库过程。
  5. 出库过程
    一个MQ异步解耦的任务队列,这个过程是扣除mysql库存
  • 如果扣mysql库存成功,出库成功,完成下订单整个流程,进入发货状态
  • 如果扣mysql库存失败,出库失败,进行一系列的操作
    • 订单状态改成取消
    • 返还redis库存
    • 退款

redis库存和mysql库存

支付前是预扣,是扣redis库存,是锁定库存的过程
支付后是真正扣,扣mysql库存Wenn der Lagerabzug erfolgreich ist, wird der Bestellstatus in Bestätigt, also die Bestellung, geändert erfolgreich aufgegeben wurde.

Wenn der Bestandsabzug fehlschlägt, ändern Sie den Status der Bestellung auf Storniert, d. h. die Bestellung ist fehlgeschlagen. Um die oben genannten Modellanforderungen zu erfüllen, ist eine zuverlässige Nachrichtenzustellung erforderlich. Vom Dienst gesendete Nachrichten werden definitiv von MQ empfangen.

  • Änderungen in der Benutzererfahrung
  • Das Frontend kooperiert mit der Schnittstelle des Warteschlangenmediums.
  • Produkte/Bestelldienste sind asynchron geworden, was für Flash-Sale-Szenarien geeignet ist. Es ist nicht geeignet, wenn der Verkehr nicht groß ist.

Asynchrones Design

Der Bestand wird in Redis gespeichert

🎜Nach Erhalt der Anfrage ermittelt Redis, ob der Bestand ausreichend ist, und subtrahiert den Bestand in Redis🎜🎜Der Bestellservice erstellt die Bestellung und schreibt sie in die Datenbank , und sendet eine Nachricht🎜🎜🎜Wenn die Bestellung erfolgreich ist, wird es einen ausgehenden Prozess geben. Da es diesen Prozess gibt, kann der ausgehende Prozess fehlschlagen. 🎜 Das Inventar besteht aus zwei Teilen: 🎜🎜🎜Cache-Redis-Schicht 🎜🎜Datenbank-MySQL-Schicht 🎜🎜🎜🎜Wenn der Kundendienst 5 Inventare hinzufügt, müssen sowohl Cache-Redis- als auch Datenbank-MySQL-Schichten 5 Inventare hinzufügen, wobei die letztendliche Konsistenz verteilter Transaktionen verwendet wird. Zufriedenheit: Entweder wird der gesamte Bestand hinzugefügt oder keiner. 🎜🎜Wenn eine Bestellung generiert wird, muss der Lagerbestand von Redis abgezogen werden. Wenn der Abzug erfolgreich ist, wird bei diesem Vorgang kein MySQL-Bestand abgezogen . 🎜🎜Wenn der Redis-Bestand abgezogen wird, kann das Produkt nicht bestellt werden und die Bestellung schlägt fehl, sodass die äußere Schicht blockiert wird. 🎜🎜In Schritt 2 Nachdem der Redis-Bestand erfolgreich abgezogen wurde, generieren Sie die Bestellung, führen Sie die Zahlung durch, die Zahlung ist erfolgreich, kehren Sie zu meinem Bestellcenter zurück und Sie werden feststellen, dass es einen ausgehenden Prozess gibt. 🎜🎜Ausgehender Prozess🎜 Eine asynchrone entkoppelte MQ-Aufgabenwarteschlange. Dieser Prozess ist MySQL-Inventar abziehen: 🎜🎜🎜🎜Wenn das MySQL-Inventar erfolgreich abgezogen wurde, ist der ausgehende Prozess erfolgreich . Schließen Sie den gesamten Bestellvorgang ab und geben Sie den Lieferstatus ein. 🎜🎜Wenn der MySQL-Bestand nicht abgezogen werden kann und der Versand fehlschlägt, wird eine Reihe von Vorgängen ausgeführt. Der Bestellstatus wird in „Storniert“ geändert. Geben Sie den Redis-Bestand zurück 🎜🎜Rückerstattung🎜🎜🎜🎜🎜🎜Redis-Inventar und MySQL-Inventar🎜🎜🎜Vor der Zahlung erfolgt eine Einbehaltung, also ein Abzug von Redis-Inventar, also ein Sperrvorgang Inventar🎜 Nach der Zahlung handelt es sich um einen echten Abzug, bei dem MySQL-Inventar abgezogen wird, um sicherzustellen, dass das Inventar letztendlich konsistent ist🎜🎜In extremen Fällen kommt es jedoch zu Dateninkonsistenzen🎜🎜🎜Wenn Redis-Inventar = MySQL-Inventar, Es wird kein Problem geben🎜🎜Wenn Redis-Inventar MySQL-Inventar, wird es überverkauft sein, und das Eine überverkaufte Bestellung schlägt während des Liefervorgangs fehl🎜🎜🎜Auf diese Weise wird sie insgesamt nicht versendet. Das Problem, die MySQL-Datenbankschicht, stellt sicher, dass es am Ende keine Probleme mit dem Lagerbestand gibt. 🎜🎜🎜Frage🎜🎜

Der Datenbankinventar und der Redis-Inventar sind inkonsistent. Wie erkennt man das?

Wenn Inkonsistenzen festgestellt werden, wie kann man synchronisieren?

Ich habe mir keinen guten Plan ausgedacht.
Eine gewalttätigere Methode besteht darin, eine Zeit mit niedriger Spitzenlast zu finden, z. B. 1 Uhr morgens, und die Abdeckung regelmäßig zu erzwingen. In extremen Fällen kann es jedoch auch nach der Synchronisierung zu Ungenauigkeiten kommen. Beispielsweise wird während des Synchronisierungsvorgangs eine Bestellung bezahlt. Nachdem die Bestellung erfolgreich bezahlt wurde, wird der MySQL-Bestand beim ausgehenden Vorgang abgezogen Das Redis-Inventar wird nicht abgezogen.

Dies ist ein Problem mit dem Aktualisierungsmechanismus des Datenbanksynchronisierungscache.
Es ist ein Problem des konsistenten logischen Designs.
缓存数 = 数据库库存数 - 待扣数
Natürlich gibt es andere Lösungen, und angesichts der Konsistenzanforderungen können Sie dies tun Verwenden Sie einfache oder komplexe. Die Lösung
hängt von der Komplexität des Systems ab. Je größer das System, desto detaillierter muss es beispielsweise in einer Warteschlange oder einem Cache abgelegt werden Lesen Sie die Zählungen einfach direkt ab. Geben Sie beispielsweise die Menge ein, die bezahlt wurde und versendet werden soll. Wenn Sie sie zählen, werden Sie nicht viel verlieren. Das allgemeine System kann nicht vollständig garantieren, dass die Datenverbindung keine Fehler verursacht, aber es muss eine Kompensation erfolgen, das heißt, Fehler können korrigiert werden geplant oder über MQ oder Überwachung von Inkonsistenz und Synchronisierung usw. . .
Wird auch als Sicherstellung der Aktualität der zwischengespeicherten Daten bezeichnet
Im Allgemeinen dauert es nicht zu lange, es kann eine halbe Stunde oder ein paar Minuten dauern. Die Anforderungen verschiedener Szenarien sind unterschiedlich Kaufen Sie sie nachts. Tickets, diese Zeit wird voraussichtlich für die Synchronisierung des Inventars und die Synchronisierung des Datenbankinventars mit dem Redis-Inventar verwendet. Beim Kauf von Bahntickets muss jedoch der tatsächliche Inventar abgezogen werden, bevor die Bestellung generiert wird, dh der MySQL-Inventar muss abgezogen werden.

denn beim Kauf von Bahntickets kann der Einkauf nach der Bezahlung versandt werden, bei Tickets muss man jedoch vor der Bezahlung das Lager verlassen. Daher muss der Versandvorgang vorangetrieben werden. Erst wenn der Versand erfolgreich ist, kann eine Bestellung generiert werden. Redis-Inventar muss ebenfalls eingeführt werden

Ziehen Sie zuerst das Inventar im Cache ab. Nachdem der Abzug erfolgreich war, können Sie das Inventar in MySQL abziehen.

Wenn das Inventar im Cache nicht abgezogen werden kann, wird es blockiert und unzureichendes Inventar wird zurückgegeben. Diese Anforderungen werden nicht in MySQL punktiert, wodurch der größte Teil des Anforderungsdrucks blockiert wird.

Das Redis-Inventar stimmt nicht mit dem MySQL-Inventar überein. In extremen Fällen ist eine Synchronisierung des Inventars erforderlich.

Wenn das Cache-Inventar größer ist als das Datenbankinventar, wird ein Ticket angezeigt In der Abfrage konnte die Bestellung jedoch nicht aufgegeben werden. In diesem Fall wurde angegeben, dass der Lagerbestand nicht ausreicht. Allerdings sollte 12306 über andere Möglichkeiten verfügen, um dieses Problem zu vermeiden , ich bin darauf gestoßen, es gab ein Ticket, aber es konnte nicht in einer einzigen Situation platziert werden.

Wenn der Cache-Bestand kleiner ist als der Datenbank-Cache, gibt es kein Problem. Es werden nur Tickets, aber keine Verkäufe vorhanden sein. Nach Abschluss der Inventarsynchronisierung wird es morgen wieder korrekt sein.

Das obige ist der detaillierte Inhalt vonLösen Sie das Problem des überverkauften Redis-Bestands. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:csdn.net
Erklärung dieser Website
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
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage