Frederic de Villamil


, , , , , , ,


Partagez sur Twitter Partagez sur Facebook Partagez sur Google Plus Partagez sur Linkedin Plus

Optimisez les performances de vos applications Ruby on Rails

Avec le passage de Google à son nouvel algorithme Caféine, la performance des sites web devient une problématique encore plus aiguë qu’elle pouvait l’être par le passé. Aux problématiques de confort de l’utilisateur, souvent laissée de côté au profit de l’esbroufe visuel vient s’ajouter celle du référencement, toujours plus vendeuse.
Le framework Ruby on Rails dispose d’un nombre intéressant d’options afin de vous permettre d’améliorer vos performances sans nécessiter de modifications en profondeur des applications existantes. Ces optimisations spécifiques au framework viennent s’ajouter aux recommandations prodiguées sur des sites comme le blog Performances Web, ou permettre leur réalisation. Parmi elles, nous allons plus particulièrement nous intéresser à :

  • Servir des fichiers statiques.
  • Créer un serveur d’assets.
  • Diminuer la quantité de fichiers servis.

Mettre en place un système de cache statique

La génération de pages dynamiques peut prendre beaucoup de temps, et être une grosse consommatrice de ressources serveur. Heureusement, Ruby on Rails supporte nativement la création de pages HTML statiques, qui seront ensuite servies par votre serveur web, sans qu’il soit besoin de faire appel au framework.

Dans chacun des contrôleurs que vous souhaitez voir cachés, ajoutez simplement la directive caches_page, suivie de la liste des actions à cacher.

<typo:code lang=’ruby’> caches_page :index, :show </typo:code>

Pour une utilisation plus fine de caches_page, je vous recommande également la lecture de Comprendre et améliorer le cache statique de vos applications Rails

Mise en place d’un serveur d’assets

Ruby On Rails propose en standard des options assez avancées de gestion des assets, et notamment des fichiers images, Javascript et CSS. Il est facile de mettre ces optimisations en place sur une application existante sans pour autant devoir réécrire plus de quelques lignes de code, ce qui est bien, voir top.

Pourquoi mettre en place des serveurs d’assets ?

  1. Ils vous permettront de pallier la limite des 2 téléchargements simultanés sur un même hôte sur IE6. Les versions suivantes font à peine mieux.
  2. Sur des applications à gros trafic, ils vous permettront de répartir la charge sur plusieurs machines.

Le code ci-dessous est tiré de la documentation de ActionView::Helpers::AssetTagHelper. Éditez le fichier de configuration de l’environnement de production, soit config/environments/production.rb.

Le plus simple est de définir un seul serveur d’assets :

<typo:code lang=”ruby”> ActionController::Base.asset_host = “assets.example.com” </typo:code>

Désormais, tous les assets appelés depuis les helpers Rails standards le seront depuis assets.example.com :

<typo:code lang=”ruby”> imagetag(‘toto.jpg’) # appelle http://assets.example.com/images/toto.jpg stylesheetlinktag(‘style’) # appellera http://assets.example.com/stylesheets/style.css javascriptinclude_tag(‘toto.js’) # appellera http://assets.example.com/javascripts/toto.js </typo:code>

Il est également possible de mettre en place une architecture un peu plus sophistiquée, avec de la répartition de charge ou de la répartition par type (ou les deux). Cependant, cette méthode n’est pas compatible avec la mise en place d’un cache statique.

Ici, vous allez choisir au hasard entre 4 serveurs d’assets, numérotés de 1 à 4 :

<typo:code lang=”ruby”> ActionController::Base.asset_host = Proc.new { |source|

"http://assets#{rand(4) + 1}.example.com"

} </typo:code>

Enfin, vous allez servir les images depuis une source, et les autres fichiers depuis une autre :

<typo:code lang=”ruby”> ActionController::Base.assethost = Proc.new { |source| if source.startswith?(‘/images’)

"http://images.example.com"

else

"http://assets.example.com"

end } </typo:code>

Diminuer la quantité de fichiers servis

Diminuer la quantité de fichiers servis fait partie des premières mesures à prendre quand on veut améliorer les performances de son site. Cela passe évidemment par la mise en place de sprites CSS, mais nous ne traiterons pas ce point car il ne relève pas directement de Ruby On Rails. Nous allons en revanche vois comment concaténer tous vos fichiers CSS d’une part, et Javascript d’autre part, afin de ne plus en servir qu’un de chaque. Là encore les helpers stylesheetlinktag et javascriptincludetag gèrent cela très bien grâce à l’option :cache.

Pour vos fichiers Javascript, vous avez le choix entre 2 syntaxes :

Appeler les fichiers à assembler nominativement.

<typo:code lang=”ruby”> javascriptincludetag ‘toto.js’, ‘tata.js’, ‘tutu.js’, :cache => true </typo:code>

Appeler tous les fichiers Javascript disponibles d’un coup

<typo:code lang=”ruby”> javascriptincludetag :all, :cache => true </typo:code>

Et même le faire récursivement (fear!) :

<typo:code lang=”ruby”> javascriptincludetag :all, :cache => true, :recursive: => true </typo:code>

Et ça marche aussi pour les fichiers CSS :

Appeler nominativement les fichiers CSS à inclure

<typo:code lang=”ruby”> stylesheetlinktag “toto.css”, “tata.css”, “tutu.css”, :cache => true </typo:code>

Appeler tous les fichiers CSS à inclure :

<typo:code lang=”ruby”> stylesheetlinktag :all, :cache => true </typo:code>

Et même récursivement :

<typo:code lang=”ruby”> stylesheetlinktag :all, :cache => true, :recursive => true </typo:code>

Elle n’est pas belle la vie ? Ah non, en fait, puisque toutes ces jolies méthodes ne réduisent pas la taille des fichiers avant de les envoyer, par exemple par obfuscation. Ça tombe bien, je ne suis personnellement pas super pour, ça a tendance à entraîner des erreurs. Votre serveur web doit en revanche envoyer les fichiers compressés, avec modgzip sous Apache 1.3 et moddeflate sous Apache 2.

Et voilà, c’est à peu près tout pour ce soir. J’espère que cette documentation vous aura été utile, au moins dans la mise en places des méthodes d’optimisation les plus évidentes, sans pour autant avoir à réinventer la roue, puisque votre framework favori le fait en standard, notamment grâce à quelques options mal connues de certains des helpers les plus utilisés. Comme quoi ça a du bon de lire le f$#@ manual de temps en temps.