„Ich laufe in meinen Schuhen“ – Moment, sind sie markiert?

Seit 2019 gibt es in Russland ein Gesetz zur Kennzeichnungspflicht. Das Gesetz gilt nicht für alle Warengruppen und die Termine für das Inkrafttreten der Kennzeichnungspflicht für Produktgruppen sind unterschiedlich. Zunächst werden Tabak, Schuhe und Medikamente einer Kennzeichnungspflicht unterliegen, später kommen weitere Produkte hinzu, beispielsweise Parfüm, Textilien und Milch. Diese gesetzgeberische Neuerung führte zur Entwicklung neuer IT-Lösungen, die es ermöglichen, die gesamte Lebenskette eines Produkts von der Produktion bis zum Kauf durch den Endverbraucher bis hin zu allen Prozessbeteiligten zu verfolgen: sowohl dem Staat selbst als auch allen Organisationen, mit denen Waren verkauft werden Kennzeichnungspflicht.

In X5 heißt das System, das gekennzeichnete Waren verfolgt und Daten mit dem Staat und Lieferanten austauscht, „Marcus“. Lassen Sie uns der Reihe nach erzählen, wie und wer es entwickelt hat, was sein Technologie-Stack ist und warum wir etwas haben, auf das wir stolz sein können.

„Ich laufe in meinen Schuhen“ – Moment, sind sie markiert?

Echtes HighLoad

„Marcus“ löst viele Probleme, das wichtigste ist die Integrationsinteraktion zwischen X5-Informationssystemen und dem staatlichen Informationssystem für gekennzeichnete Produkte (GIS MP) zur Verfolgung der Bewegung gekennzeichneter Produkte. Die Plattform speichert außerdem alle von uns erhaltenen Etikettierungscodes sowie den gesamten Verlauf der Bewegung dieser Codes zwischen Objekten und trägt dazu bei, eine Neubewertung etikettierter Produkte zu vermeiden. Am Beispiel der Tabakwaren, die zu den ersten gekennzeichneten Warengruppen zählten, enthält eine LKW-Ladung Zigaretten etwa 600 Packungen, von denen jede über einen eigenen, eindeutigen Code verfügt. Und die Aufgabe unseres Systems besteht darin, die Rechtmäßigkeit der Bewegungen jeder dieser Packungen zwischen Lagern und Filialen zu verfolgen und zu überprüfen und letztendlich die Zulässigkeit ihres Verkaufs an den Endkäufer zu überprüfen. Und wir erfassen etwa 000 Bargeldtransaktionen pro Stunde, und wir müssen auch erfassen, wie jedes dieser Pakete in den Laden gelangt ist. Unter Berücksichtigung aller Bewegungen zwischen Objekten rechnen wir also mit mehreren zehn Milliarden Datensätzen pro Jahr.

Team M

Obwohl Marcus als Projekt innerhalb von X5 gilt, wird es mithilfe eines Produktansatzes umgesetzt. Das Team arbeitet nach Scrum. Das Projekt begann letzten Sommer, aber die ersten Ergebnisse kamen erst im Oktober – unser eigenes Team war vollständig zusammengestellt, die Systemarchitektur wurde entwickelt und Ausrüstung wurde gekauft. Mittlerweile besteht das Team aus 16 Personen, davon sind sechs in der Backend- und Frontend-Entwicklung tätig, drei davon in der Systemanalyse. Sechs weitere Personen sind an manuellen, Lade-, automatisierten Tests und Produktwartungen beteiligt. Darüber hinaus verfügen wir über einen SRE-Spezialisten.

In unserem Team schreiben nicht nur Entwickler Code; fast alle Jungs wissen, wie man Autotests programmiert und schreibt, Skripte lädt und Automatisierungsskripte erstellt. Darauf legen wir besonderen Wert, da auch der Produktsupport einen hohen Automatisierungsgrad erfordert. Wir versuchen immer, Kollegen, die noch nicht programmiert haben, mit Rat und Tat zur Seite zu stehen und ihnen kleine Aufgaben zur Bearbeitung zu geben.

Aufgrund der Coronavirus-Pandemie haben wir das gesamte Team auf Remote-Arbeit umgestellt; die Verfügbarkeit aller Tools für das Entwicklungsmanagement, der integrierte Workflow in Jira und GitLab machten es möglich, diese Phase problemlos zu bestehen. Die Monate, die remote verbracht wurden, zeigten, dass die Produktivität des Teams dadurch nicht gelitten hat; für viele stieg der Komfort am Arbeitsplatz, es fehlte nur noch die Live-Kommunikation.

Remote-Teambesprechung

„Ich laufe in meinen Schuhen“ – Moment, sind sie markiert?

Besprechungen während der Remote-Arbeit

„Ich laufe in meinen Schuhen“ – Moment, sind sie markiert?

Technologie-Stack der Lösung

Das Standard-Repository und CI/CD-Tool für X5 ist GitLab. Wir verwenden es für die Codespeicherung, kontinuierliche Tests und die Bereitstellung auf Test- und Produktionsservern. Wir nutzen auch die Praxis der Codeüberprüfung, bei der mindestens zwei Kollegen die vom Entwickler am Code vorgenommenen Änderungen genehmigen müssen. Die statischen Code-Analysatoren SonarQube und JaCoCo helfen uns, unseren Code sauber zu halten und das erforderliche Maß an Unit-Test-Abdeckung sicherzustellen. Alle Änderungen am Code müssen diese Prüfungen durchlaufen. Alle manuell ausgeführten Testskripte werden anschließend automatisiert.

Für die erfolgreiche Implementierung von Geschäftsprozessen durch „Marcus“ mussten wir eine Reihe technologischer Probleme der Reihe nach lösen.

Aufgabe 1. Die Notwendigkeit einer horizontalen Skalierbarkeit des Systems

Um dieses Problem zu lösen, haben wir einen Microservice-Architekturansatz gewählt. Gleichzeitig war es sehr wichtig, die Verantwortungsbereiche der Dienste zu verstehen. Wir haben versucht, sie unter Berücksichtigung der Besonderheiten der Prozesse in Geschäftsabläufe zu unterteilen. Beispielsweise ist die Annahme in einem Lager kein sehr häufiger, aber sehr umfangreicher Vorgang, bei dem es notwendig ist, von der staatlichen Aufsichtsbehörde schnell Informationen über die angenommenen Wareneinheiten einzuholen, deren Anzahl in einer Lieferung 600000 erreicht , prüfen Sie die Zulässigkeit der Aufnahme dieses Produkts in das Lager und geben Sie alle notwendigen Informationen an das Lagerautomatisierungssystem zurück. Der Versand aus Lagerhäusern ist jedoch wesentlich intensiver, operiert aber gleichzeitig mit geringen Datenmengen.

Wir implementieren alle Dienste zustandslos und versuchen sogar, interne Abläufe in Schritte zu unterteilen, indem wir sogenannte Kafka-Selbstthemen verwenden. Dabei sendet ein Microservice eine Nachricht an sich selbst, was es Ihnen ermöglicht, die Last auf ressourcenintensivere Vorgänge auszugleichen und die Produktwartung zu vereinfachen, aber dazu später mehr.

Wir haben uns entschieden, Module für die Interaktion mit externen Systemen in separate Dienste aufzuteilen. Dadurch konnte das Problem häufig wechselnder APIs externer Systeme gelöst werden, ohne dass dies Auswirkungen auf Dienste mit Geschäftsfunktionalität hatte.

„Ich laufe in meinen Schuhen“ – Moment, sind sie markiert?

Alle Microservices werden in einem OpenShift-Cluster bereitgestellt, was sowohl das Problem der Skalierung jedes Microservices löst als auch es uns ermöglicht, auf die Verwendung von Service Discovery-Tools von Drittanbietern zu verzichten.

Aufgabe 2. Die Notwendigkeit, eine hohe Auslastung und einen sehr intensiven Datenaustausch zwischen Plattformdiensten aufrechtzuerhalten: Allein während der Projektstartphase werden etwa 600 Operationen pro Sekunde durchgeführt. Wir gehen davon aus, dass dieser Wert auf 5000 Vorgänge/Sek. ansteigt, wenn sich Einzelhandelsgeschäfte mit unserer Plattform verbinden.

Dieses Problem wurde durch den Einsatz eines Kafka-Clusters und den fast vollständigen Verzicht auf die synchrone Interaktion zwischen den Microservices der Plattform gelöst. Dies erfordert eine sehr sorgfältige Analyse der Systemanforderungen, da nicht alle Vorgänge asynchron sein können. Dabei übermitteln wir nicht nur Ereignisse über den Broker, sondern übermitteln in der Nachricht auch alle erforderlichen Geschäftsinformationen. Somit kann die Nachrichtengröße mehrere hundert Kilobyte erreichen. Die Nachrichtengrößenbeschränkung in Kafka erfordert, dass wir die Nachrichtengröße genau vorhersagen und sie bei Bedarf aufteilen. Die Aufteilung ist jedoch logisch und bezieht sich auf den Geschäftsbetrieb.
Beispielsweise teilen wir Waren, die im Auto ankommen, in Kartons auf. Für synchrone Vorgänge werden separate Microservices zugewiesen und gründliche Lasttests durchgeführt. Die Verwendung von Kafka stellte uns vor eine weitere Herausforderung: Durch das Testen des Betriebs unseres Dienstes unter Berücksichtigung der Kafka-Integration werden alle unsere Komponententests asynchron. Wir haben dieses Problem gelöst, indem wir unsere eigenen Hilfsmethoden mit dem Embedded Kafka Broker geschrieben haben. Dadurch entfällt zwar nicht die Notwendigkeit, Unit-Tests für einzelne Methoden zu schreiben, wir testen jedoch lieber komplexe Fälle mit Kafka.

Der Nachverfolgung von Protokollen wurde große Aufmerksamkeit geschenkt, damit ihre TraceId nicht verloren geht, wenn beim Betrieb von Diensten oder bei der Arbeit mit Kafka-Batch Ausnahmen auftreten. Und wenn es im ersten Fall keine besonderen Probleme gab, sind wir im zweiten Fall gezwungen, alle TraceIds zu protokollieren, mit denen der Stapel geliefert wurde, und eine auszuwählen, um die Verfolgung fortzusetzen. Bei der Suche anhand der ursprünglichen TraceId kann der Benutzer dann leicht herausfinden, mit welcher Ablaufverfolgung die Verfolgung fortgesetzt wurde.

Aufgabe 3. Die Notwendigkeit, eine große Datenmenge zu speichern: Allein für Tabak kommen pro Jahr mehr als 1 Milliarde Etiketten bei X5 an. Sie erfordern einen ständigen und schnellen Zugriff. Insgesamt muss das System etwa 10 Milliarden Datensätze zum Bewegungsverlauf dieser gekennzeichneten Waren verarbeiten.

Um das dritte Problem zu lösen, wurde die NoSQL-Datenbank MongoDB ausgewählt. Wir haben einen Shard mit 5 Knoten erstellt und jeder Knoten verfügt über einen Replikatsatz mit 3 Servern. Dadurch können Sie das System horizontal skalieren, dem Cluster neue Server hinzufügen und dessen Fehlertoleranz sicherstellen. Hier sind wir auf ein weiteres Problem gestoßen: die Sicherstellung der Transaktionalität im Mongo-Cluster unter Berücksichtigung der Verwendung horizontal skalierbarer Mikrodienste. Zu den Aufgaben unseres Systems gehört es beispielsweise, Versuche des Weiterverkaufs von Produkten mit gleichen Kennzeichnungscodes zu erkennen. Hier kommt es zu Überlagerungen mit fehlerhaften Scans oder Fehlbedienungen durch Kassierer. Wir haben festgestellt, dass solche Duplikate sowohl innerhalb eines verarbeiteten Kafka-Batches als auch innerhalb zweier parallel verarbeiteter Batches auftreten können. Daher hat die Suche nach Duplikaten durch Abfragen der Datenbank nichts ergeben. Für jeden Microservice haben wir das Problem separat basierend auf der Geschäftslogik dieses Services gelöst. Für Schecks haben wir beispielsweise eine Prüfung innerhalb des Stapels und eine separate Verarbeitung für das Auftreten von Duplikaten beim Einfügen hinzugefügt.

Um sicherzustellen, dass die Arbeit der Benutzer mit der Betriebshistorie das Wichtigste – das Funktionieren unserer Geschäftsprozesse – in keiner Weise beeinträchtigt, haben wir alle historischen Daten in einen separaten Dienst mit separater Datenbank aufgeteilt, der auch Informationen über Kafka erhält . Auf diese Weise arbeiten Benutzer mit einem isolierten Dienst, ohne die Dienste zu beeinträchtigen, die Daten für den laufenden Betrieb verarbeiten.

Aufgabe 4: Neuverarbeitung und Überwachung der Warteschlange:

In verteilten Systemen treten zwangsläufig Probleme und Fehler bei der Verfügbarkeit von Datenbanken, Warteschlangen und externen Datenquellen auf. Im Fall von Marcus liegt die Ursache solcher Fehler in der Integration mit externen Systemen. Es musste eine Lösung gefunden werden, die wiederholte Anfragen nach fehlerhaften Antworten mit einem bestimmten Zeitlimit zulässt, gleichzeitig aber die Verarbeitung erfolgreicher Anfragen in der Hauptwarteschlange nicht stoppt. Hierzu wurde das sogenannte „Topic Based Retry“-Konzept gewählt. Für jedes Hauptthema werden ein oder mehrere Wiederholungsthemen erstellt, an die fehlerhafte Nachrichten gesendet werden, und gleichzeitig wird die Verzögerung bei der Verarbeitung von Nachrichten vom Hauptthema beseitigt. Interaktionsschema -

„Ich laufe in meinen Schuhen“ – Moment, sind sie markiert?

Um ein solches Schema zu implementieren, brauchten wir Folgendes: diese Lösung in Spring zu integrieren und Codeduplizierung zu vermeiden. Beim Surfen im Internet sind wir auf eine ähnliche Lösung auf Basis von Spring BeanPostProccessor gestoßen, die uns jedoch unnötig umständlich vorkam. Unser Team hat eine einfachere Lösung entwickelt, die es uns ermöglicht, den Frühlingszyklus zum Erstellen von Verbrauchern zu integrieren und zusätzlich Wiederholungskonsumenten hinzuzufügen. Wir haben dem Spring-Team einen Prototyp unserer Lösung angeboten, den Sie sehen können hier. Die Anzahl der Retry-Consumer und die Anzahl der Versuche für jeden Consumer werden über Parameter entsprechend den Anforderungen des Geschäftsprozesses konfiguriert. Damit alles funktioniert, muss nur noch die Annotation org.springframework.kafka.annotation.KafkaListener hinzugefügt werden , das allen Spring-Entwicklern bekannt ist.

Wenn die Nachricht nach allen Wiederholungsversuchen nicht verarbeitet werden konnte, wird sie mit Spring DeadLetterPublishingRecoverer an DLT (Dead Letter Topic) weitergeleitet. Auf Wunsch des Supports haben wir diese Funktionalität erweitert und einen separaten Dienst erstellt, der es Ihnen ermöglicht, in DLT, StackTrace, TraceId enthaltene Nachrichten und andere nützliche Informationen dazu anzuzeigen. Darüber hinaus wurden allen DLT-Themen Überwachung und Warnungen hinzugefügt, und nun ist das Erscheinen einer Nachricht in einem DLT-Thema tatsächlich ein Grund, einen Fehler zu analysieren und zu beheben. Das ist sehr praktisch – anhand des Themennamens erkennen wir sofort, in welchem ​​Schritt des Prozesses das Problem aufgetreten ist, was die Suche nach der Grundursache erheblich beschleunigt.

„Ich laufe in meinen Schuhen“ – Moment, sind sie markiert?

Zuletzt haben wir eine Schnittstelle implementiert, die es uns ermöglicht, Nachrichten über unseren Support erneut zu versenden, nachdem deren Ursachen beseitigt wurden (z. B. die Funktionalität des externen Systems wiederhergestellt wurden) und natürlich der entsprechende Fehler zur Analyse festgestellt wurde. Hier kommen unsere Selbstthemen zum Einsatz: Um eine lange Verarbeitungskette nicht neu zu starten, können Sie diese ab dem gewünschten Schritt neu starten.

„Ich laufe in meinen Schuhen“ – Moment, sind sie markiert?

Plattformbetrieb

Die Plattform ist bereits im Produktivbetrieb, täglich führen wir Lieferungen und Sendungen durch, binden neue Distributionszentren und Filialen an. Im Rahmen des Piloten arbeitet das System mit den Produktgruppen „Tabak“ und „Schuhe“.

Unser gesamtes Team beteiligt sich an der Durchführung von Pilotprojekten, analysiert auftretende Probleme und macht Vorschläge zur Verbesserung unseres Produkts, von der Verbesserung von Protokollen bis hin zu Prozessänderungen.

Um unsere Fehler nicht zu wiederholen, werden alle während des Pilotprojekts gefundenen Fälle in automatisierten Tests widergespiegelt. Das Vorhandensein einer großen Anzahl von Autotests und Unit-Tests ermöglicht es Ihnen, Regressionstests durchzuführen und einen Hotfix buchstäblich innerhalb weniger Stunden zu installieren.

Jetzt entwickeln und verbessern wir unsere Plattform weiter und stehen ständig vor neuen Herausforderungen. Bei Interesse sprechen wir in den folgenden Artikeln über unsere Lösungen.

Source: habr.com

Kommentar hinzufügen