„Walking in my shoes“ – halt, sind die gekennzeichnet?

Seit 2019 gilt in Russland das Gesetz zur obligatorischen Kennzeichnung. Das Gesetz erstreckt sich nicht auf alle Warengruppen, und die Fristen fĂŒr das Inkrafttreten der obligatorischen Kennzeichnung variieren je nach Warengruppe. ZunĂ€chst fallen Tabak, Schuhe, Arzneimittel unter die obligatorische Kennzeichnung, spĂ€ter werden weitere Waren wie Parfums, Textilien und Milch hinzukommen. Diese gesetzliche Neuerung hat zur Entwicklung neuer IT-Lösungen gefĂŒhrt, die es ermöglichen, die gesamte Lebensdauer eines Produkts vom Herstellungsprozess bis zum Kauf durch den Endverbraucher fĂŒr alle Beteiligten im Prozess zu verfolgen: sowohl fĂŒr den Staat als auch fĂŒr alle Organisationen, die Produkte mit obligatorischer Kennzeichnung vertreiben.

Im H5-System wurde die Lösung, die die gekennzeichneten Produkte verfolgt und Daten mit dem Staat und den Lieferanten austauscht, "Markus" genannt. Lassen Sie uns Schritt fĂŒr Schritt erklĂ€ren, wie und von wem sie entwickelt wurde, welcher Technologiestack verwendet wird und warum wir darauf stolz sein können.

„Walking in my shoes“ – halt, sind die gekennzeichnet?

Echtzeit-HighLoad

"Markus" löst eine Vielzahl von Aufgaben, die wichtigste ist die Integrationsinteraktion zwischen den Informationssystemen von H5 und dem staatlichen Informationssystem der gekennzeichneten Produkte (GIS MP) zur Nachverfolgung der Lieferung der gekennzeichneten Produkte. Die Plattform speichert alle Codes der Kennzeichnung, die bei uns eingegangen sind, sowie die gesamte Historie der Bewegung dieser Codes zwischen den Objekten und hilft, MissverstĂ€ndnisse bei gekennzeichneten Produkten zu vermeiden. Beispielsweise enthĂ€lt bereits ein Lkw mit Zigaretten etwa 600.000 Packungen, von denen jede ihren eigenen einzigartigen Code hat. Die Aufgabe unseres Systems besteht darin, die legalen Bewegungen jeder einzelnen Packung zwischen Lagern und GeschĂ€ften nachzuvollziehen und letztlich die ZulĂ€ssigkeit ihres Verkaufs an den Endverbraucher zu ĂŒberprĂŒfen. Dabei erfassen wir etwa 125.000 Kassentransaktionen pro Stunde und mĂŒssen zudem dokumentieren, wie jede dieser Packungen ins GeschĂ€ft gelangt ist. Somit erwarten wir, unter BerĂŒcksichtigung aller Bewegungen zwischen den Objekten, jĂ€hrlich Milliarden von DatensĂ€tzen.

Das Team M

Obwohl „Markus“ im Rahmen von X5 als Projekt gilt, wird es nach einem produktorientierten Ansatz umgesetzt. Das Team arbeitet nach Scrum. Der Projektstart war im Sommer des letzten Jahres, aber die ersten Ergebnisse kamen erst im Oktober – es wurde ein eigenes Team vollstĂ€ndig zusammengestellt, die Systemarchitektur entworfen und die Hardware gekauft. Momentan besteht das Team aus 16 Personen, von denen sechs die Backend- und Frontend-Entwicklung ĂŒbernehmen, wĂ€hrend drei sich mit der Systemanalyse beschĂ€ftigen. Sechs weitere Personen kĂŒmmern sich um manuelle, Last- und automatisierte Tests sowie um die Produktbetreuung. DarĂŒber hinaus haben wir einen SRE-Spezialisten.

In unserem Team schreiben nicht nur die Entwickler Code, praktisch alle Kollegen können programmieren und erstellen automatisierte Tests, Lastscripts und Automatisierungsskripte. Wir legen besonderen Wert darauf, da selbst die ProduktunterstĂŒtzung ein hohes Maß an Automatisierung erfordert. Wir bemĂŒhen uns, Kollegen, die vorher nicht programmiert haben, zu unterstĂŒtzen und ihnen kleine Aufgaben zu geben.

Im Zusammenhang mit der Coronavirus-Pandemie haben wir das gesamte Team auf Remote-Arbeit umgestellt. Das Vorhandensein aller Werkzeuge fĂŒr das Management der Entwicklung sowie der Workflow in Jira und GitLab haben es ermöglicht, diesen Schritt problemlos zu bewĂ€ltigen. Die Monate im Homeoffice haben gezeigt, dass die ProduktivitĂ€t des Teams nicht darunter gelitten hat, fĂŒr viele hat sich der Arbeitskomfort erhöht, das Einzige, was fehlt, ist persönliche Kommunikation.

Teammeeting vor dem Remote-Arbeiten

„Walking in my shoes“ – halt, sind die gekennzeichnet?

Meetings wÀhrend des Remote-Arbeitens

„Walking in my shoes“ – halt, sind die gekennzeichnet?

Technologischer Stack der Lösung

Das standardmĂ€ĂŸige Repository und das CI/CD-Tool fĂŒr X5 ist GitLab. Wir verwenden es zur Speicherung des Codes, fĂŒr kontinuierliches Testen sowie fĂŒr die Bereitstellung auf Test- und Produktionsservern. Zudem nutzen wir die Praxis des Code-Reviews, bei dem mindestens zwei Kollegen die vom Entwickler vorgenommenen Änderungen im Code genehmigen mĂŒssen. Die statischen Code-Analysetools SonarQube und JaCoCo helfen uns, den Code sauber zu halten und den erforderlichen Grad der Abdeckung durch Unit-Tests sicherzustellen. Alle Änderungen im Code mĂŒssen unbedingt diese PrĂŒfungen bestehen. Alle TestfĂ€lle, die manuell durchgefĂŒhrt werden, werden anschließend automatisiert.

Um die GeschĂ€ftsprozesse von „Markus“ erfolgreich umzusetzen, mussten wir eine Reihe technologischer Aufgaben lösen, von denen wir jede einzeln betrachten.

Aufgabe 1. Die Notwendigkeit der horizontalen Skalierbarkeit des Systems

Um diese Aufgabe zu lösen, haben wir einen mikroskopischen Ansatz fĂŒr die Architektur gewĂ€hlt. Dabei war es wichtig, die Verantwortungsbereiche der Dienste zu verstehen. Wir haben versucht, diese nach GeschĂ€ftsoperationen zu unterteilen, wobei wir die spezifischen AblĂ€ufe berĂŒcksichtigt haben. Zum Beispiel ist die Wareneingangskontrolle im Lager keine sehr hĂ€ufige, aber eine sehr umfangreiche Operation, bei der man so schnell wie möglich Informationen ĂŒber die angenommenen Produkte vom staatlichen Regulierungsbehörde einholen muss, wobei die Menge in einer Lieferung bis zu 600.000 Einheiten erreichen kann, sowie die ZulĂ€ssigkeit der Annahme dieser Waren im Lager ĂŒberprĂŒft und alle notwendigen Informationen dem Lagerautomatisierungssystem ĂŒbermittelt werden mĂŒssen. Im Gegensatz dazu hat die Auslieferung aus den Lagern eine deutlich höhere IntensitĂ€t, jedoch bearbeitet sie kleinere Datenmengen.

Alle unsere Dienste implementieren wir nach dem stateless Prinzip, und selbst interne AblÀufe versuchen wir in Schritte zu unterteilen, indem wir, wie wir sie nennen, self-Topics in Kafka verwenden. Das bedeutet, dass ein Mikrodienst eine Nachricht an sich selbst sendet, was es ermöglicht, die Last bei ressourcenintensiveren Operationen zu verteilen und die Wartung des Produkts zu vereinfachen, aber dazu spÀter mehr.

Wir haben beschlossen, Module, die mit externen Systemen interagieren, in separate Dienste auszulagern. Das hat es uns ermöglicht, das Problem hÀufig wechselnder APIs externer Systeme nahezu ohne Einfluss auf Dienste mit GeschÀfts-FunktionalitÀt zu lösen.

„Walking in my shoes“ – halt, sind die gekennzeichnet?

Alle Mikrodienste werden im OpenShift-Cluster bereitgestellt, das sowohl das Problem der Skalierung jedes Mikrodienstes löst als auch die Verwendung von Drittanbieter-Tools zur Service-Entdeckung unnötig macht.

Aufgabe 2. Die Notwendigkeit, hohe Last und sehr intensiven Datenaustausch zwischen den Diensten der Plattform aufrechtzuerhalten: nur in der Startphase des Projekts werden etwa 600 Operationen pro Sekunde durchgefĂŒhrt. Wir erwarten, dass dieser Wert auf 5000 Op/Sek ansteigt, wenn Handelsobjekte mit unserer Plattform verbunden werden.

Diese Aufgabe wurde durch den Einsatz eines Kafka-Clusters und nahezu vollstĂ€ndigen Verzicht auf synchrone Interaktion zwischen den Microservices der Plattform gelöst. Dies erfordert eine sehr sorgfĂ€ltige Analyse der Systemanforderungen, da nicht alle Operationen asynchron sein können. Dabei ĂŒbermitteln wir nicht nur Ereignisse ĂŒber den Broker, sondern auch alle erforderlichen GeschĂ€ftsinformationen in der Nachricht. Somit kann die NachrichtenlĂ€nge mehrere hundert Kilobyte erreichen. Die EinschrĂ€nkung der Nachrichtenvolumina in Kafka erfordert von uns eine genaue Vorhersage der NachrichtenlĂ€ngen, und falls erforderlich, teilen wir sie auf, wobei diese Aufteilung logisch und mit den GeschĂ€ftsoperationen verbunden ist.
Zum Beispiel teilen wir die Ware, die mit dem Fahrzeug angekommen ist, nach Kisten. FĂŒr synchrone VorgĂ€nge werden separate Microservices bereitgestellt und es wird umfassendes Lasttesting durchgefĂŒhrt. Der Einsatz von Kafka hat uns vor eine neue Herausforderung gestellt: Die FunktionsprĂŒfung unseres Dienstes in Bezug auf die Integration mit Kafka macht alle unsere Unit-Tests asynchron. Diese Aufgabe haben wir durch das Schreiben eigener Hilfsfunktionen unter Verwendung von Embedded Kafka Broker gelöst. Dies mindert nicht die Notwendigkeit, Unit-Tests fĂŒr einzelne Methoden zu schreiben, aber komplexe FĂ€lle testen wir lieber mit Kafka.

Wir haben sehr viel Wert auf die Protokollverfolgung gelegt, damit ihre TraceId bei Auftreten von Ausnahmen wĂ€hrend des Betriebs der Dienste oder beim Arbeiten mit Kafka-Batch nicht verloren gehen. WĂ€hrend bei ersterem keine besonderen Fragen auftauchten, mussten wir im zweiten Fall alle TraceIds, mit denen das Batch kam, in das Protokoll schreiben und eine fĂŒr die Fortsetzung der Verfolgung auswĂ€hlen. So kann der Benutzer bei der Suche nach der ursprĂŒnglichen TraceId leicht herausfinden, mit welcher die Verfolgung fortgesetzt wurde.

Aufgabe 3. Die Notwendigkeit, eine große Menge an Daten zu speichern: Über 1 Milliarde Kennzeichnungen pro Jahr nur fĂŒr Tabak gehen bei X5 ein. Diese erfordern einen stĂ€ndigen und schnellen Zugriff. Insgesamt sollte das System etwa 10 Milliarden DatensĂ€tze zur Historie der Bewegungen der gekennzeichneten Waren verarbeiten.

Zur Lösung der dritten Aufgabe wurde die NoSQL-Datenbank MongoDB gewĂ€hlt. Wir haben einen Shard aus 5 Knoten aufgebaut und in jedem Knoten ein Replica Set aus 3 Servern. Dies ermöglicht es, das System horizontal zu skalieren, indem man hinzufĂŒgt. neue Server in einem Cluster, und seine Ausfallsicherheit zu gewĂ€hrleisten. Hierbei stehen wir vor einem weiteren Problem – die GewĂ€hrleistung der TransaktionsfĂ€higkeit im Mongo-Cluster unter BerĂŒcksichtigung der Nutzung horizontal skalierbarer Mikrodienste. Zum Beispiel ist eine der Aufgaben unseres Systems, Versuche zum Wiederverkauf von Waren mit identischen Kennzeichnungscodes zu identifizieren. Hierbei treten Probleme mit fehlerhaften Scans oder fehlerhaften Kassenoperationen auf. Wir haben festgestellt, dass solche Duplikate sowohl innerhalb eines verarbeiteten Kafka-Batches als auch innerhalb von zwei parallel verarbeiteten Batches auftreten können. Somit brachte die ÜberprĂŒfung auf Duplikate durch Anfragen an die Datenbank keine Ergebnisse. FĂŒr jeden der Mikrodienste haben wir das Problem individuell gemĂ€ĂŸ der GeschĂ€ftslogik dieses Dienstes gelöst. Beispielsweise haben wir fĂŒr Belege eine ÜberprĂŒfung innerhalb des Batches hinzugefĂŒgt und eine separate Verarbeitung zur Identifizierung von Duplikaten bei der EinfĂŒgung implementiert.

Damit die Nutzung der Transaktionshistorie durch die Benutzer keinen Einfluss auf das Wichtigste hat – die FunktionsfĂ€higkeit unserer GeschĂ€ftsprozesse, haben wir alle historischen Daten in einen separaten Dienst mit einer eigenen Datenbank ausgelagert, der ebenfalls Informationen ĂŒber Kafka erhĂ€lt. So arbeiten die Nutzer mit einem isolierten Dienst, ohne Einfluss auf die Dienste, die die Daten zu aktuellen Operationen verarbeiten.

Aufgabe 4. Wiederverarbeitung von Warteschlangen und Monitoring:

In verteilten Systemen treten unvermeidbar Probleme und VerfĂŒgbarkeitsfehler von Datenbanken, Warteschlangen und externen Datenquellen auf. Im Fall von 'Markus' ist eine Quelle solcher Fehler die Integration mit externen Systemen. Es war notwendig, eine Lösung zu finden, die es ermöglicht, fehlerhafte Antworten nach einer bestimmten Timeout-Zeit erneut anzufragen, ohne dabei die Verarbeitung erfolgreicher Anfragen in der Hauptwarteschlange zu unterbrechen. Daher wurde das sogenannte Konzept des 'topic based retry' gewĂ€hlt. FĂŒr jedes Haupt-Topic wird ein oder mehrere Retry-Topics erstellt, in die fehlerhafte Nachrichten geleitet werden, wobei eine Verzögerung bei der Verarbeitung von Nachrichten aus dem Haupt-Topic ausgeschlossen wird. Das Interaktionsschema ist –

„Walking in my shoes“ – halt, sind die gekennzeichnet?

Um ein solches Schema umzusetzen, benötigten wir Folgendes – diese Lösung mit Spring zu integrieren und Code-Duplikate zu vermeiden. Im Internet stießen wir auf eine Ă€hnliche Lösung, die auf Spring BeanPostProcessor basierte, aber sie schien uns zu umstĂ€ndlich. Unser Team entwickelte eine einfachere Lösung, die es ermöglicht, sich in den Spring-Zyklus zur Erstellung von Consumer einzufĂŒgen und zusĂ€tzlich Retry-Consumer hinzuzufĂŒgen. Ein Prototyp unserer Lösung wurde dem Spring-Team angeboten, den man sich ansehen kann. hier. Die Anzahl der Retry-Consumer und die Anzahl der Versuche jedes Consumers werden ĂŒber Parameter konfiguriert, abhĂ€ngig von den Anforderungen des GeschĂ€ftsprozesses, und damit alles funktioniert, bleibt nur noch die bekannte Annotation org.springframework.kafka.annotation.KafkaListener zu setzen.

Falls eine Nachricht nach allen Retry-Versuchen nicht verarbeitet werden konnte, gelangt sie mit Hilfe des Spring DeadLetterPublishingRecoverer in das DLT (Dead Letter Topic). Auf Wunsch des Supports haben wir diese FunktionalitĂ€t erweitert und einen separaten Dienst erstellt, der es ermöglicht, Nachrichten, die im DLT gelandet sind, sowie Stacktraces, traceId und weitere nĂŒtzliche Informationen einzusehen. Außerdem wurden Überwachungen und Alarme fĂŒr alle DLT-Topics hinzugefĂŒgt, so dass das Auftreten einer Nachricht im DLT-Topic im Grunde Anlass zur Untersuchung und zur Erstellung eines Defekts ist. Das ist sehr praktisch – an der Bezeichnung des Topics erkennen wir sofort, an welcher Stelle im Prozess das Problem aufgetreten ist, was die Suche nach der zugrunde liegenden Ursache erheblich beschleunigt.

„Walking in my shoes“ – halt, sind die gekennzeichnet?

Neulich haben wir eine Schnittstelle umgesetzt, die es unserer UnterstĂŒtzung ermöglicht, Nachrichten nach der Beseitigung ihrer Ursachen (zum Beispiel Wiederherstellung der FunktionsfĂ€higkeit eines externen Systems) erneut zu senden und natĂŒrlich einen entsprechenden Defekt zur Analyse anzulegen. Hier kamen unsere Self-Topics ins Spiel: Um eine lange Verarbeitungskette nicht neu zu starten, kann man sie ab dem benötigten Schritt neu starten.

„Walking in my shoes“ – halt, sind die gekennzeichnet?

Betrieb der Plattform

Die Plattform ist bereits im produktiven Einsatz, tĂ€glich fĂŒhren wir Lieferungen und Verladungen durch, binden neue Verteilzentren und GeschĂ€fte an. Im Rahmen des Piloten arbeitet das System mit den Warengruppen 'Tabak' und 'Schuhe'.

Unser gesamtes Team ist an der DurchfĂŒhrung von Piloten beteiligt, analysiert aufkommende Probleme und macht VorschlĂ€ge zur Verbesserung unseres Produkts, von der Optimierung der Protokolle bis hin zu Änderungen der Prozesse.

Um meine Fehler nicht zu wiederholen, spiegeln sich alle im Rahmen des Piloten gefundenen FĂ€lle in den automatisierten Tests wider. Eine Vielzahl von automatisierten Tests und Unit-Tests ermöglicht es, Regressionstests durchzufĂŒhren und Hotfixes buchstĂ€blich innerhalb weniger Stunden bereitzustellen.

Derzeit entwickeln und verbessern wir unsere Plattform weiter und stehen stĂ€ndig neuen Herausforderungen gegenĂŒber. Wenn Sie interessiert sind, erzĂ€hlen wir in den kommenden Artikeln von unseren Lösungen.

Quelle: habr.com

60GB SSD 8Gb DDR4