Advies voor technische implementatie van website

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • nickpma
  • Registratie: Mei 2004
  • Laatst online: 13-09 14:59
Mijn vraag
Momenteel ben ik een website aan het ontwikkelen waarop meerdere gebruikers (bijv 100 of later 1000 tegelijk) kunnen inloggen met een unieke code en een spel kunnen starten.

Het is allemaal text based, dus grafisch geen uitdaging.
Wat alleen wel een uitdaging is, is dat deze gebruikers allemaal moeten kunnen zien wat de laatste stand van zaken is. Dus 1 iemand voert een antwoord in en alle andere gebruikers zien daarvan het resultaat.

Mijn huidige setup is HTML/JS/PHP met een MySQL database.
Met deze tech stack zie ik de volgende opties:
  1. AJAX GET calls maken elke seconde of 2
  2. Websockets gebruiken
  3. SSE gebruiken
Momenteel ga ik voor optie 3, waarbij ik een verbinding open met de server en voor iedere gebruiker netjes afwacht wat de huidige status is. Op zich is een verbinding met de MySQL server niet eens nodig, ik kan gewoon een json bestand aanmaken en bij iedere POST die updaten, samen met de DB.
Bij een GET check ik alleen het JSON bestand, niet de DB.

Als het spel klaar is sluit ik de SSE verbinding met de server.

Wat ik al geprobeerd heb
Optie 1 lijkt minder geschikt dan optie 3, omdat SSE bedoelt is om een verbinding open te zetten.
Optie 2 is vrij ingewikkeld en ik ben ook weer geen professional.
NodeJS is wellicht een optie, maar dat is weer een nieuwe taal om te leren

Ik weet dat Facebook en andere bedrijven ook gebruik maken van PHP, dus ik neem toch aan dat dit wel mogelijk moet zijn op deze manier?
Weten jullie of SSE een goede oplossing is of dat er, ook met het oog op de toekomst, betere opties zijn?
Er zijn genoeg online Trivias die neem ik aan dezelfde uitdaging hebben.

Op Stackoverflow en Google al gezocht en daar kwam SSE uit. Alleen ik ben wel bang voor de server belasting.

Alle reacties


Acties:
  • +1 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
nickpma schreef op woensdag 26 augustus 2020 @ 17:39:
Op zich is een verbinding met de MySQL server niet eens nodig, ik kan gewoon een json bestand aanmaken en bij iedere POST die updaten
Dat gaat geheid fout met honderden of duizenden gebruikers - race conditions, concurrency enzo ;)

Ik zit zelf in de .Net hoek maar ik zou eens kijken naar SignalR. Als ik dan naar PHP alternatieven zoek kom ik hier en hier bijvoorbeeld uit.

[ Voor 20% gewijzigd door RobIII op 26-08-2020 17:55 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • DJMaze
  • Registratie: Juni 2002
  • Niet online
Naast dat de client luistert, zou je dat ook op de server moeten doen.
Database pollen voor een update is geen luisteren...

Er zijn databases die het wel kunnen, zoals FirebirdSQL. Of je gaat voor een andere oplossing.

Maak je niet druk, dat doet de compressor maar


Acties:
  • 0 Henk 'm!

  • nickpma
  • Registratie: Mei 2004
  • Laatst online: 13-09 14:59
RobIII schreef op woensdag 26 augustus 2020 @ 17:52:
[...]

Dat gaat geheid fout met honderden of duizenden gebruikers - race conditions, concurrency enzo ;)

Ik zit zelf in de .Net hoek maar ik zou eens kijken naar SignalR. Als ik dan naar PHP alternatieven zoek kom ik hier en hier bijvoorbeeld uit.
Bedankt voor de reactie. En vandaar ook de vraag, hoopte dat iemand ervaring heeft met SSE.
Opzich kan ik prima een kleine vertraging hebben, het gaat niet op tijd.
Maar ik ben inderdaad bang dat het met genoeg gebruikers wel fout gaat idd.

Dus prima om het nu te bouwen in PHP als proof of concept, om vervolgens te kijken hoe dit op te schalen.
ASP gaat het niet worden, maar je hebt me wel op andere ideeen gebracht:
1. Laravel Echo: als ik toch al een PHP framework wil gaan gebruiken, wellicht is dit geschikt
2. Websockets: lijkt hiervoor ontworpen, dus toch maar induiken
3. Zal morgen naar de andere opties kijken

Thanks!

Acties:
  • 0 Henk 'm!

  • nickpma
  • Registratie: Mei 2004
  • Laatst online: 13-09 14:59
DJMaze schreef op woensdag 26 augustus 2020 @ 18:12:
Naast dat de client luistert, zou je dat ook op de server moeten doen.
Database pollen voor een update is geen luisteren...

Er zijn databases die het wel kunnen, zoals FirebirdSQL. Of je gaat voor een andere oplossing.
Sorry, maar begrijp je reactie niet helemaal. Wellicht praten we langs elkaar heen.

De connectie met de server wordt geopend met een SSE connectie om de client te informeren.
Voor updates van users kan ik een simpele AJAX POST request doen naar de server, waarbij de server vervolgens een actie uitvoert (naar DB schrijven + naar file)

De load op de database blijft zo minimaal, alleen bij POST requests, niet bij GET.
Dus database pollen is niet nodig, gewoon het json bestandje per spel checken voor de laatste status.

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Wat DJMaze bedoeld is dat je nu wel een oplossing hebt over hoe je een event kunt pushen van de server naar de client. Wat hij aanstipt is hoe je vervolgens op de server weet wanneer je dat bericht ook daadwerkelijk moet versturen. Mijn kennis van PHP is niet heel groot, maar last time I checked was er geen applicatie scope die je daarvoor zou kunnen gebruiken.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 19-09 21:09
Laravel Echo gebruikt Websockets inderdaad. Kan met https://github.com/beyondcode/laravel-websockets bijv. Dan in Laravel simpelweg update broadcasten en dan krijgt iedereen het direct binnen.

[ Voor 29% gewijzigd door Barryvdh op 26-08-2020 20:56 ]


Acties:
  • +1 Henk 'm!

  • merauder
  • Registratie: November 2005
  • Laatst online: 17-09 19:22
Ik sluit mij aan bij de Laravel echo oplossing. Niet heel erg ingewikkeld om op te zetten, en je zou ervoor kunnen kiezen om ipv een JSON file te kiezen voor een REDIS oplossing, zodat je zeer snel data kan lezen / schrijven.

  • Hopscotch
  • Registratie: September 2015
  • Laatst online: 28-09-2021
Volgens mij moet je twee "problemen" onderscheiden.
- De manier waarop je updates naar clients pushed, ik denk dat client side SSE iets eenvoudiger is en meer past bij wat je applicatie doet.
- De manier waarop je binnen je applicatie registreert dat er iets is gebeurt dat naar de clients gestuurd moet worden. Dat kan door een reactive database achtige oplossing maar ook door een event te raisen en daar naar te luisteren. Ik zou zellf voor het laatste gaan denk ik.

  • nickpma
  • Registratie: Mei 2004
  • Laatst online: 13-09 14:59
Hopscotch schreef op donderdag 27 augustus 2020 @ 10:25:
Volgens mij moet je twee "problemen" onderscheiden.
- De manier waarop je updates naar clients pushed, ik denk dat client side SSE iets eenvoudiger is en meer past bij wat je applicatie doet.
- De manier waarop je binnen je applicatie registreert dat er iets is gebeurt dat naar de clients gestuurd moet worden. Dat kan door een reactive database achtige oplossing maar ook door een event te raisen en daar naar te luisteren. Ik zou zellf voor het laatste gaan denk ik.
Heb nog niet veel tijd gehad om op verder onderzoek uit te gaan na andere reacties op dit topic.
Maar er zijn 2 soorten activiteiten inderdaad:
1. Clients laten luisteren naar updates.
Als SSE geschikt is, dan top. Dat heb ik inmiddels al zo ongeveer werkend en de refresh tijd voor events kun je instellen. Voor mijn doel is een seconde of 2 a 3 prima.
Per groep die het spel spelen zijn er maximaal 6 mensen, dus niet honderden tegelijk die allemaal op dezelfde update wachten.

Anders inderdaad naar iets als Laravel Echo kijken.

2. Updates naar server versturen
Dit is wat mij betreft voor nu gewoon een simpele AJAX POST request.
Dit gebeurt maar 1x per minuut of iets dergelijks, dus levert geen intensieve load op. Dat kan prima naar de DB geschreven worden en ook naar een JSON bestand of een andere oplossing.

Misschien moet ik even een loadtest doen en met mijn hosting provider praten over wat de max load is voor SSE. Als kleine startup kan ik helaas geen grote investeringen doen.
Dus een team van devs aannemen zit er niet in, grootste gedeelte doe ik voorlopig zelf.

  • nickpma
  • Registratie: Mei 2004
  • Laatst online: 13-09 14:59
Janoz schreef op woensdag 26 augustus 2020 @ 20:21:
Wat DJMaze bedoeld is dat je nu wel een oplossing hebt over hoe je een event kunt pushen van de server naar de client. Wat hij aanstipt is hoe je vervolgens op de server weet wanneer je dat bericht ook daadwerkelijk moet versturen. Mijn kennis van PHP is niet heel groot, maar last time I checked was er geen applicatie scope die je daarvoor zou kunnen gebruiken.
Als ik gewoon telkens mijn PHP file de laatste stand van zaken laat sturen naar de clients, dan moet dat geen probleem zijn. Evt kun je met een timestamp werken, maar dat is niet eens nodig.
Je hoeft van server naar client niet eens de DB te raadplegen.

Het gaat hier om 10 veldjes, dus niks speciaals.
Met SSE stuur je dan standaard bijvoorbeeld elke 3 seconden een update naar client over de bestaande open connectie.

  • _DeWie_
  • Registratie: November 2001
  • Laatst online: 31-05 19:17
Je kunt eens naar elixir met liveview kijken

Acties:
  • +1 Henk 'm!

  • Douweegbertje
  • Registratie: Mei 2008
  • Laatst online: 20-09 20:54

Douweegbertje

Wat kinderachtig.. godverdomme

Ik wil niet zeggen dat het niet mogelijk is met PHP, maar het is er gewoon niet heel lekker voor. Dat heeft simpelweg te maken met het feit dat het pas wat doet als je (client) het vraagt.

Dus ja, je zou dan je clients kunnen laten pollen (via JS bijv). Maar lekker werkt dat ook niet en als het op een gegeven moment iets complexer wordt dan wordt jij ook ongelukkig. Want wat je eigenlijk wilt is ook zelf eens iets kunnen gaan pushen naar je clients.

SSE kende ik zelf eigenlijk nog niet. Echter ik zie nu dat het domweg een connectie open zetten is en "luisteren". Dat houdt dus in dat je je PHP script dermate moet gaan opzetten dat hij in een oneindige loop zit en dan lekker gaat flushen om de zoveel tijd. Ik weet niet hoe ik dit moet zeggen, maar ik zou heel hard weg rennen. Echter ben je dit serieus aan het overwegen dus even concreet:

- PHP is er niet voor gemaakt om oneindig te draaien of als socket te dienen. Ja het kan, nee je wilt het niet. Ik kan er wel een hele discussie over gaan voeren en natuurlijk heb je Laravel Echo, echter er zijn dan zoveel andere oplossing die er ook voor gemaakt zijn om als server zelf te draaien.
- Als een connectie constant open staat met PHP, dan ga je tegen hele andere limits aan lopen. Even simpel gezegd zul al snel tegen een soort max threads van PHP aanlopen of max connections van de 'webserver' i.e. nginx/apache.
Als kleine startup kan ik helaas geen grote investeringen doen.
Ik zit hier met dubbel gedachtes maar laat ik dan de positieve gedachte pakken maar wel even recht voor z'n raap:

- Bouw een proof of concept met de kennis die je wel hebt. Al is het zonder sockets/updates. Verzin een manier zonder die harde tech, maar dat je toch je idee uitwerkt.
- f*** de server load, bouw je ding eerst eens
- Haal nooit meer "maar facebook doet het ook" erbij
- En maak zo snel mogelijk iteraties

En ga naar productie. Misschien gaat het op z'n gat, maar anders weet je nooit of het wat is.

Waarom ik dit zo zeg: Al zit je er een jaar aan te werken; wat jij gaat maken is met alle respect nooit vitaal om een serieuze productie load a 1000++++ concurrent spelers aan te kunnen. Laten we realistisch zijn, je begint je startup met een vraag op Tweakers: hoe bouw ik mijn core onderdeel van mijn startup idee.

Echter dat is juist niet erg. Want je wilt innoveren (hoop ik), dus moet je ook leren en dan kan je beter;
- snel itereren
- 95% kans dat het helemaal niets is
- kennis mee nemen naar je volgende poging en dan ben je al 1 stapje verder

Als je die 5% aantikt, dan heb je of krijg je, de middelen om het echt productie waardig te gaan opzetten.

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

nickpma schreef op donderdag 27 augustus 2020 @ 11:44:
[...]


Als ik gewoon telkens mijn PHP file de laatste stand van zaken laat sturen naar de clients, dan moet dat geen probleem zijn. Evt kun je met een timestamp werken, maar dat is niet eens nodig.
Je hoeft van server naar client niet eens de DB te raadplegen.

Het gaat hier om 10 veldjes, dus niks speciaals.
Met SSE stuur je dan standaard bijvoorbeeld elke 3 seconden een update naar client over de bestaande open connectie.
Het is niet de 10 veldjes, het zijn die 1000 connecties die je open houd. En al will je elke 3 seconden een update sturen, dan betekent dat dat je elke 3 ms een bericht moet sturen. Sowieso is het complete onzin om een thread + conectie te laten lopen voor iets wat elke 3 seconden een beetje data stuurt. Zeker voor een platform wat niet bedoeld is voor langlopende processen.Als elke 3 seconden een update krijgen voldoende is, laat de client dan lekker pollen en hoop ten eerste dat je db het aan kan, en ten tweede dat de updates van 1000 kanten geen raceproblemen op gaat leveren.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • +1 Henk 'm!

  • Solopher
  • Registratie: December 2002
  • Laatst online: 11-09 14:55
Mocht je voor SSE willen gaan, dan kun je altijd kijken naar Mercure.

De Mercure server is geschreven in Go, en Client-side kun je er d.m.v. JavaScript mee verbinden.
Documentatie: https://mercure.rocks/docs/mercure
Getting started: https://mercure.rocks/docs/getting-started

In PHP kun events sturen via de Symfony/Mercure Component: https://github.com/symfony/mercure (Symfony components zijn losse onderdelen, en dus ook goed zonder Symfony te gebruiken).

Wij gebruiken dit in productie, het tot nu toe bevalt het ons erg goed. Het is vrij eenvoudig te installeren voor zowel Development als productie, er is namelijk een Docker image en een Helm Chart: Mocht je geen Docker/Kubernetes willen gebruiken, er zijn ook binaries beschikbaar voor: macOS, Linux, Windows: https://github.com/dunglas/mercure/releases/tag/v0.10.3

Voorbeelden:

Server-side (publisher):
PHP:
1
2
3
4
5
6
7
8
9
10
11
// change these values accordingly to your hub installation
define('HUB_URL', 'https://demo.mercure.rocks/.well-known/mercure');
define('JWT', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InN1YnNjcmliZSI6WyJmb28iLCJiYXIiXSwicHVibGlzaCI6WyJmb28iXX19.LRLvirgONK13JgacQ_VbcjySbVhkSmHy3IznH3tA9PM');

use Symfony\Component\Mercure\Jwt\StaticJwtProvider;
use Symfony\Component\Mercure\Publisher;
use Symfony\Component\Mercure\Update;

$publisher = new Publisher(HUB_URL, new StaticJwtProvider(JWT));
// Serialize the update, and dispatch it to the hub, that will broadcast it to the clients
$id = $publisher(new Update('https://example.com/books/1.jsonld', 'Hi from Symfony!'));



Client-side (Subscriber):
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
// The subscriber subscribes to updates for the https://example.com/users/dunglas topic
// and to any topic matching https://example.com/books/{id}
const url = new URL('http://localhost:3000/.well-known/mercure');
url.searchParams.append('topic', 'https://example.com/books/{id}');
url.searchParams.append('topic', 'https://example.com/users/dunglas');
// The URL class is a convenient way to generate URLs such as http://localhost:3000/.well-known/mercure?topic=https://example.com/books/{id}&topic=https://example.com/users/dunglas

const eventSource = new EventSource(url);

// The callback will be called every time an update is published
eventSource.onmessage = e => console.log(e); // do something with the payload

Acties:
  • 0 Henk 'm!

  • nickpma
  • Registratie: Mei 2004
  • Laatst online: 13-09 14:59
Bedankt iedereen voor de reacties.

De conclusie is dat meer onderzoek nodig is.
Een aantal van jullie raden het af, terwijl anderen juist weer zeggen dat het prima te doen moet zijn.
Ik heb net een verzoek bij de hosting provider ingediend om te kijken wat de limieten zijn.

Bedankt voor je uitgebreide voorbeeld Solopher, erg gewaardeerd!

Janoz, het openhouden van een connectie is wellicht een stuk minder intensief dan iedere keer weer een nieuwe connectie opzetten. Juist hiervoor is SSE bedoelt.
Bovendien wil ik niet elke 3 seconde een update sturen, je luistert naar de server.
Zoals al vaker gezegd, de database krijgt alleen load bij een POST request, dus dit is te verwaarlozen.

Mijn conclusie is wel dat ik mooi klein ga beginnen, waarschijnlijk met SSE, en dan inderdaad uitbouwen en professionaliseren naarmate het bedrijf groeit.
En natuurlijk even loadtesten, om te zien wat de limieten zijn.

Bedankt iedereen! Tijd voor wat meer coden!
Pagina: 1