Page tree
Skip to end of metadata
Go to start of metadata

L'idée est de déployer des instances de Grails sur une ou plusieurs machines différentes.

Ce que le guide fait:

  • "Clusteriser" une application Grails test (presque vide)
  • Utiliser le load balancer pour répartir les requêtes et gérer les pannes
  • Partager le cache et la session avec Terracotta

Il est donc totalement indépendant de Cytomine.

Deux possibilités de cluster du cache avec Terracotta pour Grails (Hibernate)

  • Partagé le "Second Level Cache" (L2): partage seulement le cache,
  • Partagé le "First Level Cache": partage les objets en session. Un même object peut être utilisé par node 1 et node 2 dans passer par la DB. Beaucoup plus efficace mais complexe a mettre en oeuvre et moins d’intérêt pour une application web dont les requêtes sont indépendantes.

Dans notre cas, on part sur un partage du cache L2

 

 

En pièce jointe de cette page se trouve l'application Grails configurée (Events)

 

 

Cela soulève plusieurs problèmes:

  • Une seule URL doit pouvoir être attaquée. Un système doit répartir les requêtes sur les différents nœuds disponibles,
  • La session doit être partagée (notamment pour l'authentification) entre les noeuds,
  • Le cache Hibernate doit être partagé ou désactivé.
    Si chaque nœud dispose de son propre cache, deux problèmes se posent. Les deux instances auront les mêmes données dans leur cache respectif (gaspillage). Des problèmes de cohérence risquent de survenir en cas de lecture/écriture sur des données présentes dans les deux caches.

Le premier point est résolu avec le Load Balancer d'Nginx et le deuxième et troisième point sont résolus avec Terracotta

Télécharger Terracotta

La version utilisée est Terracotta 3.7.5.

https://terracottatech.com/downloads/open-source/destination?name=terracotta-3.7.5.tar.gz&bucket=tcdistributions&file=terracotta-3.7.5.tar.gz ou http://terracotta.org/downloads/open-source/catalog

tar -xvf terracotta-3.7.5.tar.gz

Terracotta écoute sur le port 9510 par défaut.

Configurer Nginx

Modifier nginx.conf.

    upstream tomcatcluster  {
        server 127.0.0.1:8081;
        server 127.0.0.1:8082;
    }
    server {
        listen       80;
        server_name  localhost;
        location / {
            proxy_pass http://tomcatcluster;
        }
    }

La ligne ip_hash; peut être ajouté dans upstream tomcatcluster. Elle permet d'envoyer les requêtes successives d'un même utilisateur sur le même serveur. En cas de crash du nœud utilisé précédemment par l'utilisateur, les requêtes seront soumises à un autre serveur.  
Cela permet de garder une session propre a chaque noeud. Mais en cas de crash du nœud utilisé par l'utilisateur, un nouveau nœud sera désigné et la session sera perdue.

Configurer l'application Grails

Configurer le buildConfig
grails.project.dependency.resolution = {
 
    repositories {
        ...
	    mavenRepo "http://www.terracotta.org/download/reflector/releases"
        ...
    }
    dependencies {
        ...
        //for cache
        runtime 'net.sf.ehcache:ehcache-core:2.6.6'
        runtime 'net.sf.ehcache:ehcache-terracotta:2.6.6'
        //for session
        runtime "org.terracotta:terracotta-toolkit-1.6-runtime:5.5.0"  
        runtime "org.terracotta.session:terracotta-session:1.3.5" 
    }

    ...
}
Configurer le cache ehcache

Le fichier ehcache.xml doit être dans grails-app/conf/.

<ehcache name="EventCache">
   <defaultCache
      maxElementsInMemory="10"
      eternal="false"
      timeToIdleSeconds="120"
      timeToLiveSeconds="120"
      overflowToDisk="false">
      <terracotta/>
    </defaultCache>
  <terracottaConfig url="localhost:9510"/>
</ehcache>

Le cache Hibernate ne sera plus géré en local mais sera commun à tous les nœuds via Terracotta.

Configurer la session

 Le fichier context.xml doit être localisé dans web-app/META-INF/ de tomcat. 

<Context>
  <Valve className="org.terracotta.session.TerracottaTomcat70xSessionValve" tcConfigUrl="localhost:9510"/>
</Context>

En mode développement, on utilise un tomcat embarqué sans utiliser de war. Par défaut le fichier context.xml n'est pas être utilisé par l'instance de tomcat.

Un hack est possible en copiant le fichier dans le répertoire temporaire du tomcat embarqué. En ajoutant au fichier scripts/_Events.groovy (a créer si non existant):

eventConfigureTomcat = { tomcat ->
    String contextFile = "web-app/WEB-INF/context.xml"
    if (new File(contextFile).exists()) {
        println "----- CONFIGURING TOMCAT REALM ----------"
        this.buildSettings = grails.util.BuildSettingsHolder.getSettings()
        def workDir = buildSettings.projectWorkDir
        def tomcatDir = new File("${workDir}/tomcat").absolutePath
		println tomcatDir
        ant.copy(file:"${contextFile}", todir:"${tomcatDir}/conf")
    } else {
		println "----- NO CONTEXT FILE in" + new File(contextFile)
	}
}

Le fichier context.xml existe dans /home/YOU/.grails/2.3.4/projects/events/tomcat/conf/context.xml

Vérifier si en mode production, le fichier context.xml est bien utilisé.

Lancer le cluster

Lancer nginx:

sudo /usr/local/nginx/sbin/nginx

Lancer terracotta:

cd terracotta-3.7.5
bin/start-tc-server.sh

Lancer la console de gestion avec:

bin/dev-console.sh

Lancer les serveurs:

grails run-app -Dgrails.server.port.http=8081
grails run-app -Dgrails.server.port.http=8082

Go to http://localhost/myapp/

Si kill 8081 => 8082
Si kill 8082 => 8081
Si kill 8081 && 8082 => KO

Avec la console Terracotta, on peut voir les 2 nœuds.

Avec l'application Events (pièce jointe), on a deux Controller.

  • EventController: utile pour tester le cache sur des domaines "event",
  • HomeController: utile pour tester la session avec un compteur.

Pour le cache, on voit la présence d'objet de type Event (2 * taille de 2 = 4 sur disque)

Pour la session:

http://localhost:8081/events/home/arrive => compteur init à 1 dans la session

http://localhost:8081/events/home/counter + http://localhost:8081/events/home/counter + http://localhost:8081/events/home/counter => compteur à 4

http://localhost:8082/events/home/counter + http://localhost:8082/events/home/counter => compteur à 6

Visualisation du compteur dans la session:

Ce qu'il faudra faire:

  • Appliquer ça a Cytomine,
  • Mesurer l’intérêt du cache Hibernate qui sera partagé entre plusieurs machines (coût réseau pour atteindre le cache VS coût de lecture de la donnée sans cache),
  • Effectuer des tests de stress pour mesurer la robustesse face aux requêtes concurrentes.
  • On reste avec un "Single point of failure" avec Terracotta. Soit les dupliquer aussi, soit essayer, en cas de d'impossibilité de joindre Terracotta, de switcher sur un cache et une session local?
  • No labels