cronjob php script & memory

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Dennis WhoCares

Dennis WhoCares

05/03/2017 18:33:43
Quote Anchor link
Dag allemaal,

ik maak gebruik van een cronjob on elke 2 uur een bestand te downloaden (csv, of zip)
dit bestand wordt uitgepakt indien nodig, en dan het csv bestand in stukken gehakt (indien nodig)
vervolgens importeer ik de csv op basis van mijn eigen database.

de import bevat voor elke regel een SELECT en indien er een resultaat is, enkele simpele berekeningen en een UPDATE achteraan.

Nou heb ik het probleem dat elke 2 uur m'n CPU omhoog vliegt en ook ALLE geheugen waardoor er op dat moment t/m 5 minuten ofzo vrijwel geen verkeer mogelijk is.
Op dat moment kan ik nieteens met ssh inloggen.
Als ik wel ingelogt ben kan ik op dat moment nieteens 'top' uitvoeren (linux server) dat er geen geheugen beschikbaar is.

Dus mijn vraag is eigenlijk:
-hoe weet ik hoeveel geheugen die cronjobs gebruiken
-hoe kan ik een memory limit geven

ik heb een simpele VPS 2x duo core cpu's en 4GB geheugen
Ik ben bang dat het niet veel uitmaak dat ik upgrade naar 4 CPU en 8GB geheugen?

Ik hoor graag van jullie!
 
PHP hulp

PHP hulp

24/12/2024 13:20:07
 
- Ariën  -
Beheerder

- Ariën -

05/03/2017 18:43:13
Quote Anchor link
Ik zou eerder kijken waarom er veel geheugen wordt gebruikt. Kijk eens naar memory_get_peak_usage()
 
Dennis WhoCares

Dennis WhoCares

05/03/2017 19:12:14
Quote Anchor link
Ho Arien

thanks, maar.. op welke momenten moet ik dit doen dan?
Aan het begin, halverwege aan het einde?
Het script geeft geen output, en ik draai t dmv nohup
Ik kan het 'loggen'

Ik zit te denken om t te loggen met timestamps naar een file
begin, voor en na download, voor/na uitpak, einde

zou ik ook bij elke regel moeten loggen?

het gaat in principe maar om een csv bestand van max. 16mb
want ik hak ze in stukken ook.

kan ik niet gewoon een max. memory geven, alleen dan is de vraag hoe bepaal ik het limiet het beste
Gewijzigd op 05/03/2017 19:13:53 door Dennis WhoCares
 
- Ariën  -
Beheerder

- Ariën -

05/03/2017 20:01:30
Quote Anchor link
Je kan de memorywaarde prima loggen in een txt-file. Als er veel geheugen wordt gebruikt denk ik vaak aan een infinite loop.
 
Dennis WhoCares

Dennis WhoCares

05/03/2017 20:09:18
Quote Anchor link
Hi Arien,

ik zal eens een beetje gaan loggen. Per script een eigen file en daarna kan ik hier snel ff een grafiek oid van maken :)


Ik had daarnet wel weer een piek, maar dat bleek CPU te zijn op een process van mysql
"/usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir............"
Alleen zegt het verder ook niet veel

De CPU voor dit process sprong van 45 seconden naar 120%

Maar ik wil dit zsm goed oplossen omdat ik in toekomst nog meer van dit soort imports zal gaan draaien..

Er is geen 'oneindige' loop in m'n cron scripts.. Dat weet ik 100% zeker, maar sommige kunnen wat langer draaien dan andere, door o.a. downloaden van grote csv of zip file, het 'splitten' van de file(s) om sneller te kunnen verwerken enz.
 
- Ariën  -
Beheerder

- Ariën -

05/03/2017 20:37:09
Quote Anchor link
Ga daarom per onderdeel de performance loggen.
 
Ivo P

Ivo P

05/03/2017 23:18:00
Quote Anchor link
misschien is een andere benadering handiger:

Mysql kan prima met LOAD DATE INFILE een csv bestand inlezen.
Kun je in een tijdelijke tabel pompen.

En daarna zou ik 1x query doen die met een join tussen de doeltabel en de tijdelijke tabel de zaak update.

Klink nu namelijk of je 1000 SELECT query's afvuurt en een berg updates. Waarbij je mogelijk steeds meer PHP variabelen aanmaakt om je geheugen te vullen.

Dan lijken 2 query's me efficiënter
 
Ben van Velzen

Ben van Velzen

05/03/2017 23:24:46
Quote Anchor link
Dat, en een borkend mysql proces geeft ook te denken over de efficientie van je queries, indexes, en mogelijk je mysql configuratie. Kijk hier dus ook zeker naar.
 
Dennis WhoCares

Dennis WhoCares

06/03/2017 07:07:58
Quote Anchor link
Goede morgen allen,

ik ga nu memory logs invoeren en dan weet ik rond 8:30 wellicht iets meer.
Om meer toelichting te geven @Ivo en Ben over de import.

ik heb verschillende csv files, met daarbij allemaal hun eigen kolommen
Een oplossing daarvoor had ik als volgt: een 'settings' file voor de import waarbij ik het volgende gedefineerd heb:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
$settings = array('import_file' => 'local_path_to_the_csv_file',
'import_colomn_0_to => mijn_database_kolom',
import_colomn_1_to => mijn_database_kolom2',
import_colomn_2_to => '',
import_colomn_3_to => '',
'import_colomn_4_to' => 'mijn_database_kolom3',
...
...
'import_colomn_31_to' => 'mijn_database_kolom4',
'import_uniqueField' => 'mijn_database_kolom_3');


Hierna volgt vanuit PHP nogmaals een nohup commando dat m'n import script triggered.

Voor elke regel in de csv file, controlleer ik of ik wel alle data heb (op basis van de 'settings' file) die ik nodig heb (het kan weleens wezen dat de csv geen goede opmaak heeft en niet alle kolommen mee komen.
Daarna normaliseer ik de waardes zoals bedragen, voorraad enz

Daarna doe ik een SELECT op import_uniqueField
als er een result is, doe ik deze updaten.

En aan het einde altijd een die(); gewoon voor het geval dat.

@Ivo,
aangezien de CSV files allemaal anders zijn, zou ik deze 'tijdelijke' tabel eerst kunnen creeren (dynamisch of 1 standaard grote tabel maken, met dezelfde veldnamen als m'n settings file, maar dan ... t/m import_colomn_100_to (als voorbeeld)) en dan alles erin zetten
Zou dat inderdaad beter zijn?

vervolgens 1 lange SELECT dmv JOIN om de relatie te leggen tussen import_uniqueField?
Ik moet alsnog alle updates 1 voor 1 doen, omdat voorraad en prijzen nogal wat berekeningen nodig heeft, dus houd ik altijd nog duizenden update queries, + uiteraard maar 1 grote SELECT query

Wellicht een goed idee
Dit is alsnog wel per import file, omdat ze allen anders zijn. En andere 'settings' hebben.


@Ben, de queries zijn simpel: SELECT field_id FROM table WHERE field_id = $cvsRow[$settings['import_uniqueField']]

Aan wat voor configuratie zat je te denken eigenlijk? Ik heb geen aparte configuratie toegepast op de mysql service.
 
Ivo P

Ivo P

06/03/2017 09:02:43
Quote Anchor link
"Daarna doe ik een SELECT op import_uniqueField
als er een result is, doe ik deze updaten."

Dus als uniqueField = "abc123" niet bestaat, doe je niets en anders doe je een update query?

Dat is dus gelijk aan
UPDATE tabel SET .... WHERE uniqueField="abc123"

als die niet gevonden is, doet zo'n query namelijk precies niets.

Toevoeging op 06/03/2017 09:08:34:

LOAD DATA INFILE kan heel snel een tabel vullen. Met alle kolommen 1 op 1 matchend, of alleen kolom 1, 5 en 23 uit je file.
Je kunt er zelfs nog een bewerking op doen op het moment van importeren:

LOAD DATA INFILE 'file.txt'
INTO TABLE t1
(column1, @var1)
SET column2 = @var1/100;

Maar ook opties als
LOAD DATA INFILE 'file.txt'
INTO TABLE t1
(column1, column2)
SET column3 = CURRENT_TIMESTAMP;

of
LOAD DATA INFILE 'file.txt'
INTO TABLE t1
(column1, @dummy, column2, @dummy, column3);

waarbij dan dus kolom 2 en 4 uit file.txt eigenlijk gewoon overgeslagen worden.

En wat voor soort berekeingen heb je nodig die zo moeilijk zijn mbt de prijs?
 
Ward van der Put
Moderator

Ward van der Put

06/03/2017 09:25:07
Quote Anchor link
Je vergelijkt data in een nieuwe CSV met data in je database, maar je zou er nog een vergelijking aan vooraf kunnen laten gaan. Als je namelijk elke 2 uur een CSV downloadt, is er een grote kans dat zo'n 50 tot misschien wel meer dan 80 procent van dat CSV-bestand identiek is aan het CSV-bestand dat je 2 uur eerder al verwerkt hebt. Kortom: je hoeft alleen de diff met nieuwe of gewijzigde data te verwerken, want de rest heb/weet je al.

Aangezien fgetcsv() een array retourneert, zou je het verschil tussen twee CSV-bestanden bijvoorbeeld kunnen vinden met array_diff().

Bijkomend voordeel is dat je dan ook nog het opschonen van de CSV-bestanden kunt beperken tot de nieuwe of gewijzigde data als je eerst alle overeenkomsten tussen de oorspronkelijke CSV's weggooit.
 
Ivo P

Ivo P

06/03/2017 09:34:32
Quote Anchor link
of gebruik tools die linux (meestal) beschikbaar heeft:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
diff --unchanged-line-format= --old-line-format= --new-line-format='%L' oldfile.csv newestfile.csv > result.csv


Dat levert je in result.csv die nieuw toegevoegde regels
en de regels met verschillen.

NB: dit werkt niet per se als de volgorde van de regels kan verschillen. Maar dat is op zich niet erg, want dan krijg je er hooguit wat meer te verwerken.
 
Dennis WhoCares

Dennis WhoCares

06/03/2017 10:01:18
Quote Anchor link
Hi Ward en Ivo,
Inderdaad zou een diff check functie ook al een hoop schelen, hoewel de csv opmaak nogal verschilt per 'aanbieder'.
Vooral de laatste comment van Ivo moet ik eens naar kijken ! Enorm bedankt daarvoor!
Deze moet ik eens goed testen

De prijzen zijn dynamisch op basis van marges,percentages en 'gemonitorde' concurrentie en als basis de inkoop prijs per hoeveelheid uit de csv welke vaak veranderd.

Ik kijk de logs later ook nog even na, heb even wat anders te doen (werk) dus geen tijd voor prive ;-)
Ik ga een pvp maken voor het verbeteren van de 'prepare import' scripts en importscript
- diff csv file => previous == NEW csv file containing only changes
-- run import if needed at all
- only run update query for import, as only changes are being

Zou ik hierbij alsnog gebruik moeten maken van een 'tijdelijke' tabel ?

Ik denk dat dit al een hele verbetering is qua performance, enorm bedankt voor jullie reacties en tips, ik neem ze zeker allemaal in overweging.

De performance van de gehele server is laatste dagen al aan het verbeteren door ssh en ftp connecties alleen vanuit NL toe te staan, en daarnaast nog fail2ban geïnstalleerd en geconfigureerd. (vanwege vele 'hack-attampts')
 
Dennis WhoCares

Dennis WhoCares

07/03/2017 12:25:46
Quote Anchor link
Hi Ivo,

ik zou graag nog ietwat hulp willen over de diff command :)
door --new-line-format='%L' raken sommige 'records' uit elkaar getrokken.
1 regel dat vele extra enters ontvangt.
met %l krijg ik alles maar op 1 regel... heb je hier meer ervaring mee ?

Ow die heb ik al opgelost met diff -w -B ......

Is het ook mogelijk om nog 'alleen' de verwijderde regels te vinden?
Gewijzigd op 07/03/2017 12:36:53 door Dennis WhoCares
 
Ivo P

Ivo P

07/03/2017 13:17:24
 
Dennis WhoCares

Dennis WhoCares

07/03/2017 13:19:30
Quote Anchor link
:'-D
http://www.lmgtfy.com/?q=diff+only+show+removed+lines
here we go...

hahaa ;-) Nee is goed, thanks! ik hoopte dat je dit toevallig wist :)

Thanks ik ga zowiezo hiermee aan de slag nu. Scheelt een hele hoop tijd met imports ;-)
 
Thomas van den Heuvel

Thomas van den Heuvel

07/03/2017 13:52:34
Quote Anchor link
Vergeet niet wat @Ben zei. Log voor de gein eens alle queries van zo'n job en kijk, naast de hoeveelheid queries, ook eens met EXPLAIN <de query> hoe (in)efficiënt deze zijn en/of hoe lang deze duren.

Heb je echt alle informatie nodig die je ophaalt? Heb je ook middelen die ervoor zorgen dat er geen informatie gewijzigd kan worden tijdens het uitvoeren van deze batch (denk bijvoorbeeld aan een transactie)?

Queries in een loop zijn meestal ook een "red flag".
 
Dennis WhoCares

Dennis WhoCares

07/03/2017 14:02:54
Quote Anchor link
Hi Thomas,

ik moet idd ook even onderzoeken hoe ik de mysql server beter kan configureren, ben er wel achter dat de mysql service de boel laat hangen... wellicht dat ik toch wel een memory upgrade moet doen.

Voor de update-import haal ik nu geen info meer op, maar het enige wat ik voorheen ophaalde was: id,item_id,price,stock
Deze script(s) zijn de enige die de data kan/mag 'updaten' eindgebruikers kunnen dit niet.

Van alle velden in de csv files gebruik ik ook eigenlijk maar 3 velden.
En ik update er 5

Wat bedoel je met "red flag", ik begrijp dat op moment dat ik een record aanpas, iemand anders niet precies op datzelfde moment dezelfde record zou mogen/kunnen aanpassen, maar in dit geval is dit ook niet mogelijk.
Gewijzigd op 07/03/2017 15:06:59 door Dennis WhoCares
 
John D

John D

07/03/2017 16:40:54
Quote Anchor link
Dennis WhoCares op 07/03/2017 14:02:54:
ik moet idd ook even onderzoeken hoe ik de mysql server beter kan configureren, ben er wel achter dat de mysql service de boel laat hangen... wellicht dat ik toch wel een memory upgrade moet doen.
Doorgaans zal de oorzaak niet bij de MySQL service liggen en is er weinig winst te halen met beter configureren. Probeer toch te analyseren, uit te zoeken, waar het probleem ontstaat. Ik lees dat je met nohup werkt en hoeveel processsen onstaan er dan met nohup? Honderden? Het inlezen van een csv of txt is peanuts voor MySQL zeker als je het met LOAD INFILE doet. Er is met deze tooling enorm veel mogelijk qua logica, zie ook de tips an Ivo. Ik vrees toch dat je programmatuur de oorzaak is van de hangup. Hoeveel records moet je inlezen per file?

Ook wanneer de gegevens verspreid of verrijkt moeten worden is het zinvol om eerst in te lezen in een platte tabel en aan de hand daarvan door te werken met updates en/of inserts om te verspreiden of te verrijken. Misschien kan je dan zelfs de php stap eruit werken. Misschien gaan er massa's onnodige gegevens (Selects) van MySQL naar php en wordt de MySQL server daar een beetje moe van ;)

Zorg voor logging in je proces, met timestamps zodat je kan meten. Schrijf de logging naar een /var/log/xxx.log file zodat MySQL daar niet voor belast wordt. Zet eens een tail -f op die logfile om te checken.
Gewijzigd op 07/03/2017 17:02:51 door John D
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.