Run java vs ruby

Preview:

Citation preview

Retour d’expérienceApplications web

Run Java vs Run Ruby

bpa@octo.com

De quoi on parle ?Une application web

Serveur

Base de données

Application web

Clients

Sommaire

• Les langages• Les application web• Le déploiement• La gestion des dépendances• Scalabilité

LES LANGAGES

• Langage « mainstream »• Compilé• Statiquement typé

• Langage non « mainstream »

• Interprété• Dynamiquement typé

Avantages

• La JVM : un bijou très optimisé• Beaucoup de recul• Gros parc déployé• Beaucoup de compétences sur le marché• Nouveaux langages qui arrivent

Virtual MachineJava

• Oracle : Hotspot– Open JDK

• IBM– Utilisée avec Websphere

• BEA : jRockit

Principales différences au niveau du GCConvergence sur Hotspot et OpenJDK

Avantages

• Langage hyper expressif• Adapté au scripting• Plus simple (notamment réutilisation)• Plus « 2011 »– gem install heroku– rvm

Exemplesdef chrono msg start = Time.now.to_i yield puts "#{msg} : #{Time.now.to_i - start} sec"end

chrono "Long operation" do run_very_long_operationend

class Integer def hex to_s(16) endend12.Hex => "c"

[1, 4, 10].map{|x| 2 * x}.sort => [2, 8, 20]

Redéfinition des

classes de bases

Passages de fonctions

en paramètres

Expressivité

Virtual MachineRuby

• Mat’z Ruby Interpreter (MRI)– Version 1.8

• Implémentation originale

– Version 1.9• « Vraie » VM : JIT, GC

• Ruby Entreprise Edition– Fork de MRI 1.8– Copy on write, GC optimisé

• jRuby– Bénéficie des performances de la JVM– De loin la plus performante VM pour Ruby (1.8 et 1.9)

En production : Un peut de tout …

APPLICATION WEB

Application WebJava

.java

.jsp

.css

.jpg

.jar

.class

.war

compilation

déploiement

code source

Stack Java« light »

javax.servlet

Stack HTTP Java

Frontal HTTP

Framework web 2

Application 2

Apache2, Nginx

Spring MVC …

Tomcat, Jetty

Framework web 1

Application 1

war2war1

API

Stack Javastandard

Frontal HTTP Apache2, Nginx

Serveur d’application

Jboss, Weblogic, Websphere

javax.servlet

Stack HTTP Java

Framework web 1

Application 1

war1

EJB Container

Annuaire

Queue

Parallélisme

javax.servlet

Stack HTTP Java

Thread worker 1

Thread worker 2

Thread worker 3

choix d’unthread worker

Thread worker 4

Appl

icati

on

JVM

Mémoire partagée entre les threads => session stockée en mémoire

Frontal HTTP

requête HTTP

Stack Java NG

• Nouvelles stacks qui apparaissent– Netty : asynchronisme– Play! : plus de javax.servlet

Serveur d’applicationsJava

• Coût– Weblogic, Websphere : $$$$$$$$$$$$$$$$$– Jboss : $$$ (support)

• Dépendance des applications vis à visdu serveur d’application qui offre beaucoupde services

• Lourd– Développement– Déploiement – Run

• En as-t-on vraiment besoin ?– Même Gartner a dit non

Url

• www.octo.com/myApp

Plusieurs applications sur le même domaineAttention au référencement, aux url, aux

cookies

Difficile de faire myApp.octo.com

Application WebRuby

.rb

.erb

.css

.jpg

déploiement

code source

Stack ruby

Serveur d’application Ruby

Frontal HTTP Apache2, Nginx

Unicorn, Passenger, Thin

Rack (API + Implémentation)

Framework web Rails, Sinatra

Application

Frontal HTTP

Unicorn

Master Unicorn

Worker Unicorn 1

socketunix

Application

requête HTTP

Rack

Rôle du master : Démarrer et surveiller les workers Pas de mémoire partageé entre les workers Le load balancing entre les workers est assuré par la socket Unix

Process UNIX unicorn (C + Ruby)

Worker Unicorn 2 ApplicationRack

Worker Unicorn 3 ApplicationRack

Frontal HTTP

Mongrel

Mongrel 1 Applicationrequête HTTP

Rack

Mongrel 2 ApplicationRack

Mongrel 3 ApplicationRack

1 port TCP, 1 processus unix par worker Le frontal http assure le load balancing Pas de mémoire partagée entre les workers

port 1901

port 1902

port 1903

Apache 2Nginx

Module Passenger

Passenger

Worker 1 Application

requête HTTP

Rack

Worker 2 ApplicationRack

Worker 3 ApplicationRack

Passenger est intégré au frontal HTTP en tant que module Les workers sont des processus Unix Gestion dynamique des workers par Passenger (en fonction de la charge) Pas de mémoire partagé entre les workers

Sessions HTTP

• Rails : Plusieurs types de session store– Cookies (défaut)– FileSystem– Memcache– DB– …

Apache 2 Prefork

PHP

Apache 2 worker 1 Application

requête HTTP

PHP

Pas de mémoire partagé entre les workers Sessions stockés sur le disque

Apache 2 worker 2 ApplicationPHP

Apache 2 worker 3 ApplicationPHP

Serveur d’applicationsRuby

• Rôle : – Implémenter la couche HTTP <> Rack

• Est capable de lancer une application Rack

– Gérer le parallélisme• Points différenciant entre les implémentations– Stratégies de gestion du parallélisme– Facilitée d’installation / déploiement / configuration– Gestion des redéploiements

• Points communs– Pas de mémoire partagées entre les workers– Inefficace pour servir le contenu statique

Multi threaden Ruby

• Existe mais est peu utilisé• 1.8– Implémentation à ne pas utiliser

• 1.9– Meilleure implémentation– Toujours pas dans la culture Ruby

A tester : Run d’une application Rails en jRuby

jRuby

• Lenteur des commandes – rails, rake– Dues à l’instanciation de la JVM

• Pour faire un war– Quelques adaptations dans le Gemfile– warble• Le war contient les gems

• Déploiement sous tomcat ok– Quelques problèmes liés à Rails– Pas d’impression de vitesse

Url

• myApp.octo.com

Une application par domaineSSL compliqué à mettre en place

Difficile de faire www.octo.com/myApp

delayed_jobs

Base de données

Application web

Worker 1 Créer un job

Worker 2

Récupère le job

Stocke le résultat

Récupère le résultat

Application et workers : même code, même application Workers lancés séparéments Exemple

• Envoyer un mail• Interaction avec un service de paiement

• Les serveurs d’applications implémentent JMS– Rarement utilisé dans les

applications Web

• Les delayed_jobs sont souvent utilisés au cœur des applications Web– Pas forcément facile à

déployer en production– Très efficace pour les

performances

Batchs Web

• Stack standard– Enorme (et souvent cher)

• Stack lights ou NG– Pas chez nos clients …

• Plusieurs Webapp• Parallélisme par threads

• Mémoire partagées entre les threads

• Petit– Pas chez nos clients …

• 1 seul Webapp• Différentes stratégies de

parallélisme• Pas de mémoire partagée

Serveurd’applications

• Stack « veillissante » en évolution

• Stack ruby un peu moins lourde

ApplicationWeb

• Stack web relativement proche

GESTION DES DÉPENDANCES

DépendancesJava

• Outil : Maven <groupId>fr.octo.apogee</groupId> <artifactId>core</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>core</artifactId> <version>3.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies>

JVM

Serveur d’application

DépendancesJava

Application (war)

WEB-INF/lib

WEB-INF/classes

lib du serveur d’application

lib JDK

Création Utilisation

Bibliothèquesspécifiques

Développeur

Gestion de configuration

Intégrationcontinue

Nexus

Code la bibliothèque

Construit l’artefact

Stocke l’artefact

Développeur Déclare l’utilisation dela bibliothèque

Maven récupère laBibiothèque dans Nexus

Dépôt d’entrepriseProxy internet

Dépendances Ruby

• Outil : bundler & gem

• Gem– Repo local de gem– gem install rails

• Bundler– Liste les dépendances– Installe les dépendances

manquantes• bundle

Gemfile

gem 'rails', '3.1.0'

gem 'json'gem 'sass-rails’gem 'fastercsv'gem 'typus', '3.1.0.rc17'gem 'foreigner’gem 'cancan'

group :development do gem 'sqlite3' gem 'capistrano'end

Gems

• Utilisation courante de librairies en C– Exemple 1 : libxml pour nokogiri– Exemple 2 : libmysql pour mysql

• Conséquences– Besoin d’avoir gcc, make, automake …– Besoin d’avoir les headers

• aptitude install libmysql-dev

Pas très pratique pour le déploiement en production

Serveur d’application

Application

DépendancesRuby

*.rb

*.rb

Gem Repository

Gem A v 1.1

Gem B v 0.7

Gem C v 1.9

Création Utilisation

Bibliothèquesspécifiques

Développeur

Gestion de configuration

Code la bibliothèque Développeur Déclare l’utilisation dela bibliothèque

Bundler récupère labibliothèque dans legestionnaire de configuration

• Outil : Maven• Toutes les dépendances sont dans le

war• Conflit de classes (App / Serveur

d’app / JDK)

• Dépots d’entreprises– Nexus

• Outil : Gem + Bundler• Les dépendances sont dans le

repo local de gems• Peu de conflits• Dépendances sur gcc et les

headers de développements• Pas de dépôts d’entreprises

Gestion desdépendances

• Système de description des dépendances• Système de récupération des dépendances sur

Internet

DÉPLOIEMENT

Déploiement

.wardépôt dans un dossierTomcat, Jetty, Jboss

.warappel d’une API sur le serveur d’applicationJboss, Websphere

• Peut déployer sur un cluster• Est en général long

Pré requis serveur

• Un OS• Un JDK (packagé avec l’OS)• Un serveur d’application• Eventuellement un serveur web

Relativement simple

Déploiement

.rb

.erb

.css

.jpg

code source

dépôt dans un dossier

signaler au serveur d’application la

nouvelle version

Installation des gemsnécessaires

Déploiementavec Capistrano

app_directory

current

shared

releases

201112061223

201112061421

201112061526

symlink

Serveur d’application

Gestion de configuration

checkout

cap deploy1. Checkout du code2. Préparation du code3. Symlink4. Signal au serveur

d’applicationcap rollback

Capistrano

• Outil écrit en Ruby– Moteur de scripting qui exécute du shell– Apporte une structure de déploiement propre à

partir du gestionnaire de configuration• Gère le multi machine (via SSH)– Déployer sur 15 machines = déployer sur une

• Gère les différents types de machines– Configurer la base de données, memcache

ExempleSkillstar

cap deploy– Passe la plateforme en maintenance– Déploie l’appli sinatra sur les query server– Execute les scripts de migration de base de

données– Purge les caches– Mets à jour le CDN– Déploie l’appli rails sur les frontaux– Sort l’application de maintenance

Pré requis serveur

• Un OS• Ruby (packagé dans l’OS)• Git• Build-essentials (gcc, make …)• Des librairies en dev• RVM, pour installer un autre ruby• Un serveur web• Bundler (installé en gem)

Peut rapidement devenir complexeExemple : • rvm-shell default -c ‘RAILS_ENV=production bundle exec rake db:migrate’

• Installation de passenger qui recompile un module Nginx

Hot deploy

• Déploiement « Hot deploy » – 0 down time– On ne perds aucune requête client– Le client ne s’aperçoit de rien

Possible quand on ne touche pas au schéma de la base

Nécessaire pour le « continuous delivery »

Hot deploy

• Incompatible avec la notion de War• Solution : 2 serveurs, et on bascule

Frontal HTTP

Serveur d’app

Frontal HTTP

Serveur d’app

Load balancer

Hot deploy

• Natif– Passenger : touch tmp/restart.txt– Unicorn : kill –s USR2 pid

• Nginx– Mise à jour des binaires à chaud

Fonctionnalité implicite dans l’écosystème ruby

Hot deployUnicorn

$ pgrep -lf unicorn_rails12113 unicorn_rails master -c config/unicorn.rb -D12118 unicorn_rails worker[0] -c config/unicorn.rb -D12136 unicorn_rails worker[1] -c config/unicorn.rb -D12137 unicorn_rails worker[2] -c config/unicorn.rb -D

$ kill -s USR2 12113

$ pgrep -lf unicorn_rails12113 unicorn_rails master (old) -c config/unicorn.rb -D12118 unicorn_rails worker[0] -c config/unicorn.rb -D12136 unicorn_rails worker[1] -c config/unicorn.rb -D12137 unicorn_rails worker[2] -c config/unicorn.rb -D12239 /usr/bin/ruby1.8 /usr/bin/unicorn_rails -c config/unicorn.rb -D

$ pgrep -lf unicorn_rails12239 unicorn_rails master -c config/unicorn.rb -D12245 unicorn_rails worker[0] -c config/unicorn.rb -D12246 unicorn_rails worker[1] -c config/unicorn.rb -D

ConfigurationBase de données

• Soit dans un .properties dans le war

• Soit par une Datasource

Peut être complexe

• Un fichier yml dans « shared »

• Un symlink

Simple et efficace

Logs

• Gérer par le serveur d’application

• Configuration en général embarquée dans le war

Sujet maîtrisé

• Symlink vers un répertoire dans « shared »

• Mélange potentiel entre workers

Sujet qui peut devenir complexe

Déploiement

• Déploiement simple sur les stacks simple

• Se complexifie avec la complexité des serveur d’applications

• Pas de hot deploy• Déploiement multi

machine plus complexe

• Simple sur le papier, mais socle compliqué à initialiser

• heroku.com, engineyard.com

• Hot deploy natif• Déploiement multi

machine simple

SCALABILITÉ

Scalabilitémono machine

Frontal HTTP

Serveur d’app

Thre

ad 1

Thre

ad 2

Thre

ad 3

Shared memory

Base de données

• ~ 50 threads par serveurs d’application– En général ~20 de workers– Difficile de monter bien plus haut

• Le serveur d’application sert souvent le statique

• Mémoire en commun– Cache, notamment L2

• Un serveur d’application = 1 processus Unix– L’utilisation de toutes les ressources CPU et

RAM sur une grosse machine peut être difficile

Scalabilitémono machine

Frontal HTTP

Serveur d’app

Wor

ker 1

Wor

ker 2

Wor

ker 3

Base de données

Sess

ion

Stor

e

• Le serveur d’application ne sert pas le contenu statique

• Pas de mémoire partagé, mais « copy on write » entre les workers

• Pas d’utilisation de threads, la scalabilité repose sur l’augmentation du nombre de workers

• Application de fait stateless• Architecture nativement plus « distribuée »

• Mesures de performances plus facile à faire car pas de JVM qui masque tout

Scalabilitémulti machine

Frontal HTTP

Serveur d’app

Base de données

Frontal HTTP

Serveur d’app

Frontal HTTP

Serveur d’app

Load balancer

• Mise en place d’affinité de session• Mise en place de caches partagés

Base de données

Scalabilitémulti machine

Frontal HTTP

Serveur d’app

Frontal HTTP

Serveur d’app

Frontal HTTP

Serveur d’app

Load balancer

• Ne change pas grand chose par rapport à mono machine

• Fail over sur la partie application facile

Memcache

Scalabilité

• 1 seul processus (la JVM) doit utiliser toutes les ressources

• Cache communs à tous les workers

• Langage rapide

• La scalabilité est à implémenter au dessus de la stack– Souvent par un serveur

d’application gérant le clustering

• Utilisation des ressources par plusieurs processus

• Pas de caches communs natifs

• Langage « suffisamment » rapide

• Le besoin de scalabilité horizontal est pris en compte dans la stack

Optimisation

• Stack complexe, donc complexe à optimiser– JVM– Serveur d’application– Frameworks– Application

Gain en performances significatif en optimisant la stack sous l’application

• Stack plus simple

Les gains en performances sont recherchés sur l’application

SUPERVISION / OUTILLAGE

SupervisionOutillage

• Visual VM• JMX• Profiling• Debugging à distance• Memory analyzer• …

SupervisionOutillage

• cat, tail, ps, curl …Pas grand chose (ou compliqué)Mais ce n’est pas forcément une douleur– Plus simple– On utilise les outils jusqu’au bout

Outils Ruby

• Tendance observée :De plus en plus d’outils Infra en Ruby

• capistrano• god• puppet• chef

Ruby est de plus en plus utilisé en infra pure

CONCLUSION

Conclusion

• Le run Ruby – Est « Production Ready »

• mais pas super industrialisé• moins performant que Java

– Force une architecture prête à scaler dès le début• Le run Java– Repose sur la JVM qui reste un bijou technologique sans

équivalent– Est en train de muter pour sortir des « usines à gaz »

• Culture différente– Java : application de gestion– Ruby : Web