Schaalbaarheid PHP script

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Tieske[82]
  • Registratie: Juli 2001
  • Laatst online: 09-02 22:11
Voor een hobby projectje ben ik aan het proberen om een (web based) stock exchange te maken. Vanwege ervaring heb ik gekozen om met PHP+MySQL aan de slag te gaan. De interface is vrij eenvoudig: je kan invoeren aandelen te willen kopen of verkopen, hoeveel, en tegen welke prijs.

Het script wat daarachter zit, bepaald bij elke invoer (er wordt ge-POST naar invoer.php) of er een ‘match’ is voor de ingevoerde gegevens. Dus als ik invoer dat ik 100 aandelen voor 30 euro per stuk wil kopen, kijkt het script of er iemand is die aandelen voor 30 euro per stuk of minder wil kopen. Zo ja, dan wisselen de aandelen van eigenaar.

Nu heeft dit hobby projectje mijn interesse gewekt over grotere systemen. Ik heb het idee dat deze oplossing niet echt schaalbaar is. Bij elke individuele POST naar invoer.php, worden de tabellen geLOCKed, vraag en aanbod aan elkaar gematched, en weer vrijgegeven voor een volgende invoer.

Stel dat er nu 10.000 mensen dit willen gaan gebruiken, met dus veel ‘invoeren’ tegelijkertijd, wordt iedereen telkens in de wachtrij gezet totdat het invoer.php script uitgevoerd is en de gebruiker aan de beurt is. Dat is natuurlijk ook maar een schijntje voor zoiets als een echte aandelenbeurs met factoren meer volumes en gebruikers.

Hoe zou zo’n script er beter uit kunnen zien? Invoer los van de verwerking? Of ‘gewoon’ heel veel capaciteit beschikbaar stellen zodat het script supersnel wordt uitgevoerd?

Acties:
  • 0 Henk 'm!

  • StephanVierkant
  • Registratie: Mei 2003
  • Laatst online: 08-09 16:22
Facebook gebruikt ook PHP en Mysql: http://developers.facebook.com/opensource/. Je kunt php en mysql dus ook voor grote sites gebruiken: 10.000 bewerkingen is voor een schijntje.

Misschien dat je eens kunt zoeken naar hoe dat soort sites het voor elkaar hebben.

Acties:
  • 0 Henk 'm!

  • Ventieldopje
  • Registratie: December 2005
  • Laatst online: 07:05

Ventieldopje

I'm not your pal, mate!

Bij lezen worden de tabellen niet gelocked, alleen bij het schrijven maar dat is een kwestie van je query's optimaliseren en werken met transactions ;)

www.maartendeboer.net
1D X | 5Ds | Zeiss Milvus 25, 50, 85 f/1.4 | Zeiss Otus 55 f/1.4 | Canon 200 f/1.8 | Canon 200 f/2 | Canon 300 f/2.8


Acties:
  • 0 Henk 'm!

Verwijderd

Bij acties die realtime moeten gebeuren, zoals beurs gerelateerde applicaties, kun je het niet maken om een vertraging te creëren dmv het locken van de tabel of het gebruik van een queue. Tenzij je van te voren aangeeft dat acties 5 minuten later worden uitgevoerd (cron van 5 minuten die alle wijzigingen doorvoert), maar dit is niet altijd wenselijk.

Over het algemeen, zoals Stephan4kant al aangeeft, is PHP + MySQL snel genoeg om acties direct uit te voeren, zelfs wanneer er een hoop acties tegelijk worden uitgevoerd. Daarnaast is het bijna onmogelijk om op exact (in miliseconden) 2 of meer acties te krijgen, maar dat wordt dan wel opgevangen door MySQL (heeft zelf een queue).

Je kunt wel zorgen dat je server genoeg lijntjes tegelijk aan kan wanneer er zeer veel gebruikers gebruik van gaan maken. Qua hardware maakt het niet veel uit (HDD afhankelijk van je database grootte, geheugen adhv aantal request per seconden), en zul je hooguit de load moeten gaan verdelen over meerdere servers. Maar dat is alleen nodig wanneer je echt 10.000 requests tegelijk krijgt en dat over langere tijd.

Het belangrijkste bij een applicatie als deze is dat je scripts gewoon goed in elkaar zitten, de rest is pas belangrijk wanneer je scripts niet meer beter kunnen en je server kuren krijgt.

Acties:
  • 0 Henk 'm!

  • bredend
  • Registratie: September 2001
  • Laatst online: 23:57
Ik zou hiervoor een vraag- en een aanbodqueue maken waarbij elk item in de queue een time-to-live heeft. Daarnaast draait een los proces dat tussen de queues matcht. Daarvoor kan je een cronjob gebruiken, maar bij een hogere load is een apart programma misschien beter.

Acties:
  • 0 Henk 'm!

  • bstudio
  • Registratie: Oktober 2007
  • Laatst online: 03-12-2022
bredend schreef op woensdag 06 april 2011 @ 13:47:
Ik zou hiervoor een vraag- en een aanbodqueue maken waarbij elk item in de queue een time-to-live heeft. Daarnaast draait een los proces dat tussen de queues matcht. Daarvoor kan je een cronjob gebruiken, maar bij een hogere load is een apart programma misschien beter.
Dat lijkt me niet heel erg handig aangezien aandelen transacties realtime uitgevoerd moeten worden...

In jouw geval zijn het waarschijnlijk redelijk simpele queries met een relatief hoge uitvoersnelheid. Zoals eerder dus is gezegd: zorg dat je database goed opgebouwd is, leg goeie indexes etc. dan zit dat wel snor.

En 10.000 simulane connecties is in het geval van een hobby systeem (of middelgroot systeem) wel aardig wat.

Acties:
  • 0 Henk 'm!

  • Grompie
  • Registratie: Maart 2010
  • Laatst online: 15-04-2024
Stephan4kant schreef op woensdag 06 april 2011 @ 13:25:
Facebook gebruikt ook PHP en Mysql: http://developers.facebook.com/opensource/. Je kunt php en mysql dus ook voor grote sites gebruiken: 10.000 bewerkingen is voor een schijntje.

Misschien dat je eens kunt zoeken naar hoe dat soort sites het voor elkaar hebben.
Facebook heeft al zijn php code omgezet naar C++ dit om snelheids redenen. Maar de basis blijft wel php natuurlijk en zolang je geen miljoenen gebruikers hebt zoals facebook blijft het ook wel redelijk doenbaar in php. Tenzij je natuurlijk over erg trage hardware beschikt.

Acties:
  • 0 Henk 'm!

  • kwaakvaak_v2
  • Registratie: Juni 2009
  • Laatst online: 02-06 12:29
Ventieldopje schreef op woensdag 06 april 2011 @ 13:28:
Bij lezen worden de tabellen niet gelocked, alleen bij het schrijven maar dat is een kwestie van je query's optimaliseren en werken met transactions ;)
En niet geheel onbelangrijk van MyIsam naar innoDB gaan, anders kun optimalizeren tot je een ons weegt, maar je blijft met table locking zitten.

Driving a cadillac in a fool's parade.


Acties:
  • 0 Henk 'm!

  • justahuman
  • Registratie: Maart 2011
  • Laatst online: 00:14
innoDB die heeft row locking ipv table locking of je gebruikt met MyIsam insert delayed.

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Neen. MyISAM is pertinent niet bruikbaar, zonder transacties ga je nergens komen.

offtopic:
En insert delayed kan ironisch genoeg ook juist voor performance problemen zorgen... ;)

[ Voor 38% gewijzigd door Voutloos op 06-04-2011 16:03 ]

{signature}


Acties:
  • 0 Henk 'm!

  • Tieske[82]
  • Registratie: Juli 2001
  • Laatst online: 09-02 22:11
Ik kon me bijna niet voorstellen dat het afwerken van een vraag&aanbod-match scriptje bij elke invoer de juiste weg was, maar daar heb ik dus ongelijk in gekregen merk ik.

Maar zijn transacties niet puur voor de consistentie van de data? Dat staat toch los van de capaciteit of snelheid? (niet dat je beide kunt missen bij een aandelenhandel natuurlijk).

Dus als ik het goed begrijp, dan is het gebruik van InnoDB, met row locking de juiste weg, en is de capaciteit daarvan erg groot.

Ik stel het dan me voor dat je een selectie maakt van 2 rijen (bv degene met de hoogste vraagprijs en die met degene laagste verkoopprijs), dan die 2 rijen locked, 'van eigenaar wisselt', en dan weer unlocked. Waar zit de 'transactie' dan in? Of is vóór de selectie zèlf al een lock nodig?

Acties:
  • 0 Henk 'm!

  • Camulos
  • Registratie: Januari 2009
  • Laatst online: 06-09 22:59

Camulos

Stampert

Even kort door de bocht:
Locking zal alleen gebeuren wanneer een transactie schrijf-acties onderneemt.
Een transactie kan bestaan uit meerdere MySQL-statements (zoals eerst een Select-query, dan een Update-query of een insert-query, en dan weer een andere query.. etc)

een DBMS kan zelf bepalen wanneer de locking nodig is, hiermee hoef je als ontwikkelaar niet bezig te zijn :)
Het belangrijkste aan een transactie is: Hij lukt in zijn geheel.. of hij lukt helemaal niet (en gaat terug naar begin toestand).

Not just an innocent bystander


Acties:
  • 0 Henk 'm!

  • ZpAz
  • Registratie: September 2005
  • Laatst online: 22:21
Tieske\[82] schreef op woensdag 06 april 2011 @ 13:14:
Voor een hobby projectje ben ik aan het proberen om een (web based) stock exchange te maken. Vanwege ervaring heb ik gekozen om met PHP+MySQL aan de slag te gaan. De interface is vrij eenvoudig: je kan invoeren aandelen te willen kopen of verkopen, hoeveel, en tegen welke prijs.
PHP kan prima schalen als je goede code hebt, het is niet zo dat een andere taal 'ineens' beter schaalt omdat het een andere taal is. Een goed schaalbaar project kan je in PHP maken. Je kan een gaar schalend project maken in ASP.NET of enig ander platform.
Grompie schreef op woensdag 06 april 2011 @ 14:46:
[...]


Facebook heeft al zijn php code omgezet naar C++ dit om snelheids redenen. Maar de basis blijft wel php natuurlijk en zolang je geen miljoenen gebruikers hebt zoals facebook blijft het ook wel redelijk doenbaar in php. Tenzij je natuurlijk over erg trage hardware beschikt.
NetLog draait ook op PHP en Mysql, en heeft ook miljoenen gebruikers.

Het is niet omdat Facebook HipHop gebruikt het 'alleen maar schaalt'. HipHop is maar een hulpmiddel.

[ Voor 30% gewijzigd door ZpAz op 06-04-2011 18:44 ]

Tweakers Time Machine Browser Extension | Chrome : Firefox


Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Ik zou eerst maar eens gaan beginnen met je werk en kijken hoe het gaat. Zorg er wel voor dat je je locking minimaliseert.
En zorg er vooral ook voor dat je je code netjes structureert en voor zover nodig in modules stopt. Dan kan je bij tegenvallende prestaties altijd nog delen van je systeem vervangen door dedicated server-software of anderzins beschikbaar gemaakte interne services (wat dan wellicht beter in Java of C# geschreven kan worden).

Wijzen naar facebook en zeggen 'zij gebruiken php' is wel erg incompleet, want ze gebruiken ook allerlei andere dedicated services voor delen van het werk. En die zijn in legio talen geschreven. Desalniettemin hangt het eerder van een slechte aanpak af dat php+mysql niet schaalt, dan dat php+mysql je de mogelijkheden niet biedt :)

Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
Camulos schreef op woensdag 06 april 2011 @ 18:20:
Locking zal alleen gebeuren wanneer een transactie schrijf-acties onderneemt.
Een transactie kan bestaan uit meerdere MySQL-statements (zoals eerst een Select-query, dan een Update-query of een insert-query, en dan weer een andere query.. etc)

een DBMS kan zelf bepalen wanneer de locking nodig is, hiermee hoef je als ontwikkelaar niet bezig te zijn :)
Het belangrijkste aan een transactie is: Hij lukt in zijn geheel.. of hij lukt helemaal niet (en gaat terug naar begin toestand).
Als je zo'n soort systeem wilt maken met echt 10.000 gebruikers dan wil je echt toch wel zelf de locking regelen... Dan is je dbms echt niet snel genoeg meer...

Als je eerst een select wilt doen in je matchingsscript wordt er geen lock gezet, als daaruit komt dat je 300 units hebt en daarna komt een update van een andere sessie die de row lockt en er 200 vanaf trekt daarna komt pas je eigen sessie weer aan de beurt die die 300 ervanaf wilt halen, wat dan? Je hebt er nog maar 100... En niet de 300 die je php dacht te hebben...

Oftewel of je moet het hele matchings verhaal ( inclusief bewerkingen ) in 1 query schrijven zodat je dbms zelf de locking goed kan regelen. Of je moet binnen de hele transactie de rows locken.

Met 10.000 transacties in een korte tijdsperiode wordt de prijs van een gefaalde transactie erg duur...

Let er ook op dat als je dit echt voor geld-transacties wilt gebruiken dat je dan eigenlijk de afhandeling serieel wilt laten verlopen. Parallel dingen verwerken is leuk, maar complex ( wat doe je als er 2 users exact tegelijk 300 dingen willen kopen ).
Dingen als race-conditions zijn bij iets als facebook onhandig, maar niet echt boeiend ( is gewoon een oeps, de volgorde van de comments klopt niet 100% slechts 99,999999% ) als je met geld gaat spelen dan kan in die 0,000001% net een transactie van een miljoen zitten.

Als bijv een facebook vanwege een (interne) synchronisatie op cacheserver99 0,1 seconde later een comment toont dan op cacheserver01 dan is het niet boeiend. Als er geldtransacties mee gemoeid zijn dan weet ik wel waar ik mijn botje op moet richten om een voordeel van 0,1 seconde te krijgen :).

Met geldtransacties is correctheid belangrijk, snelheid is een 2e

Acties:
  • 0 Henk 'm!

  • Camulos
  • Registratie: Januari 2009
  • Laatst online: 06-09 22:59

Camulos

Stampert

@Gomez12 :: je zit fout te redeneren;.. de situatie die je schets lijkt meer te maken te hebben met implementatie van de code.. dan met correctheid van de database.

een DBMS ( MySQL / PostgreSQL / Oracle en andere DBMS'es) heeft doet ruwweg 2 eigenschappen:
- ACID properties te respecteren (Atomicity / Consistency / Isolation / Durability) voor elke transactie
- Transacties in zijn geheel te laten lukken; of in zijn geheel te "negeren"/aborteren

Soms is er een optie om de locking zelf in te stellen ( row / page / table locking / en/of anderen).
Maar dan NOG steeds bepaald de DBMS welke rijen/pages/tables er gelocked worden gedurende een bepaalde tijd.

10K aan transacties is echt niet veel voor een fatsoenlijke dedicated database.

Wanneer je voor snelheid kiest en het niet uitmaakt of er dirty-reads / dirty-writes / ghosts en andere fenomenen voorkomen.. dan zet je de instelling voor locking zo laag mogelijk ( alleen write locks )
Wanneer je het hebt over banken/transacties dan zet je de locking juist zo hoog mogelijk, hiervoor moet je wel weer iets aan prestatie inleveren (inclusief read en write locks). Dit is wel een bewuste keuze van de programmeur/DBMS-engineer, en slechts noodzakelijk met kritieke transacties

Terug naar jouw voorbeeld: 1 transactie met read en write locks == 100% correct voor elke transactie (met multiple statements). Dat je meteen 10.000 transacties wilt doen is prima... Mocht de queue te lang worden dan krijg je een negatieve respons (oftewel.. transactie niet uitgevoerd/gefaald :: dit heeft geen invloed op de correctheid van de DB); maar ik verwacht eigenlijk geen problemen voor een stevige database.

De database zal het altijd correct afhandelen (mits je het hoogste niveau van locking gebruikt).
Code en statement optimalisaties zijn vele malen belangrijker.

Transacties serieel laten lopen ipv parallel is echt een non-argument; je verspilt hiermee te veel tijd en resources omdat de meeste queries geen/weinig overlap hebben (zelfs andere databases binnen het DBMS)

PS : excuus voor de off-topic

[ Voor 4% gewijzigd door Camulos op 07-04-2011 13:11 ]

Not just an innocent bystander


Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Camulos schreef op donderdag 07 april 2011 @ 13:00:
Wanneer je het hebt over banken/transacties dan zet je de locking juist zo hoog mogelijk, hiervoor moet je wel weer iets aan prestatie inleveren (inclusief read en write locks). Dit is wel een bewuste keuze van de programmeur/DBMS-engineer, en slechts noodzakelijk met kritieke transacties

[...]

Transacties serieel laten lopen ipv parallel is echt een non-argument; je verspilt hiermee te veel tijd en resources omdat de meeste queries geen/weinig overlap hebben (zelfs andere databases binnen het DBMS)
Die laatste opmerking snap ik niet ivt je voorgaande (terechte) opmerking over 'het hoogste locking niveau' kiezen. In typische RDMBS-en is dat niveau namelijk het 'serializable'-niveau. Oftewel, transacties worden niet alleen gegarandeerd compleet wel of compleet niet uitgevoerd, maar ook gegarandeerd in een bepaalde volgorde als eindresultaat zichtbaar. Waardoor de zgn 'phantom reads' (jij noemt ze ghost reads geloof ik) ook niet kunnen gebeuren.

Desalniettemin betekent serializable niet dat transacties nooit parallel kunnen lopen. Zie voor meer uitleg bijvoorbeeld de uitleg erover in de manual van PostgreSQL.

Acties:
  • 0 Henk 'm!

  • johnkeates
  • Registratie: Februari 2008
  • Laatst online: 04-07 16:30
Je zou Gearman en PostgreSQL kunnen combineren, met hiphop van facebook, dan kan je daemons in PHP schrijven als workers voor je gearman queue en die naar C++ omzetten, dan heb je zeer sneller workers zodat je queue niet volstroomt. Daarna even goede frontend maken en je bent er wel met snelheid. MySQL en PostgreSQL is niet zo'n probleem als je gaat programmeren, als je het een gebruikt kan je de andere ook wel snel leren, SQL=SQL.

Acties:
  • 0 Henk 'm!

  • Camulos
  • Registratie: Januari 2009
  • Laatst online: 06-09 22:59

Camulos

Stampert

@ACM :: je hebt helemaal gelijk.. ik las in zijn bericht serieel als sequentieel :)
Maar idd Serializable transacties kunnen idd parallel lopen :)

Not just an innocent bystander


Acties:
  • 0 Henk 'm!

  • krvabo
  • Registratie: Januari 2003
  • Laatst online: 20:52

krvabo

MATERIALISE!

Nou weet ik niet hoe 'echt' je aandelensoftware wordt en of er dus rekening gehouden moet worden met een externe invoer (livedata van de beurs), maar als het je eigen beursspel wordt kan je wellicht ook overwegen om de hoogste bied en laagste laat bij te houden van elk aandeel. Dit kun je in het geheugen bijhouden met bijvoorbeeld memcache.

Bij elke transactie (BUY 100 MT 26.67) kun je dan kijken of de prijs boven de laat van MT ligt.
Dus stel:
BUY 100 MT 26.67
Bied: 26.65
Laat: 26.66

De BUY-order is dus boven de laat ('op deze prijs verkoop ik m'n aandelen aan je') dus kun je doorgaan met de transactie. Hier doe je nu alsnog wat extra checks om zeker te weten dat er genoeg aandelen zijn.

Stel dat de BUY-order niet door kan gaan, dan moet je hem in de queue zetten om later alsnog te kopen (Met een 'time to die'). Bij elke verandering van de bied / laat kun je dan een trigger laten afgaan die kijkt of er nog koop-orders zijn (kijken in de queue).

Het is in ieder geval een stuk gecompliceerder dan alleen even kijken of er op dat moment aandelen worden verkocht tegen die prijs. Wat nou als iemand een order inlegt tegen de Laat-prijs, maar er staat ook nog een oudere BUY-order in je queue voor die prijs.. wie krijgt hem dan? Dan zou je dus alle orders moeten queuen, en wellicht gebruikmaken van een extra tabel die een queue heeft die ver van de huidige bied/laat afzitten en deze elke x-tijd over moeten zetten naar de 'live queue'.

Pong is probably the best designed shooter in the world.
It's the only one that is made so that if you camp, you die.


Acties:
  • 0 Henk 'm!

  • gorgi_19
  • Registratie: Mei 2002
  • Laatst online: 06:57

gorgi_19

Kruimeltjes zijn weer op :9

Ik vraag me af of de aanpak de juiste is; je kijkt nu naar vraag en aanbod, maar je vergeet het gehele principe van prijsbepaling. Wat doe je met bestens orders of wat doe je als je orders moet opslitsen?

Als je een beursapplicatie wil maken, kan je beter met een orderboek werken en deze periodiek (dat kan ook om de seconde zijn, bij benadering realtime) verwerken. Hierbij ga je het orderboek nalopen, kijken bij welke prijs het meeste volume wordt verhandeld (dit wordt de nieuwe prijs) en vervolgens de orders tegen die prijs gaan uitvoeren.

Verkijk je trouwens niet op het principe van realtime; voor een simulatiespel heb ik ook een dergelijke beurs ingebouwd. Vaak is je markt niet liquide genoeg om realtime mogelijk te maken (in praktijk heb je ook beurzen die niet realtime zijn, maar waarbij de handel op 1 moment per dag uitgevoerd wordt).

Op deze wijze heb je ook geen problemen met 'locking' (anders dan annuleren van orders waar je een oplossing voor moet vinden :))
Het is in ieder geval een stuk gecompliceerder dan alleen even kijken of er op dat moment aandelen worden verkocht tegen die prijs. Wat nou als iemand een order inlegt tegen de Laat-prijs, maar er staat ook nog een oudere BUY-order in je queue voor die prijs.. wie krijgt hem dan? Dan zou je dus alle orders moeten queuen, en wellicht gebruikmaken van een extra tabel die een queue heeft die ver van de huidige bied/laat afzitten en deze elke x-tijd over moeten zetten naar de 'live queue'.
Dit soort gezeik moet je ook niet willen hebben :) Orderboek werkt daarin het eenvoudigst; limietorders bepalen de prijs, bestens orders hebben voorrang en daarna verwerk je de orders binnen de valide range (geldige prijs) op volgorde van datum.

[ Voor 34% gewijzigd door gorgi_19 op 08-04-2011 07:47 ]

Digitaal onderwijsmateriaal, leermateriaal voor hbo

Pagina: 1