Që nga viti 2019, në Rusi ka hyrë në fuqi një ligj për markimin e detyrueshëm. Ligji nuk zbatohet për të gjitha grupet e mallrave, dhe afatet e hyrjes në fuqi për grupet e mallrave janë të ndryshme. Së pari, markimi i detyrueshëm do të përfshijë duhanin, këpucët, ilaçet, dhe më vonë do të shtohen edhe mallra të tjera, siç janë parfumeritë, tekstili, dhe qumështi. Ky ndryshim ligjor ka nxitur zhvillimin e zgjidhjeve të reja IT që do të lejojnë ndjekjen e gjithë zinxhirit të jetës së produktit nga prodhimi deri te blerësi fundor, për të gjithë pjesëmarrësit në proces: si vetë shteti, ashtu edhe të gjitha organizatat që shesin mallra me markim të detyrueshëm.
Në X5, sistemi që do të ndjekë produktet me markim dhe do të ndajë të dhëna me shtetin dhe furnizuesit ka marrë emrin “Markus”. Do të tregojmë në rend se si dhe kush e ka zhvilluar, çfarë është steku i saj teknologjik, dhe pse kemi diçka për të qenë krenarë.

HighLoad i vërtetë
“Markusi” zgjidh shumë çështje, kryesorja e të cilave është ndërveprimi integrues midis sistemeve informative të H5 dhe sistemit publik të informacionit për produktet e markuara (GIS MP) për ndjekjen e lëvizjes së produkteve të markuara. Gjithashtu, platforma ruan të gjithë kodet e markimit që na kanë ardhur dhe gjithë historinë e lëvizjes së këtyre kodeve në objekte, ndihmon në eliminimin e përzierjes së produkteve të markuara. Në shembullin e produkteve të duhanit, të cilat ishin në grupet e para të produkteve të markuara, vetëm një kamion me cigare përmban rreth 600,000 paketa, secila prej të cilave ka kodin e saj unik. Dhe detyra jonë është të ndjekim dhe verifikojmë ligjshmërinë e lëvizjeve të secilës paketë të tillë midis depo dhe dyqaneve, dhe në fund të verifikojmë lejueshmërinë e shfrytëzimit të tyre nga blerësi i fundit. Kemi regjistruar rreth 125,000 operacione kasash në orë, dhe duhet gjithashtu të regjistrojmë se si çdo paketë e tillë ka mbërritur në dyqan. Prandaj, duke marrë parasysh të gjitha lëvizjet midis objekteve, ne presim disa dhjetra miliardë regjistrime në vit.
Ekipi M
Megjithëse "Markus" konsiderohet një projekt brenda H5, ai zbatohet sipas një qasje produkti. Ekipa punon sipas Scrum. Projektet filluan verën e vitit të kaluar, por rezultatet e para erdhën vetëm në tetor — u formua plotësisht ekipi ynë, u zhvillua arkitektura e sistemit dhe u ble materiale. Tani ekipi ka 16 persona, gjashtë prej të cilëve merren me zhvillimin e backend dhe frontend, tre me analizën sistematike. Testimi manual, krijimi i ngarkesave, testimi automatizuar dhe mbështetje e produktit përfshin edhe gjashtë persona të tjerë. Përveç kësaj, kemi një specialist SRE.
Kode në ekipin tonë shkruajnë jo vetëm zhvilluesit, pothuajse të gjithë djemtë dinë të programojnë dhe shkruajnë teste automatike, skenare ngarkese dhe skenare automatizimi. Ne i kushtojmë një kujdes të veçantë këtij, pasi edhe mbështetje e produktit kërkon një nivel të lartë automatizimi. Kolegëve që nuk kanë pasur eksperiencë në programim, gjithmonë përpiqemi t'u japim ndihmë dhe të sugjerojmë disa detyra të vogla për të punuar.
Me lidhjen e pandemisë së infeksionit nga koronavirusi, ne e transferuam tërë ekipin në punë të largët; disponimi i të gjitha mjeteve për menaxhimin e zhvillimit, si dhe punimi i strukturuar në Jira dhe GitLab na lejuan të kalojmë lehtësisht këtë fazë. Mënyra si zhvillua puna gjatë muajve të qëndrimit të largët tregoi se produktiviteti i ekipit nuk u prekur, për shumë persona komoditeti në punë u rrit, e vetmja gjë që mungon është komunikimi përballë përballë.
Takimi i ekipit para punës nga distanca

Takimet gjatë punës nga distanca

Staku teknologjik i zgjidhjes
Repositori standard dhe mjeti CI/CD për H5 është GitLab. Ne e përdorim atë për të ruajtur kodin, për testim të vazhdueshëm dhe për implementim në serverat testues dhe produktivë. Gjithashtu, ne përdorim praktikat e vlerësimit të kodit, ku së paku 2 kolegë duhet të miratojnë ndryshimet e bërë nga zhvilluesi në kod. Analisat statike të kodit me SonarQube dhe JaCoCo na ndihmojnë të mbajmë kodin të pastër dhe të sigurojmë nivelin e kërkuar të mbulimit me teste unitare. Të gjitha ndryshimet në kod duhet të kalojnë patjetër përmes këtyre verifikimeve. Të gjitha skenarët e testit që ekzekutohen manualisht, pas kësaj automatizohen.
Për të realizuar me sukses proceset biznesore me “Markus”, na duhej të zgjidhnim një sërë çështjesh teknologjike, për secilën nga to në rend të duhur.
Çështja 1. Nevoja për shkallëzimin horizontal të sistemit
Për ta zgjidhur këtë çështje, zgjodhëm një qasje mikropërfaqësuese në arkitekturë. Ishte shumë e rëndësishme të kuptonim zonat e përgjegjësive të shërbimeve. Përpiqemi t’i ndajmë ato sipas operacioneve të biznesit, duke marrë parasysh karakteristikat e proceseve. Për shembull, pranimi në magazinë është një operacion jo shumë i shpeshtë, por me një volum të madh, gjatë të cilit duhet të marrësh informacionin nga rregullatori shtetëror për njësi të pranueshme të mallrave, numri i të cilave në një dërgesë arrin deri në 600,000, të kontrollosh pranueshmërinë e këtij produkti në magazinë dhe të japësh të gjitha informacionet e nevojshme për sistemin e automatizimit të magazinës. Nga ana tjetër, shkarkimi nga magazinat ka një intensitet shumë më të lartë, por operon me sasi më të vogla të të dhënave.
Të gjitha shërbimet i realizojmë sipas parimit stateless dhe madje përpiqemi ta ndajmë operacionet e brendshme në hapa, duke përdorur, siç i quajmë ne, self-temat Kafka. Kjo është kur një mikroshërbim dërgon një mesazh vetes, gjë që lejon balancimin e ngarkesës për operacione më burimore dhe e thjeshton mbështetje produktit, por për këtë do flasim më vonë.
Ne vendosëm t’i ndajmë në shërbime të veçanta modulet e ndërveprimit me sistemet e jashtme. Kjo lehtësoi zgjidhjen e problemit të API-ve të jashtme që ndryshojnë shpesh, praktikisht pa ndikuar në shërbimet me funksionalitet biznesi.

Të gjithë mikroshërbimet vendosen në klasterin OpenShift, i cili zgjidh si problemin e shkallëzimit të çdo mikroshërbimi, ashtu edhe na lejon të mos përdorim mjete të jashtme për Zbulimin e Shërbimeve.
Detyra 2. Nevoja për të mbajtur një ngarkesë të lartë dhe një shkëmbim shumë intensiv të të dhënave midis shërbimeve të platformës: vetëm në fazën e fillimit të projektit kryhen rreth 600 operacione në sekondë. Ne presim që ky numër të rritet në 5000 ops/sek me lidhjen e objekteve tregtare në platformën tonë.
Kjo detyrë u zgjodh duke instaluar një klastri Kafka dhe duke eliminuar në mënyrë të praktikshme ndërlidhjen sinkrone midis mikroshërbimeve të platformës. Kjo kërkon një analizë shumë të kujdesshme të kërkesave për sistemin, pasi jo të gjitha operacionet mund të jenë asinkrone. Në të njëjtën kohë, ne nuk po kalojmë thjesht ngjarje përmes brokerit, por gjithashtu po përcjellim në mesazhin e kërkuar të gjitha informacionet e biznesit. Kështu, madhësia e mesazhit mund të arrijë disa qindra kilobajtë. Kufizimi i volumit të mesazheve në Kafka kërkon nga ne parashikimin e saktë të madhësive të mesazheve, dhe, në rast nevoje, ne i ndajmë ato, por ndarja është logjike, e lidhur me operacionet e biznesit.
Për shembull, mallrat që mbërrijnë me makinë, ne i ndajmë sipas kutive. Për operacionet sinhrone, krijohen shërbime mikro të veçanta dhe kryhet një testim i hollësishëm i ngarkesës. Përdorimi i Kafka na vuri përballë një sfidë tjetër — kontrolli i funksionimit të shërbimit tonë me integrimin e Kafka e bën çdo testim njësi të asinkronizuar. Këtë detyrë ne e zgjidhëm duke shkruar metoda tona utilitare duke përdorur Embedded Kafka Broker. Kjo nuk e anulon nevojën për të shkruar teste njësi për metodat e veçanta, por rastet e ndërlikuara preferojmë t'i testojmë duke përdorur Kafka.
I kemi kushtuar shumë vëmendje ndjekjes së logeve, në mënyrë që TraceId-t e tyre të mos humbasin kur ndodhin përjashtime gjatë funksionimit të shërbimeve ose gjatë punës me grumbuj Kafka. Dhe nëse me rastin e parë nuk kemi pasur ndonjë shqetësim të veçantë, në rastin e dytë jemi detyruar të regjistrojmë në log të gjithë TraceId-t me të cilat erdhi grumbulli, dhe të zgjedhim një për të vazhduar ndjekjen. Kështu, gjatë kërkimit për TraceId fillestar, përdoruesi do të zgjidhë lehtësisht se me cilin vazhdoi ndjekja.
Detyra 3. Nevoja për të ruajtur një sasi të madhe të dhënash: më shumë se 1 miliard markimesh në vit vjen vetëm nga duhani në X5. Këta kërkojnë akses të vazhdueshëm dhe të shpejtë. Sistemi duhet të përpunojë rreth 10 miliardë të dhëna për historinë e qarkullimit të produkteve të markuara.
Për zgjidhjen e detyrës së tretë u zgjodh baza NoSQL MongoDB. Ne kemi ndërtuar një shard prej 5 nodash dhe në çdo nod ka një Replica Set prej 3 serverash. Kjo lejon që sistemi të shkallëzohet horizontalisht, duke shtuar servera të rinj në klaster dhe të sigurojmë disponueshmërinë e tij. Këtu u përballëm me një problem tjetër — sigurimin e transaksionit në klasterin mongo duke marrë parasysh përdorimin e mikroshërbimeve që shkallëzohen horizontalisht. Për shembull, një nga detyrat e sistemit tonë është të identifikojë përpjekjet për shitje të përsëritura të produkteve me kode të njëjta etiketimi. Këtu shfaqen problematika me skanimet e gabuara ose me operacionet e gabuara të kasave. Ne zbuluam se këto kopje mund të ndodhin si brenda një batch-i të përpunuar nga Kafka, ashtu edhe brenda dy batch-esh që përpunohen paralelisht. Prandaj, kontrolli i shfaqjes së kopjeve përmes një kërkese ndaj bazës nuk jepte asgjë. Për secilin nga mikroshërbimet ne zgjidhëm problemin veçmas duke u bazuar në logjikën e biznesit të këtij shërbimi. Për shembull, për faturat, shtuam një kontroll brenda batch-it dhe një përpunim të veçantë për shfaqjen e dublikatave gjatë futjes.
Për të siguruar që puna e përdoruesve me historinë e operacioneve të mos ndikojë në të rëndësishmen — funksionimin e proceseve tona biznesore, të gjitha të dhënat historike i kemi veçuar në një shërbim të veçantë me një bazë të dhënash të veçantë, e cila gjithashtu merr informacione përmes Kafka. Kështu, përdoruesit punojnë me një shërbim të izoluar, pa ndikuar në shërbimet që përpunojnë të dhëna për operacionet aktuale.
Detyra 4. Riprocesimi i radhëve dhe monitorimi:
Në sistemet e shpërndara, problemet dhe gabimet e aksesueshmërisë së bazave të dhënash, radhëve dhe burimeve të jashtme të të dhënave janë të pashmangshme. Në rastin e "Markus", burimi i këtyre gabimeve është integrimi me sistemet e jashtme. Duhej të gjendej një zgjidhje që lejonte kryerjen e kërkesave të përsëritura për përgjigje të gabuara brenda një afati të caktuar, por pa ndalur trajtimin e kërkesave të suksesshme në radhën kryesore. Për këtë, u zgjodh koncepti i quajtur "ripozitim i bazuar në tema". Për secilën temë kryesore krijohen një ose disa tema të ripozituara, në të cilat dërgohen mesazhet e gabuara, duke përjashtuar vonesën në përpunimin e mesazheve nga tema kryesore. Skema e bashkëpunimit —

Për realizimin e këtij skenari na duhej të bënim të mundur integrimin e këtij zgjidhjeje me Spring dhe të evitonim dublimin e kodit. Në hapësirën virtuale ne u ndeshëm me një zgjidhje të ngjashme, të bazuar në Spring BeanPostProcessor, por na dukej tepër e rëndë. Ekipa jonë krijoi një zgjidhje më të thjeshtë, që lejon të integrohen në ciklin e krijimit të konsumatoreve të Spring dhe të shtohen për më tepër Konsumatorët me Rikthim. Prototipi i zgjidhjes sonë iu propozua ekipit të Spring, mund ta shikoni . Numri i Konsumatorëve me Rikthim dhe numri i përpjekjeve të çdo konsumatoreje konfigurohen përmes parametrave, në varësi të nevojave të procesit të biznesit, dhe, për t'u siguruar që gjithçka të funksionojë, mbetet vetëm të vendosni njohuritin e njohur për të gjithë zhvilluesit e Spring, annotimin org.springframework.kafka.annotation.KafkaListener.
Në rast se mesazhi nuk mund të procesonit pas të gjitha përpjekjeve për riprovim, ai kalon në DLT (temën e letrave të vdekur) me ndihmën e Spring DeadLetterPublishingRecoverer. Në kërkesë nga ekipi i mbështetjes, ne zgjatëm funksionalitetin dhe krijuam një shërbim të veçantë që lejon shikimin e mesazheve të dërguara në DLT, stackTrace, traceId dhe informacione të tjera të dobishme në lidhje me to. Përveç kësaj, monitorimi dhe alarmin janë shtuar për të gjitha temat DLT, dhe tani, në thelb, shfaqja e një mesazhi në temën DLT është një shpërndarje dhe ka të bëjë me regjistrimin e një defekti. Kjo është shumë e përshtatshme — nga emri i temës ne menjëherë kuptojmë në cilin hap të procesit ka ndodhur problemi, që ndjeshëm shpejton kërkimin e shkakut të saj të rrënjosur.

Së fundmi kemi implementuar një ndërfaqe që lejon dërgimin e mesazheve përsëri nga ekipi ynë i mbështetjes, pas zgjidhjes së shkakut të tyre (për shembull, rikthimi i funksionalitetit të sistemit të jashtëm) dhe, natyrisht, regjistrimin e një defekti për analizë. Këtu na erdhën në ndihmë temat tona self, që për të mos riparësa një zinxhir të gjatë përpunimi, mund ta nisim atë nga hapi i duhur.

Eksploatimi i platformës
Platforma është tashmë në funksionim produktiv, çdo ditë ne realizojmë dërgesa dhe shpërndarje, duke lidhur qendrat e reja të shpërndarjes dhe dyqane. Në kuadër të pilotit, sistemi punon me grupe produktesh "Tavak" dhe "Këpucë".
E gjithë ekipi ynë merr pjesë në zhvillimin e pilotëve, analizon problemet e shfaqura dhe propozon përmirësime për produktin tonë nga përmirësimi i shtypshkrimeve deri te ndryshimet në procese.
Për të shmangur përsëritjen e gabimeve tona, të gjitha rastet që u zbuluan gjatë pilotit reflektohen në testet automatike. Prania e një numri të madh testesh automatik dhe testeve unitare na lejon të kryejmë teste regresioni dhe të vendosim hotfix brenda disa orësh.
Aktualisht, ne vazhdojmë të zhvillojmë dhe përmirësojmë platformën tonë, dhe vazhdimisht përballemi me sfida të reja. Nëse jeni të interesuar, do të flasim për zgjidhjet tona në artikujt e ardhshëm.
Burimi: habr.com
