Verze 8.17 ve znamení optimalizace publikačního žurnálu

V nové verzi naší CMS a e-commerce platformy jsme se zaměřili na důležitou optimalizaci publikačního mechanismu. Nyní funguje nesrovnatelně rychleji.

Edee.one udržuje data ve dvou formách:

  1. primární data jsou optimalizovaná pro jednoduchost zápisu a správu uživateli systému a integrace s ERP systémy
  2. sekundární data jsou optimalizovaná pro rychlé čtení a konzumaci stovkami paralelních uživatelů současně

V systému existuje tzv. žurnál operací, který sleduje operace v primárním úložišti a umožňuje tyto změny přenést do sekundárních úložišť. Tento žurnál se používá nejen pro interní tzv. publikační mechanismus, ale i pro kontinuální export změn do externích systémů např. Mall marketplace.

Cílem je udržovat publikační proces tak rychlý, aby veřejná část za primárními daty příliš nezaostávala. 

Objem aktualizací, které si naše e-shopy vyměňují s ERP na pozadí však neustále narůstá a s tím se zpomaloval i výkon publikačního procesu. Jen pro představu denně si některé instalace s ERP vymění i desítky tisíc aktualizací. Jedna aktualizace v ERP často znamená potřebu zaktualizovat mnoho záznamů publikovaných informací, protože produkt je prodáván na několika různých e-shopech nebo díky dědičnosti mezi produkty se tato změna propaguje do dalších položek, které ze zdrojového produktu tuto informaci tzv. “dědí”.

Drobné, ale důležité optimalizace publikačního mechanismu

   1. Původní forma publikace produktu probíhala tak, že pokud se jakýkoliv údaj u produktu změnil, produkt se na frontendu přepublikoval. Bylo to nejjednodušší programátorské řešení. Měřením se však zjistilo, že díky tomuto přístupu, tráví publikační proces hodně času na přepisu dat, které se vlastně nezměnily. 

Tj. pokud se změnil třeba jen stav produktu, bylo nutné přepsat produkt celý včetně titulku, popisu a dalších údajů. Nově jsme pro často modifikované vlastnosti entit zavedli zvláštní typy žurnálových záznamů a publikace pro ně probíhá samostatně a mnohem efektivněji.

   2. Pokud dnes u jednoho produktu proběhne více změn se společným průnikem, tak se z hlediska publikace tyto změny zpracují dávkově a pouze jednou. 

Jako příklad je možné uvést změnu, kdy se na produktu změní skladové množství, dostupnost a současně viditelnost. Všechny tyto charakteristiky mají vliv na to, zda bude produkt na e-shopu viditelný, či nikoliv. Dříve každá změna vytvořila záznam do změnového žurnálu, který se publikoval samostatně. Nově systém vyhodnotí, že všechny 3 změny vyvolají publikaci viditelnosti, a tato publikace se provede pouze jednou.

   3. Někteří naši klienti nabízí produkty s mnoha variantami (tedy různé barvy, velikosti, provedení) - někdy i tisíce kombinací jediného produktu. Pro takové produkty si vedeme tzv. master produkt, který obsahuje agregovaná, zjednodušená data o všech variantách, a potom pro každou kombinaci variantních parametrů jeden produkt tzv. varianty. Při změně informací varianty (např. změna stavu, dostupnosti, viditelnosti) se změna musí projevit u varianty i u master produktu. Dříve změny u dvou set variant vyvolaly také 200x přepublikování master produktu. 

Nově se změny pouze evidují a až po vypublikování změn u variant se změny aplikují i u masteru, ale pouze už jednou. Při publikaci první změněné varianty se zaznamená, že je změnu nutné promítnout i u masteru. Pro další varianty se další záznam nezapisuje, protože již existuje. Na závěr, po zpracování všech variant, se teprve publikuje jednorázově změna u master produktu.

   4. Některé změny, které se provádí na master produktu, se musí promítnout i do variant. Například pokud varianty dědí ceny z masteru, tak změna ceny na masteru se musí promítnout i na variantě. V případě, že variant bylo mnoho, tak při zpracování změn v rámci master produktu docházelo k velkým paměťovým nárokům a někdy i vyčerpání paměti. Publikace změn na variantách nyní probíhá samostatně, což sice prodlužuje publikaci, ale systém je celkově stabilnější.

Změna přístupu k třídění v primárních i publikovaných datech

V původním řešení (které nebylo stavěné na současné množství položek, zejména produktů) měla každá entita svoji prioritu, podle které se určovalo její pořadí při výpisu na frontendu. 

Priorita bylo celé číslo od jedničky (nejnižší priorita, zobrazení až na konci výpisu) výše (nejprioritnější entita měla tedy prioritu rovnou počtu entit). V případě potřeby některou entitu posunout ve výpisu vpřed či vzad, bylo nutné všem entitám ležícím mezi aktuální a novou pozicí posunout prioritu o 1 vzad či vpřed a všechny tyto změněné entity znovu vypublikovat do sekundárních úložišť (totéž se muselo dít v případě odstranění entity či přidání úplně nové). 

Při častých změnách (zejména při synchronizaci s externími systémy) to neúměrně zatěžovalo publikační proces (např. při odstranění 100 produktů ze začátku seznamu se 100 tisíci produkty způsobilo vygenerování 10 milionu publikačních změn - při zpracování se sice zpracovalo vždy 100 záznamů pro stejný produkt najednou, ale práce s databázovou tabulkou s takovým množstvím záznamů již nebyla příliš rychlá).

Zvažovali jsme i metodu půlení intervalu, aby nebylo nutné měnit prioritu ostatním entitám, ale pouze té aktuálně přesouvané/vytvářené. Při tomto přístupu ovšem velmi brzy (již po desítkách přesunů) dojde k vyčerpání rozsahů datových typů v relační databázi. Pak by muselo pravidelně docházet k nějaké normalizaci uložených údajů priorit a opět bychom se tím dostali do úzkých při přepublikaci těchto změn do sekundárních úložišť.

Nové řešení využívá principu spojového seznamu, konkrétně toho, že každá entita má vazbu (ukazatel) na předchozí entitu. V případě přesunu tak stačí publikovat pouze změny v původním a novém okolí přesouvané entity (tedy přesněji v jejím původním následníkovi, v jejím novém následníkovi a v entitě samotné - tedy pouze 3 změny, bez ohledu na vzdálenost posunu). Obdobně při mazání entity či přidávání nové. 

Samozřejmě i při vývoji nového řešení nastaly komplikace. Např. pokud je potřeba nové záznamy ukládat místo na konec záznamu na jeho začátek - tedy je potřeba odkázat původní první entitu na nově ukládanou, která ovšem nemá do doby uložení do databáze přiřazené ID. 

Další komplikace nastává v případě, kdy vznikne požadavek přebírat hodnotu samotné priority z externího systému. V takovou chvíli již nelze posunovat priority ostatních entit a je nutné tedy počítat s duplicitami i mezerami v posloupnosti priorit (alespoň dočasnými, protože synchronizace z externích systémů probíhá jednotlivě), z tohoto důvodu se při výpočtu vazby na předchozí entitu bere v potaz ještě její id jako sekundární atribut pro určení pořadí. 

Při publikaci pro frontend je nyní také potřeba dávat pozor na pořadí publikace (entita, na kterou se aktuálně publikovaná entita odkazuje, již musí být sama vypublikovaná), což se ještě komplikuje u produktů, u nichž eshop bere v potaz dvojí prioritu - jednu globální a druhou ve vazbě na zařazení produktu do kategorie - pořadí stejných produktů v těchto dvou řadách může být opačné. V takovém případě je třeba publikaci takových vazeb odložit do doby, kdy již bude předchozí produkt vypublikovaný (ve smyslu zařazení do kategorie).

Toto řešení by nebylo možné, pokud bychom pro vyhledávání na frontendu nepoužívali vlastní řešení, které řazení dle spojového seznamu umožňuje. Novější verze mysql sice umožňují hierarchické dotazy, ale výkonnost se na větších množstvích entit ukazuje jako nedostatečná.

Chcete zapojit Edee.one
do budování úspěchu
své společnosti?