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

Is mijn webservice geschikt voor shared hosting of niet?

Pagina: 1
Acties:

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 18-11 13:07
Ten eerste, ik weet niet zo goed waar mijn topic hoort dus als dit het verkeerde forum is dan hoor ik het graag.


Ik heb al een hele tijd een webservice draaien op een Windows shared host. Het gaat om een ASP.NET WCF service in combinatie met een MySQL database. De service draait al lang en ik heb "vrij veel" gebruikers. In de database heb ik 20,000 accounts maar ze worden lang niet allemaal actief gebruikt. Echter heb ik nooit echt tegen problemen aangelopen en de laatste tijd ook niet echt gekeken hoe het verbruik van de service nou precies lag (hoeveel requests er binnen komen etc).

Laatst ben ik naar een nieuwe host overgestapt. Nog steeds shared hosting. Na het verhuizen van de service loop ik vrijwel meteen tegen limieten voornamelijk in de database (meer dan max_user_connections verbindingen). De code nagelopen maar ik denk niet dat er ergens connecties open blijven. Wel staat de "wait_timeout" setting hoog (28800 sec ipv 20 sec bij m'n oude host) wat denk ik zou kunnen verklaren waarom het nu niet meer werkt (veel connecties die op "Sleep" blijven).


Nu ben ik toch maar eens wat logging gaan installeren om uit te zoeken hoeveel de service eigenlijk aangeroepen wordt. Met een snelle schatting kom ik op ongeveer 10 - 30 requests per seconde. Dit klinkt voor mij zeer veel maar ik heb hier eigenlijk geen verstand van.

Is dit iets wat ik op een shared host zou kunnen draaien (zoals het al tijden lang draait) of moet ik hier toch echt naar een VPS oid gaan overstappen? Dit wil ik echt voorkomen want dat is toch echt een stap te duur aangezien ik deze service gratis beschikbaar stel.

Ik heb geen flauw idee wat een typisch verbruik is en of dit "nog wel kan" of totaal onrealistisch en extreem te veel verbruik is. Kan iemand mij opheldering geven?

Mijn iRacing profiel


  • GlowMouse
  • Registratie: November 2002
  • Niet online
Hier valt geen klap over te zeggen zonder duidelijkheid over wat die 10-30 requests inhouden. Static files zullen geen probleem zijn, terwijl scripts die elk een seconde cpu-tijd nodig hebben en 50 MB geheugen alloceren een ander verhaal is.

Zeker omdat je een duidelijke bottleneck hebt (aantal databaseverbindingen) is het allemaal vrij eenvoudig uit te zoeken: hoeveel verbindingen mag je maken, hoeveel http-requests worden er gedaan die tot een databaseverbinding leiden, en hoelang duurt het afhandelen van zo'n request?

  • johnkeates
  • Registratie: Februari 2008
  • Laatst online: 04-07 16:30
Als je constant nieuwe verbindingen maakt gaat het vanzelf wel mis. En 1 server neerzetten voor een service die constant door meerdere mensen gebruikt wordt lijkt me ook niet wenselijk, zet er dan twee neer achter een reverse proxy of load balancer.

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 18-11 13:07
GlowMouse schreef op woensdag 28 maart 2018 @ 21:19:
Hier valt geen klap over te zeggen zonder duidelijkheid over wat die 10-30 requests inhouden. Static files zullen geen probleem zijn, terwijl scripts die elk een seconde cpu-tijd nodig hebben en 50 MB geheugen alloceren een ander verhaal is.

Zeker omdat je een duidelijke bottleneck hebt (aantal databaseverbindingen) is het allemaal vrij eenvoudig uit te zoeken: hoeveel verbindingen mag je maken, hoeveel http-requests worden er gedaan die tot een databaseverbinding leiden, en hoelang duurt het afhandelen van zo'n request?
Excuus.

De requests die ik noem zijn allemaal requests die een (relatief simpele) database query uitvoeren (1 select van ~10 columns met 1 inner join). 90% van die requests resulteert daarna in een static file download van ongeveer 2 kB terug naar de client. De file staat niet in de database maar los op de schijf.

Hoeveel CPU/RAM ze gebruiken kan ik zo snel niet terugvinden. Volgens de trace logs die ik via de WCF config heb aangezet duren de requests enkele seconden maar dat is denk ik de totaal tijd van client naar server inclusief ping etc (dan nog vind ik paar seconden erg lang, voor zover ik merk is het veel minder dan 1 sec).

Aantal verbinden (max_user_connections) is 50. Erg weinig dus maar door shared hosting niet aan te passen. Echter was dit op de oude host hetzelfde en niet zo'n probleem (enkel in piek tijden), ik gok omdat de wait_timeout veel korter was (20s vs 28800s)? Of wellicht nog een andere instelling. Maar ik ben bang dat ik ook deze niet kan aanpassen.

Ik kan niet echt vinden / berekenen / loggen hoe lang de daadwerkelijke database query duurt. Dat zal echt niet meer dan een paar ms zijn per geval. Als de connectie in die paar ms ook open en weer dicht gaat dan denk ik niet dat ik tegen problemen loop tenzij er toevallig net 50 users exact op hetzelfde moment iets doen. Die kans is klein genoeg dat dit geen probleem is (deze service is lang niet kritiek en als er af en toe een actie misgaat is geen ramp). Het lijkt er echter op dat de connectie veel langer open blijft.
johnkeates schreef op woensdag 28 maart 2018 @ 21:21:
Als je constant nieuwe verbindingen maakt gaat het vanzelf wel mis. En 1 server neerzetten voor een service die constant door meerdere mensen gebruikt wordt lijkt me ook niet wenselijk, zet er dan twee neer achter een reverse proxy of load balancer.
Al mijn ervaring met WCF / .NET en databases (Entity Framework) geeft aan dat het beste is om voor elke request (webmethod) een nieuwe connectie te gebruiken. Of in ieder geval een nieuwe database context aan te maken, achter de schermen doet EF zelf volgens mij nog wel aan slim recyclen / openhouden van connecties maar daar heb ik geen verstand van.

Meerdere servers en load balancing klinkt toch als een zeer definitieve "nee" voor shared hosting... Daar heb ik dus ook 0 verstand van.

[ Voor 9% gewijzigd door NickThissen op 28-03-2018 21:55 ]

Mijn iRacing profiel


  • GlowMouse
  • Registratie: November 2002
  • Niet online
NickThissen schreef op woensdag 28 maart 2018 @ 21:52:
[...]

Excuus.

De requests die ik noem zijn allemaal requests die een (relatief simpele) database query uitvoeren (1 select van ~10 columns met 1 inner join). 90% van die requests resulteert daarna in een static file download van ongeveer 2 kB terug naar de client. De file staat niet in de database maar los op de schijf.
Heb je de output van EXPLAIN van die query?
NickThissen schreef op woensdag 28 maart 2018 @ 21:52:
[...]

De requests die ik noem zijn allemaal requests die een (relatief simpele) database query uitvoeren (1 select van ~10 columns met 1 inner join). 90% van die requests resulteert daarna in een static file download van ongeveer 2 kB terug naar de client.
Static files voeren geen queries uit.

Een seconde is absurd lang.

[ Voor 31% gewijzigd door GlowMouse op 28-03-2018 22:02 ]


  • NickThissen
  • Registratie: November 2007
  • Laatst online: 18-11 13:07
De meest voorkomende query (by far) is een "get user" query, zelfs zonder join:
SQL:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
EXPLAIN SELECT
`Extent1`.`Id`, 
`Extent1`.`CreatedTime`, 
`Extent1`.`UpdatedTime`, 
`Extent1`.`Username`, 
`Extent1`.`Email`, 
`Extent1`.`PasswordHash`, 
`Extent1`.`AdminLevel`, 
`Extent1`.`Status`, 
`Extent1`.`ConfirmationKey`, 
`Extent1`.`Tzi`, 
`Extent1`.`LoginToken`
FROM `users` AS `Extent1`
 WHERE `Extent1`.`Username` = 'Nick Thissen' LIMIT 2


code:
1
2
3
4
5
6
7
8
9
10
id: 1
select_type: SIMPLE
table: Extent1
type: ALL
possible_keys: null
key: null
key_len: null
ref: null
rows: 25387
Extra: Using where


Execution time volgens MySQL workbench: 0.032 sec.

Mijn iRacing profiel


  • GlowMouse
  • Registratie: November 2002
  • Niet online
Daar gaat het dus al mooi mis. Zet eens een index op username (en zorg dat het juiste type is ingesteld, geen utf-8 als dat niet nodig is).

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 18-11 13:07
Stom inderdaad, die had er al lang op moeten zitten... Ik ben bang dat er nogal wat van dit soort fouten in zitten en ik ben van plan om die eruit te gaan halen maar heb helaas weinig tijd om dat echt extensief te doen. Ik denk dat er nog wel wat te winnen valt maar toch blijf ik me afvragen of ik zoiets wel op een shared host kan draaien zonder telkens in de problemen te komen.


Na de index is het resultaat:
code:
1
2
3
4
5
6
7
8
9
10
id: 1   
select_type: SIMPLE 
table: Extent1  
type: ref   
possible_keys: Username 
key: Username   
key_len: 767    
ref: const  
rows: 1 
Extra: Using index condition


Met mijn gebrekkige kennis maak ik hierop uit dat hij het resultaat uit de index zoekt en dus niet alle rows af moet zoeken. De query duurt nu 0.031s, nauwelijks winst dus. Wat ik me afvraag is waarom zou dit helpen met mijn "max aantal connecties" probleem? Doet hij iets met caching waardoor hij hiervoor niet telkens een nieuwe connectie nodig heeft?

Ik zal meer van dit soort dingen opzoeken en kijken of het veel zin heeft. Bedankt!

Mijn iRacing profiel


  • GlowMouse
  • Registratie: November 2002
  • Niet online
key_len: 767
Dit is nog een probleem. Zoek eens uit hoe indices op strings werken, wat het gevolg is van utf-8, en hoe je de lengte het beste kunt bepalen.

Hoe time je de query?

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 18-11 13:07
Ik heb begrepen dat ik utf8 nodig heb omdat ik veel namen met "vreemd" alfabet heb. Wellicht kan ik de index op de eerste 15-20 karakters alleen doen ofzo?

Mijn iRacing profiel


  • GlowMouse
  • Registratie: November 2002
  • Niet online
NickThissen schreef op woensdag 28 maart 2018 @ 22:29:
Ik heb begrepen dat ik utf8 nodig heb omdat ik veel namen met "vreemd" alfabet heb. Wellicht kan ik de index op de eerste 15-20 karakters alleen doen ofzo?
In veel gevallen kom je met 5 karakters ook al een eind.

  • killercow
  • Registratie: Maart 2000
  • Laatst online: 28-11 15:56

killercow

eth0

johnkeates schreef op woensdag 28 maart 2018 @ 21:21:
Als je constant nieuwe verbindingen maakt gaat het vanzelf wel mis. En 1 server neerzetten voor een service die constant door meerdere mensen gebruikt wordt lijkt me ook niet wenselijk, zet er dan twee neer achter een reverse proxy of load balancer.
Wat een onzin, een enkele server kan prima multi-threaded zn werk doen *mits* de database niet locked en mits je niet elders condities hebt die een single thread alles laten blokkeren (wat met een load balancing oplossing net zo veel issues zou geven).

Je code sluit mogelijk gewoon niet netjes de database connectie af, waardoor er uiteindelijk te veel slapende connecties open blijven staan die danwel niet echt resources gebruiken, maar wel mee-tellen aan het max-nummer van connecties dat de database accepteerd.

openkat.nl al gezien?


  • Glewellyn
  • Registratie: Januari 2001
  • Laatst online: 25-11 15:36

Glewellyn

is er ook weer.

killercow schreef op woensdag 28 maart 2018 @ 22:33:
[...]


Wat een onzin, een enkele server kan prima multi-threaded zn werk doen *mits* de database niet locked en mits je niet elders condities hebt die een single thread alles laten blokkeren (wat met een load balancing oplossing net zo veel issues zou geven).

Je code sluit mogelijk gewoon niet netjes de database connectie af, waardoor er uiteindelijk te veel slapende connecties open blijven staan die danwel niet echt resources gebruiken, maar wel mee-tellen aan het max-nummer van connecties dat de database accepteerd.
Hiermee ben ik het helemaal eens. Jouw query duurt 0.031. Je zou er dus (ideaal gezien) 32 sequentieel per seconde kunnen doen over 1 database connectie. Nu weet ik niet hoe hoog max_user_connections staat, maar ik verwacht toch zeker hoger dan 10, waarschijnlijker is 30 of 50.

Loop je code eens goed na en controleer dat je echt de user sessions afsluit.

*zucht*


  • NickThissen
  • Registratie: November 2007
  • Laatst online: 18-11 13:07
killercow schreef op woensdag 28 maart 2018 @ 22:33:
[...]

Je code sluit mogelijk gewoon niet netjes de database connectie af, waardoor er uiteindelijk te veel slapende connecties open blijven staan die danwel niet echt resources gebruiken, maar wel mee-tellen aan het max-nummer van connecties dat de database accepteerd.
Dit was uiteraard mijn eerste gedachte maar ik kan geen enkele instantie vinden waar de connectie open blijft. Alles zit netjes in een using statement (C#) dus voor zover ik weet moet dat gewoon goed gaan.

Hoe zie ik het verschil tussen een connectie die door mijn fout open blijft en een connectie die 'gewoon' op Sleep staat? Via de query "show processlist" zie ik dat er continu 10-20 connecties zijn maar 95% daarvan staat op Sleep. Na paar keer refreshen lijkt een van die connecties weer hergebruikt te worden voor een nieuwe query. Dat lijkt mij gewoon hoe het hoort, toch?

De lijst met processes groeit echter nu niet meer zo snel. Na 10 min ofzo zit ik nog steeds op die 10-20, waar er voor de veranderingen die GlowMouse voorstelde na 2-3 min wel een volle tabel zat (30*).

Tot nu toe lijkt het te werken dus, bedankt! Ik kan nog veel meer optimalizeren hopelijk vind ik daar de tijd voor.

*De limiet lijkt trouwens 30 te zijn en niet 50 zoals m'n host me vertelde.

Mijn iRacing profiel


  • Glewellyn
  • Registratie: Januari 2001
  • Laatst online: 25-11 15:36

Glewellyn

is er ook weer.

NickThissen schreef op woensdag 28 maart 2018 @ 22:40:
[...]
*De limiet lijkt trouwens 30 te zijn en niet 50 zoals m'n host me vertelde.
Daar kan je achter komen (aangenomen dat je de juiste permissies hebt)

show global variables like '%connections%'

*zucht*

Pagina: 1