pavelevap / ceske-sluzby

České služby pro WordPress
56 stars 25 forks source link

XML feedy velké množství produktů 20k+ #27

Open novetrendy opened 8 years ago

novetrendy commented 8 years ago

Narazil jsem na problém u jednoho shopu, který má kolem 20 tisíc produktů. I když má 256 MB memory limit, tak je pořád hláška memory exhaust.

pavelevap commented 8 years ago

Tak 20 tisíc jsem tedy nezkoušel :-) Můžete zkusit, zda se nevygeneruje ani soubor pro Pricemania? Ten je generován trochu jiným způsobem, který by měl být trochu úspornější...

novetrendy commented 8 years ago

To bohužel nejde, protože při aktivaci xml se shodí kompletně celý web, včetně frontendu.

novetrendy commented 8 years ago

Tak jsem zakomentoval heureku a zbozi, spustil jen pricemania a chyba se změnila. Feed vygeneruje, ale je chyba s parsováním.

Chyba parsování XML: Nenalezen žádný prvek
Adresa: http://domena.cz/obsah/pricemania.xml
Řádek 73982, sloupec 1:
pavelevap commented 8 years ago

Po aktivaci feedů dojde automaticky k vygenerování souboru pro Pricemania: https://github.com/pavelevap/ceske-sluzby/blob/master/ceske-sluzby.php#L399

A tam patrně dojde k problému s pamětí. Ostatní feedy by měly být zpracovány pouze v případě, když si je někdo zobrazí.

Chyba parsování může souviset s tím, že skript někde skončil kvůli nedostatečné paměti. Pokud má každá položka cca 7 řádků, tak mohl skončit někde v polovině. Zatím jsem zkoušel maximálně 3000 produktů a tam bohatě stačil limit 128 MB, ale asi by se to dalo nějak optimalizovat...

Mohl bych dostat přístupy a podívat se, co způsobuje konkrétně problémy s pamětí?

novetrendy commented 8 years ago

Zítra večer Vám pošlu email s přístupy, aby jste mohl otestovat.

pavelevap commented 8 years ago

Tak jsem to zkoušel a máte pravdu, 128 MB stačí asi na 3000 produktů, takže na 20 tisíc potřebujete paměť skoro 1 GB :-( Zkusím se na to ještě podívat, zda by to nešlo optimalizovat...

novetrendy commented 8 years ago

Super, díky. Přístup jsem Vám ještě nestihl zřídit, kdyby jste potřeboval jen řekněte. Ale je to ostrý web, proto Vám budu muset udělat i ftp přístup, protože když plugin aktivujete, už se nikam nedostanete.

novetrendy commented 8 years ago

Ještě mě napadlo, jestli by nebylo lepší tahat to přímo z databáze, než přes api, tím by se asi trošku ušetřilo. A jeden dotaz, kdy se generuje feed heureka a zbozi? Jen při otevření URL, nebo je na to nějaký cron? U pricemanie je to přes schedule, to jsem si všiml, ale u těch předchozích nevím. Pokud se ve stejný čas generuje heureka a zbozi, chce to logicky 2x více paměti. Pokud ne, berte dotaz jako bezpředmětný.

pavelevap commented 8 years ago

Celá problematika je trochu složitější :-)

Nejdříve jsem XML feedy přidal jen jako klasický RSS zdroj, tedy že se generují pouze ve chvíli, kdy je zobrazena jejich URL adresa. Hlavním důvodem byla okamžitá aktuálnost (ve chvíli zobrazení feedu byl nejaktuálnější stav) a nebylo potřeba řešit ukládání souborů a nastavování cronů.

Pak ale nastal problém s Pricemania, která to neumožňuje a chce klasický soubor (a nikoli průběžně generovaný RSS zdroj). Takže jsem to musel nakonec stejně všechno implementovat :-)

Občas má ale někdo problémy s velikostí feedu a tam není průběžně generovaný RSS zdroj moc vhodný, zejména proto, že to trvá hodně dlouho a např. robot Zboží.cz s tím má problém a když je tam třeba cca 2000 produktů, tak dojde k timeoutu (u Heureky jsem se s tím nesetkal). Takže bude třeba všechny feedy migrovat na klasické generování souborů, které probíhá jednou denně, což je asi dostačující. Problém ale je, že stovky lidí tam už mají doplněnou adresu feedu, který pak přestane fungovat, takže tam musím přidat ještě nějaké automatické přesměrování.

Pro velké eshopy jsem ale implementoval nové řešení, kde je feed zpracováván dávkově. Jednou denně je spuštěn proces cronu pro generování feedu, ale nebude se generovat celý najednou, ale pokaždé bude zpracováno pouze 1000 produktů. Potřeboval jsem to i pro další projekty, takže se to bude hodit :-) U malých eshopů to tedy bude hned, velké eshopy to budou mít generované postupně. Fungovat to bude tak, že se zapíše prvních 1000 produktů do tmp souboru a zároveň se nastaví další cron za 3 minuty, kdy se zapíše dalších 1000 produktů, atd. Jakmile bude hotovo, tak se tmp soubor přejmenuje na feed a smaže se dřívější soubor. V tomto případě by mělo stačit i 64 MB PHP paměti pro desítky tisíc produktů. Už to mám hotové, po otestování to sem pustím. Pokud máte 20 tisíc produktů, tak může generování souboru probíhat poměrně dlouho (teoreticky sice jen 20 x 3 minuty, ale cron je spouštěn pouze při návštěvě nějakého uživatele, takže prakticky to bude spíše několik hodin). Nebo by se mohl zvýšit limit, zatím je odhadem potřeba cca 128 MB paměti na 2500 produktů.

Nějaké nápady, kde by mohl být problém? Než bude feed kompletně vygenerován, tak můe dojít třeba k nějaké změně ceny, ale to by nemělo vadit, protože to pak bude ve feedu druhý den aktualizováno správně. Zatím jediné, co mě napadlo spočívá v tom, že proběhne prvních 1000 produktů a někdo v administraci třeba nějaký produkt smaže či přidá. Potom tam pak ale bude chybět, takže když budeme v druhé dávce pokračovat od produktu č. 1001, tak to může být produkt, který měl dříve pořadí 999 (a už je zahrnut ve feedu), potom někdo přidal (třeba i nějaký importní skript) další novější produkty a nově má pořadí č. 1001 a bude v druhé dávce, takže bude v XML duplicitně. Je to asi náhoda, ale nevím jak porovnávače řeší duplicity?

pavelevap commented 8 years ago

Zájemci mohou zkusit otestovat, bez nějakých pozitivních zpětných reakcí to nemůžu pustit ven pro všechny :-)

novetrendy commented 8 years ago

Dobrý den, na email jsem Vám poslal loginy do eshopu s velkým množstvím produktů. Pořád vykazuje chyby, tak se na to prosím mrkněte. Díky

pavelevap commented 8 years ago

Zkuste prosím feed pro Zboží v nejnovější verzi, už by to měl také zvládnout (pozor, může to nějakou dobu trvat než se vygeneruje, záleží na počtu produktů). Odkaz na soubor je uveden v administraci (u nastavení XML).

novetrendy commented 8 years ago

Nainstaloval jsem nejnovější verzi, zítra dám vědět :)

novetrendy commented 8 years ago

Jedka chybka, v odkazu v administraci je natvrdo uveden wp-content, místo . WP_CONTENT_URL . Včera jsem spustil nyní tam mám feed zbozi-tmp.xml, který je kompletní (166084 řádků :)) zbozi.xml není, možná se nepřejmenoval, nedíval jsem se do kódu, jak to máte provedené. Díky, super práce!

novetrendy commented 8 years ago

Tak bohužel, do souboru zbozi-tmp.xml se neustále přidává, nyní je v něm feed již 3x a má přes 30MB. Původní měl 10MB.

pavelevap commented 8 years ago

@novetrendy: Pravda, souvisí to s tím, že se soubor vůbec nepřejmenuje, protože tam je chybná podmínka. Dnes nebo zítra opravím, ale mělo by stačit soubor zbozi-tmp.xml přejmenovat na zbozi.xml a dál už to bude bez problémů fungovat a při dalším spuštění se to dá všechno do pořádku. Během testování jsem tam už totiž tento soubor měl, takže jsem chybu neodhalil, ale když ještě neexistuje, tak dochází k problémům...

novetrendy commented 8 years ago

Super! Díky za odpověď.

pavelevap commented 8 years ago

@novetrendy: Během několika posledních commitů jsem všechny nahlášené chybky snad opravil, díky za report!

novetrendy commented 8 years ago

Dobrá práce! Během zítřka otestuji a dám vědět.

pavelevap commented 8 years ago

@novetrendy: Pozor, nejnovější commit (https://github.com/pavelevap/ceske-sluzby/commit/bdd1966c7ca2b3da961da300e9050b8995d0da7b) umožnil aktivovat pouze generování některých feedů, takže je musíte po aktualizaci ještě v nastavení ručně povolit, jinak se už do budoucna nebudou .xml soubory pravidelně aktualizovat. Klasických feedů na adrese ?feed=nazev se to netýká, ty budou fungovat stále. Bohužel to ale jinak udělat nešlo a bylo to potřeba, protože ne všichni používají všechny porovnávače a nechceme zbytečně zatěžovat servery. A stále jsme alpha verze :-)

pavelevap commented 8 years ago

Asi ještě raději použít content_url() místo WP_CONTENT_URL.

alesmenzel commented 8 years ago

Velké množství produktů jsem řešil drobnou úpravou skriptu následovně:

   ... //foreach loop pro projití produktů        

       if ($key%25 == 0){ // po 25 produktech se uloží do souboru
            file_put_contents($file_name, $xmlWriter->flush(true), FILE_APPEND);
            $xmlWriter->flush();
        }
    }

    wp_reset_postdata();

    $xmlWriter->endElement();
    file_put_contents($file_name, $xmlWriter->flush(true), FILE_APPEND); // přidá zbylé produkty

    // nakonec vypíši pouze soubor
    header( 'Content-type: text/xml' );
    echo file_get_contents($file_name);

Samozřejmě počet produktů, dle kterého se ta iterace provede by bylo hezčí mít jako parametr a mít možnost jej měnit v administraci.

pavelevap commented 8 years ago

@AlesMenzel: Zajímavé, podobné řešení (rozsekat na více cyklů) jsem také původně zkoušel, ale bohužel mi to s pamětí moc nepomáhalo... Nemohl byste celý skript někam nahrát, abych ho mohl vyzkoušet? Díky!

pavelevap commented 8 years ago

Pokud dojde k nějaké chybě skriptu (např. https://github.com/pavelevap/ceske-sluzby/commit/62d688b31930d48b12322b02374366c81163699c), tak zůstane .lock option uložena a brání dalšímu spouštění, asi by to chtělo uživatele nějak upozornit nebo automaticky jednou denně pročistit?

pavelevap commented 8 years ago

Opravena jedna nepěkná chybka (naštěstí se tam dostala teprve nedávno): https://github.com/pavelevap/ceske-sluzby/commit/3d55f0b0c9f9e3902d44b495cb7a10fb326cc416

Generování do souboru se bude ještě vylepšovat (viz úkoly výše), ale asi až v další verzi.

pavelevap commented 5 years ago

Tak tohle se myslím docela povedlo :-) Nově je možné jednoduše zkontrolovat zobrazení jednotlivého produktu v konkrétním XML feedu a už není potřeba si stahovat celý feed a pracně ho tam hledat.