Het hart van de omgeving is de storage server. Hier ligt alle data van alle andere servers opgeslagen. De lokale disken van de andere servers bevatten alleen het OS. Het voordeel van deze opzet is dat als er een server uit mocht vallen, deze zeer snel te vervangen is door een reserveserver. Omdat er geen data op de uitgevallen server staat, hoeft er geen restore uitgevoerd te worden en kan de reserverserver zeer snel weer online zijn. De storage server zelf is o.a. geselecteerd op z'n betrouwbaarheid, zodat de kans dat deze uitvalt zeer gering is.

Middels NFS over een prive netwerk is de storage server gekoppeld aan de frontproxy-, applicatie- en database servers. Deze servers zijn op hun beurt via een publiek netwerk (en een tussenliggende router) aan het internet verbonden. Op de router gebeurt afscherming, zodat alleen http verkeer (webserving) en ssh verkeer (uploaden bestanden) tussen het internet en de servers mogelijk is. Daarnaast vindt op de hosts zelf ook afscherming plaats, zodat er geen ongeoorloofd verkeer tussen verschillende servers in hetzelfde cluster mogelijk is.

In onderstaand overzicht zijn 4 servers getekend, in werkelijkheid zijn dit er in het appcluster nu bijna 30. Het geheel van alle servers tezamen vormt het hosting cluster.

upload-, proxy,app,db- en storageservers

Instanties

Een belangrijk concept in het cluster is dat van een “instantie”. Een instantie is de combinatie van een proces en resources behorende bij zo'n proces (met name storage en een eigen IP adres) Bekendste voorbeeld is een database instantie. Daar heb je dus het database proces en de on-disk data files waar het database proces op werkt. Maar, ook van andere diensten kan je een instantie hebben. Denk aan een webserver instantie. Een proces (“apache”) in combinatie met storage (o.a. de documentroot van een website) waar dat proces wat mee doet.

Dit concept is zo belangrijk, omdat de individuele nodes (servers) in het cluster “instantie agnostisch” zijn opgezet. Dwz er is geen binding tussen een node en een instantie. Een instantie kan draaien op node A, maar net zo goed op node B. (bedenk dat de storage van een instantie niet op de lokale disken van een node ligt, maar op de gesharede disken van de fileserver)

Sterker nog, er kunnen meerdere instanties van hetzelfde type (webservers, database servers) draaien op dezelfde node. Bijvoorbeeld, in het appcluster hebben we een node aangewezen als plekje waar normaliter alle shared databases moeten draaien. Op dit moment draaien daar 4 database instanties op. Als we hardware zouden hebben met heel veel CPU en geheugen, dan zou niets ons letten om alle instanties van het hele cluster op die ene superkrachtige node te draaien.

Dit kan omdat we ervoor zorgen dat een instantie nooit “unieke” resources van een node in kan pikken. Bijvoorbeeld: apache laten we nooit binden aan het 0.0.0.0 adres, maar alleen maar een een specifiek, bij die instantie behorend ip adres. Net zo voor databases. Die willen vaak graag een socket in /tmp aanmaken. Dat gaat mooi niet door, want zo'n socket kan maar 1x aangemaakt worden. In de start/stop scripts zorgen we er dus voor dat zo'n socket niet in de globale /tmp directory aangemaakt wordt, maar in een directory behorende bij de instantie.

Tegelijkertijd hebben we onze eigen versies van de normale start/stop scripts (dwz de scripts die je normaal in /etc/init.d vindt); onze versies doen extra zaken. Waaronder het dynamisch opbrengen van het IP adres behorende bij een instantie, op de node waar je op dat moment de instantie opstart. Bij het afluiten van de instantie wordt het IP adres ook weer verwijderd.

De grap nu van die instanties is dat het dus heel makkelijk is om een individuele node even tijdelijk uit de running te halen. Simpel alle instanties die op die node draaien even “overhupsen” naar een andere node. Stoppen aan de ene kant, weer opstarten aan de andere kant en de dienst draait weer verder. Dit kan binnen seconden geregeld zijn. Hiermee is het mogelijk om b.v. nodes voorzien van kernel of OS upgrades, zonder dat de diensten die aan de buitenwereld geleverd worden down gebracht hoeven te worden.

Naamgeving

De policy voor naamgeving is als volgt: (ingewikkeld? Vertel ons wat u wilt en wij regelen het zonder u te vermoeien met onderstaande details)

  • Websites

Elke omroep is geheel vrij een naam voor de website te kiezen. Elke applicatie kan onder een andere naam draaien (bv “www.groente.nl” vs “www.fruit.nl”), een gedeelde naam (bv “www.plantaardig.nl/groente vs www.plantaardig.nl/fruit”) of onder de default naam “sites.omroep.nl” (bv sites.omroep.nl/groente) De naam die u kiest, is de naam die in de locatiebalk van de webserver zichbaar is en de naam die extern bekend gemaakt wordt. Alle naamgeving die hieronder nog staat is alleen maar intern, en niet extern zichtbaar. In de testomgeving hebben wij liefst dat applicaties draaien onder “testsites.omroep.nl/<applicatie>”, maar indien gewenst kunnen er ook (lange!) namen als “<omroep>-<applicatie>test.omroep.nl” aangemaakt worden (bv degezondeomroep-groentetest.omroep.nl)

  • Frontproxies

Deze worden genoemd naar de omroep waar ze bij horen, gevolgd door een volgnummer. B.v. /e/fp/dgo01 zou de 1e frontproxy van “De Gezonde Omroep” (DGO) zijn. De shared frontproxy heet <tt/shrd01/ De dns naam van een frontproxy wordt “<omroep>-sites.omroep.nl”. (bv “degezondeomroep-sites.omroep.nl”). Deze naam wordt iha niet extern genoemd, maar is alleen een “kapstok” om domeinnamen aan op te kunnen hangen, dmv DNS CNAMES. (b.v. www.groente.nl is een CNAME naar degezondeomroep-sites.omroep.nl; dmv een virtualhost constructie in de frontproxy zorgen wij er dan voor dat www.groente.nl uitkomt bij de groente applicatie)

  • Databases

Deze worden ook genoemd naar de omroep waar ze bij horen, gevolgd door een volgnummer. In de naamgeving wordt geen onderscheid tussen de verschillende types database (mysql of postgresql) aangehouden. B.v. /e/db/dgo01 zou de eerste database instance van de gezonde omroep zijn. De shared database instances heten shrd01 (mysql) en shrd02 (postgresql) Binnen de database instances kunnen voor de diverse applicaties diverse databases aangemaakt worden. Als er een applicatie genaamd “groente” zou zijn, zou de database die daarbij hoort “groentedb” heten en de database user die daarbij hoort zou “groente' heten.

  • Applicatie Servers

Ook deze worden genoemd naar de omroep waar ze bij horen, met een volgnummer. De tiende DGO applicatieserver zou /e/as/dgo10 heten. De naam van applicatieservers wordt generiek gehouden, omdat een applicatieserver geen 1 op 1 relatie met een applicatie heeft.

  • Applicaties

Voor applicaties wordt bij voorkeur gepoogd om een 1 op 1 mapping tussen url en applicatienaam te hebben. Dwz als een website www.groentenenfruit.nl heet, dan is de applicatienaam ook /e/ap/www.groentenenfruit.nl In geval van java hosting wil het nog wel eens voorkomen dat er onder 1 url meerdere applicaties hangen (verschillende mountpoints in tomcat) In dat geval wordt gepoogd een min of meer descriptieve naam te gebruiken. Stel dat onder de groentenenfruit site nog een speciale shop module nodig is, dan zou deze op disk /e/ap/groentenenfruitshop kunnen heten en bereikbaar kunnen zind als www.groentenenfruit.nl/shop.

  • Upload Accountnamen

De upload accounts worden meestal genoemd naar de organisatie die de uploads wil kunnen doen. Stel dat DGO het maken van z'n Groenten en Fruit site geheeld uit zou besteden aan de “DeNeefjesCompany Ltd” dan zou het upload account iets als “neefjes” kunnen heten; dit account zou vervolgens schrijfrechten onder onder /e/ap/groentenenfruit/web-app krijgen om daar de applicatie te plaatsen. Als een omroep zelf z'n eigen applicaties plaatst, dan wordt de accountnaam weer iets als “omroep+volgnummer”.

Webservers leven altijd onder /e/fp. De naam daaronder ziet eruit als xxxx[0-9][a-z], waarbij de xxxx een tag is om aan te duiden van of voor wie deze instantie is (bv een omroepnaam of een applicatienaam), daarna volgt een cijfer, wat een volgnummer is. De N'e instance van klant xxxx. Tenslotte volgt weer een letter om aan te geven dat iets geloadbalanced is. Stel dat foo1 geloadbalanced zou worden over 3 instanties, dan zou je deze onder /e/fp terugvinden als foo1a, foo1b en foo1c.

Vaak zullen de a,b en c instanties onderling veel configuratie delen. Om deze nu niet 3x te dupliceren is deze terug te vinden in een gedeelde directory /e/fp/foo1 (dwz zonder volgletter).

Zowel de static proxies, als de php enabled servers zijn webservers en leven dus beide onder /e/fp. Er is geen onderscheid in naamgeving tussen proxies en php servers. In praktijk betekent dit vaak dat een proxy en php server dezelfde prefix hebben (“foo”), maar een ander volgnummertje (“foo1” tegenover “foo2”). Het kan natuurlijk ook zo zijn dat 1 setje proxies (foo1&lsqb;a-z&rsqb;) loadbalanced over meerdere setjes php servers (foo2&lsqb;a-z&rsqb; voor applicatie X en foo3&lsqb;a-z&rsqb; voor applicatie Y). Wij streven ernaar om in het GECOS veld van de password file aan te geven wat een webserver isntantie precies doet.

De user waar een webserver onder draait is z'n naam gevolgd door de letters “fp”. B.v. foo1afp. En het adres waar die aan bindt heeft meestal als DNS naam foo1afp.omroep.nl,

Shared vhost includes

de configuratie van apache virtual hosts leeft bij ons altijd in losse .vhost files, welke door de webserver geinclude worden. In een loadbalanced context moeten zowel de proxies als de php servers weet hebben van de vhosts. Om nu niet alle informatie N maal te dupliceren hebben we vsan elke vhost file slechts een kopie, die door alle (proxies <em>en</em> php servers) webserver geinclude wordt. In de vhost file wordt met Define's gespeeld om ervoor te zorgen dat elke instantie alleen maar het stukje configuratie krijgt dat voor die instantie van toepassing is.

Sessies

Niet alles is rozegeur en maneschijn, nl sessies zijn een probleem. Er is geen garantie dat een sessie altijd bij dezelfde php node terecht komt. Er zijn een aantal oplossingen:

  • route constructies gebruiken

We gaan er van uit dat sessie informatie in http cookies gestopt zit. Als de cookies op een zodanige wijze gegenereerd kunnen worden dat het duidelijk is door welke worker node dit gedaan is, dan zit er in de http proxy functionaliteit om op basis van zo'n cookie het request naar de juiste worker door te sturen. Concreet betekent dat dat de cookiename statisch moet zijn (bv PHPSESSIONID) en dat de waarde van de cookie eruit moet zien als sessiadata.NODE_ID, waarbij het NODE_ID bepalend is voor naar welke node een request doorgezet moet worden. In een java tomcat context is dit tamelijk eenvoudig te doen door in de tomcat server.xml een jvmRoute op te nemen:

<Engine name="Standalone" defaultHost="none" jvmRoute="NODE_x">

Dit zorgt ervoor dat er cookies JSESSIONID=sessiedata.NODE_x gezet worden. Vervolgens stellen we op de proxy in:

ProxyPass / balancer://cluster/ stickysession=JSESSIONID
<Proxy balancer://cluster>
	BalancerMember	http://node1 route=NODE_1
	BalancerMember	http://node2 route=NODE_2
	BalancerMember	http://node3 route=NODE_3
	...
</Proxy>

En zo weet de proxy dat sessies met NODE_1 doorgestuurd moeten worden naar node1. Het probleem hierbij echter is dat dat bij php niet zo fijn werkt. Er is in php geen makkelijke manier (a la jvmRoute in tomcat) om php duidelijk te maken dat ie z'n sessie namen volgens een bepaalde syntax aan moet maken. Daarom hebben we een speciale truc verzonnen, waardoor door middel van een RewriteRule in de PHP-worker een cookie geset wordt (vaak iets als 'BALANCEID'), wat dan als stickysession gebruikt kan worden. Hierdoor komt uiteindelijk dan alsnog brafa elk request van 1 bezoeker op dezelfde PHP-worker terecht.

  • sessies in database opslaan

Aangezien de verschillende webserver nodes uiteindelijk weer aan dezelfde database refereren, kan de database goed gebruikt worden om sessie informatie in op te slaan.

  • sessies op het filesysteem opslaan

Dit zou in theorie kunnen, maar is in praktijk een slecht idee. De gedachte is dat de verschillende php nodes een shared filesysteem hebben. Dus, als node 1 op het filesysteem wat sessie info neerzet, dan kan node 2 dat weer oppikken. Probleem hierbij is dat we NFS gebruiken voor het filesysteem en dat NFS geen cache consistency biedt. Dat betekent dat op het moment dat node 1 iets weggeschreven heeft, dit niet meteen op node 2 bekend is.

  • sessies in memcache opslaan

We bieden inmiddels ook support voor memcache, een stukje geheugen dat op een eigen intern ip-adresje beschikbaar is voor alle php-workers.

  • sterretje-cluster/cluster-hosting_opbouw-omgeving.txt
  • Last modified: 2019/04/26 10:34
  • (external edit)