Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[Node/PHP/MySQL/Redis?] Best practise data opslaan / load

Pagina: 1
Acties:

  • FrankvR
  • Registratie: Mei 2004
  • Laatst online: 01-01 21:05
We draaien een cluster van meerdere webservers (nginx/fpm-php en node.js) en daarachter een database (MySQL) server.

We hebben duizenden gebruikers die vooral de volgende actie doen:
  1. Sturen een json-data-object naar de server
  2. PHP voegt de user_id toe aan de hand van de sessie van de gebruiker
  3. PHP doet een MySQL query om te kijken hoe dit object beoordeeld moet worden.
  4. PHP beoordeelt het json-data-object en geeft er een score aan
  5. PHP slaat het json-data-object inclusief de score op in de MySQL database
  6. PHP laat de gebruiker weten dat het object goed is opgeslagen.
Nu willen we toe naar een systeem waarbij stap 3, 4 en 5 asynchroon worden uitgevoerd (bijvoorbeeld middels beanstalkd, of redis en een node.js process).

Ook willen we andere gebruikers de mogelijkheid geven een live-stream van de opgeslagen json-data-objects te ontvangen. Voor deze stream hadden we node.js en socket.io in gedachten.

De vraag is nu wat de beste setup hiervoor zou zijn, waarbij de database het meest ontzien wordt. Mijn voorstel zou zijn:
  1. Gebruiker stuurt json-data-object naar de server
  2. PHP voegt de user_id toe aan de hand van de sessie van de gebruiker
  3. PHP slaat json-data-object in Redis op
  4. PHP laat de gebruiker weten dat het object goed is opgeslagen.
en daarnaast in Node.js
  1. Node.js draait een process dat geregeld kijkt of redis nog json-data-objecten bevat die nog niet zijn behandeld.
  2. Node.js doet een MySQL query om te kijken hoe dit object beoordeeld moet worden.
  3. Node.js beoordeelt het json-data-object en geeft er een score aan
  4. Node.js slaat het json-data-object inclusief de score op in de MySQL database
  5. Node.js stuurt het json-data-object naar alle gebruikers die aangemeld zijn voor de stream.
Ik vraag me af of dit een goed werkende opstelling zal worden, of dat we iets over het hoofd zien. Daarnaast biedt dit nog een uitdaging om te kijken hoe we gebruikers die op webserver A zijn aangemeld voor de stream laten weten dat er op webserver B een json-data-object is opgeslagen.

  • TheNephilim
  • Registratie: September 2005
  • Laatst online: 21-11 15:31

TheNephilim

Wtfuzzle

Je eerste stappen kun je toch ongeveer zo laten; de punten 1 - 6 kun je netjes met AJAX regelen en dus gebruiksvriendelijk maken voor je gebruiker. Als je bij punt 6 dus helemaal klaar bent en de gebruiker laat weten dat het gelukt is, push je (in php) meteen een request naar de comet server (socket.io) die de request realtime publiceerd voor de andere gebruikers.

In je eigen verhaal ga je een heleboel stappen ineens ergens anders neerleggen terwijl er (volgens mij) niks veranderd aan 'uitslag'. Je kunt namelijk toch pas de rest van je gebruikers op de hoogte stellen als de versturende gebruiker ook een reactie terug gekregen heeft.

Kortom; 6. PHP laat de gebruiker weten dat het object goed is opgeslagen en verstuurd de gegevens naar socket.io om ze realtime naar alle andere gebruikers te publiceren.

  • FrankvR
  • Registratie: Mei 2004
  • Laatst online: 01-01 21:05
Het probleem met het laten van stappen 1-6 is dat stappen 3,4 en 5 complex zijn (foutgevoelig) en in sommige gevallen lang kunnen duren.

Ik ben daarom op zoek naar een structuur waarbij het object sowieso (ergens) goed wordt opgeslagen, dat de gebruiker daarvan snel op de hoogte wordt gesteld, en dat het daarna ge-processed wordt. Denk ik te moeilijk?

  • Hydra
  • Registratie: September 2000
  • Laatst online: 06-10 13:59
Waar zit nu je bottleneck?

Als dat MySQL is zou je kunnen overwegen juist reeks daar als cache in te zetten. Redis is niet acid compliant maar je vertelt niet of dat een issue is voor die json berichten.

Je zou kunnen kijken naar vert.x voor het verwerken van die berichten. Is een async framework lijkend op node maar dan specifiek voor workers ed op een pub/sub queue. In jouw geval zou je dus die objecten de queue induwen en die worden dan door workers opgepikt en verwerkt. Na verwerking publiceer je ze voor de desbetreffende stream. Vertx ondersteunt ook socketjs als je via websockets wil werken.

[ Voor 91% gewijzigd door Hydra op 16-05-2014 11:05 ]

https://niels.nu


  • FrankvR
  • Registratie: Mei 2004
  • Laatst online: 01-01 21:05
De bottleneck zit in stap 3 en 4. Deze zijn (1) complex en (2) duren in sommige gevallen te lang om de gebruiker op tijd van feedback te kunnen voorzien.

1) De complexiteit zorgt ervoor dat het mogelijk is dat door een bug het php process niet bij stap 5 uitkomt, waardoor het object helemaal niet wordt opgeslagen. Dit wil ik voorkomen door het al op te slaan in Redis voordat er complexe code wordt uitgevoerd. Een andere optie is het object aan het begin van het proces al op te slaan (INSERT) in de database en later een UPDATE te doen met de toegevoegde score van stap 3 en 4. Dan verdubbel ik echter het aantal queries op de database, wat me performance-wise niet intelligent lijkt.

2) De tijdsduur van stappen 3 en 4 is soms zodanig dat ik die stappen asynchroon wil doen, zodat de gebruiker niet te lang op feedback hoeft te wachten.

PS. Je geeft een aantal tools waar ik niet eerder van gehoord heb, ik ga daar even induiken. Dank.

  • FrankvR
  • Registratie: Mei 2004
  • Laatst online: 01-01 21:05
Wat betreft ACID-compliant: het is belangrijk dat het durable is, maar wat ik lees over de AOF-persistence mode, lijkt me dat voldoende durable.

vert.x ziet er interessant uit. Ik heb zelf weinig ervaring met Java, maar ik begrijp dat andere talen ook mogelijk zijn. Vraag blijft dan of de structuur zoals ik die in mijn eerst post beschrijf de juiste is (maar dan bijvoorbeeld vert.x ipv node.js).

  • Hydra
  • Registratie: September 2000
  • Laatst online: 06-10 13:59
Vert.x is Java based maar ondersteund ook andere talen. JS, Ruby, Groovy en Python geloof ik zo uit m'n hoofd.

Hoe ik het voor me zie is relatief simpel: je hebt een X aantal verticles (vert.x containers) met daarin de workers die het zware werk doen. Vert.x regelt zelf het clustering; je hoeft alleen maar een command-line option aan te geven (-cluster) geloof ik en de verticles gaan zelf met elkaar communiceren.

Je definieert een input queue waarop je workers gaan luisteren. Op het moment dat er een niet JSON bericht gepost wordt (gewoon op een HTTP API) gaan die workers er mee aan de gang. Als ze er mee klaar zijn, publiceren ze het resultaat op een andere queue. Je kunt dan gewoon met een socketJS client daarop luisteren: je browser client krijgen zo meteen resultaat gepushed. Ook is polling natuurlijk een optie.

Dus:
- HTTP post JSON naar Vert.x
- Vert.x zet deze op een queue
- 1 Worker pakt bericht van de queue
- Worker bevraagt MySQL / een cache en berekent score
- Worker publiceert het resultaat
- Via socketjs luisterende webclients ontvangen het resultaat

Komt dan verder geen PHP of andere webservers e.d. bij kijken. Je kunt nginx hier wel als proxy op laten treden (zodat je alles op poort 80 kunt hebben) als je dat wil, maar het is niet perse nodig.

Mocht je hier commerciele ondersteuning op willen hebben; wij hebben een paar mensen met veel Vert.x ervaring.

https://niels.nu


  • FrankvR
  • Registratie: Mei 2004
  • Laatst online: 01-01 21:05
Dat vert.x de clustering zelf regelt is wel erg interessant!

In dat geval moet dan PHP-sessie-data (om een gebruiker te identificeren) binnen Vert.x beschikbaar komen. Wat zou daar dan de beste methode voor zijn? Sessies opslaan in memcached? Of toch in de MySQL-db?

Ik ga nog wat meer lezen over vert.x. Het lijkt nog wel erg jong en weinig gebruikt. De vraag is of dat verstandig is om te draaien op een productieomgeving. Node.js biedt standaard niet die clustering-support, maar heeft een veel grotere user base.
Pagina: 1