<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
xmlns:media="http://search.yahoo.com/mrss/"
> <channel><title>Blog Xebia France &#187; Performance</title> <atom:link href="http://blog.xebia.fr/category/performance/feed/" rel="self" type="application/rss+xml" /><link>http://blog.xebia.fr</link> <description>J2EE, Agilité et SOA</description> <lastBuildDate>Wed, 08 Feb 2012 09:23:16 +0000</lastBuildDate> <language>fr</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=</generator> <copyright>CC BY-NC-ND 2.0 http://creativecommons.org/licenses/by-nc-nd/2.0/fr/</copyright> <managingEditor>blog-france@xebia.com (Xebia France)</managingEditor> <webMaster>blog-france@xebia.com (Xebia France)</webMaster> <ttl>1440</ttl> <image> <url>http://blog.xebia.fr/videos/xebia-podcast.png</url><title>Blog Xebia France</title><link>http://blog.xebia.fr</link> <width>144</width> <height>144</height> </image> <itunes:new-feed-url>http://blog.xebia.fr/feed/podcast/</itunes:new-feed-url> <itunes:subtitle>Les podcasts de Xebia France vous permettent de suivre l&#039;actualité autour de Java, de l&#039;agilité, des technologies Web et bien d&#039;autres. Xebia France est une entreprise spécialisée dans les technologies Java et JEE en environnement agi[...]</itunes:subtitle> <itunes:summary>Les podcasts de Xebia France vous permettent de suivre l&#039;actualité autour de Java, de l&#039;agilité, des technologies Web et bien d&#039;autres. Xebia France est une entreprise spécialisée dans les technologies Java et JEE en environnement agile.</itunes:summary> <itunes:keywords>Xebia, Java, JEE, SOA, Agile, Méthodes, Agiles</itunes:keywords> <itunes:category text="Technology" /> <itunes:category text="Technology"> <itunes:category text="Software How-To" /> </itunes:category> <itunes:category text="Technology"> <itunes:category text="Tech News" /> </itunes:category> <itunes:author>Xebia France</itunes:author> <itunes:owner> <itunes:name>Xebia France</itunes:name> <itunes:email>blog-france@xebia.com</itunes:email> </itunes:owner> <itunes:block>no</itunes:block> <itunes:explicit>no</itunes:explicit> <itunes:image href="http://blog.xebia.fr/videos/xebia-podcast.png" /> <item><title>Atelier performance avec Kirk Pepperdine</title><link>http://blog.xebia.fr/2012/01/26/atelier-performance-avec-kirk-pipperdine/</link> <comments>http://blog.xebia.fr/2012/01/26/atelier-performance-avec-kirk-pipperdine/#comments</comments> <pubDate>Thu, 26 Jan 2012 04:11:09 +0000</pubDate> <dc:creator>Xebia France</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[Tech Events]]></category> <category><![CDATA[java]]></category> <category><![CDATA[Performances]]></category> <category><![CDATA[vidéo]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=10423</guid> <description><![CDATA[Avec cette vidéo vous allez découvrir comment Kirk a procédé lors de cet atelier pour identifier les points d&#8217;amélioration d&#8217;un système et la manière de les résoudre. Tout cela sans préparation initiale ni code source : du live optimizing ! Écoutez également Kirk interviewé par Cyrille Le Clerc la veille de cet atelier. Tous les [...]]]></description> <content:encoded><![CDATA[<p>Avec cette vidéo vous allez découvrir comment Kirk a procédé lors de <a
href="http://blog.xebia.fr/2011/11/07/atelier-performance-avec-kirk-pepperdine" rel="nofollow">cet atelier</a> pour identifier les points d&#8217;amélioration d&#8217;un système et la manière de les résoudre. Tout cela sans préparation initiale ni code source : du <em>live optimizing</em> !<br
/> Écoutez également <a
href="http://blog.xebia.fr/2012/01/12/interview-de-kirk-pepperdine-sur-les-performances-en-java-par-cyrille-le-clerc" rel="nofollow">Kirk interviewé par Cyrille Le Clerc</a> la veille de cet atelier.</p><div
align="center"> <iframe
src="http://player.vimeo.com/video/35387464?title=0&amp;byline=0&amp;portrait=0&amp;color=800079" width="720" height="405" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe></div><hr/> <strong>Tous les podcasts Xebia France :</strong></p><ul><li><a
href="itpc://blog.xebia.fr/feed/podcast/" title="Subscribe to the Podcast Feed with iTunes"><img
src="http://blog.xebia.fr/wp-content/plugins/podpress/images/itunes.png" class="podpress_feed_buttons" alt="Subscribe with iTunes"></a></li><li><a
href="http://blog.xebia.fr/feed/podcast/" title="Les podcasts de Xebia France vous permettent de suivre l'actualité autour de Java, de l'agilité, des technologies Web et bien d'autres. Xebia France est une entreprise spécialisée dans les technologies Java et JEE en environnement agile."><img
src="http://blog.xebia.fr/wp-content/plugins/podpress/images/feed_button-rss-podcast.png" class="podpress_feed_buttons" alt="Xebia France Podcast Feed"></a></li></ul><div
class="shr-publisher-10423"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2012%2F01%2F26%2Fatelier-performance-avec-kirk-pipperdine%2F' data-shr_title='Atelier+performance+avec+Kirk+Pepperdine'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2012%2F01%2F26%2Fatelier-performance-avec-kirk-pipperdine%2F' data-shr_title='Atelier+performance+avec+Kirk+Pepperdine'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2012/01/26/atelier-performance-avec-kirk-pipperdine/feed/</wfw:commentRss> <slash:comments>2</slash:comments> <enclosure
url="http://xebia-video.s3-website-eu-west-1.amazonaws.com/2012-01-pepperdine-performance.mov" length="2147483647" type="video/quicktime" /> <itunes:duration>0:55:14</itunes:duration> <itunes:subtitle>Avec cette vidéo vous allez découvrir comment Kirk a procédé lors de cet atelier pour identifier les points d&#8217;amélioration d&#8217;un système et la manière de les résoudre. Tout cela sans préparation initiale ni code source : du live optimizin[...]</itunes:subtitle> <itunes:summary>Avec cette vidéo vous allez découvrir comment Kirk a procédé lors de cet atelier pour identifier les points d&#8217;amélioration d&#8217;un système et la manière de les résoudre. Tout cela sans préparation initiale ni code source : du live optimizing !
Écoutez également Kirk interviewé par Cyrille Le Clerc la veille de cet atelier.
Tous les podcasts Xebia France : </itunes:summary> <itunes:keywords>Performance</itunes:keywords> <itunes:author>Xebia France</itunes:author> <itunes:explicit>no</itunes:explicit> <itunes:block>no</itunes:block> </item> <item><title>Interview de Kirk Pepperdine sur les performances en Java par Cyrille Le Clerc</title><link>http://blog.xebia.fr/2012/01/12/interview-de-kirk-pepperdine-sur-les-performances-en-java-par-cyrille-le-clerc/</link> <comments>http://blog.xebia.fr/2012/01/12/interview-de-kirk-pepperdine-sur-les-performances-en-java-par-cyrille-le-clerc/#comments</comments> <pubDate>Thu, 12 Jan 2012 07:49:47 +0000</pubDate> <dc:creator>Xebia France</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[Tech Events]]></category> <category><![CDATA[interview]]></category> <category><![CDATA[java]]></category> <category><![CDATA[Performances]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=10255</guid> <description><![CDATA[Cyrille Le Clerc a profité du passage de Kirk Pepperdine à Paris pour l&#8217;interviewer sur les performances en Java ; au programme de ces discussions : Comment troubleshooter des problèmes de performances : les points d&#8217;entrées de l&#8217;investigation, Nouveaux langages sur la JVM : Scala, Clojure, &#8230; Cloud computing et virtualisation, JVM et appliances Java [...]]]></description> <content:encoded><![CDATA[<p><span
style="float: right"><img
src="http://blog.xebia.fr/wp-content/uploads/2012/01/pepperdine-leclerc.png" style="border: 0px solid black; margin: 1em 1em 1em 1em;" /></span><br
/> <a
href="http://blog.xebia.fr/author/cleclerc/" rel="nofollow">Cyrille Le Clerc</a> a profité du passage de <a
href="http://kirk.blog-city.com/" rel="nofollow">Kirk Pepperdine</a> à Paris pour l&#8217;interviewer sur les performances en Java ; au programme de ces discussions :</p><ul><li>Comment <em>troubleshooter</em> des problèmes de performances : les points d&#8217;entrées de l&#8217;investigation,</li><li>Nouveaux langages sur la JVM : Scala, Clojure, &#8230;</li><li>Cloud computing et virtualisation,</li><li>JVM et <em>appliances</em> Java : Hotspot, jRockit, IBM J9, Azul, ExaLogic, &#8230;</li><li>Support des <em>large heaps</em> : G1, Direct Memory, &#8230;</li><li>&#8230; et quelques recommandations de programmation en Java.</li></ul><p>Bonne écoute !</p><p></p><div
id='kirk-pepperdine-java-performances-cyrille-le-clerc'></div><p><script type="text/javascript">jwplayer('kirk-pepperdine-java-performances-cyrille-le-clerc').setup({
    	flashplayer: '/videos/player.swf',
	    'id': 'playerID',
    	'width': '560',
	    'height': '24',
	    'file': '/videos/kirk-pepperdine-java-performances-cyrille-le-clerc.mp3',
	    'controlbar': 'bottom'
	});</script></p><hr/> <strong>Tous les podcasts Xebia France :</strong></p><ul><li><a
href="itpc://blog.xebia.fr/feed/podcast/" title="Subscribe to the Podcast Feed with iTunes"><img
src="http://blog.xebia.fr/wp-content/plugins/podpress/images/itunes.png" class="podpress_feed_buttons" alt="Subscribe with iTunes"></a></li><li><a
href="http://blog.xebia.fr/feed/podcast/" title="Les podcasts de Xebia France vous permettent de suivre l'actualité autour de Java, de l'agilité, des technologies Web et bien d'autres. Xebia France est une entreprise spécialisée dans les technologies Java et JEE en environnement agile."><img
src="http://blog.xebia.fr/wp-content/plugins/podpress/images/feed_button-rss-podcast.png" class="podpress_feed_buttons" alt="Xebia France Podcast Feed"></a></li></ul><div
class="shr-publisher-10255"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2012%2F01%2F12%2Finterview-de-kirk-pepperdine-sur-les-performances-en-java-par-cyrille-le-clerc%2F' data-shr_title='Interview+de+Kirk+Pepperdine+sur+les+performances+en+Java+par+Cyrille+Le+Clerc'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2012%2F01%2F12%2Finterview-de-kirk-pepperdine-sur-les-performances-en-java-par-cyrille-le-clerc%2F' data-shr_title='Interview+de+Kirk+Pepperdine+sur+les+performances+en+Java+par+Cyrille+Le+Clerc'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2012/01/12/interview-de-kirk-pepperdine-sur-les-performances-en-java-par-cyrille-le-clerc/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <enclosure
url="http://blog.xebia.fr/videos/kirk-pepperdine-java-performances-cyrille-le-clerc.mp3" length="34756986" type="audio/mpeg" /> <itunes:duration>0:36:12</itunes:duration> <itunes:subtitle> Cyrille Le Clerc a profité du passage de Kirk Pepperdine à Paris pour l&#8217;interviewer sur les performances en Java ; au programme de ces discussions :
Comment troubleshooter des problèmes de performances : les points d&#8217;entrées de l[...]</itunes:subtitle> <itunes:summary> Cyrille Le Clerc a profité du passage de Kirk Pepperdine à Paris pour l&#8217;interviewer sur les performances en Java ; au programme de ces discussions :
Comment troubleshooter des problèmes de performances : les points d&#8217;entrées de l&#8217;investigation,
Nouveaux langages sur la JVM : Scala, Clojure, &#8230;
Cloud computing et virtualisation,
JVM et appliances Java : Hotspot, jRockit, IBM J9, Azul, ExaLogic, &#8230;
Support des large heaps : G1, Direct Memory, &#8230;
&#8230; et quelques recommandations de programmation en Java.
Bonne écoute !
Tous les podcasts Xebia France : </itunes:summary> <itunes:keywords>Performance</itunes:keywords> <itunes:author>Xebia France</itunes:author> <itunes:explicit>no</itunes:explicit> <itunes:block>no</itunes:block> </item> <item><title>Devoxx &#8211; Performance comparison of Java Web frameworks</title><link>http://blog.xebia.fr/2011/11/18/devoxx-performance-comparison-of-java-web-frameworks/</link> <comments>http://blog.xebia.fr/2011/11/18/devoxx-performance-comparison-of-java-web-frameworks/#comments</comments> <pubDate>Fri, 18 Nov 2011 10:52:26 +0000</pubDate> <dc:creator>Nicolas Jozwiak</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[Devoxx]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=9257</guid> <description><![CDATA[Après une intervention controversée de Matt Raible à Devoxx 2010 concernant la comparaison de frameworks Web, cette année trois personnes ont choisi de remettre le couvert :  Stijn Van den Enden, Guy Veraghert et Ward Vijfeijken. Stijn débute la présentation en nous rassurant : leur recherche concerne une poignée de frameworks Web et est basée sur [...]]]></description> <content:encoded><![CDATA[<p><span
style="float: right"><img
src="http://blog.xebia.fr/wp-content/uploads/2011/11/webComparison1.jpg" height="280" width="340" style="margin: 1em 1em 1em 1em; border: 0px solid black" /></span></p><p>Après une <a
href="http://raibledesigns.com/rd/entry/my_comparing_jvm_web_frameworks" rel="nofollow">intervention controversée de Matt Raible à Devoxx 2010</a> concernant la comparaison de frameworks Web, cette année trois personnes ont choisi de remettre le couvert :  Stijn Van den Enden, Guy Veraghert et Ward Vijfeijken.</p><p>Stijn débute la présentation en nous rassurant : leur recherche concerne une poignée de frameworks Web et est basée sur la scalabilité. Pour lui cette dernière est une notion importante :</p><ul><li>Elle influe sur l’infrastructure</li><li>Elle assure une qualité de service</li><li>Elle a un coût non négligeable</li></ul><p>Stijn nous explique qu’ils ont pris le parti de baser leur expérience sur les frameworks Web suivants :</p><ul><li>GWT</li><li>JSF</li><li>Wicket</li><li>Spring MVC</li></ul><p>Il poursuit avec le type d’application qui les intéresse :</p><ul><li>Ecrans détaillés</li><li>Navigation de pages</li><li>Autocompletion</li><li>Ajax validation</li><li>Mise à jour du DOM</li></ul><p>Ensuite pour tester la scalabilité de ces frameworks, l’expérience a porté sur :</p><ul><li>Les temps de réponse</li><li>Think time (temps d’attente par un utilisateur avant de pouvoir effectuer une autre action)</li><li>Throughput (nombre de requêtes en succès par secondes)</li></ul><p>Concernant la plateforme, les tests ont été effectués sur Amazon Web Server avec un Tomcat et une base de donnée MySQL.</p><p>Avant de nous dévoiler les résultats, Stijn nous explique que pour les analyser son équipe s’est basée sur le modèle théorique de la <a
href="http://en.wikipedia.org/wiki/Little%27s_law" rel="nofollow">loi de Little</a> afin d’avoir une référence pour faire parler les données. En résumé, le principe est de trouver un optimum concernant les temps de réponse et le nombre de threads supportés.</p><p>Ayant collecté énormément de données (plus de 300 millions de mesures), l’équipe a mis en place une application Web permettant de tracer des graphiques basés sur un bon nombre de paramètres activables / désactivables (CPU data, Memory data, nombre d’utilisateurs, etc..)</p><p>Après toutes ces explications sur l’environnement de tests, les résultats tombent enfin :</p><p>GWT est le grand gagnant suivi de très près par Spring MVC. Un peu plus loin nous avons Vaadin et dans les plus mauvais élèves nous retrouvons dans l’ordre JSF/Wicket et MyFaces. L’équipe a choisi d’intégrer Vaadin et MyFaces car ils n’avaient pas beaucoup de modifications à apporter.</p><p><span
style="float: right"><img
src="http://blog.xebia.fr/wp-content/uploads/2011/11/webComparison3.jpg" height="280" width="330" style="margin: 1em 1em 1em 1em; border: 0px solid black" /></span></p><p>A ce stade de la présentation, l’équipe nous dévoile qu&#8217;elle a été plus loin : la réalisation de tests sur le rendu des navigateurs.</p><p>Leur principal problème était que JMeter ne permet pas ce genre de tests. Ward nous présente alors leur solution: des plugins sur les navigateurs (firebug + network, Chrome developpment tool, HTTPWatcher) permettent d’extraire les données. Il nous parle ensuite de l’outil <a
href="http://www.softwareishard.com/blog/har-viewer/" rel="nofollow">HAR Viewer</a> qui permet d’interpréter et analyser ces données exportées, et nous explique l&#8217;automatisation de ces processus avec <a
href="http://seleniumhq.org/" rel="nofollow">Selenium Web Server</a>.</p><p>Encore une fois les résultats tombent : Wicket est le gagnant suivi de JSF, GWT et Spring MVC.</p><p>Néanmoins, Ward nous explique que les résultats sont légèrement biaisés : HAR déclenche son analyse trop tôt pour GWT. En effet, ce dernier a besoin de télécharger les javascripts avant de pouvoir effectuer un rendu. Des solutions en cours de développement peuvent y remédier (W3C Navigation timing API et W3C Resource timing API), mais ne sont pas encore disponibles.</p><p>Ward finit par nous présenter rapidement l’outil <a
href="http://code.google.com/intl/fr/webtoolkit/speedtracer/" rel="nofollow">SpeedTracer</a>, capable d’analyser les points de contentions sur les navigateurs (disponible seulement sous Chrome).</p><p>A travers tous ces tests, nous voyons que l’équipe a réalisé un travail réfléchi : mise en place d’un bon environnement de test, modèle théorique d’analyse des données, etc…, rendant les résultats justifiés et pertinents. Nous pouvons cependant regretter qu’ils n’aient pas intégré d’autres frameworks Web.</p><p>L’équipe conclue par le palmarès des frameworks en terme de coût de scaling pour 10000 utilisateurs avec des temps de réponse moyen à 200 ms</p><p><span
style="display: block; text-align: center"><img
src="http://blog.xebia.fr/wp-content/uploads/2011/11/coutScale.jpg" height="280" width="350" style="border: 0px solid black" /></span></p><p>Le résultat final est GWT en premier, Spring MVC et JSF/Wicket.</p><p>Pour finir, Stijn ouvre le débat et pose la question suivant : c’est bien d’être rapide, mais le framework Web est-il vraiment le point de contention ? A méditer.</p><div
class="shr-publisher-9257"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F11%2F18%2Fdevoxx-performance-comparison-of-java-web-frameworks%2F' data-shr_title='Devoxx+-+Performance+comparison+of+Java+Web+frameworks'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F11%2F18%2Fdevoxx-performance-comparison-of-java-web-frameworks%2F' data-shr_title='Devoxx+-+Performance+comparison+of+Java+Web+frameworks'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2011/11/18/devoxx-performance-comparison-of-java-web-frameworks/feed/</wfw:commentRss> <slash:comments>5</slash:comments> </item> <item><title>Java NIO et Framework Web Haute performance</title><link>http://blog.xebia.fr/2011/11/09/java-nio-et-framework-web-haute-performance/</link> <comments>http://blog.xebia.fr/2011/11/09/java-nio-et-framework-web-haute-performance/#comments</comments> <pubDate>Wed, 09 Nov 2011 09:37:17 +0000</pubDate> <dc:creator>Séven Le Mesle</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[Apache Mina]]></category> <category><![CDATA[API]]></category> <category><![CDATA[async-http-client]]></category> <category><![CDATA[challenge OCTO]]></category> <category><![CDATA[Deft]]></category> <category><![CDATA[framework]]></category> <category><![CDATA[GlassFish]]></category> <category><![CDATA[Jackson]]></category> <category><![CDATA[Jetty]]></category> <category><![CDATA[Netty]]></category> <category><![CDATA[NIO]]></category> <category><![CDATA[Restlet]]></category> <category><![CDATA[Servlet 3.0]]></category> <category><![CDATA[Tomcat 7]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=9010</guid> <description><![CDATA[Comme nous l’avons déjà évoqué sur le blog, à l’occasion du challenge USI 2011, nous nous sommes intéressés à différents serveurs et framework web NIO en Java. Le principe était simple en mettant à plat la spécification du challenge, nous avons identifié quelques besoins techniques : Une solution pour le marshalling JSON Un serveur web [...]]]></description> <content:encoded><![CDATA[<p>Comme nous l’avons déjà évoqué sur le blog, à l’occasion du challenge USI 2011, nous nous sommes intéressés à différents serveurs et framework web NIO en Java. Le principe était simple en mettant à plat la spécification du challenge, nous avons identifié quelques besoins techniques :</p><ul><li>Une solution pour le marshalling JSON</li><li>Un serveur web NIO supportant le long polling</li><li>Une solution pour la persistence et le partage des données</li></ul><p>Notre démarche a été de réaliser des POCs implémentant la création des utilisateurs et le <em>long polling</em> pour retenir la meilleure solution. La solution devait être simple et rapide à implémenter, et tenir une charge conséquente en la testant à l’aide de <a
href="http://www.manpagez.com/man/8/ab/" rel="nofollow">ab</a> l’outil de benchmark Apache et de la librairie <a
href="https://github.com/sonatype/async-http-client" rel="nofollow">Async Http Client</a>. Pour le JSON, nous nous sommes tous rapidement mis d’accord sur l’utilisation de la librairie Jackson. Nous étions tous convaincus qu’il nous faudrait un serveur web NIO sans passer par la case Servlet. C’est à partir de là que notre tour d’horizon des API NIO en Java a commencé.</p><h3><a
name="JavaNIOetFrameworkWebHauteperformance-PourquoiNIO%3F"></a>Pourquoi NIO ?</h3><p>Revenons d’abord à l’essentiel, nous ne pouvons justifier notre choix sans expliquer ce qu’est cette API Java. Cette API existe depuis la version 1.4 du JDK et permet essentiellement de réaliser des traitements non-bloquants sur les entrées-sorties. <a
href="http://download.oracle.com/javase/1.4.2/docs/guide/nio/" rel="nofollow">NIO</a> est en fait l’acronyme de New IO, la nouvelle api java.nio vient en supplément de l’API java.io existante.<br
/> Prenons l’exemple d’une Socket en Java, par défaut les opérations de lecture et d’écriture sont bloquante. Le thread lançant une opération de lecture ou d’écriture sur Socket sera bloqué sur cet appel tant que l’opération ne sera pas terminée. Tant qu’il n’y aura rien à lire sur la socket ou qu’il n’y aura pas d’espace disponible pour écrire dessus, le thread sera bloqué. Il sera aussi débloqué en cas d’exception dû à un timeout par exemple.</p><p><span
style="display: block; text-align: center"><img
src="http://blog.xebia.fr/wp-content/uploads/2011/11/java-io-01.png" style="border: 0px solid black" /></span></p><p>Depuis java.nio, il est possible de réaliser ces appels sans avoir à attendre qu’il y ait de l’espace libre ou des données à lire sur la Socket. Pour éviter ce temps de bloquage, l’API fournit un système pour écouter les évènements sur les sockets il s’agit du Selector. On enregistre la ou les Sockets dans le selector en précisant si l’on veut lire et/ou écrire, et/ou accepter des connexions sur la socket. Sur chaque appel à select(), le sélecteur créera une liste des Channel pour lesquels une opération est prête à réaliser.  Bien sûr, le serveur devra toujours attendre qu’il y ait des opérations disponibles sur ses sockets clients, mais la grande différence est que le serveur attend une fois pour l’ensemble de ses clients au lieu d’attendre une fois par client.</p><p><span
style="display: block; text-align: center"><img
src="http://blog.xebia.fr/wp-content/uploads/2011/11/java-io-02.png" style="border: 0px solid black" /></span></p><p>Pendant que le thread de l’API historique java.io attend un client, un Thread utilisant java.nio pourra traiter d’autres clients. Pour traiter les requêtes en parallèle avec l’API java.io, il suffit de multiplier le nombre de Thread avec un thread par client, il n’y aura pas d’attente non plus. Malheureusement on ne peut pas multiplier indéfiniment les Threads sans impact sur l’espace mémoire. Dans le cadre du challenge, nous étions limités en mémoire et nous devions supporter le maximum possible de client concurrents. Avec son faible nombre de Threads (1 par CPU) et donc sa consommation de mémoire inférieur, NIO est rapidement devenu une évidence pour tous.<br
/> Pour ces même raisons, nous avions décidé d’éliminer les serveurs de Servlet. L’API Servlet est consommatrice par essence et apporte une quantité non négligeable de raffinements dont nous n’avions pas besoin. Depuis l’API Servlet 3.0, il est possible de réaliser des Servlets Asynchrone qui permettent de libérer le Thread d&#8217;exécution de la requête pour envoyer la réponse plus tard à partir d’un autre Thread. Par curiosité nous avons donc testés Tomcat 7 en Servlet asynchrone, avec de forts à priori.</p><h3><a
name="JavaNIOetFrameworkWebHauteperformance-Letest"></a>Le test</h3><p>Afin de départager les différentes API, nous avons réalisé une implémentation du service de création des utilisateurs qui les persistent dans une Map. Quelque soit le framework, le service de mapping du JSON et de persistance sont les mêmes. Ainsi, nous pouvions nous intéresser à notre seul problème: la performance du serveur HTTP.  Les tests ont été réalisés sur un macbook pro 2,4 Ghz core i5 sans optimisation de JVM. Les seules modifications réalisées sur le système sont:</p><ul><li>L’augmentation du nombre de port éphémères via  sysctl net.inet.ip.portrange.first</li><li>La réduction du maximum segment lifetime afin de réduire la durée de réservation des sockets en TIME_WAIT.<br
/> Ces configurations ont pour seule but de permettre à ab d’injecter une charge conséquente sans souffrir de timeout dûe à un nombre trop élevé de socket réservé.</li></ul><h3><a
name="JavaNIOetFrameworkWebHauteperformance-Tourd%E2%80%99horizondesimpl%C3%A9mentationsNIO"></a>Tour d’horizon des implémentations NIO</h3><h4><a
name="JavaNIOetFrameworkWebHauteperformance-Restlet"></a>Restlet</h4><p><a
href="http://www.restlet.org/" rel="nofollow">Restlet</a> est un framework REST qui embarque le serveur HTTP et permet de choisir parmi différentes implémentations de Mina par défaut à Jetty en passant par Grizzly et Netty.<br
/> Restlet, semblait donc parfaitement adapté à la réalisation du serveur REST tout en nous offrant la possibilité de choisir le serveur à utiliser. En ultime recours sachez tout de même qu’il est parfaitement possible d’embarquer Restlet dans un war.<br
/> Nous avons donc créé un POC pour le service de création des utilisateurs (1Million d’utilisateurs en moins d’une heure). Après quelques tests rapides, l’API est convaincante pour sa simplicité d’utilisation et sa rapidité de prise en main. Mais les performances ne sont pas à la hauteur de nos espérances. Nous étions bien sûr largement capables de créer le million d’utilisateur en moins d’une heure, mais le temps passé dans les API Restlet, Mina et Jetty était trop impactant. Nous avons testé ce POC avec Mina et Jetty sans nous intéresser aux autres solutions que nous souhaitions tester en direct. Pour la solution Jetty, ab indiquait en moyenne 5k requêtes par secondes pour un temps de traitement moyen de 11ms à la création des utilisateurs. Si cette performance est encourageante et s’avère la meilleure disponible toute implémentation de serveur confondue, il y a tout de même une consommation en mémoire importante et des points de synchronisation bloquants. Pour le test via Mina la solution par défaut, les tests de charge supportaient mal l’augmentation du nombre d’injecteurs qui cause une cascade de Timeout. D’autre part alors que Jetty se limite à 80 Threads, avec son implémentation Mina, Restlet crée rapidement des centaines de Threads et consomme beaucoup de mémoire. Retenez donc que l’implémentation Jetty NIO de Restlet est très performante et répondra à la majorité des besoins en informatique de gestion.</p><h4><a
name="JavaNIOetFrameworkWebHauteperformance-Tomcat7"></a>Tomcat 7</h4><p>Le développement de ces POCs était une bonne occasion pour tester Tomcat 7 et les Servlets 3.0. Nous avons donc implémenté notre service avec des Servlets déclarées par annotation et utilisant l’exécution asynchrone pour maximiser le nombre de connexions concurrentes supportées.<br
/> Notez que l’utilisation des Servlets asynchrones a un impact immédiat sur les performances du serveur. La version asynchrone de la solution supportait effectivement plus de connexions avec des temps de réponse à peu près similaires. Le simple fait de passer la Servlet en traitement asynchrone permet donc de gagner en performance. Malheureusement en examinant les ThreadDump, il était clair que Tomcat avait un gros impact sur les temps de réponse (files d’attente et autre point de synchro était omni-présent).<br
/> Une dernière remarque, les tests ont été réalisés en utilisant deux connecteurs HTTP différents : le standard et le NIO. La solution NIO était bien plus performante en terme de parallélisme, mais le connecteur souffrait alors d’une fuite de mémoire conséquente. Le connecteur NIO de Tomcat aurait pu être une bonne option, mais nous ne voulions pas partir sur une solution reposant d’emblée sur des API instables comme c’était le cas du connecteur. A priori le bug a été corrigé dans les versions suivantes de Tomcat. Notez aussi que Tomcat a une empreinte mémoire importante et implique l’utilisation quasi permanente du GC car la mémoire utilisée dans la heap augmente régulièrement.</p><h4><a
name="JavaNIOetFrameworkWebHauteperformance-Grizzly"></a>Grizzly</h4><p>Pour mémoire, Grizzly est l’API réseaux utilisée par GlassFish. La librairie fournie un serveur de Servlet et un framework de traitement réseau NIO, “haute performance”. Tant qu’à faire, c’est à la partie framework NIO que nous nous sommes intéressés.  Pour créer le serveur, il suffit d’utiliser <code>HttpServer.createSimpleServer()</code> auquel on ajoute ensuite des HttpRequestProcessor mappés par URL. Bien que très mal documentée, l’API est simple à mettre en place. Le problème vient plutôt du fine tuning car il est facile de changer le port d’écoute et d’activer le monitoring JMX, par contre la gestion des ThreadsPool s’avère bien plus complexe. Il n’existe pas dans Grizzly un moyen simple de spécifier son <code>ExecutorService</code>. Sur le scénario simple d’injection des utilisateurs, Grizzly crée rapidement plusieurs centaines de Threads et souffre de nombreux points de synchronisation. N’ayant pas beaucoup de temps à consommer dans cette phase de POC, nous avons rapidement éliminés Grizzly qui nécessitait d’emblé des optimisations et ne répondait pas aux besoins directement sorti de sa boite. En tests nous avons atteint une moyenne de 1500 req/s pour l’injection de 100k joueur dans une simple HashMap. Notez tout de même que Grizzly supporte différentes stratégies pour gérer les IO (<a
href="http://grizzly.java.net/nonav/docs/docbkx2.0/html/iostrategies.html" rel="nofollow">http://grizzly.java.net/nonav/docs/docbkx2.0/html/iostrategies.html</a>), par défaut il applique le WorkerThread qui consiste à déléguer le traitement des IO à un worker séparé. Nous n’avons pas testé d’autres stratégies que celle par défaut; cela aurait nécessité plus de temps que nous ne souhaitions en allouer au POC. En résumé, les tests sur grizzly se sont avérés décevants; avec plus de temps nous aurions sûrement amélioré ces performances.</p><h4><a
name="JavaNIOetFrameworkWebHauteperformance-Deft"></a>Deft</h4><p><a
href="http://incubator.apache.org/deft/" rel="nofollow">Deft</a> est une implémentation Java s’inspirant de <a
href="http://www.tornadoweb.org/" rel="nofollow">Tornado</a>, le serveur HTTP de facebook en python. Son principe est de créer une boucle infinie unique exécutant l’ensemble des évènements remontés par le Selector dans le même thread. Comme dans NodeJS, ce système permet de réaliser les traitements de façon évènementiel sans se soucier de la concurrence. Avec quelques tests sur un seul Thread, nous avons constaté des performances impressionnantes. En temps de réponse, en nombre de requêtes concurrentes, comme en consommation mémoire le serveur dépasse l’ensemble de ses concurrents sans aucune optimisation. Il y avait toutefois quelques bugs rédhibitoires dans l’API causant des erreurs graves à l’exécution de certains tests de charge. Le code étant simple, Séven a réalisé des corrections de bugs et implémenté un mode multi-thread permettant de lancer plusieurs boucles infinies pour tirer au mieux parti des CPU multi-coeurs. Sur le test d’injection de 100k joueurs, nous avons atteint entre 10 et 11k req/s pour une moyenne de 6ms de temps de réponse. Pour Deft, nous avons donc fait exception à la règle du temps consommé, n’étant jamais à l’abri d’une bonne surprise cela pouvait valoir le coups. Au final, l’API étant encore un peu trop instable et manquant de raffinement, comme la gestion des cookies ou le support de la compression gzip, ou encore une solution clé en main de longpolling, nous avons abandonné ce POC pourtant prometteur. Notez que, depuis la fin du challenge, le projet est rentré en incubation chez Apache avec pour but de fournir un serveur Java haute performance non J2EE. L’histoire continue pour Séven qui a rejoint l’équipe des commiters de ce nouveau projet Apache.</p><h4><a
name="JavaNIOetFrameworkWebHauteperformance-Netty"></a>Netty</h4><p><a
href="http://www.jboss.org/netty" rel="nofollow">Netty</a> est le framework NIO de JBoss, il permet de créer rapidement un serveur HTTP. Netty utilise deux ThreadPool, l’un pour écouter et accepter les connexions entrantes et l’autre pour traiter les échanges de données sur socket établies (Boss / Worker). Il définit ensuite une liste de Handler permettant de traiter les messages lus et d’écrire une réponse. Les handlers se comportent comme des filtres passant un événement portant un message, ils sont invoqués dans le sens de la lecture puis dans le sens de l’écriture vers le SocketChannel. La création d’un serveur HTTP nécessite donc de configurer les décodeurs dans le bon ordre mais l’exemple fournit dans la documentation permet de mettre le tout en œuvre en quelques minutes. Pour les habitués des documentations Jboss, notez que celle de Netty est riche et lisible : un bel effort pour ces experts du labyrinthe. Netty a l’avantage de supporter nativement le long-polling et de parfaitement gérer les envois de réponse en masse sur les sockets client. Sur le test d’injection des 100k utilisateurs, nous avons atteint les 9k req/s pour des temps de réponses de 6ms en moyenne. Pendant le test, Netty alloue un peu de mémoire supplémentaire mais se stabilise rapidement sans avoir d’activité GC. Comme vous pouvez le constater, cette solution supporte une charge légèrement inférieure mais apporte une stabilité accrue par rapport à Deft et surtout bénéficie d’optimisation pour le long-polling. La seule optimisation dont nous avons eu besoin par rapport au code de démonstration, fût l’utilisation d’un MemoryAwareThreadPool en lieu et place du CachedThreadPool qui causait un goulet d’étranglement. C’est donc la maturité de l’API, la simplicité d’usage et la performance de la solution qui ont fait la différence au final sur notre choix.</p><h3><a
name="JavaNIOetFrameworkWebHauteperformance-Conclusion"></a>Conclusion</h3><p>Pour conclure, ce tour d’horizon nous a permis finalement de découvrir qu’avec un peu d’optimisation, il est facile de faire des serveurs de hautes performance en reposant sur nos bons vieux serveurs J2EE comme Tomcat et Jetty. Les solutions NIO font surtout la différence sur l’application du long-polling, et les réponses groupées. Ainsi que sur la consommation mémoire et le nombre de Thread utilisés favorisant ainsi l’économie des FullGC et plus globalement du temps de traitement du garbage collector. NIO prend tout son sens pour le messaging et les serveurs de type événementiels. Parmi les API NIO non couvertes par nos tests, notez aussi l’existence de <a
href="http://www.simpleframework.org/" rel="nofollow">Simple</a> : un serveur web prometteur permettant d’héberger des application Jersey en JAX-RS et intégré dans Restlet. <br
/> Vous trouverez les sources des pocs sur le GitHub de Xebia: <a
href="https://github.com/xebia-france/NIO" rel="nofollow">https://github.com/xebia-france/NIO</a></p><div
class="shr-publisher-9010"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F11%2F09%2Fjava-nio-et-framework-web-haute-performance%2F' data-shr_title='Java+NIO+et+Framework+Web+Haute+performance'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F11%2F09%2Fjava-nio-et-framework-web-haute-performance%2F' data-shr_title='Java+NIO+et+Framework+Web+Haute+performance'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2011/11/09/java-nio-et-framework-web-haute-performance/feed/</wfw:commentRss> <slash:comments>8</slash:comments> </item> <item><title>Atelier Performance avec Kirk Pepperdine</title><link>http://blog.xebia.fr/2011/11/07/atelier-performance-avec-kirk-pepperdine/</link> <comments>http://blog.xebia.fr/2011/11/07/atelier-performance-avec-kirk-pepperdine/#comments</comments> <pubDate>Mon, 07 Nov 2011 09:13:25 +0000</pubDate> <dc:creator>Xebia France</dc:creator> <category><![CDATA[Performance]]></category> <category><![CDATA[Tech Events]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=8959</guid> <description><![CDATA[Votre site a-t-il les reins solides ? Qu&#8217;il s&#8217;agisse d&#8217;un site grand public, d&#8217;un intranet largement utilisé ou d&#8217;une application plus anecdotique, vous aurez toujours besoin de vous assurer qu&#8217;elle tient la route et qu&#8217;un seul utilisateur ou même deux ne risquent pas de mettre vos serveurs à genoux. Pour cet atelier, nous vous fournirons [...]]]></description> <content:encoded><![CDATA[<p><span
style="float: right"><img
src="http://blog.xebia.fr/wp-content/uploads/2009/11/kirk-pepperdine.jpg" style="border: 0px solid black; margin: 1em 1em 1em 1em;" /></span><br
/> Votre site a-t-il les reins solides ?<br
/> Qu&#8217;il s&#8217;agisse d&#8217;un site grand public, d&#8217;un intranet largement utilisé ou d&#8217;une application plus anecdotique, vous aurez toujours besoin de vous assurer qu&#8217;elle tient la route et qu&#8217;un seul utilisateur ou même deux ne risquent pas de mettre vos serveurs à genoux.</p><p>Pour cet atelier, nous vous fournirons une application Spring MVC consommant les WebServices d&#8217;une seconde application web à déployer sur vos machines. Vous aurez à votre disposition les scripts JMeter pour générer de la charge sur vos déploiements. Vous serez en compétition avec notre expert performance qui en parallèle vous exposera sa méthode et ses résultats. À chaque optimisation trouvée, Kirk pourra expliquer plus avant le problème et comment l&#8217;identifier, puis détaillera sa solution.</p><p>Nous terminerons l&#8217;atelier par une séance de questions/réponses avec Kirk. Puis, un buffet campagnard sera proposé, offrant à chacun le temps d&#8217;échanger sur le sujet et de diner bien sûr.</p><p>Cet atelier gratuit aura lieu le mercredi 7 Décembre à 19h00, l&#8217;inscription sera ouverte très prochainement sur <a
href="http://xfr-performance-kirk-peperdine.eventbrite.com" rel="nofollow">EventBrite</a> (le lundi 14 novembre à 9 heures).</p><div
class="shr-publisher-8959"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F11%2F07%2Fatelier-performance-avec-kirk-pepperdine%2F' data-shr_title='Atelier+Performance+avec+Kirk+Pepperdine'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F11%2F07%2Fatelier-performance-avec-kirk-pepperdine%2F' data-shr_title='Atelier+Performance+avec+Kirk+Pepperdine'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2011/11/07/atelier-performance-avec-kirk-pepperdine/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Présentation Java NIO 2 de la soirée Java 7</title><link>http://blog.xebia.fr/2011/07/30/presentation-java-nio-2-de-la-soiree-java-7/</link> <comments>http://blog.xebia.fr/2011/07/30/presentation-java-nio-2-de-la-soiree-java-7/#comments</comments> <pubDate>Sat, 30 Jul 2011 10:29:47 +0000</pubDate> <dc:creator>Séven Le Mesle</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[Fork-Join]]></category> <category><![CDATA[java7]]></category> <category><![CDATA[nio / io]]></category> <category><![CDATA[NIO2]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=8268</guid> <description><![CDATA[Xebia et Zenika s’étaient associés ce Jeudi 28 Juillet pour fêter la sortie de Java 7. La soirée fût l’occasion de présenter les nouveautés du JDK à travers deux présentations et une démonstration du Fork-Join. Nous tenons tout d’abord à remercier tous les participants pour cette belle soirée qui s’est d’ailleurs terminée tard dans la [...]]]></description> <content:encoded><![CDATA[<p>Xebia et Zenika s’étaient associés ce Jeudi 28 Juillet pour fêter la sortie de Java 7. La soirée fût l’occasion de présenter les nouveautés du JDK à travers deux présentations et une démonstration du Fork-Join. Nous tenons tout d’abord à remercier tous les participants pour cette belle soirée qui s’est d’ailleurs terminée tard dans la nuit ou tôt le matin selon le point de vue.<br
/> Voici pour celles et ceux qui n’étaient pas à la soirée où qui souhaiteraient en profiter encore une fois, les slides de notre présentation sur NIO 2.</p><p>Merci encore et à bientôt !</p><div
align="center"><div
style="width:425px" id="__ss_8727513"> <strong
style="display:block;margin:12px 0 4px"><a
href="http://www.slideshare.net/XebiaFrance/java-nio2" title="Java Nio2" target="_blank">Java Nio2</a></strong> <object
id="__sse8727513" width="425" height="355"><param
name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=nio2-110729145101-phpapp01&#038;stripped_title=java-nio2&#038;userName=XebiaFrance" /><param
name="allowFullScreen" value="true"/><param
name="allowScriptAccess" value="always"/><embed
name="__sse8727513" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=nio2-110729145101-phpapp01&#038;stripped_title=java-nio2&#038;userName=XebiaFrance" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div
style="padding:5px 0 12px"> View more <a
href="http://www.slideshare.net/" target="_blank">presentations</a> from <a
href="http://www.slideshare.net/XebiaFrance" target="_blank">Xebia France</a></div></p></div></div><div
class="shr-publisher-8268"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F07%2F30%2Fpresentation-java-nio-2-de-la-soiree-java-7%2F' data-shr_title='Pr%C3%A9sentation+Java+NIO+2+de+la+soir%C3%A9e+Java+7'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F07%2F30%2Fpresentation-java-nio-2-de-la-soiree-java-7%2F' data-shr_title='Pr%C3%A9sentation+Java+NIO+2+de+la+soir%C3%A9e+Java+7'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2011/07/30/presentation-java-nio-2-de-la-soiree-java-7/feed/</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>14 Avril &#8211; Soirée Monitoring Pragmatique d&#8217;Applications Java avec le Fondateur et CTO d&#8217;AppDynamics</title><link>http://blog.xebia.fr/2011/04/04/14-avril-soiree-monitoring-pragmatique-dapplications-java-avec-le-fondateur-et-cto-dappdynamics/</link> <comments>http://blog.xebia.fr/2011/04/04/14-avril-soiree-monitoring-pragmatique-dapplications-java-avec-le-fondateur-et-cto-dappdynamics/#comments</comments> <pubDate>Mon, 04 Apr 2011 11:48:30 +0000</pubDate> <dc:creator>Pablo Lopez</dc:creator> <category><![CDATA[Exploitation]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[AppDynamics]]></category> <category><![CDATA[java]]></category> <category><![CDATA[monitoring]]></category> <category><![CDATA[soirée]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=7362</guid> <description><![CDATA[Cyrille Le Clerc et Pablo Lopez ont le plaisir de vous inviter Jeudi 14 Avril à 19h00 pour une &#171;&#160;Soirée Monitoring d&#8217;Applications Java avec le Fondateur et CTO d&#8217;AppDynamics&#160;&#187; . Nous avons profité du passage en Europe de Jyoti Bansal pour organiser avec les équipes d&#8217;AppDynamics un événement autour du monitoring de la &#171;&#160;vraie vie&#160;&#187; [...]]]></description> <content:encoded><![CDATA[<p>Cyrille Le Clerc et Pablo Lopez ont le plaisir de vous inviter Jeudi 14 Avril à 19h00 pour une <strong>&laquo;&nbsp;Soirée Monitoring d&#8217;Applications Java avec le Fondateur et CTO d&#8217;<a
title="AppDynamics" href="http://www.appdynamics.com/">AppDynamics</a>&nbsp;&raquo; </strong>.</p><p>Nous avons profité du passage en Europe de Jyoti Bansal pour organiser avec les équipes d&#8217;AppDynamics un événement autour du monitoring de la &laquo;&nbsp;<em>vraie vie</em>&nbsp;&raquo; .</p><p>A l&#8217;heure où l&#8217;architecture des applications d&#8217;entreprise devient de plus en plus complexe et distribuée, l&#8217;outillage dans le domaine du monitoring et du troubleshooting est un élément clé du système d&#8217;information. Notre objectif est que <strong>chacun en retire des idées immédiatement applicables et se forge une vision des problématiques que les systèmes de monitoring gèrent aujourd&#8217;hui et traiteront demain</strong>.</p><p>Après avoir consulté des Dev et des Ops des secteurs Telcos, Finance, Retail et Voyage, nous avons établi un programme reprenant des cas de notre vie quotidienne illustrés dans une application transactionnelle de eCommerce &laquo;&nbsp;réaliste&nbsp;&raquo; (1) que nous avons déployée en cluster sur 5 serveurs Amazon EC2., que nous soumettrons à diverses déconvenues courantes.</p><p><u><strong>Programme</strong></u></p><ul><li>15 minutes de <strong>présentation de la nouvelle génération de systèmes de monitoring d&#8217;applications</strong> Java (AppDynamics, dynaTrace, JXInsight)</li><li>60 minutes de démonstration de <strong>cas concrets de monitoring</strong> :<ul><li>Installation et configuration : mise en place du monitoring, auto découverte, déclaration d&#8217;indicateurs applicatifs, ajout de nouveaux serveurs au cluster,</li><li>Mise en place de <strong>tableaux de bord pour les équipes d&#8217;exploitation mais aussi de marketing et de développement</strong>,</li><li><strong>Monitoring durant les situations de crise</strong> : tableaux de bord &laquo;&nbsp;sur mesure&nbsp;&raquo; temporaires pour le management, le marketing et les équipes de troubleshooting,</li><li><strong>Monitoring au service du marketing</strong> : nous simulerons la mise en place de la sécurisation <a
title="3-D Secure" href="http://fr.wikipedia.org/wiki/3-D_Secure">3-D Secure</a> des paiements carte bleue en mode <a
title="AB Testing" href="http://en.wikipedia.org/wiki/A/B_testing">A/B Testing</a>,</li></ul></li><li><strong>La place dans l&#8217;infrastructure</strong> du système de monitoring : synergies et chevauchement avec les serveurs d&#8217;application, les systèmes de gestion de logs, etc</li><li><strong>La vision de Jyoti Bansal</strong> sur les tendances du monitoring d&#8217;application, ce à quoi nous devons nous attendre</li><li><strong>Les internes des systèmes de monitoring</strong> de nouvelles génération :<ul><li>&laquo;&nbsp;java agent embarqué&nbsp;&raquo; versus &laquo;&nbsp;agent autonome&nbsp;&raquo; versus &laquo;&nbsp;sans agent&nbsp;&raquo;,</li><li>les tableaux de bords, comment faciliter leur développement et leur utilisation à l&#8217;heure des <a
title="widgets Open Social" href="http://en.wikipedia.org/wiki/OpenSocial">widgets Open Social</a> ?</li><li>scalabilité des systèmes de monitoring à l&#8217;heure où le nombre de serveurs s&#8217;envole.</li></ul></li><li><strong>Coktail avec Jyoti et son équipe.</strong></li></ul><p>N&#8217;hésitez pas à nous proposer des questions ou des cas d&#8217;utilisation que nous ajouterons à nos préparations (cleclerc@xebia.fr et plopez@xebia.fr).</p><p><strong><u>Bio</u></strong></p><p><strong><a
title="Jyoti Bansal" href="http://www.linkedin.com/in/jyotibansal">Jyoti Bansal</a></strong> est fondateur, CEO et CTO d&#8217;AppDynamics. Il a auparavant été <em>Principal Architect</em> de Wily Introscope.</p><p><strong><a
title="AppDynamics" href="http://www.appdynamics.com/">AppDynamics</a></strong> a été fondé en 2008. Cette solution de monitoring est utilisée par des clients de la génération Internet aux infrastructures avant-gardistes comme NetFlix (1700 JVM sur Amazon EC2) mais aussi des clients plus traditionnels comme l&#8217;opérateur télécoms Swisscom, l&#8217;assureur Provinzial Insurance ou l&#8217;agence de voyage <a
title="Pricelinecom" href="http://www.priceline.com/">Priceline.com</a>.</p><p><strong><u>Organisation de la soirée</u></strong></p><p>La soirée se déroulera dans les locaux de Xebia au 156, boulevard Haussmann, 75008 Paris, à partir de 19h00.<br
/> Les inscriptions peuvent se faire :</p><ul><li>Par mail : <a
title="infoxebiatrainingfr" href="mailto:info@xebia-training.fr">info@xebia-training.fr</a></li><li>Par téléphone : 01.53.89.99.93</li></ul><p>(1) Nous avons retenu Spring Travel enrichie par les <a
title="Spring Payment Services" href="http://www.springsource.org/spring-payment">Spring Payment Services</a> et une brique &laquo;&nbsp;Anti Fraude&nbsp;&raquo; pour montrer les appels inter applications java. Le code source est disponible sous licence Apache <a
title="ici" href="http://xebia-france.googlecode.com/svn/training/production-ready-application/trunk/">ici</a> .</p><div
class="shr-publisher-7362"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F04%2F04%2F14-avril-soiree-monitoring-pragmatique-dapplications-java-avec-le-fondateur-et-cto-dappdynamics%2F' data-shr_title='14+Avril+-+Soir%C3%A9e+Monitoring+Pragmatique+d%27Applications+Java+avec+le+Fondateur+et+CTO+d%27AppDynamics'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F04%2F04%2F14-avril-soiree-monitoring-pragmatique-dapplications-java-avec-le-fondateur-et-cto-dappdynamics%2F' data-shr_title='14+Avril+-+Soir%C3%A9e+Monitoring+Pragmatique+d%27Applications+Java+avec+le+Fondateur+et+CTO+d%27AppDynamics'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2011/04/04/14-avril-soiree-monitoring-pragmatique-dapplications-java-avec-le-fondateur-et-cto-dappdynamics/feed/</wfw:commentRss> <slash:comments>30</slash:comments> </item> <item><title>Performance &#8211; Maîtriser son framework de test, The Grinder</title><link>http://blog.xebia.fr/2011/03/31/performance-maitriser-son-framework-de-test-the-grinder/</link> <comments>http://blog.xebia.fr/2011/03/31/performance-maitriser-son-framework-de-test-the-grinder/#comments</comments> <pubDate>Thu, 31 Mar 2011 12:28:28 +0000</pubDate> <dc:creator>Issam El Fatmi</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[Tests]]></category> <category><![CDATA[Performances]]></category> <category><![CDATA[The Grinder]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=7340</guid> <description><![CDATA[La performance a été souvent considérée comme étant le parent pauvre des applications. Afin de combler ce défaut et de détecter les éventuels points de faiblesse des applications, plusieurs outils propriétaires et open source ont vu le jour sur le marché: Compuware/Qaload, LoadRunner, OpenSTA, JMeter, etc, et notamment The Grinder. L’adoption de ce dernier fut [...]]]></description> <content:encoded><![CDATA[<p>La performance a été souvent considérée comme étant le parent pauvre des applications. Afin de combler ce défaut et de détecter les éventuels points de faiblesse des applications, plusieurs outils propriétaires et open source ont vu le jour sur le marché: Compuware/Qaload, LoadRunner, OpenSTA, JMeter, etc, et notamment <strong>The Grinder</strong>. L’adoption de ce dernier fut moins évidente que celle de son homologue côté Apache, du fait de l’absence de support et d’une interface GUI pour la définition, la configuration et le paramétrage des scripts ; ce manque de l’aspect « cliquodrome » a fait croire aux utilisateurs que l’outil est à mettre uniquement dans les mains d’un développeur python, et a également conduit à en dissimuler les talents.<br
/> Le but de cet article est de donner un ensemble de guidelines pour faire un meilleur usage de l’outil.</p><h3><a
name="LeframeworkTheGrinder"></a>Le framework The Grinder</h3><h4><a
name="CestquoiTheGrinder"></a>C&#8217;est quoi The Grinder ?</h4><p><a
title="The Grinder" href="http://grinder.sourceforge.net/">The Grinder</a> est un framework de test de charge « Jython-based scripting » écrit en Java. Il est open source (sous licence BSD) et  hébergé chez sourceForge.</p><p>Il permet de tester:</p><ul><li>Les serveurs web en mode HTTP /HTTPS.</li><li>Tout ce qui vit dans un serveur d’application (Web service SOAP/REST, EJB, JMS,…)</li><li>Les bases de données avec JDBC.</li><li>Les servers FTP, POP3, SMTP, LDAP.</li></ul><p>The Grinder s&#8217;exécute sur une plateforme supportant une version Java 1.4 ou supérieur.</p><p>Il peut être utilisé à des fins telles que :</p><ul><li>Test fonctionnel : contrôler le rendu de l’application par rapport au résultat attendu.</li><li>Test de charge : vérifier que l’application peut supporter une charge donnée.</li><li>Test de capacité : connaître la charge maximale supportée par l’application avant l’apparition d’erreurs</li><li>Test de stress : vérifier la stabilité de l’application.</li></ul><h4><a
name="Historique"></a>Historique</h4><p>The Grinder, « Le moulin », a été initialement développé pour les besoins du livre <a
title="J2EE Performance Testing with BEA WebLogic Server" href="http://grinder.sourceforge.net/links.html#book">J2EE Performance Testing with BEA WebLogic Server</a> par Paco Gómez et Peter Zadrozny.</p><p>Par la suite, Philip Aston a pris possession du code et l’a retravaillé pour en créer The Grinder 2.</p><p>C’est en Juillet 2003 que la première édition du livre fut publiée par Peter, Philippe et Ted Osborne, faisant ainsi un usage intensif de l’outil à sa deuxième version (The Grinder 2).</p><p>Peu après, Philip Aston commence à travailler sur The Grinder 3. Cette version offre de nombreuses nouvelles fonctionnalités, la plus importante est le Scripting Jython.</p><p><strong>Environnement de développement</strong></p><ul><li>Eclipse 3.6.</li><li>Apatana 3/Pydev : plugin eclipse pour le développement de projets python :<ul><li>Update Site : <a
title="httpdownloadaptanacomstudio3plugininstall" href="http://download.aptana.com/studio3/plugin/install">http://download.aptana.com/studio3/plugin/install</a></li></ul></li><li>Grinder Stone : plugin eclipse pour exécuter les scripts grinder. Il permet également de lancer des sessions de debugging.<ul><li>Update Site : <a
title="httpgrinderstonegooglecodecomsvnupdatesitexml" href="http://grinderstone.googlecode.com/svn/update/site.xml">http://grinderstone.googlecode.com/svn/update/site.xml</a></li></ul></li><li>Jython 2.2.1</li><li>Grinder 3.4</li></ul><h3><a
name="ArchitectureConceptiondesScrip"></a>Architecture &amp; Conception des Scripts</h3><h4><a
name="Architecture"></a>Architecture</h4><p>Il est important de comprendre l’architecture du framework,  ses différents composants et son mode fonctionnement.</p><p>Afin d’illustrer ce propos, je vous propose les deux schémas ci-dessous ;  l’un qui fait apparaitre les composants de base d’une plateforme d’injection d’un point de vue conceptuel, et l’autre illustrant l’architecture et les terminologies spécifiques à The Grinder.</p><p><span
style="text-decoration: underline;">Design View</span></p><div
style="text-align: center;"><a
href="http://blog.xebia.fr/wp-content/uploads/2011/03/Architecture.png"><img
class="alignnone size-medium wp-image-7346" title="Architecture" src="http://blog.xebia.fr/wp-content/uploads/2011/03/Architecture-300x173.png" alt="Architecture" width="300" height="173" /></a></div><p><span
style="text-decoration: underline;">The Grinder View</span></p><div
style="text-align: center;"><a
href="http://blog.xebia.fr/wp-content/uploads/2011/03/Architecture2.png"><img
class="alignnone size-medium wp-image-7345" title="Architecture2" src="http://blog.xebia.fr/wp-content/uploads/2011/03/Architecture2-300x165.png" alt="Architecture2" width="300" height="165" /></a></div><ul><li>La console contrôle les workers (les injecteurs) par le biais des agents et se charge d’agréger les résultats de test de l’ensemble des injecteurs de tous les agents.</li><li>Les agents sont en charge de piloter un ou plusieurs worker (généralement une instance « agent » est créé par JVM).</li><li>Les workers (grinder.processes) permettent d’injecter la charge au système à tester en démarrant le nombre de thread spécifié par la clé « grinder.threads » (les utilisateurs virtuels) et remontent les statistiques à la console. Chaque thread ainsi créé, exécute le script de test « grinder.runs » fois.</li></ul><h4><a
name="Conceptiondesscriptsetdesscnar"></a>Conception des scripts et des scénarios</h4><p>Le diagramme ci-dessous permet d’illustrer la séquence d’exécution d’un script grinder (gérée par le framework) couplée avec celle d’un scénario composé de deux tâches (gérée par le développeur) :</p><div
style="text-align: center;"><a
href="http://blog.xebia.fr/wp-content/uploads/2011/03/DiargrammeSéquence.png"><img
class="alignnone size-medium wp-image-7344" title="DiargrammeSéquence" src="http://blog.xebia.fr/wp-content/uploads/2011/03/DiargrammeSéquence-261x300.png" alt="DiargrammeSéquence" width="261" height="300" /></a></div><p>Généralement les scénarios fonctionnels à dérouler se différencient  en bout de chaîne, ou plus simplement dit, partagent un certain  nombre de transactions (Tâches) ; Ce qui fait apparaître le besoin de décomposer vos scénarios en un ensemble de tâches réutilisables.</p><p>Le lien entre deux tâches successives (récupérer l’output d’une tâche pour le faire passer en input de la tâche suivante) est réalisé par la requête suivante:</p><pre class="brush: python; title: ; notranslate">
HTTPPluginControl.getHTTPUtilities().getLastResponse()
</pre><p>Un scénario est donc défini par la succession d’un ensemble de tâches. Il encapsule la logique d’exécution de ses tâches (Scenario.run()).</p><p>Un « ScenarioAScript » permet la création et l’initialisation d’un « Scenario » composé de deux tâches « Task1 » et « Task2 ». Il est également responsable de la gestion de la rampe pour son scénario se traduisant généralement par une attente d’une durée égale au « pacingTime » (le temps d’attente entre le lancement de la première exécution de deux Threads successifs).</p><p>Un « Tir » constitue le script d’entrée pour The Grinder, il joue le rôle d’un orchestrateur et permet de répartir les threads sur l’ensemble des scénarios (affectation Thread / Scenario<strong>X</strong>Script) selon la configuration souhaitée.</p><p>L’exemple ci-dessous permet de répartir les threads sur 3 scénarios avec les proportions suivantes : le  Scenario<strong>A</strong>Script 50%, le Scenario<strong>B</strong>Script 25 % et le Scenario<strong>C</strong>Script 25 %</p><pre class="brush: python; title: ; notranslate">
from net.grinder.script.Grinder import grinder
scripts = [&quot;ScenarioAScript&quot;, &quot;ScenarioBScript&quot;, &quot;ScenarioCScript&quot;]
# Ensure modules are initialised in the process thread.
for script in scripts: exec(&quot;import %s&quot; % script)
def createTestRunner(script):
    exec(&quot;x = %s.TestRunner()&quot; % script)
    return x
class TestRunner:
    def __init__(self):
        tid = grinder.threadNumber
        if tid % 4 == 2:
            self.testRunner = createTestRunner(scripts[1])
        elif tid % 4 == 3:
            self.testRunner = createTestRunner(scripts[2])
        else:
            self.testRunner = createTestRunner(scripts[0])
    # This method is called for every run.
    def __call__(self):
        self.testRunner()
</pre><h3><a
name="Cequilfautsavoir"></a>Ce qu&#8217;il faut savoir</h3><h4><a
name="Rinitialisationdescookiesaulan"></a>Réinitialisation des cookies au lancement de chaque run</h4><p>Il faut savoir qu’à chaque run, The Grinder effectue un « cookie-reset » ; ce qui pourrait être très embêtant dans le cas où votre démarche de test s’inscrit dans la logique suivante:</p><ul><li>S’authentifier (création de la session, initialisation des cookies)</li><li>Boucler sur le scénario fonctionnel n fois</li><li>Se déconnecter</li></ul><p>Pour pallier ce problème, la solution la plus simple consiste à récupérer l’ensemble des cookies initialisés au démarrage de la session lors du premier run et les injecter par la suite dans les runs qui suivent comme suit :</p><pre class="brush: python; title: ; notranslate">
# récupérer l’objet HTTPClientContext pour le thread en cours au premier run.
threadContext = HTTPPluginControl.getThreadHTTPClientContext()
#récupération de l’ensemble des cookies au premier run
cookies=CookieModule.listAllCookies(threadContext)
      # récupérer l’objet HTTPClientContext pour le thread en cours.
      threadContext = HTTPPluginControl.getThreadHTTPClientContext()
      # Injection des cookies dans le header http du thread en cours
      for cookie in cookies:
          CookieModule.addCookie(cookie, threadContext)
</pre><p>Une deuxième solution est envisageable ; Il s’agit de désactiver la gestion automatique des cookies :</p><pre class="brush: python; title: ; notranslate">
HTTPPluginControl.getConnectionDefaults().useCookies = 0
</pre><p>et de créer son propre « handler » de cookie :</p><pre class="brush: python; title: ; notranslate">
# un « implements » à la python de l’interface «CookiePolicyHandler»
class MyCookiePolicyHandler(CookiePolicyHandler):
    # implement your own cookie acceptance policy.
    def acceptCookie(self, cookie, request, response):
        # traitement souhaité
        return 1
    # control the sending of cookies according to the matching rules
    # for the path, domain, protocol, etc
    def sendCookie(self, cookie, request):
        # traitement souhaité
        return 1
</pre><p>Par la suite, quelque part dans vos scripts, vous devrez faire un « set » du custom-handler :</p><pre class="brush: python; title: ; notranslate">
CookieModule.setCookiePolicyHandler(MyCookiePolicyHandler())
</pre><h4><a
name="HttpGETnonimplicitedesressourc"></a>Http/GET non implicite des ressources statiques</h4><p>Les requêtes http exécutées par le framework ne permettent pas de récupérer systématiquement les ressources statiques (cacheables par défaut) liées à la page demandée, comme les fichiers de type *.css, *.jpeg, *.gif, *.jar,… Il faut donc penser à les récupérer explicitement (par un http/GET du fichier en question) dans le cas où vous jugerez que cela pourrait avoir un impact sur les résultats de test.</p><h4><a
name="Gestiondesnbsprunsnbsp"></a>Gestion des « runs »</h4><p>A un certain moment, lors du développent de vos scripts,  vous auriez été tentés de gérer le nombre d’exécutions (grinder.runs) par vous-mêmes afin de contourner certains problèmes, notamment celui du cookie-reset précédemment évoqué. Je comprendrais que vous eussiez été plus à l&#8217;aise avec un « loop » et des « if » pour implémenter toute la logique d’exécution souhaitée, mais vous auriez sans doute constaté que les temps de réponse augmentaient d’une manière aberrante et proportionnelle au nombre de VUs (grinder.threads) ; ce qui est certainement lié à la contention des ressources et des threads dans vos « loop ». Je voulais donc en venir à la règle suivante: <strong>« Déléguer au framework ce qu’il a à faire reste un principe fondamental de son utilisation à ne pas négliger ». </strong></p><h4><a
name="Externalisationetcentralisatio"></a>Externalisation et centralisation de la configuration au niveau de grinder.properties</h4><p>Mettre toute la configuration de vos scripts dans le fichier grinder.properties vous permettra de regrouper l’ensemble des paramètres d’une manière centralisée: «  un seul fichier à maintenir ». Vous disposez nativement de la méthode «  grinder.getProperties ()«clé» pour récupérer les valeurs des différentes clés (pas besoin d’une classe utilitaire avec un java.util.Properties.load()).</p><h4><a
name="Gestiondesexceptions"></a>Gestion des exceptions</h4><p>N’hésitez pas à renforcer vos tests par des blocs de try / catch afin de passer le test précédemment exécuté ou encore celui qui est en cours d’exécution en « fail ».</p><p>Il faudra également distinguer les erreurs techniques liées au traitement de la requête par le serveur (serveur injoignable, http code = ! 200,…) des erreurs fonctionnelles liées à la logique du déroulement du scénario (jeu de données invalide, des inputs introuvables, rendu de la page incohérent,…).</p><p>Ci-dessous une manière de faire:</p><pre class="brush: python; title: ; notranslate">
import sys, traceback
request = Test(1, &quot;Basic request&quot;).wrap(HTTPRequest(url = &quot;http://localhost:7001&quot;))
     try:
        result = request.GET(&quot;index.html&quot;)
     except:
        # mark the test as a failure
        grinder.statistics.forLastTest.success = 0
        # tracer l’erreur d’origine:
        grinder.getLogger().error(&quot;Unexpected error: %s: %s: %s&quot; % (sys.exc_info()[0], sys.exc_info()[1], traceback.print_exc()))
        # throw new ExceptionTechnique
        raise ExceptionTechnique(« message d’erreur »)
     # Si le traitement dans le bloc try est exécuté
     # correctement, on vérifie que le status du dernier test est
     # OK, et que le code retour http == 200
     else:
        # récupérer l’objet Statistique pour le dernier test
        statisticsForTest = grinder.statistics.forLastTest
        # Si le test s’est terminé avec succès  et
        # http reponse code == 200
        if statisticsForTest.success and
           statisticsForTest.getLong(&quot;httpplugin.responseStatus&quot;)
           == 200:
            try:
               Dérouler votre checkList sur le rendu attendu
            except:
               # mark the test as a failure
               grinder.statistics.forLastTest.success = 0
               # tracer l’erreur d’origine:
               grinder.getLogger().error(&quot;Unexpected error: %s: %s: %s&quot; % (sys.exc_info()[0], sys.exc_info()[1], traceback.print_exc()))
               # throw new ExceptionFocntionnelle :
               raise ExceptionFonctionnelle(« message d’erreur »)
        # sinon : erreur lors du traitement de la requête
        else:
            # mark the test as a failure
            grinder.statistics.forLastTest.success = 0
            # throw new ExceptionTechnique
            raise ExceptionTechnique(« message d’erreur »)
</pre><h4><a
name="ParsingXMLetXPath"></a>Parsing XML et XPath:</h4><p>Le parsing xml de la réponse constitue une étape quasi-évidente pour dérouler votre check-list sur les éléments attendus et également pour récupérer les valeurs de certains d’entre eux ; ainsi, vous pourrez savoir s’il est possible de passer à l’étape suivante de votre scénario.</p><p>En terme de technologie adoptée, je vous laisse faire votre choix entre l’utilisation des APIs standards fournies avec le JDK (javax.xml.parsers, org.xml.sax, javax.xml.xpath) et l’API <a
title="vtd-xml" href="http://vtd-xml.sourceforge.net/">vtd-xml</a> qui est plus puissante et moins consommatrice (basée sur la technique <a
title="Virtual Token Descriptor" href="http://vtd-xml.sourceforge.net/VTD.html">Virtual Token Descriptor</a> (VTD))</p><h4><a
name="Accsconcurrentsauxressourcesnb"></a>Accès concurrents aux ressources « statiques »</h4><p>Si vous manipulez des variables statiques dans vos scripts python, vous êtes sûrement face à un problème d&#8217;accès concurrentiel du moment que vous avez plus d’un injecteur sur une même JVM (grinder.processes&gt;1).</p><p>On reconnaît ce cas de figure par le positionnement du mot clé « global » sur une variable précédemment déclarée dans le script, dans le but de pourvoir modifier sa valeur <strong>(accès en écriture)</strong> à l’intérieur d’une méthode :</p><pre class="brush: python; title: ; notranslate">
maVariable = 0
   def incrementMaVariable() :
      global maVariable
      maVariable += 1
</pre><p>Pour remédier à ce problème, la solution la plus évidente consiste clairement à éviter d’employer ce genre de pratique qui n’est pas en phase avec l’architecture distribuée de The Grinder.<br
/> Néanmoins si vous y tenez, il est possible d&#8217;utiliser la classe Lock du module threading.py:</p><pre class="brush: python; title: ; notranslate">
import threading
# récupérer un 	Object Lock pour la gestion d'accès concurrent à la ressource &quot; maVariable &quot;
lock = threading.Lock()
maVariable = 0
    def incrementMaVariable() :
       try:
           # will block if lock is already held
           lock.acquire()
           # lecture de la variable
           global maVariable
           # écriture de la variable
           maVariable += 1
       finally:
           # release lock
           lock.release()
</pre><h4><a
name="Nommagedestransactionsetunicit"></a>Nommage des transactions et unicité des identifiants de test</h4><p>Pensez à nommer vos transactions d’une manière homogène et ordonnée ; cela vous facilitera la lecture des résultats de test par la suite.<br
/> Le modèle suivant pourrait apporter un certain confort de lisibilité et de clarté : <em>SC-&lt;<strong>R</strong><strong>éférence du scénario</strong>&gt;-STEP-&lt;<strong>Numéro de la transaction</strong>&gt;)&lt;<strong>Libellé de la transaction</strong>&gt;</em></p><p>Prenons par exemple le scénario « consultation du profil », composé de trois transactions à savoir : login, consulter profil et logout.<br
/> Cela aurait donné quelque chose de ce genre lors de la définition des tests:</p><pre class="brush: python; title: ; notranslate">
request1 = Test(1, &quot;SC-CONSULTATION-PROFIL-STEP-1)Login&quot;)
request2 = Test(2, &quot;SC-CONSULTATION-PROFIL-STEP-2)Consultation du profil&quot;)
request3 = Test(3, &quot;SC-CONSULTATION-PROFIL-STEP-3)Logout&quot;)
</pre><p>Les identifiants de vos tests doivent être uniques dans un scope «grinder-project» ; cela vous permettra d’une part d’établir rapidement le lien entre le test id et son libellé, et d’autre part d’éviter toute confusion de transaction (un même identifiant pour deux transactions différentes, bien qu’il soit toujours possible de les distinguer par le libellé).</p><p>N’optez pas pour des variables statiques (avec un système d’incrémentation), vous risquez de vous replonger dans le problème d’accès concurrents à partir du moment où vous êtes dans le cas d’une configuration multi-process par JVM; à la limite gardez-les en dur.</p><h4><a
name="IntgrationdansleBuildPipeLine"></a>Intégration dans le Build PipeLine</h4><p>Il existe un plugin Hudson : <a
title="http://wiki.hudson-ci.org/display/HUDSON/Grinder+Plugin" href="http://wiki.hudson-ci.org/display/HUDSON/Grinder+Plugin">http://wiki.hudson-ci.org/display/HUDSON/Grinder+Plugin</a>:</p><p>Ce plugin permet d’exécuter les scripts « grinder » pendant le build et d’inclure les résultats de tests obtenus dans le rapport hudson.</p><h4><a
name="Gnrationdesrapportsgraphiques"></a>Génération des rapports graphiques</h4><p>Il existe principalement deux outils :</p><ul><li><a
title="Grinder Analyzer " href="http://track.sourceforge.net/analyzer.html|http://track.sourceforge.net/analyzer.html">Grinder Analyzer </a>: Permet de parser les logs grinder et de générer des rapports graphiques (au format html). L’utilisation de cet outil reste très simple et suffisante  pour un aperçu visuel des résultats lorsqu’il s’agit d’un environnement de test mono-agent et mono-worker. Cependant, il trouve rapidement ses limites face à des données  issues de plusieurs « agents » et « workers », ou également lorsqu’il s’agit de générer des graphiques de comparaison entre deux tests.<ul><li>Démo: <a
title="httptracksourceforgenetexamplereporthtml" href="http://track.sourceforge.net/example/report.html">http://track.sourceforge.net/example/report.html</a></li></ul></li><li><a
title="groundreport " href="http://ground.sourceforge.net/|http://ground.sourceforge.net">ground-report </a>: Produit un ensemble de rapports graphiques (rapport de synthèse, rapport individuel par test, rapport de comparaison entre plusieurs tests,…) au format pdf et à partir d’une base de données PostgreSQL. Il est également possible de produire des rapports au format rtf, xml  ou xhtml.<ul><li>Démo: <a
title="httpgroundsourceforgenetsampleshtml" href="http://ground.sourceforge.net/samples.html">http://ground.sourceforge.net/samples.html</a></li><li>Il se distingue par :<ul><li>La qualité de ses rapports.</li><li>Configuration rapide.</li><li>La sauvegarde des résultats de test en base de données garantissant ainsi d’avoir l’historique de l’ensemble tests.</li><li>Son « ToolKit » pour  les opérations d’injection des données « grinder » en base.</li></ul></li></ul></li></ul><h3><a
name="Leslimites"></a>Les limites</h3><ul><li>Ne produit pas nativement des graphiques.</li><li>Ne permet pas de simuler des sessions à partir d’adresses IP différentes, ce qui constitue  généralement un point très important lorsque le target system  est « load-balancé » (souvent le cas en production).</li><li>Manque du support.</li></ul><h3><a
name="Conclusion"></a>Conclusion</h3><p>Dans la mesure où les tests de performance s&#8217;imposent de plus en plus, comme c&#8217;est le cas actuellement pour les tests unitaires, les tests d&#8217;intégration et les tests fonctionnels qui ne cessent de se greffer dans nos projets, il me semble envisageable de compléter la stack de test en faisant d&#8217;eux une partie intégrante des projets; ce qui nous permettra de les faire constamment marier aux évolutions que subissent les applications.</p><p>Aujourd&#8217;hui on parle d&#8217;un test unitaire cassé, on pourrait bien parler d&#8217;un script de test de charge cassé.</p><p>Pour peu que l&#8217;on ait conçu et développé ses scripts proprement (sans pour autant frôler la limite de l&#8217;over-design), on gagne énormément en maintenabilité: modifier le comportement d&#8217;un script, c&#8217;est comme si l&#8217;on s&#8217;apprêtait à modifier une  méthode d&#8217;un service.</p><p>Le fait que The Grinder s&#8217;appuie sur du Jython (implémentation de Python en Java),  on garde toujours un même environnement d&#8217;exécution; que ce soit du .java  vers du .class ou du .py vers $py.class jusqu&#8217;au runtime, c&#8217;est toujours la JVM qui bosse. En plus, vous continuez à profiter de toutes les API Java; ce qui vous offre le moyen de rester dans vos habitudes et de ne pas forcément glisser dans une démarche full-python.</p><div
class="shr-publisher-7340"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F03%2F31%2Fperformance-maitriser-son-framework-de-test-the-grinder%2F' data-shr_title='Performance+-+Ma%C3%AEtriser+son+framework+de+test%2C+The+Grinder'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F03%2F31%2Fperformance-maitriser-son-framework-de-test-the-grinder%2F' data-shr_title='Performance+-+Ma%C3%AEtriser+son+framework+de+test%2C+The+Grinder'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2011/03/31/performance-maitriser-son-framework-de-test-the-grinder/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Java Collection Performance</title><link>http://blog.xebia.fr/2011/02/17/java-collection-performance/</link> <comments>http://blog.xebia.fr/2011/02/17/java-collection-performance/#comments</comments> <pubDate>Thu, 17 Feb 2011 06:09:05 +0000</pubDate> <dc:creator>Yves Amsellem</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[Algorithme]]></category> <category><![CDATA[Collection]]></category> <category><![CDATA[Complexité]]></category> <category><![CDATA[Constant]]></category> <category><![CDATA[Linéaire]]></category> <category><![CDATA[List]]></category> <category><![CDATA[Logarithme]]></category> <category><![CDATA[Map]]></category> <category><![CDATA[Set]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=6875</guid> <description><![CDATA[Le temps de [ ] est révolu ; celui de < > est venu. La liste a remplacé le tableau et type ses éléments &#8212; comme son prédécesseur &#8212; depuis java 1.5. Mais est-elle efficace ? À quel prix s&#8217;entoure-t-on d&#8217;un de ses cadets, LinkedList, HashSet, TreeMap ? La JavaDoc détaille leurs complexités, pourtant aucun [...]]]></description> <content:encoded><![CDATA[<p>Le temps de [ ] est révolu ; celui de < > est venu. La liste a remplacé le tableau et type ses éléments &#8212; comme son prédécesseur &#8212; depuis java 1.5. Mais est-elle efficace ? À quel prix s&#8217;entoure-t-on d&#8217;un de ses cadets, <code>LinkedList</code>, <code>HashSet</code>, <code>TreeMap</code> ? La JavaDoc détaille leurs complexités, pourtant aucun site ni ouvrage semblent n&#8217;en faire l&#8217;écho. Quelques indices glanés dans « <em>Java in a Nutshell</em> » quelques autres dans « <em>Java Generics and Collections</em> » pas beaucoup plus sur la toile à ma connaissance. Les Collections, utilisées si généreusement, seraient méconnues ? Petite revue des troupes.</p><ul><li><a
href="http://blog.xebia.fr/2011/02/17/java-collection-performance/#Classiques">Collections classiques</a></li><li><a
href="http://blog.xebia.fr/2011/02/17/java-collection-performance/#Insertion">Respect de l&#8217;ordre d&#8217;insertion</a></li><li><a
href="http://blog.xebia.fr/2011/02/17/java-collection-performance/#Naturel">Respect de l&#8217;ordre naturel</a></li></ul><div
style="border: dotted 1px #6A205F; background: #F0EDF1; padding:10px 30px;"><p><b>Complexité(s)</b></p><p>Deux complexités sont couramment exprimées dans le domaine informatique, complexité en temps et en mémoire. Dans ce but, des symboles portant une indication chiffrée entre parenthèses sont utilisés (<a
href="http://en.wikipedia.org/wiki/Big_O_notation" title="en savoir plus" target="_blank">en savoir plus</a>). Cet article traite de la complexité en temps et utilise le symbole O &#8212; limite supérieure &#8212; pour ce faire.</p><ul><li><strong>O(n)</strong> — temps linéaire — indique la nécessité de parcourir chacun des n éléments d&#8217;une collection (dans le pire des cas) pour y réaliser une opération ;</li><li><strong>O(log n)</strong> — temps logarithmique — indique que, plus le nombre d&#8217;éléments est élevé, plus la complexité d&#8217;une opération se tasse ;</li><li><strong>O(1)</strong> — temps constant — indique que, quel que soit son nombre d&#8217;éléments, l&#8217;opération aura toujours un coup similaire.</li></ul></div><h3><a
name="Classiques"></a>Collections classiques</h3><p>Commençons par la star de ces dames : <code><a
href="http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html" title="ArrayList" target="_blank">ArrayList</a></code>. Comme toute List qui se respecte, cette implémentation est une séquence d&#8217;objets autorisant les doublons, la valeur <code>null</code> et l&#8217;ajout à un index donné. Elle est bâtie sur un tableau dont la taille est gérée en interne.</p><style>table {border: hidden; border-collapse: collapse; font-size: small;}
tr, th, td {border: dotted 1px #6A205F; padding: 5px;}
th {background: #F0EDF1;}
td {text-align: center;}</style><table><tr><td></td><th> add(e)</th><th> get(i)</th><th> remove(e) / remove(i)</th><th> contains(e)</th><th> size()</th><th> iteration</th></tr><tr><th> ArrayList</th><td> O(1)</td><td> O(1)</td><td> <strong>O(n)</strong></td><td> <strong>O(n)</strong></td><td> O(1)</td><td> O(n)</td></tr></table><p><em>légende : e = élément, i = index, n = nombre d&#8217;éléments</em></p><p>Cette liste est donc toute désignée lorsqu&#8217;il s&#8217;agit d&#8217;itérer sur des éléments ou d&#8217;y accéder par index. Mais, dès lors qu&#8217;une suppression ou une recherche est nécessaire, il faudra s&#8217;en remettre à une autre collection ; pourquoi pas au matheux de la bande : <code><a
href="http://download.oracle.com/javase/6/docs/api/java/util/HashSet.html" title="HashSet" target="_blank">HashSet</a></code>. Cet ensemble ne tolère ni doublons, ni valeur <code>null</code> ni accès à un élément donné. Il permet, cependant, de vérifier la présence d&#8217;un élément en son sein ou de l&#8217;en retirer en temps constant.</p><table><tr><td></td><th> add(e)</th><th> remove(e)</th><th> contains(e)</th><th> size(e)</th><th> iteration</th></tr><tr><th> HashSet</th><td> O(1)</td><td> O(1)</td><td> O(1)</td><td> O(1)</td><td> O(c)</td></tr></table><p><em>légende : c = capacité (c > n)</em></p><p>Cet ensemble serait la collection idéale si il offrait la possibilité d&#8217;accéder à un élément par index. Il n&#8217;en demeure pas moins un alié de choix lorsque l&#8217;appartenance d&#8217;un élément prime sur la valeur de ses attributs. Si ces deux informations comptent, c&#8217;est à sa soeur ainée qu&#8217;il faut s&#8217;adresser : <code><a
href="http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html" title="HashMap" target="_blank">HashMap</a></code>. Ce dictionnaire référence ses objets par clé (à l&#8217;image du rangement d&#8217;une définition par mot dans un dictionnaire classique). L&#8217;ajout d&#8217;un objet pour une clé existante remplace l&#8217;ancien objet.</p><table><tr><td></td><th> put(k, e)</th><th> get (k)</th><th> remove(k)</th><th> containsKey(k)</th><th> containsValue(e)</th><th> size()</th><th> iteration</th></tr><tr><th> HashMap</th><td> O(1)</td><td> O(1)</td><td> O(1)</td><td> O(1)</td><td> <strong>O(n)</strong></td><td> O(1)</td><td> O(c)</td></tr></table><p><em>légende : k = clé (de type objet)</em></p><p>Attention toutefois, les objets clés sont transformés en entier à l&#8217;aide d&#8217;un algorithme de hash (la structure sous-jacente peut être vue ainsi <code>Map&lt;int, Objet&gt;</code>). Ce calcul est effectué à partir de la référence java de l&#8217;objet ; deux objets aux attributs égaux ne correspondent pas à la même clé. Il est possible de modifier cet état de fait via la surcharge des méthodes <code>hashCode()</code> et <code>equals()</code> (<em>« Effective Java » souligne que les deux méthodes doivent toujours être implémentées de paire</em>). Les wraps de type primitifs les surchargent par défaut (deux <code>Integer</code> de même valeur représentent la même clé).</p><p>Comme le souligne la JavaDoc, la complexité des types à base de hash est garantie à condition que la fonction de hash répartisse correctement leurs valeurs. Les collisions sont prises en charge ; lorsque deux objets aux attributs différents obtiennent le même hash, ils sont tous deux conservés. Si la fonction de hash est correcte, n opérations s&#8217;effectuent en O(n), les erreurs étant amorties par le nombre d&#8217;éléments, une opération est bien en O(1).</p><p>En Java les hash sont couramment calculés ainsi, pour <code>n</code> attributs <code>a</code> : <code>((17 * 31 + a<sub>1</sub>) * 31 + a<sub>2</sub>) * ... * 31 + a<sub>n</sub></code> 31 offre les qualités d&#8217;être un nombre premier, impair et de permettre une multiplication optimisée <code>31 * i == (i << 5) - i</code> Et, toujours selon « <em>Effective Java</em> », ce nombre offre une bonne distribution (<code><a
href="http://commons.apache.org/lang/apidocs/org/apache/commons/lang3/builder/HashCodeBuilder.html" title="HashCodeBuilder" target="_blank">HashCodeBuilder</a></code> de commons-lang s'appuie lui, par défaut, sur 37). La valeur initiale 17 diminue le nombre de collisions qu'aurait occasionné un premier attribut de valeur 0. Sa valeur est arbitraire.</p><h3><a
name="Insertion"></a>Respect de l'ordre d'insertion</h3><p>Certaines implémentations des collections sont dédiées au maintient des éléments dans leur ordre d'insertion.</p><table><tr><td></td><th> add(e) / ... / size(e)</th><th> iteration</th></tr><tr><th> LinkedHashSet</th><td> idem HashSet</td><td> O(n)</td></tr></table><p>À l'instar du <code>HashSet</code>, les opérations du <code><a
href="http://download.oracle.com/javase/6/docs/api/java/util/LinkedHashSet.html" title="LinkedHashSet" target="_blank">LinkedHashSet</a></code> sont en temps constant. Ses performances sont légèrement moins bonnes (à cause du coût de maintient du tri), à une exception : itérer sur ses éléments sera moins coûteux (relatif à son nombre d'éléments et non à sa capacité).</p><p>Ces mêmes remarques s'appliquent à <code><a
href="http://download.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html" title="LinkedHashMap" target="_blank">LinkedHashMap</a></code>, respectant elle aussi l'ordre d'insertion.</p><table><tr><td></td><th> put(k, e) / ... / size()</th><th> iteration</th></tr><tr><th> LinkedHashMap</th><td> idem HashMap</td><td> O(n)</td></tr></table><p>En ce qui concerne les listes, ArrayList maintient déjà les éléments dans leur ordre d'insertion, mais des compères peuvent lui prêter main forte dans certains cas particuliers.</p><table><tr><td></td><th> add(e)</th><th> get(i)</th><th> remove(e)</th><th> remove(i)</th><th> contains(e)</th><th> size()</th><th> iteration</th></tr><tr><th> LinkedList</th><td> O(1)</td><td> <strong>O(n)</strong></td><td> O(1)</td><td> <strong>O(n)</strong></td><td> <strong>O(n)</strong></td><td> O(1)</td><td> O(n)</td></tr></table><p><em>légende : ajout en queue, retrait en tête</em></p><p>Comme ses paires, la liste doublement chainée <code><a
href="http://download.oracle.com/javase/6/docs/api/java/util/LinkedList.html" title="LinkedList" target="_blank">LinkedList</a></code> n'est pas allouée d'un bloc ; ses éléments se référencent les uns les autres. Récupérer un élément à un index donné peut être coûteux si l'on ignore son prédécesseur ou son successeur (<code>LinkedHashSet</code> et <code>LinkedHashMap</code> ont recours à ce procédé pour garantir l'itération ; chaque élément connait le suivant).</p><table><tr><td></td><th> push(e)</th><th> peek()</th><th> pop()</th><th> contains(e)</th><th> size()</th><th> iteration</th></tr><tr><th> ArrayDeque</th><td> O(1)</td><td> O(1)</td><td> O(1)</td><td> <strong>O(n)</strong></td><td> O(1)</td><td> O(n)</td></tr></table><p>Une <code><a
href="http://download.oracle.com/javase/6/docs/api/java/util/ArrayDeque.html" title="ArrayDeque" target="_blank">ArrayDeque</a></code> peut être utilisée comme une file d'attente ; premier arrivé, premier servi (FIFO). Elle peut également l'être comme une pile d'assiettes ; dernière arrivée, première utilisée (LIFO). Cette implémentation est à préférer à celle de <code><a
href="http://download.oracle.com/javase/6/docs/api/java/util/Stack.html" title="Stack" target="_blank">Stack</a></code>, basée sur <code>Vector</code>. Comme elle n'accède qu'aux premier et dernier éléments, cette implémentation offre une suppression en temps constant.</p><h3><a
name="Naturel"></a>Respect de l'ordre naturel</h3><p>Certaines implémentations des collections sont dédiées au maintient des éléments dans leur ordre naturel (les chiffres et les chaines de caractères par ordre croissant, les objets selon leur implémentation de l'interface <code>Comparable</code>) évitant d'avoir recours à un tri.</p><table><tr><td></td><th> add(e)</th><th> remove(e)</th><th> contains(e)</th><th> size(e)</th><th> iteration</th></tr><tr><th> TreeSet</th><td> O(log n)</td><td> O(log n)</td><td> O(log n)</td><td> O(1)</td><td> O(c)</td></tr></table><p>Un <code><a
href="http://download.oracle.com/javase/6/docs/api/java/util/TreeSet.html" title="TreeSet" target="_blank">TreeSet</a></code> peut remplacer avantageusement un ensemble classique lorsque des éléments y sont ajoutés à différentes reprises et que leur ordre importe.</p><table><tr><td></td><th> put(k, e)</th><th> get (k)</th><th> remove(k)</th><th> containsKey(k)</th><th> containsValue(e)</th><th> size()</th><th> iteration</th></tr><tr><th> TreeMap</th><td> O(log n)</td><td> O(log n)</td><td> O(log n)</td><td> O(log n)</td><td> <strong>O(n)</strong></td><td> O(1)</td><td> O(c)</td></tr></table><p>Une <code><a
href="http://download.oracle.com/javase/6/docs/api/java/util/TreeMap.html" title="TreeMap" target="_blank">TreeMap</a></code> permet de s'assurer de l'ordre d'itération sur ses clés.</p><table><tr><td></td><th> add(e)</th><th> get(i)</th><th> remove(e) / remove(i)</th><th> contains(e)</th><th> size()</th><th> iteration</th></tr><tr><th> TreeList</th><td> O(log n)</td><td> O(1)</td><td> O(log n)</td><td> O(log n)</td><td> O(1)</td><td> O(n)</td></tr></table><p>Une <code><a
href="http://commons.apache.org/collections/api-3.2/org/apache/commons/collections/list/TreeList.html" title="TreeList" target="_blank">TreeList</a></code>, proposée dans commons-collections car absente du langage natif, améliore suppression et vérification d'appartenance d'un élément au détriment d'une insertion plus coûteuse. Sa documentation souligne que <code><a
href="http://download.oracle.com/javase/6/docs/api/java/util/LinkedList.html" title="LinkedList" target="_blank">LinkedList</a></code> est rarement un bon choix (via des statistiques que l'on aimerait voir plus souvent ; TreeList vs ArrayList vs LinkedList).</p><h3><a
name="LimitedescollectionsduJDK"></a>Limite des collections du JDK</h3><p>Malgré sa richesse, certains cas de figure ne sont pas adressés par les collections du JDK. C'est là qu'Apache avec ses <a
href="http://commons.apache.org/collections/api-3.2.1/org/apache/commons/collections/package-summary.html" title="commons-collections" target="_blank">commons-collections</a> et Google avec <a
href="http://guava-libraries.googlecode.com/svn/tags/release08/javadoc/com/google/common/collect/package-summary.html" title="guava-collections" target="_blank">guava-collections</a> (anciennement google-collections) prennent le relais. Contrairement aux secondes, et malgré leur popularité, les premières ne supportent pas les génériques (un portage de la version 3.1 par une entreprise externe les y ajoute ; mais ne semble plus maintenu). Voici leurs dépendances maven : <a
href="http://mvnrepository.com/artifact/com.google.guava/guava-collections" title="guava-collections" target="_blank">guava-collections</a>, <a
href="http://mvnrepository.com/artifact/commons-collections/commons-collections" title="commons-collection" target="_blank">commons-collection</a> (et de son port en <a
href="http://mvnrepository.com/artifact/net.sourceforge.collections/collections-generic" title="collectionsgeneric" target="_blank">collections-generic</a>).</p><p>Retenir une collection pour sa complexité en temps n'a pas que des vertus d'optimisation, elle est porteuse de sens pour l'algorithme qu'elle accompagne ; elle porte plus que l'opération elle-même la logique des traitements attendus.</p><p><em>Ce billet est dédié à Denis Lapoire</em></p><div
class="shr-publisher-6875"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F02%2F17%2Fjava-collection-performance%2F' data-shr_title='Java+Collection+Performance'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F02%2F17%2Fjava-collection-performance%2F' data-shr_title='Java+Collection+Performance'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2011/02/17/java-collection-performance/feed/</wfw:commentRss> <slash:comments>20</slash:comments> </item> <item><title>Kirk Pepperdine : Java Performance Tuning</title><link>http://blog.xebia.fr/2010/05/04/kirk-pepperdine-java-performance-tuning-2/</link> <comments>http://blog.xebia.fr/2010/05/04/kirk-pepperdine-java-performance-tuning-2/#comments</comments> <pubDate>Tue, 04 May 2010 09:24:40 +0000</pubDate> <dc:creator>Xebia France</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[J2EE]]></category> <category><![CDATA[JEE]]></category> <category><![CDATA[optimisation]]></category> <category><![CDATA[tuning]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=4546</guid> <description><![CDATA[Xebia-training a le plaisir d’accueillir Kirk Pepperdine, un référent de la communauté Java EE pour une formation d’optimisation des performances Java EE (Java performance tuning) les 7, 8, 9 et 10 juin dans nos locaux. Cette formation approfondie de 4 jours vous permettra d’obtenir les compétences nécessaires pour optimiser la performance de vos applications Java. [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://training.xebia.fr">Xebia-training</a> a le plaisir d’accueillir Kirk Pepperdine, un référent de la communauté Java EE pour une formation d’optimisation des performances Java EE <em>(Java performance tuning)</em> les 7, 8, 9 et 10 juin dans nos locaux.</p><p>Cette formation approfondie de 4 jours vous permettra d’obtenir les compétences nécessaires pour optimiser la performance de vos applications Java. Vous aborderez pendant cette formation tous les aspects de la performance : l’outillage nécessaire, les méthodologies à appliquer, les concepts d’architecture sous jacents à la performance, les meilleures pratiques, le benchmarking et la gestion de mémoire.</p><p>A l’issue de cette formation, vous serez en mesure :</p><ul><li>D’identifier rapidement et régler les problèmes de performance de vos applications.</li><li>D’identifier et résoudre des problèmes de fuite mémoire en quelques heures.</li><li>D’isoler des problèmes classiques et d’éviter de s’engager dans des plans d’actions couteux et inefficaces.</li><li>D’identifier des problèmes de performance avant qu’ils ne deviennent critiques pour les applications.</li></ul><p>Les stagiaires bénéficieront des Tips de Kirk Pepperdine, référence reconnue dans le monde de l’optimisation de performance objet.<br
/> Kirk Pepperdine dispose de 15 ans d’expérience dans les technologies OO et l’optimisation de la performance. Figure emblématique du monde Java et élu <em>&laquo;&nbsp;Champion JAVA&nbsp;&raquo;</em> en 2005, Kirk est reconnu comme le référent de l’optimisation de performance Java.<br
/> Vous pouvez consulter le programme complet de cette formation en consultant notre site : <a
href="http://training.xebia.fr/formation-java-performance-tuning-kirk-pepperdine/">http://training.xebia.fr/formation-java-performance-tuning-kirk-pepperdine/</a>.</p><div
class="shr-publisher-4546"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F05%2F04%2Fkirk-pepperdine-java-performance-tuning-2%2F' data-shr_title='Kirk+Pepperdine+%3A+Java+Performance+Tuning'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F05%2F04%2Fkirk-pepperdine-java-performance-tuning-2%2F' data-shr_title='Kirk+Pepperdine+%3A+Java+Performance+Tuning'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/05/04/kirk-pepperdine-java-performance-tuning-2/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Performance, les Xebians jouent les démineurs 3</title><link>http://blog.xebia.fr/2010/04/16/performance-les-xebians-jouent-les-demineurs-3/</link> <comments>http://blog.xebia.fr/2010/04/16/performance-les-xebians-jouent-les-demineurs-3/#comments</comments> <pubDate>Fri, 16 Apr 2010 09:00:30 +0000</pubDate> <dc:creator>Pablo Lopez</dc:creator> <category><![CDATA[Exploitation]]></category> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[datasource]]></category> <category><![CDATA[Hibernate]]></category> <category><![CDATA[jmeter]]></category> <category><![CDATA[JMX]]></category> <category><![CDATA[Performances]]></category> <category><![CDATA[threaddump]]></category> <category><![CDATA[VisualVM]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=4398</guid> <description><![CDATA[3ème épisode de notre série. Il est temps pour notre magnifique application de dépasser la barre symbolique de l&#8217;utilisateur unique. Mais comme nous nous sentons confiants et forts, nous allons pousser le vice de passer à, tenez vous bien, 5 utilisateurs concurrents. Et comme certains diraient, &#171;&#160;Et là, c&#8217;est le drame&#160;&#187;. Les temps se dégradent [...]]]></description> <content:encoded><![CDATA[<p>3ème épisode de notre série. Il est temps pour notre magnifique application de dépasser la barre symbolique de l&#8217;utilisateur unique. Mais comme nous nous sentons confiants et forts, nous allons pousser le vice de passer à, tenez vous bien, 5 utilisateurs concurrents. Et comme certains diraient, &laquo;&nbsp;Et là, c&#8217;est le drame&nbsp;&raquo;. Les temps se dégradent à vitesse grand V.</p><p>Pour rappel, nous avions laissé notre utilisateur unique avec un temps mirobolant de 1,7 secondes par requête en moyenne.</p><p>Le tableau ci dessous montre que la concurrence est nuisible à nos temps de réponse.</p><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2010/04/tempsInitial.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2010/04/tempsInitial670.png" alt="tempsInitial" title="tempsInitial" class="alignnone size-medium wp-image-4402" /></a></div><h3><a
name="Labaseuneressourcecritique"></a>La base une ressource critique.</h3><p>Première amélioration, quasiment gratuite. En allant chercher dans les problèmes que nous avions mis de coté (il y a quelques semaines sur le blog, mais quelques minutes auparavant lors du Xke <img
src='http://blog.xebia.fr/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> , nous pouvons exhumer le traçage de la totalité des requêtes SQL dans les fichiers de log. Cette fonctionnalité est bien connue des utilisateurs d&#8217;Hibernate (très pratique pour débugger), mais elle se retrouve malheureusement bien trop souvent en production.</p><pre class="brush: xml; title: ; notranslate">
&lt;prop key=&quot;hibernate.show_sql&quot;&gt;false&lt;/prop&gt;
</pre><p>Il suffit alors d&#8217;une simple modification dans la configuration d&#8217;Hibernate, d&#8217;un redéploiement, et miracle, les temps s&#8217;améliorent déjà un peu.</p><ul><li>hibernate.show_sql à false</li><li>Temps moyen de 8,2 s à 7,6 s pour 5 utilisateurs</li><li>1 point pour l&#8217;équipe qui a trouvé</li></ul><p>Après cette correction facile, attaquons nous à plus complexe.</p><p>Si la montée en charge induit une augmentation du temps de réponse, c&#8217;est que les utilisateurs sont en concurrence sur un certain type de ressource, ou bien qu&#8217;ils mettent la machine à genoux. Un rapide coup d&#8217;oeil dans VisualVm nous montre que la CPU et la mémoire ne sont pas saturées, on a donc à faire à une contention applicative.</p><p>Celles ci peuvent être de deux types :</p><ul><li>une concurrence applicative, <i>mal</i> gérée avec les outils fournis par <code>java.concurrent.util</code></li><li>une contention sur des ressources externes, comme un pool de connexions JDBC dans une DataSource.</li></ul><p>Comme nous étions déjà sur Hibernate dans la correction précédente, continuons à creuser le sillon. Et profitons en pour dégainer un nouvel outil de notre couteau suisse de diagnostic : JMX.<br
/> Pour vérifier si nos connexions JDBC sont bloquantes, utilisons l&#8217;api de monitoring de Java. Une fois de plus, utilisons notre VisualVm, qui propose une interface graphique d&#8217;affichage des MBeans.<br
/> Nous sommes chanceux, nos GO ont utilisé la dataSource standard de Tomcat, elle est donc exposée <code>Catalina:type=DataSource,class=javax.sql.DataSource,name="jdbc/petclinicMySQL"</code></p><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2010/04/numActive.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2010/04/numActive-300x152.png" alt="numActive" title="numActive" width="300" height="152" class="alignnone size-medium wp-image-4400" /></a></div><p>En procédant par sondage rapide (à l&#8217;aide de la fonction &#8216;refresh&#8217; du MBean), on constate rapidement que les valeurs <em>maxActive</em> et <em>numActive</em> se rejoignent autour de la valeur 3. Pas la peine d&#8217;en dire beaucoup plus&#8230; Comme d&#8217;habitude, la documentation va nous confirmer ce que nous pouvions supposer à la lecture de ces valeurs. <em>maxActive</em> nous donne le nombre maximal de connexion JDBC, alors que <em>numActive</em> nous donne celles qui sont utilisées à l&#8217;instant t. Ce qui signifie que lorsque les 3 connexions sont prises, les process suivant se mettent en attente, pendant un temps fixé par <em>maxWait</em> soit 3 secondes. Le goulet d&#8217;étranglement est évident. Il suffit donc de le fluidifier.</p><p>Ce paramétrage se trouve dans la configuration du serveur tomcat, dans le fichier <em>server.xml</em>. Nous allons agir sur deux paramètres : le <em>maxActive</em>, que nous allons positionner à 30 connexions (ce qui est plus que raisonnable) et sur le <em>maxWait</em> afin de ne pas attendre en vain une connexion qui ne viendra jamais.</p><pre class="brush: xml; title: ; notranslate">
&lt;GlobalNamingResources&gt;
    &lt;Resource name=&quot;jdbc/petclinicMySQL&quot; auth=&quot;Container&quot; type=&quot;javax.sql.DataSource&quot; driverClassName=&quot;org.gjt.mm.mysql.Driver&quot; url=&quot;jdbc:mysql://localhost:3306/petclinic_light?autoReconnect=true&quot; username=&quot;petclinic&quot; password=&quot;petclinic&quot; maxActive=&quot;30&quot; maxIdle=&quot;10&quot; removeAbandoned=&quot;true&quot; removeAbandonedTimeout=&quot;60&quot; logAbandoned=&quot;true&quot; maxWait=&quot;60&quot;/&gt;
&lt;/GlobalNamingResources&gt;
</pre><p>Les résultats sont immédiats et nous passons à un temps moyens de 7,2 s :</p><ul><li>Paramétrage de la datasource</li><li>Temps moyen de 7,6 s à 7,2 s pour 5 utilisateurs</li><li>2 points pour l&#8217;équipe qui a trouvé</li></ul><h3><a
name="CacoincetoujoursOletempsestilc"></a>Ca coince toujours. Où le temps est il consommé ?</h3><p>Pas la peine d&#8217;envisager de passer à plus d&#8217;utilisateurs tant que le temps moyen de requête est aussi catastrophique. Si l&#8217;on s&#8217;intéresse plus en détail aux résultats de JMeter, on constate que la requête <em>Owner detail</em> est la plus consommatrice. Sûrement quelque chose à optimiser de ce côté là.<br
/> On ne va pas déroger aux bonnes habitudes prises, on retourne dans VisualVm. Et quand quelque chose coince au niveau applicatif, on réalise un ensemble de ThreadDump. Comme nous sommes avides de nouveauté, nous allons laisser les commandes Unix <em>vi</em> et <em>grep</em> aux dinosaures et utiliser les possibilités de VisualVm, <a
href="https://visualvm.dev.java.net/plugins.html" title=" savoir le plugin Tda" >à savoir le plugin Tda</a>.</p><p>Pour mettre en évidence notre problème, nous allons tout d&#8217;abord restreindre les scenarii JMeter à la seule et unique requête <em>Owner Details</em>. Ensuite, nous allons réaliser une série de ThreadDump très rapproché (de 5 à 10 en quelques secondes). Nous allons ensuite utiliser une des possibilités de TDA, à savoir la détection des Thread longue durée <i><em>Long Running Thread</em></i>. TDA va tenter d&#8217;identifier les threads &#8216;bloqués&#8217; dans la même méthode au travers de n ThreadDump.<br
/> Comme auparavant, nous ne nous occuperons que des <em>catalina-exec-xx RUNNABLE</em>. Et nous avons de la chance, puisque sur nos cinq utilisateurs, nous trouvons 2 threads bloqués au même point, dans la même méthode (vous l&#8217;aurez compris, la détection de thread longue durée est principalement basée sur un &#8216;coup de sonde&#8217; statistique).</p><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2010/04/longRuningThreads.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2010/04/longRuningThreads-300x172.png" alt="longRuningThreads" title="longRuningThreads" width="300" height="172" class="alignnone size-medium wp-image-4399" /></a></div><p>Un petit tour dans le code, dans la classe incriminée.</p><pre class="brush: java; title: ; notranslate">
/**
     &lt;strong&gt; Custom handler for rendering images.
     &lt;/strong&gt;
     &lt;strong&gt; @param petId
     &lt;/strong&gt;            the ID of the pet whose visits to display
     &lt;strong&gt; @param response to output the image bytes
     &lt;/strong&gt; @throws IOException
     */
    @RequestMapping(value = &quot;/owners/*/pets/{petId}/image&quot;, method = RequestMethod.GET)
    public void petImageHandler(@PathVariable int petId, HttpServletResponse response) throws IOException {
        int imgId = petId % 6;
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(&quot;img/pet-&quot; + imgId + &quot;.jpg&quot;);
        response.setContentType(&quot;image/jpeg&quot;);
        OutputStream out = response.getOutputStream();
        IoUtils.copy(in, out);
        clean();
    }
</pre><p>A priori, rien de très suspect dans la façon de servir des images stockées côté serveur (le but de l&#8217;exercice n&#8217;étant pas d&#8217;éliminer le problème, en changeant le comportement de l&#8217;application et en déplaçant ces images côté apache).<br
/> Si on revient à nos ThreadDump, nous constatons que nous pouvons encore descendre dans le code, à l&#8217;intérieur de la classe IoUtils.</p><pre class="brush: java; title: ; notranslate">
    public static void copy(InputStream in, OutputStream out) throws IOException {
        OutputStream bufferedOutputStream = new BufferedOutputStream(out);
        byte[] buffer = new byte[512];
        int length;
        while ((length = in.read(buffer)) &gt;= 0) {
            bufferedOutputStream.write(buffer, 0, length);
        }
        bufferedOutputStream.close();
    }
</pre><p>A priori, si les copies d&#8217;InputStream / Outputstream étaient à ce point sous performantes, cela se saurait. Mais ne mésestimons pas la fourberie de nos poseurs de bombes.</p><p>En y regardant de plus près, on constate en effet que nous avons une belle implémentation maison de la méthode write, inspirée de celle du <code>ByteArrayOutputstream</code>.</p><pre class="brush: java; title: ; notranslate">
public synchronized void write(int b) {
            int newcount = count + 1;
            if (newcount &gt; buf.length) {
                buf = Arrays.copyOf(buf, (buf.length &lt;&lt; 1) / 2 + 3);
            }
            buf[count] = (byte) b;
            count = newcount;
        }
</pre><p>Et là où le <code>ByteArrayOutputstream</code> se redimensionne de manière intelligente pour accélérer la copie</p><pre class="brush: java; title: ; notranslate">
    public synchronized void write(int b) {
	int newcount = count + 1;
	if (newcount &gt; buf.length) {
            buf = Arrays.copyOf(buf, Math.max(buf.length &lt;&lt; 1, newcount));
	}
	buf[count] = (byte)b;
	count = newcount;
    }
</pre><p>, l&#8217;implémentation maison reste définitivement bloquée et recopie les octets 2 à 2&#8230;</p><p>Si nous remplaçons cette implémentation par <code>java.io.BufferedOutputstream</code>, nous devrions avoir de bien meilleurs résultats.</p><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2010/04/tempsFinal.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2010/04/tempsFinal670.png" alt="tempsFinal" title="tempsFinal"  class="alignnone size-medium wp-image-4401" /></a></div><p>Et en effet cette fois, c&#8217;est spectaculaire. Pour nos cinq utilisateurs, nous passons à un temps moyen de 1,4 s avec une très remarquée dégringolade du temps moyen de <em>ownersDetail</em> qui passe de 32 s à 3,7 s.</p><ul><li>Suppression d&#8217;un java.io maison</li><li>Temps moyen de 7,2 s à 1,4 s pour 5 utilisateurs</li><li>3 points pour l&#8217;équipe qui a trouvé</li></ul><p>Il va bientôt être temps de passer à un nombre d&#8217;utilisateurs &laquo;&nbsp;raisonnable&nbsp;&raquo;.</p><div
class="shr-publisher-4398"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F04%2F16%2Fperformance-les-xebians-jouent-les-demineurs-3%2F' data-shr_title='Performance%2C+les+Xebians+jouent+les+d%C3%A9mineurs+3'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F04%2F16%2Fperformance-les-xebians-jouent-les-demineurs-3%2F' data-shr_title='Performance%2C+les+Xebians+jouent+les+d%C3%A9mineurs+3'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/04/16/performance-les-xebians-jouent-les-demineurs-3/feed/</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>Kirk Pepperdine : Java Performance Tuning</title><link>http://blog.xebia.fr/2010/04/06/kirk-pepperdine-java-performance-tuning/</link> <comments>http://blog.xebia.fr/2010/04/06/kirk-pepperdine-java-performance-tuning/#comments</comments> <pubDate>Tue, 06 Apr 2010 10:27:55 +0000</pubDate> <dc:creator>Xebia France</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[JEE]]></category> <category><![CDATA[Performances]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=4316</guid> <description><![CDATA[Xebia-training a le plaisir d’accueillir Kirk Pepperdine, un référent de la communauté Java EE pour une formation d’optimisation des performances Java EE (Java performance tuning) les 7, 8, 9 et 10 juin dans nos locaux. Cette formation approfondie de 4 jours vous permettra d’obtenir les compétences nécessaires pour optimiser la performance de vos applications Java. [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://training.xebia.fr">Xebia-training</a> a le plaisir d’accueillir Kirk Pepperdine, un référent de la communauté Java EE pour une formation d’optimisation des performances Java EE <em>(Java performance tuning)</em> les 7, 8, 9 et 10 juin dans nos locaux.</p><p>Cette formation approfondie de 4 jours vous permettra d’obtenir les compétences nécessaires pour optimiser la performance de vos applications Java. Vous aborderez pendant cette formation tous les aspects de la performance : l’outillage nécessaire, les méthodologies à appliquer, les concepts d’architecture sous jacents à la performance, les meilleures pratiques, le benchmarking et la gestion de mémoire.</p><p>A l’issue de cette formation, vous serez en mesure :</p><ul><li>D’identifier rapidement et régler les problèmes de performance de vos applications.</li><li>D’identifier et résoudre des problèmes de fuite mémoire en quelques heures.</li><li>D’isoler des problèmes classiques et d’éviter de s’engager dans des plans d’actions couteux et inefficaces.</li><li>D’identifier des problèmes de performance avant qu’ils ne deviennent critiques pour les applications.</li></ul><p>Les stagiaires bénéficieront des Tips de Kirk Pepperdine, référence reconnue dans le monde de l’optimisation de performance objet.<br
/> Kirk Pepperdine dispose de 15 ans d’expérience dans les technologies OO et l’optimisation de la performance. Figure emblématique du monde Java et élu <em>&laquo;&nbsp;Champion JAVA&nbsp;&raquo;</em> en 2005, Kirk est reconnu comme le référent de l’optimisation de performance Java.<br
/> Vous pouvez consulter le programme complet de cette formation en consultant notre site : <a
href="http://training.xebia.fr/category/filiere-java-jee/">http://training.xebia.fr/category/filiere-java-jee/</a>.</p><div
class="shr-publisher-4316"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F04%2F06%2Fkirk-pepperdine-java-performance-tuning%2F' data-shr_title='Kirk+Pepperdine+%3A+Java+Performance+Tuning'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F04%2F06%2Fkirk-pepperdine-java-performance-tuning%2F' data-shr_title='Kirk+Pepperdine+%3A+Java+Performance+Tuning'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/04/06/kirk-pepperdine-java-performance-tuning/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Soirée &#171;&#160;Les applications Java et la Production&#160;&#187; suivie d&#8217;un cocktail</title><link>http://blog.xebia.fr/2010/03/25/soiree-les-applications-java-et-la-production-suivie-dun-cocktail/</link> <comments>http://blog.xebia.fr/2010/03/25/soiree-les-applications-java-et-la-production-suivie-dun-cocktail/#comments</comments> <pubDate>Thu, 25 Mar 2010 16:03:02 +0000</pubDate> <dc:creator>Xebia France</dc:creator> <category><![CDATA[Exploitation]]></category> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[JEE]]></category> <category><![CDATA[Production]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=4270</guid> <description><![CDATA[Xebia organise le 12 Avril à partir de 19h, une soirée &#171;&#160;Les dix bonnes pratiques des applications Java prêtes pour la production&#160;&#187; suivie d’un cocktail. Cette soirée gratuite vous permettra d’appréhender les bonnes pratiques que se doivent de respecter les Directions Etudes et Développement pour rendre leurs applications Java/J2EE prêtes pour la production. Elle se [...]]]></description> <content:encoded><![CDATA[<p>Xebia organise le 12 Avril à partir de 19h, une soirée &laquo;&nbsp;Les dix bonnes pratiques des applications Java prêtes pour la production&nbsp;&raquo; suivie d’un cocktail.</p><p>Cette soirée gratuite vous permettra d’appréhender les bonnes pratiques que se doivent de respecter les Directions Etudes et Développement pour rendre leurs applications Java/J2EE prêtes pour la production.</p><p>Elle se déroulera dans les locaux de Xebia : 156, boulevard Haussmann, 75008 Paris.<br
/> Les inscriptions peuvent se faire :</p><ul><li>Par mail : <a
href="mailto:info@xebia-training.fr">info@xebia-training.fr</a></li><li>Par téléphone : 01.53.89.99.93</li><li>En ligne <a
href="http://training.xebia.fr/soiree-les-applications-java-et-la-production/"> sur le site de Xebia Training</a></li></ul><p>Les technologies Java ont été massivement adoptées par les DSI pour la réalisation de leurs applications critiques. Porteuses de valeur et d’innovation, elles posent régulièrement problème au niveau des départements Exploitation/Production. Instabilité chronique, manque de capacité à monter en charge, difficultés de diagnostiques en cas de dysfonctionnement, déploiement chaotique sont autant de maux fréquemment rencontrés par les entreprises utilisatrices.</p><p>Les bonnes pratiques que se doivent de respecter les Directions Etudes et Développement pour rendre leurs applications Java/J2EE prêtes pour la production s’articulent autour des axes suivants :</p><h4>Les bonnes pratiques pour le déploiement</h4><p>Le déploiement est le baptême du feu d’une application en production. Comment réussir cette épreuve ?</p><ul><li>Complexité des composants à déployer : simplicité rime avec fiabilité,</li><li>Les paramètres de configuration : éviter l’anarchie,</li><li>Traçabilité et build automatisés : maitriser sa plateforme.</li></ul><h4>Les bonnes pratiques de robustesse</h4><p>Dans l’adversité, une application robuste assure un service minimum plutôt que de s’arrêter :</p><ul><li>Dépendances inter-application : fail fast est il synonyme de fragilité ?</li><li>Prévention des saturations et des effets “domino” : l’art du code défensif,</li><li>Modes dégradés : les négociation technico-fonctionnelles.</li></ul><h4>Les bonnes pratiques pour la supervision et le monitoring</h4><p>Une application en production doit exposer son état aux équipes d’exploitation et faciliter la détection de problèmes :</p><ul><li>Indicateurs de bon fonctionnement d’une application : ne pas se noyer dans les chiffre,</li><li>Comment exposer les indicateurs de performances ? Fichier de log versus page JSP versus Java Management eXtension (JMX) ?</li></ul><h4>Les bonnes pratiques de log</h4><p>Grande source d’incompréhension entre les départements études et exploitation, les logs d’application Java ? Quels formats de messages ?</p><ul><li>Codes erreurs chers aux exploitants, exceptions chainées et stacktraces familières aux développeurs, quel compromis ?</li><li>Des logs de troubleshooting extrêmement verbeuses aux logs d’audit sécurité à conserver plus d’un an en passant par celles de perfs et celles de diagnostique, comment organiser les logs ?</li></ul><h4>Les bonnes pratiques organisationnelles</h4><p>Avoir une application prête pour la production ne se limite pas à des bonnes pratiques techniques, la collaboration des départements études et exploitation est essentielle :</p><ul><li>Prendre en considération les réalités de production dans les développements : une amélioration continue,</li><li>Les incidents : comment s’y préparer pour qu’ils ne se transforment pas en longues indisponibilité.</li></ul><h4>BONUS</h4><p>Les bonnes pratiques de robustesse</p><ul><li>Les mécanismes de ré-essai</li></ul><div
class="shr-publisher-4270"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F03%2F25%2Fsoiree-les-applications-java-et-la-production-suivie-dun-cocktail%2F' data-shr_title='Soir%C3%A9e+%22Les+applications+Java+et+la+Production%22+suivie+d%27un+cocktail'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F03%2F25%2Fsoiree-les-applications-java-et-la-production-suivie-dun-cocktail%2F' data-shr_title='Soir%C3%A9e+%22Les+applications+Java+et+la+Production%22+suivie+d%27un+cocktail'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/03/25/soiree-les-applications-java-et-la-production-suivie-dun-cocktail/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Catalogue Xebia Training</title><link>http://blog.xebia.fr/2010/02/24/catalogue-xebia-training/</link> <comments>http://blog.xebia.fr/2010/02/24/catalogue-xebia-training/#comments</comments> <pubDate>Wed, 24 Feb 2010 12:32:34 +0000</pubDate> <dc:creator>Xebia France</dc:creator> <category><![CDATA[Exploitation]]></category> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Méthodes agiles]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[RIA]]></category> <category><![CDATA[SOA]]></category> <category><![CDATA[eXtrem Programming]]></category> <category><![CDATA[JEE]]></category> <category><![CDATA[SCRUM]]></category> <category><![CDATA[XP]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=4085</guid> <description><![CDATA[Nous sommes heureux de vous proposer le nouveau catalogue de formation Xebia Traning : Le catalogue numérique. Le catalogue PDF. Xebia Training se positionne logiquement dans la continuité de Xebia, tant sur la qualité de son offre de formation technique que méthodologique (méthodes agiles), en proposant des formations haut de gamme animées uniquement par les [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://flipflashpages.uniflip.com/2/26742/50371/pub/"><img
src="http://blog.xebia.fr/wp-content/uploads/2010/02/xebia-training.png" style="margin: 1em 1em 1em 1em; float: right;" /></a><br
/> Nous sommes heureux de vous proposer le nouveau <a
href="http://flipflashpages.uniflip.com/2/26742/50371/pub/">catalogue de formation Xebia Traning</a> :</p><ul><li>Le <a
href="http://flipflashpages.uniflip.com/2/26742/50371/pub/">catalogue numérique</a>.</li><li>Le <a
href="http://training.xebia.fr/wp-content/uploads/catalogue%20des%20formations%202010-xebia-training.pdf">catalogue PDF</a>.</li></ul><p><a
href="http://training.xebia.fr">Xebia Training</a> se positionne logiquement dans la continuité de Xebia, tant sur la qualité de son offre de formation technique que méthodologique (méthodes agiles), en proposant des formations haut de gamme animées uniquement par les référents de leur domaine.</p><p>Avec pour principe premier le refus de tout compromis sur la qualité du formateur et du contenu, <a
href="http://training.xebia.fr">Xebia Training</a> fait systématiquement intervenir des acteurs de références dans leurs domaines respectifs.</p><p>Nos formations, savant équilibre entre théorie et travaux pratiques, sont destinées à un large public soucieux d’acquérir les meilleures pratiques de notre industrie.</p><div
class="shr-publisher-4085"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F02%2F24%2Fcatalogue-xebia-training%2F' data-shr_title='Catalogue+Xebia+Training+'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F02%2F24%2Fcatalogue-xebia-training%2F' data-shr_title='Catalogue+Xebia+Training+'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/02/24/catalogue-xebia-training/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Performance, les Xebians jouent les démineurs 2</title><link>http://blog.xebia.fr/2010/02/16/performance-les-xebians-jouent-les-demineurs-2/</link> <comments>http://blog.xebia.fr/2010/02/16/performance-les-xebians-jouent-les-demineurs-2/#comments</comments> <pubDate>Tue, 16 Feb 2010 13:51:05 +0000</pubDate> <dc:creator>Pablo Lopez</dc:creator> <category><![CDATA[Exploitation]]></category> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[dump]]></category> <category><![CDATA[HTTPConnector]]></category> <category><![CDATA[JEE]]></category> <category><![CDATA[Mémoire]]></category> <category><![CDATA[Performances]]></category> <category><![CDATA[Threads]]></category> <category><![CDATA[Xssn]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=4004</guid> <description><![CDATA[Suite de nos investigations sur l&#8217;application PetClinic dégradée. Après une première passe qui nous a permis de calibrer les logs de manière un peu plus pertinente, il est temps, toujours sans l&#8217;aide du code source, de mettre les mains sous le capot de Tomcat (6.0.20). Et pour cela, rien de mieux que de jeter de [...]]]></description> <content:encoded><![CDATA[<p>Suite de nos investigations sur l&#8217;application PetClinic dégradée.</p><p>Après <a
href="http://blog.xebia.fr/2010/01/27/performance-les-xebians-jouent-les-demineurs/" title="une premire passe" >une première passe</a> qui nous a permis de calibrer les logs de manière un peu plus pertinente, il est temps, toujours sans l&#8217;aide du code source, de mettre les mains sous le capot de Tomcat (6.0.20).</p><p>Et pour cela, rien de mieux que de jeter de nouveau un œil à notre VisualVm.</p><h4><a
name="Tantdethreadspourunseulutilisa"></a>Tant de threads pour un seul utilisateur.</h4><p>Pour (re)commencer, penchons nous sur nos threads, juste après le démarrage du serveur (et donc avant la première connexion d&#8217;un utilisateur)</p><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2010/02/threadsOverview.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2010/02/threadsOverview.png" alt="threadsOverview" title="threadsOverview" width="567" height="272" class="aligncenter size-full wp-image-4009" /></a></div><p>Lorsque l&#8217;on démarre un serveur Tomcat, un certain nombre de threads sont affectés à sa &#8216;tuyauterie&#8217; interne (connecteurs RMI, JMX). Mais de là à avoir 165 threads, il y a certainement un souci quelque part !<br
/> Creusons un peu, et entrons dans le détail de ces threads en utilisant l&#8217;onglet <em>Threads</em>.</p><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2010/02/threadsDetails.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2010/02/threadsDetails.png" alt="threadsDetails" title="threadsDetails" width="700" class="aligncenter size-large wp-image-4013" /></a></div><p>Hormis les threads &#8216;connecteurs&#8217; de Tomcat, on voit apparaître 150 threads catalina-exec. Ces threads sont en charge des traitements des requêtes HTTP, via le HTTP-8080-acceptor. Nous avons donc, &laquo;&nbsp;à froid&nbsp;&raquo; 150 unités d&#8217;œuvre prêtes à traiter nos requêtes. Sachant que pour l&#8217;instant nos tests se limitent à un utilisateur, on sent que nous sommes très légèrement surarmés par rapport à nos besoins.<br
/> Tomcat ne devrait-il pas gérer automatiquement ces problématiques de montée ou descente en charge ?<br
/> Allons faire un petit tour dans la documentation, <a
href="<br /> http://tomcat.apache.org/tomcat-6.0-doc/config/http.html">du côté du connecteur HTTP</a>.</p><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2010/02/httpConnector.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2010/02/httpConnector.png" alt="httpConnector" title="httpConnector" width="700" class="aligncenter size-large wp-image-4015" /></a></div><p>Si nous recherchons le paramètre minSpareThreads dans nos fichiers de configuration, nous le trouvons dans server.xml. Repassons le à une valeur plus réaliste de 10 threads, sachant que Tomcat montera automatiquement en charge si besoin.<br
/> Cela n&#8217;a pas d&#8217;impact visible sur les performances, mais au moins, les ThreadDumps deviennent lisibles (obfusquer les ThreadDumps était le but recherché de ce paramétrage).<br
/> Autre paramètre qui a interpellé les connaisseurs de Tomcat, la classe de l&#8217;Executor. <code>org.apache.catalina.core.extended.PrestartingThreadExecutor</code> n&#8217;est pas une classe courante. D&#8217;habitude, on utilise plutôt le <code>StandardThreadExecutor</code>. Une fois encore, on peut remercier nos buggers en chef : PrestartingThreadExecutor est une classe custom, qui démarre automatiquement tous les threads HTTP. De nouveau, l&#8217;impact sur les performances est négligeable pour un utilisateur, mais mieux vaut laisser Tomcat gérer toutes les problématiques de vie du serveur d&#8217;application. Sans vouloir leur faire offense, nos maîtres de cérémonie n&#8217;ont pas le niveau des équipes Apache rodées à l&#8217;exercice depuis de très nombreuses années <img
src='http://blog.xebia.fr/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /><br
/> Dernier paramètre &laquo;&nbsp;malin&nbsp;&raquo; introduit au niveau de Tomcat, le paramètre -Xss. Celui-ci peut être découvert via l&#8217;overview de VisualVm. -Xmx, -Xms sont des paramètres classiques (nous reviendrons dessus) que grand nombre de développeurs connaissent. Mais -Xss ? Comme d&#8217;habitude, notre meilleure arme est <a
href="http://java.sun.com/javase/6/docs/technotes/tools/windows/java.html" title="la documentation de Sun" >la documentation de Sun</a>.</p><pre class="brush: java; title: ; notranslate">-Xssn
    Set thread stack size.</pre><p>Avons nous réellement besoin d&#8217;une taille de stack de 1024 Ko ? Difficile à dire, surtout a priori. Mais une fois encore, le plus simple est de faire confiance à Tomcat, quitte à devoir intervenir a posteriori. Nous ne sommes plus à un redémarrage près.</p><p>Maintenant que notre application est déployée et paramétrée de manière à peu près correcte, il est temps de rentrer &laquo;&nbsp;dans le dur&nbsp;&raquo; : mettre les mains dans le cambouis et explorer le code source.</p><h4><a
name="Fuitemmoirethreadsdumpaexplose"></a>Fuite mémoire, threads dump, ça explose de tous les côtés.</h4><p>Dès que nous avons eu le code source entre les mains, plusieurs stratégies se sont dégagées :</p><ul><li>la première consiste à conserver un seul utilisateur dans les scripts JMeter et à le pousser à faire plus d&#8217;itérations,</li><li>la seconde consiste à mettre plus d&#8217;utilisateurs JMeter en parallèle.</li></ul><p>Toujours dans le but de rester très didactique, nous allons appliquer la première stratégie. Qui trouve rapidement sa limite :</p><p>Aux environs de la 70ème itération, la <em>heap used</em> tangente la <em>heap max</em>, le Garbage Collector est déclenché plusieurs dizaines de fois par seconde de manière totalement inefficace, et la JVM finit par faire un joli OutOfMemory. Les symptômes classiques de la fuite mémoire.</p><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2010/02/memoryLeak.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2010/02/memoryLeak.png" alt="memoryLeak" title="memoryLeak" width="700" class="aligncenter size-medium wp-image-4017" /></a></div><p>Comment faire pour la trouver ?<br
/> C&#8217;est à la fois simple et complexe : depuis la JVM 6, il est très facile, grâce à VisualVm de réaliser des &laquo;&nbsp;photographies&nbsp;&raquo; exhaustives de la mémoire de la JVM, les célèbres heap dumps. Malheureusement, ce n&#8217;est possible que sur les JVM locales.<br
/> Conformons nous donc à l&#8217;énoncé et n&#8217;installons pas notre Tomcat en local. La solution consiste à utiliser la commande jmap.<br
/> Commençons par générer un histogramme, que nous allons filtrer.<br
/> <code>jmap -histo &lt;pid_jvm&gt; | grep org.spring</code><br
/> Notre premier candidat arrive en 16ème position dans l&#8217;histogramme :<br
/> <code>16:         14000         560000  org.springframework.samples.petclinic.Vet</code><br
/> 14 000 vétérinaires, voilà qui est surprenant&#8230; De là à dire que notre fuite tourne autour de cet objet métier, il n&#8217;y a qu&#8217;un pas. Malheureusement, à part en allant dans le code à la pioche, il va être difficile de colmater la fuite avec aussi peu d&#8217;information. De nouveau, jmap va nous rendre service, cette fois en générant un heap dump.<br
/> <code>jmap -dump:format=b,file=/tmp/dump.hprof &lt;pid_jvm&gt;</code><br
/> Pour exploiter ce dump, nous avons choisi d&#8217;utiliser l&#8217;outil <a
href="http://www.eclipse.org/mat/" title="Eclipse Mat" >Eclipse Mat</a>. Dès l&#8217;ouverture, Mat nous propose de rechercher les <em>leak suspects</em><br
/> Et là, le diagnostic est assez évident.</p><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2010/02/leakMat.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2010/02/leakMat.png" alt="leakMat" title="leakMat" width="700" class="aligncenter size-medium wp-image-4020" /></a></div><p>Un type d&#8217;objet monopolise à lui seul 92 % de la mémoire. Il ne reste plus qu&#8217;à creuser dans le heap dump pour déceler l&#8217;allocation coupable.<br
/> Passons donc à la vue <em>dominator tree</em>. En dépliant progressivement la pile mémoire (en cliquant sur l&#8217;objet qui a la plus grande <em>retained heap</em>), on constate que la mémoire est occupée par de très nombreuses occurences de <code>org.springframework.samples.petclinic.util.CacheFilter$CacheEntry</code></p><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2010/02/memoryLeakMat.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2010/02/memoryLeakMat.png" alt="memoryLeakMat" title="memoryLeakMat" width="700" class="aligncenter size-medium wp-image-4018" /></a></div><p>Maintenant que nous avons un coupable, il est temps, pour la première fois, d&#8217;ouvrir notre code source sous Eclipse. En faisant une simple recherche de classe sur notre coupable désigné, nous arrivons au code suivant :</p><pre class="brush: java; title: ; notranslate">
HttpSession session = request.getSession();
Map&lt;String, CacheEntry&gt; cache = (Map&lt;String, CacheEntry&gt;) session.getAttribute(&quot;pages.cache&quot;);
if (cache == null){
    cache = new Hashtable&lt;String, CacheEntry&gt;();
    session.setAttribute(&quot;pages.cache&quot;, cache);
}
...
//Return cached content if available
String path = context.getRealPath(&quot;&quot;) + request.getRequestURI() + request.getQueryString();
CacheEntry cacheEntry = cache.get(path);
if (cacheEntry != null) {
    response.setContentType(cacheEntry.t);
} else {
    //Else, fetch it
    cacheEntry = new CacheEntry();
    CacheResponseWrapper wrapper = new CacheResponseWrapper(response);
    chain.doFilter(request, wrapper);
    byte[] buf = cacheEntry.buf;
    InputStream in = wrapper.getContentAsInputStream();
    OutputStream out = cacheEntry.c;
    int length;
    while((length = in.read(buf)) &gt;= 0) {
        out.write(buf, 0, length);
    }
cacheEntry.t = wrapper.getContentType();
cache.put(path, cacheEntry);
}
</pre><p>Chaque page est donc mise en cache dans la session de l&#8217;utilisateur. Le timeout du cache étant fixé à l&#8217;infini, on voit de manière assez évidente que chaque fois que notre JMeter lance une campagne de test, il ouvre une nouvelle Session dans laquelle l&#8217;ensemble des pages vues est gardée en mémoire (avec un taux de réutilisation proche de zéro).<br
/> L&#8217;utilisation des ressources mémoire de notre JVM est ici particulièrement mauvaise.<br
/> Deux solutions sont envisageables :</p><ul><li>basculer le cache dans un scope application. Mais dans ce cas, attention, la taille de celui-ci peut vite exploser et l&#8217;utilisation d&#8217;un filtre qui cache systématiquement tout le contenu de la réponse peut rapidement échapper à tout contrôle.</li><li>supprimer purement et simplement ce cache dont le taux de hit est ridiculement bas. C&#8217;est la solution que nous choisirons ici, car c&#8217;est la plus économique (une ligne à commenter dans le <code>web.xml</code>).</li></ul><p>Cette correction ne devrait toutefois pas affecter notre nombre élevé de <code>Vets</code> trouvés via l&#8217;histogramme&#8230; Nous y reviendrons probablement.</p><p>Ne reste alors plus qu&#8217;à re-construire (via Maven) et relivrer l&#8217;application pour voir le résultat.</p><p>Cette fois, le gain de performance ne se mesure pas directement dans JMeter. Les temps de réponse de l&#8217;application sont sensiblement identiques à ce qu&#8217;ils étaient avant nos interventions.</p><p>En revanche, nous avons largement gagné en performance dans deux domaines :</p><ul><li>le plus immédiat, celui du ressenti utilisateur : plus la peine de rebooter notre serveur tous les 70 scenarii, et ça toutes les équipes d&#8217;exploitation vous le diront (sauf les mauvais élèves qui ont bêtement automatisé leurs redémarrages), c&#8217;est un énorme gain.</li><li>celui plus égoïste, d&#8217;avoir des traces propres et peu nombreuses, donc beaucoup plus exploitables.</li></ul><p>Pour finir, les points attribués :</p><ul><li> Fuite mémoire de CacheFilter en session</li><li> Passage de la barre des 70 scenarii pour 1 utilisateur</li><li> 2 points pour l&#8217;équipe qui a trouvé</li></ul><p>Comme l&#8217;a très bien pressenti l&#8217;un de nos lecteurs (voir les <a
href="http://blog.xebia.fr/2010/01/27/performance-les-xebians-jouent-les-demineurs/#comment-20398" title="commentaires" >commentaires</a> sur l&#8217;article précédent), nous ne sommes pas encore au bout de nos <em>surprises</em></p><div
class="shr-publisher-4004"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F02%2F16%2Fperformance-les-xebians-jouent-les-demineurs-2%2F' data-shr_title='Performance%2C+les+Xebians+jouent+les+d%C3%A9mineurs+2'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F02%2F16%2Fperformance-les-xebians-jouent-les-demineurs-2%2F' data-shr_title='Performance%2C+les+Xebians+jouent+les+d%C3%A9mineurs+2'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/02/16/performance-les-xebians-jouent-les-demineurs-2/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>Performance, les Xebians jouent les démineurs</title><link>http://blog.xebia.fr/2010/01/27/performance-les-xebians-jouent-les-demineurs/</link> <comments>http://blog.xebia.fr/2010/01/27/performance-les-xebians-jouent-les-demineurs/#comments</comments> <pubDate>Wed, 27 Jan 2010 17:19:40 +0000</pubDate> <dc:creator>Pablo Lopez</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[debug]]></category> <category><![CDATA[JEE]]></category> <category><![CDATA[log4j]]></category> <category><![CDATA[VisualVM]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=3883</guid> <description><![CDATA[Le premier XKE dans nos nouveaux locaux a donné lieu à de bien curieuses scènes : des bisounours ont hué des poubelles sous le regard moqueur de pokemons ! Et, non, les cartons de déménagement ne nous sont pas tombés sur la tête. Ce n&#8217;était là que quelques uns des noms choisis par des équipes [...]]]></description> <content:encoded><![CDATA[<p><img
style="margin: 1em 1em 1em 1em; float: right;" src="http://blog.xebia.fr/wp-content/uploads/2010/01/picto.png" alt="" /></p><p>Le premier <a
title="XKE" href="http://blog.xebia.fr/2008/03/03/un-xke-chez-xebia/">XKE</a> <a
title="dans nos nouveaux locaux" href="http://blog.xebia.fr/2010/01/15/2010-xebia-fait-peau-neuve/">dans nos nouveaux locaux</a> a donné lieu à de bien curieuses scènes : des <em>bisounours</em> ont hué des <em>poubelles</em> sous le regard moqueur de <em>pokemons</em> ! Et, non, les cartons de déménagement ne nous sont pas tombés sur la tête. Ce n&#8217;était là que quelques uns des noms choisis par des équipes de 3 à 4 consultants, qui se sont mesurés dans un concours de tuning de performance, sur une application Java EE standard, buggée (<em>volontairement</em>, pour une fois) par les maîtres de cérémonie, <a
title="Guillaume Bodet" href="http://blog.xebia.fr/author/gbodet/">Guillaume Bodet</a> et <a
title="Cyrille Le Clerc" href="http://blog.xebia.fr/author/cleclerc/">Cyrille Le Clerc</a>. Tous les participants se sont vus remettre une VM, contenant un Tomcat, une application (<em>PetClinic</em> de Spring, revue et &laquo;&nbsp;corrigée&nbsp;&raquo;) et des scripts de performance JMeter. Le code source n&#8217;a, dans un premier temps, pas été fourni.</p><p>Pour tous, un seul but : faire diminuer les temps de réponses de l&#8217;application.</p><p>Les règles étaient les suivantes :</p><ul><li>Un bug n&#8217;est considéré comme trouvé que lorsqu&#8217;il a été identifié, qu&#8217;un correctif a été proposé et que la preuve est faite que ce correctif permet d&#8217;améliorer significativement les temps de réponse.</li><li>Il existe trois niveaux de difficulté, allant du bug évident à l&#8217;anomalie la plus fourbe.</li><li>Le choix des outils est libre.</li></ul><p>A vos marques&#8230; Prêts ? Débuggez !</p><h3><a
name="Prambule"></a>Préambule</h3><p>L&#8217;un des buts de ce Xke était d&#8217;être très didactique, dans les méthodes de recherche et dans l&#8217;utilisation des outils. Les bombes placées dans le code permettaient de réaliser une progression linéaire (dans la difficulté comme dans les gains attendus). Cette progression est retranscrite dans cet article et ceux qui vont suivre.</p><p>Cependant, pour différentes raisons que nous aurons l&#8217;occasion d&#8217;expliquer, l&#8217;ordre des analyses, et donc de découvertes des bugs, n&#8217;est pas celui qu&#8217;aurait choisi un champion de la performance, j&#8217;ai nommé Kirk Pepperdine. Nous lui avons soumis notre application, et nous vous exposerons sa méthode d&#8217;analyse et les raisons qui la motivent dans le dernier article de la série.</p><h3><a
name="Premiercontactaveclapplication"></a>Premier contact avec l&#8217;application&#8230;</h3><p>Ouverture du navigateur, entrée de l&#8217;url, et, pas de surprise, l&#8217;application PetClinic s&#8217;ouvre.</p><div><img
src="http://blog.xebia.fr/wp-content/uploads/2010/01/application.png" border="0" alt="" /></div><p>Premier lancement de JMeter, et première constatation : avec un seul utilisateur, l&#8217;application met en moyenne plus de 2 secondes à répondre. Inacceptable pour la plupart des sites web (surtout avec un seul utilisateur actif).</p><div><a
href="http://blog.xebia.fr/wp-content/uploads/2010/01/JMeter1.png"><img
class="alignnone size-medium wp-image-3886" title="JMeter1" src="http://blog.xebia.fr/wp-content/uploads/2010/01/JMeter1-650.png" alt="JMeter1" /></a></div><h3><a
name="etpremiersrglages"></a>&#8230; et premiers réglages</h3><p>A première vue, la machine ne semble pas à genoux, on peut donc incriminer directement l&#8217;application.<br
/> Nous allons donc chercher à savoir ce qu&#8217;elle fait. Un réflexe classique, qu&#8217;un certain nombre d&#8217;entre nous a eu, est d&#8217;aller ouvrir les logs. Catalina.out est vide, on n&#8217;a pas de répertoire de logs applicatives évident, à priori le coupable classique, la configuration log4j, est à écarter. Et pourtant&#8230; Pour savoir ce que fait réellement notre application, il est possible de réaliser une série de thread dumps. Pour cela, deux possibilités :</p><ul><li>la vieille école, qui va dumper le contenu des threads à l&#8217;aide d&#8217;un kill -3 sur la jvm.</li><li>l&#8217;école moderne, qui va utiliser <a
title="JVisualVm" href="http://blog.xebia.fr/2008/10/22/diagnostic-dune-jvm-a-distance/">JVisualVm</a> (et <a
title="ses plugins" href="https://visualvm.dev.java.net/plugins.html">ses plugins</a>) pour réaliser la même opération à l&#8217;aide d&#8217;une belle interface.</li></ul><div><a
href="http://blog.xebia.fr/wp-content/uploads/2010/01/TDLog4j.png"><img
class="alignnone size-medium wp-image-3890" title="TDLog4j" src="http://blog.xebia.fr/wp-content/uploads/2010/01/TDLog4j-650.png" alt="TDLog4j" /></a></div><p>Et là, demie surprise, notre thread actif est souvent surpris dans la méthode <code>org.apache.log4j.spi.LoggingEvent.getLocationInformation</code>. Nous aurions donc un logger actif. Nos soupçons initiaux se confirment, ne reste plus qu&#8217;à débusquer le coupable.<br
/> Nous n&#8217;avons pas (encore) le code source. Or, cette bombe plombe tellement l&#8217;application qu&#8217;il n&#8217;est pas envisageable que nous ne puissions pas la résoudre de suite. On doit donc avoir un fichier de paramétrage de la log externalisé. Là encore, VisualVm va nous aider. Dans la fenêtre overview, les paramètres de démarrage de la VM sont affichés. Et l&#8217;on voit apparaitre une directive de configuration log4j, <code>-Dlog4j.configuration</code>.</p><div><img
src="http://blog.xebia.fr/wp-content/uploads/2010/01/VMOverview.png" border="0" alt="" /></div><p>Un petit grep dans le répertoire de lancement de Tomcat (<code>$TOMCAT_HOME/bin</code>), et nous voyons apparaître dans le setEnv.sh la ligne <code>-Dlog4j.configuration=file:$CATALINA_HOME/conf/log.xml</code>. Et si nous ouvrons ce fichier, le root Logger est bien en DEBUG. Mais aucune directive spécifique pour logger ailleurs que dans la console. Tout devrait donc aller dans catalina.out. Ca sent la redirection &#8216;sauvage&#8217;. Continuons à parcourir les fichiers de lancement. Un petit tour dans catalina.sh, et surprise, une belle redirection Unix <code>"$CATALINA_BASE"/logs/catalina.out 1&gt; /var/log/catalina/tomcat.log  &amp;</code><br
/> Et en ouvrant ce fichier, on comprend mieux le temps perdu : des milliers de lignes de debug !</p><div><a
href="http://blog.xebia.fr/wp-content/uploads/2010/01/debugLog.png"><img
class="alignnone size-medium wp-image-3895" title="debugLog" src="http://blog.xebia.fr/wp-content/uploads/2010/01/debugLog-650.png" alt="debugLog" /></a></div><p>Celles ci ont d&#8217;ailleurs une particularité sympathique : à chaque ligne de debug, le numero de ligne de la classa Java est indiqué.<br
/> C&#8217;est pratique ! Pourquoi ne met on pas systématiquement en place cette configuration sur nos projets ?<br
/> Un petit tour dans la documentation Log4J nous apprend :</p><div><a
href="http://blog.xebia.fr/wp-content/uploads/2010/01/docLog4J.png"><img
class="alignnone size-medium wp-image-3896" title="docLog4J" src="http://blog.xebia.fr/wp-content/uploads/2010/01/docLog4J-650.png" alt="docLog4J" /></a></div><p>Log4J nous prévient, ces méthodes sont sous performantes. Si l&#8217;on creuse un peu dans le source, on trouve la classe affichant les pattern %M et %L, <code>org.apache.log4j.spi.LocationInfo</code>, qui contient le constructeur suivant :</p><pre class="brush: java; title: ; notranslate">
public LocationInfo(Throwable t, String fqnOfCallingClass) {
if(t == null || fqnOfCallingClass == null)
return;
String s;
// Protect against multiple access to sw.
synchronized(sw) {
t.printStackTrace(pw);
s = sw.toString();
sw.getBuffer().setLength(0);
}
[...]
</pre><p>Autrement dit, pour chaque ligne de log, Log4J génère une stackTrace pour pouvoir récupérer le numéro de la ligne et le nom de la méthode. Pas vraiment performant.<br
/> Modifions donc le pattern et observons le résultat.</p><div><a
href="http://blog.xebia.fr/wp-content/uploads/2010/01/JMeter2.png"><img
class="alignnone size-medium wp-image-3887" title="JMeter2" src="http://blog.xebia.fr/wp-content/uploads/2010/01/JMeter2-650.png" alt="JMeter2" /></a></div><ul><li> Suppression de %M:%L dans le pattern du Logger</li><li> Temps moyen de 2,3 s à 2,0 s pour 1 utilisateur</li><li> 2 points pour l&#8217;équipe qui a trouvé</li></ul><p>Toujours concernant ce fichier de log, nous voyons apparaître une ligne ne respectant pas le <em>PatternLayout</em> de Log4J, préfixée par <em>Hibernate</em>, qui trace une requête SQL. Gardons cette ligne en mémoire, nous y repenserons quand nous aurons le code source.</p><p>Deuxième amélioration immédiate envisageable, une application, qui plus est en production, ne devrait pas avoir besoin d&#8217;un niveau de log aussi fin. Passons le donc à ERROR.</p><div><a
href="http://blog.xebia.fr/wp-content/uploads/2010/01/JMeter3.png"><img
class="alignnone size-medium wp-image-3888" title="JMeter3" src="http://blog.xebia.fr/wp-content/uploads/2010/01/JMeter3-650.png" alt="JMeter3"  /></a></div><ul><li> Logger de DEBUG à ERROR</li><li> Temps moyen de 2,0 s à 1,75 s pour 1 utilisateur</li><li> 1 point pour l&#8217;équipe qui a trouvé</li></ul><p>Nous avons fait un sort au logger. Mais nous n&#8217;en avons pas encore fini avec la configuration out-of-the-box de cette application.</p><h4><a
name="Source"></a>Source</h4><p><a
title="Image libre de droits" href="http://commons.wikimedia.org/wiki/File:Magnifying_glass_and_Stamp_tong.jpg">Image libre de droits</a></p><div
class="shr-publisher-3883"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F01%2F27%2Fperformance-les-xebians-jouent-les-demineurs%2F' data-shr_title='Performance%2C+les+Xebians+jouent+les+d%C3%A9mineurs'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F01%2F27%2Fperformance-les-xebians-jouent-les-demineurs%2F' data-shr_title='Performance%2C+les+Xebians+jouent+les+d%C3%A9mineurs'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/01/27/performance-les-xebians-jouent-les-demineurs/feed/</wfw:commentRss> <slash:comments>6</slash:comments> </item> <item><title>Devoxx &#8211; Jour 4 &#8211; Java Performance Tuning</title><link>http://blog.xebia.fr/2009/11/27/devoxx-jour-4-java-performance-tuning/</link> <comments>http://blog.xebia.fr/2009/11/27/devoxx-jour-4-java-performance-tuning/#comments</comments> <pubDate>Fri, 27 Nov 2009 16:37:11 +0000</pubDate> <dc:creator>Michaël Figuière</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[Devoxx]]></category> <category><![CDATA[Performances]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=3412</guid> <description><![CDATA[A Devoxx, deux sessions étaient dédiées au thème du tuning de performance en Java : Performance for the performance-shy par Holly Cummins et The not so dark art of performance tunning par Kirk Pepperdine et Dan Hardiker. Nous nous attardons ici sur cette dernière. Kirk Pepperdine (photo ci-contre) est Java Champion et possède une expertise [...]]]></description> <content:encoded><![CDATA[<p><img
src="http://blog.xebia.fr/wp-content/uploads/2009/11/kirk-pepperdine.jpg" border="0" alt="Kirk Pepperdine - Devoxx09" style=" margin: 1em 1em 1em 1em; float: right;" /></p><p>A Devoxx, deux sessions étaient dédiées au thème du <em>tuning</em> de performance en Java : <a
href="http://www.devoxx.com/display/DV09/Performance+for+the+performance-shy" title="Performance for the performance-shy" >Performance for the performance-shy</a> par Holly Cummins et <a
href="http://www.devoxx.com/display/DV09/The+not+so+dark+art+of+Performance+Tuning" title="The not so dark art of performance tunning" >The not so dark art of performance tunning</a> par Kirk Pepperdine et Dan Hardiker. Nous nous attardons ici sur cette dernière.</p><p>Kirk Pepperdine (photo ci-contre) est <a
href="https://java-champions.dev.java.net/" title="Java Champion" >Java Champion</a> et possède une expertise reconnue dans le domaine des performances des applications Java. On se souvient également de sa présentation <a
href="http://www.parisjug.org/xwiki/bin/view/Meeting/20080408">en avril 2008 au ParisJUG</a> où il avait fournit un aperçu des problématiques liées à ce sujet.<br
/> Dan Hardiker est pour sa part le fondateur d&#8217;une entreprise spécialisée dans l&#8217;<em>hosting</em> de solutions basées sur Confluence.</p><p>La session qu&#8217;ils ont tous deux présentée à Devoxx ne se voulait pas exhaustive sur le sujet de la performance, bien trop vaste et complexe pour être traité en une heure, mais cherchait surtout à mettre en avant des principes et des attitudes à adopter.</p><p>&nbsp;<br
/> <br
/>&nbsp;<br
/> <br
/>&nbsp;</p><h3><a
name="Lesantipatternsdetuningdeperfo"></a>Les <em>anti-patterns</em> de <em>tuning</em> de performance</h3><p>La session commence avec la présentation de deux <em>anti-patterns</em> couramment rencontrés lors des procédures d&#8217;amélioration de performance. Ces <em>anti-patterns</em> avaient été formalisés il y a trois ans par Kirk Pepperdine : l&#8217;absence de test de montée en charge (<a
href="http://kirk.blog-city.com/antipattern_nostress_testing.htm" title="No stress testing" ><em>No stress testing</em></a>) et le tir à l&#8217;aveugle (<a
href="http://kirk.blog-city.com/proposed_antipattern_shot_in_the_dark.htm" title="Shot in the dark" ><em>Shot in the dark</em></a>).</p><h4><a
name="Aucuntestdemonteencharge"></a>Aucun test de montée en charge</h4><p>Il s&#8217;agit là d&#8217;un cas courant : une application, un nouveau système ou simplement une mise à jour majeure est mise en production sans avoir effectué le moindre test de montée en charge. L&#8217;estimation de la viabilité de l&#8217;installation se faisant alors sur l&#8217;expérience passée et la réactivité de l&#8217;application lors des phases de recette.</p><p>Bien sûr cela peut très bien se passer. Mais dans certain cas, il en résulte une pure et simple indisponibilité de service due à un écroulement des performances ayant entraîné une saturation des serveurs.</p><p>Les tests de montée en charge sont indispensables pour connaître et éventuellement corriger par avance les limitations des applicatifs que l&#8217;on va mettre en production.</p><h4><a
name="Tirlaveugle"></a>Tir à l&#8217;aveugle</h4><p>Il s&#8217;agit là également d&#8217;un comportement courant, mais conduisant à des actions inefficaces voir erronées. Lorsqu&#8217;un problème de performance est constaté, l&#8217;équipe en charge de l&#8217;application fait quelques suppositions et procède immédiatement à des ajustements en conséquence.</p><p>Là encore, ce type de comportement peut conduire à une résolution du problème, mais la procédure manque de précision et peut mener à une aggravation de la situation ou à des solutions mal maitrisées et difficilement explicables.</p><p>Lorsqu&#8217;un problème de performance est constaté, seule la prise de mesure permet de mettre en œuvre des corrections sérieuses car décidées en toute connaissance de cause.</p><h3><a
name="Lescausesdaugmentationdutempsd"></a>Les causes d&#8217;augmentation du temps de réponse</h3><p>Il est important de connaître les points pouvant être responsables de l&#8217;augmentation du temps de réponse au sein d&#8217;un système. Si l&#8217;on considère un système 3 tiers classique, les localisations de ces points sont nombreuses :</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2009/11/performance.png" border="0" alt="" /></div><p>De part la nature distribuée de l&#8217;architecture 3 tiers, le temps de réponse est en général consommé autour de l&#8217;envoi des requêtes et de la réception des réponses. Cette latence peut alors être causée par l&#8217;OS, la JVM, le <em>middleware</em> ou par l&#8217;application. Il est important de considérer l&#8217;ensemble de ces acteurs.</p><h3><a
name="Lesoutilsdediagnostic"></a>Les outils de diagnostic</h3><p>Kirk Pepperdine et Dan Hardiker ont également présenté deux outils très courants et simples d&#8217;utilisation pour faciliter le diagnostic des applications présentant des problèmes de performances :</p><ul><li><a
href="https://visualvm.dev.java.net/" title="VisualVM" >VisualVM</a> : cet outil très populaire est disponible en standard dans le JDK depuis sa version 6.0. Il permet d&#8217;analyser le comportement du <em>garbage collector</em> et d&#8217;observer les métriques JMX d&#8217;un serveur d&#8217;application.</li><li><a
href="https://tda.dev.java.net/" title="TDA (Thread Dump Analyser)" >TDA (Thread Dump Analyser)</a> : ce <em>plugin</em> pour VisualVM permet d&#8217;effectuer des analyses de <em>thread dumps</em>. Cette analyse permet d&#8217;aider à localiser les <em>locks</em> ou les parties de code consommant la majorité du CPU en montrant l&#8217;activité de chaque <em>thread</em> d&#8217;une JVM à un instant donné.</li></ul><h3><a
name="Conclusion"></a>Conclusion</h3><p>A Devoxx, il est toujours intéressant d&#8217;observer la fréquentation des différentes sessions. Si le succès de certains sujets tels que JEE 6, Spring 3.0, Maven 3.0 ou encore JDK7 est très facilement prévisible, celui du <em>tuning</em> de performance en Java est moins évident à priori. Pourtant les deux sessions dédiées à ce sujet ont fait salle comble. Cette tendance montre que ce sujet concerne beaucoup de monde mais reste peu maitrisé&#8230;</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2009/11/public.jpg" border="0" alt="" /></div><p>L&#8217;approche de Kirk Pepperdine et Dan Hardiker présentée ici est intéressante car ils s&#8217;efforcent de considérer la problématique des performances d&#8217;un point de vue global : alors que le développeur se focalise principalement sur son code pour améliorer les performances d&#8217;une application, il est nécessaire de considérer la question de la performance à tous les niveaux &#8211; l&#8217;application, le <em>middleware</em>, la JVM, la base de données, le matériel, le réseau &#8211; pour être efficace. En ce sens, la performance est une problématique globale et non locale.</p><p>Les lecteurs intéressés par ce sujet noteront que Kirk Pepperdine proposera pour la première fois en France, <a
href="http://blog.xebia.fr/2009/11/06/formation-java-performance-tuning-par-kirk-pepperdine/" title="une formation en Janvier  Paris" >une formation en Janvier à Paris</a> où il aura l&#8217;occasion de développer en détail les connaissances théoriques et pratiques liées au <em>tuning</em> de performance en Java.</p><div
class="shr-publisher-3412"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F11%2F27%2Fdevoxx-jour-4-java-performance-tuning%2F' data-shr_title='Devoxx+-+Jour+4+-+Java+Performance+Tuning'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F11%2F27%2Fdevoxx-jour-4-java-performance-tuning%2F' data-shr_title='Devoxx+-+Jour+4+-+Java+Performance+Tuning'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/11/27/devoxx-jour-4-java-performance-tuning/feed/</wfw:commentRss> <slash:comments>4</slash:comments> </item> <item><title>Formation Java Performance Tuning par Kirk Pepperdine</title><link>http://blog.xebia.fr/2009/11/06/formation-java-performance-tuning-par-kirk-pepperdine/</link> <comments>http://blog.xebia.fr/2009/11/06/formation-java-performance-tuning-par-kirk-pepperdine/#comments</comments> <pubDate>Fri, 06 Nov 2009 16:31:12 +0000</pubDate> <dc:creator>Xebia France</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[J2EE]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=3071</guid> <description><![CDATA[Xebia organise une formation d’optimisation des performances d’applications Java/J2EE avec Kirk Pepperdine, une première en France, entre le 18 et 21 janvier 2010. Pour ceux qui ne le connaissent pas, Kirk Pepperdine dispose de plus de 15 ans d’expérience dans les technologies orientées objets et l’optimisation de la performance. Figure emblématique du monde Java et [...]]]></description> <content:encoded><![CDATA[<p>Xebia organise une <a
href="http://www.xebia.fr/sites/default/files/formation-java-performance-tuning-kirk-pepperdine.pdf">formation d’optimisation des performances d’applications Java/J2EE</a> avec <strong>Kirk Pepperdine</strong>, une première en France, entre le 18 et 21 janvier 2010.</p><p>Pour ceux qui ne le connaissent pas, Kirk Pepperdine dispose de plus de 15 ans d’expérience dans les technologies orientées objets et l’optimisation de la performance. Figure emblématique du monde Java et élu <em>&laquo;&nbsp;Champion JAVA&nbsp;&raquo;</em> en 2005, Kirk est reconnu comme le référent de l’optimisation de performance Java. Il est le DSI de Kodewerk Ltd et le principal contributeur de <a
href="http://javaperformancetuning.com">javaperformancetuning.com</a>.</p><p>Cette formation approfondie de 4 jours permettra aux stagiaires d’obtenir les compétences nécessaires pour optimiser la performance de leurs applications Java/J2EE. Vous aborderez pendant cette formation tous les aspects de la performance :</p><ul><li>L’outillage nécessaire.</li><li>Les méthodologies à appliquer.</li><li>Les concepts d’architecture sous jacents à la performance.</li><li>Les meilleures pratiques.</li><li>Le benchmarking.</li><li>La gestion de mémoire.</li></ul><p>Si cette formation vous intéresse, n’hésitez pas à contacter Roderic Pratt au 06.09.69.05.49.</p><div
class="shr-publisher-3071"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F11%2F06%2Fformation-java-performance-tuning-par-kirk-pepperdine%2F' data-shr_title='Formation+Java+Performance+Tuning+par+Kirk+Pepperdine'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F11%2F06%2Fformation-java-performance-tuning-par-kirk-pepperdine%2F' data-shr_title='Formation+Java+Performance+Tuning+par+Kirk+Pepperdine'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/11/06/formation-java-performance-tuning-par-kirk-pepperdine/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Booster vos recherches avec Oracle Coherence</title><link>http://blog.xebia.fr/2009/10/14/booster-vos-recherches-avec-oracle-coherence/</link> <comments>http://blog.xebia.fr/2009/10/14/booster-vos-recherches-avec-oracle-coherence/#comments</comments> <pubDate>Wed, 14 Oct 2009 08:36:24 +0000</pubDate> <dc:creator>Benoit Moussaud</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[Coherence]]></category> <category><![CDATA[Oracle]]></category> <category><![CDATA[Performances]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=2996</guid> <description><![CDATA[Oracle Coherence est une solution de Data Grid. Elle permet de constituer des grilles de données à l&#8217;aide de 4 types de caches: Cache distribué: l&#8217;ensemble des données est réparti sur les différents nœuds qui composent le cluster Coherence. Afin de garantir une bonne tolérance aux pannes, les données peuvent être sauvegardées sur un ou [...]]]></description> <content:encoded><![CDATA[<p>Oracle Coherence est une solution de <a
href="http://blog.xebia.fr/2009/05/06/paris-jug-soiree-grid-computing-le-12-mai/" title="Data Grid" >Data Grid</a>. Elle permet de constituer des grilles de données à l&#8217;aide de 4 types de caches:</p><ul><li>Cache distribué: l&#8217;ensemble des données est réparti sur les différents nœuds qui composent le cluster Coherence. Afin de garantir une bonne tolérance aux pannes, les données peuvent être sauvegardées sur un ou plusieurs nœuds du cluster. Cette typologie est extrêmement extensible : il suffit d&#8217;ajouter des nouveaux nœuds pour augmenter la capacité globale du cache.</li><li>Cache répliqué: l&#8217;ensemble des données est répliqué sur l&#8217;ensemble des nœuds du cluster. La modification d&#8217;une entrée sera propagée à l&#8217;ensemble des nœuds. Cette typologie permet d&#8217;offrir un accès très rapide en lecture car un seul nœud est sollicité dans l&#8217;opération. La contre-partie est que les opérations d&#8217;écriture sont lentes et que la taille du cache est indépendante du nombre de nœuds qui composent le cluster.</li><li>Cache local: les données sont conservées exclusivement sur la JVM.</li><li>Near Cache: il permet d&#8217;offrir le meilleur des caches de type &#8216;Répliqué&#8217; (Performance) et de type &#8216;Distribué&#8217; (Extensibilité) en fournissant un accès rapide aux données accédées le plus fréquemment et le plus récemment. Il est composé de 2 parties:</li><ul><li>le &#8216;front-cache&#8217; pour les accès locaux, de petite taille, typiquement un cache Local (Local Cache),</li><li>le &#8216;back-cache&#8217; un cache de plus grande envergure, typiquement un cache distribué (Distributed Cache), qui contient l&#8217;ensemble des données avec leurs éventuelles sauvegardes.</li></ul></ul><p>Le point fort d&#8217;Oracle Coherence est de proposer la même API quelque soit le type de cache. Il est donc possible, par simple configuration, de modifier le type de cache et de l&#8217;adapter en fonction des besoins ou de l&#8217;environnement: cache local en &laquo;&nbsp;Développement&nbsp;&raquo;, cache distribué en &laquo;&nbsp;Intégration&nbsp;&raquo;, &laquo;&nbsp;Near&nbsp;&raquo; cache en &laquo;&nbsp;Production&nbsp;&raquo;.</p><p>En première approche, l&#8217;API d&#8217;Oracle Coherence est extrêmement simple : elle se résume à obtenir une <a
href="http://java.sun.com/javase/6/docs/api/java/util/Map.html" title="Map" ><code>Map</code></a> et à la manipuler par les opérations habituelles: put(), get(), keySet(), entrySet()&#8230;.</p><pre class="brush: java; title: ; notranslate">
import com.tangosol.net.CacheFactory;
Map cache = CacheFactory.getCache(&quot;moncache&quot;);        //1. Récupération d'une instance de cache,
cache.put(&quot;benoit&quot;,&quot;moussaud&quot;);                       //2. Ajout d'un élément dans le cache
String name = (String)cache.get(&quot;benoit&quot;);            //3. Recherche par sa clé d'un élément dans le cache
assert name.equals(&quot;moussaud&quot;);
</pre><p>Le type de cache est déduit du nom du cache. Il est configuré dans le fichier <code>coherence-cache-config.xml</code> inclus dans <code>coherence.jar</code>. Par défaut, les règles suivantes sont appliquées:</p><table
cellspacing="0" cellpadding="5" style="border: 1px solid black"><tr><td
bgcolor="#663366" style="color: #ffffff; border: 1px solid black"> Nom du cache</td><td
bgcolor="#663366" style="color: #ffffff; border: 1px solid black"> Type</td></tr><tr><td
style="border: 1px solid black"> <code>dist-*</code></td><td
style="border: 1px solid black"> distribué</td></tr><tr><td
style="border: 1px solid black"> <code>near-*</code></td><td
style="border: 1px solid black"> near cache</td></tr><tr><td
style="border: 1px solid black"> <code>repl-*</code></td><td
style="border: 1px solid black"> repliqué</td></tr><tr><td
style="border: 1px solid black"> <code>local-*</code></td><td
style="border: 1px solid black"> local</td></tr><tr><td
style="border: 1px solid black"> sinon</td><td
style="border: 1px solid black"> distribué</td></tr></table><p>Si l&#8217;on veut appliquer ses propres règles, il faut définir son propre fichier de configuration et indiquer son emplacement au lancement de Coherence avec la propriété système <code>tangosol.coherence.cacheconfig</code>.</p><p>La suite de l&#8217;article va montrer comment interroger un cache Coherence autrement que par une clé dans une Map.</p><h4><a
name="Unservicederecherchedecommunes"></a>Un service de recherche de communes&#8230;</h4><p>Prenons un service qui permet de rechercher l&#8217;ensemble des communes françaises en précisant le début de leur nom.</p><pre class="brush: java; title: ; notranslate">
public interface CatalogService {
	public List&lt;Commune&gt; getCommuneByName(String name);
}
</pre><p>Une implémentation classique est de créer une table &#8216;COMMUNE&#8217; dans une base de données, d&#8217;y insérer les ensembles des communes de France (38206 dans mon exemple) avec leur libellé, un code postal et un code Insee, et d&#8217;effectuer la requête SQL <code>SELECT ID, DEP_CODE, CODE_INSEE, LIBELLE FROM COMMUNE where LIBELLE like #name#</code>.</p><p>Voici le résultat d&#8217;un benchmark du service avec pour paramètre la première lettre de la commune (de A à Z)</p><div
id="attachment_3003" class="wp-caption aligncenter" style="width: 643px"><img
src="http://blog.xebia.fr/wp-content/uploads/2009/10/bdd.png" alt="Résultat du benchmark Base de données" title="Résultat du benchmark Base de données" width="633" height="426" class="size-full wp-image-3003" /><p
class="wp-caption-text">Benchmark Base de données</p></div><p>Le temps de réponse du service est mauvais et proportionnel au nombre de communes retournées</p><h4><a
name="Coherencelarescousse"></a>&#8230;Coherence à la rescousse&#8230;</h4><p>La première idée est de placer le résultat de la recherche dans un cache avec pour clé le paramètre de recherche. Ce type de conception est efficace seulement si le nombre de filtres est fini, par exemple s&#8217;il résulte d&#8217;une sélection d&#8217;une combo-box dans une page web. Si la valeur du filtre est moins contrainte, le service sera appelé par un grand nombre de filtres différents et donc le cache risque d&#8217;être peu efficace (à moins de disposer d&#8217;une mémoire infinie de manière à conserver toutes les requêtes !).</p><p>La seconde idée est de charger dans un cache l&#8217;ensemble des communes et d&#8217;effectuer une recherche directement dans le cache. L&#8217;API Coherence offre la notion de <code>Filter</code></p><pre class="brush: java; title: ; notranslate">
public class CatalogServiceWithCoherence implements CatalogService,
     private final NamedCache cacheCommunes = CacheFactory.getCache(&quot;Commune&quot;);
     public List&lt;Commune&gt; getCommuneByName(String name) {
         Filter filter = new LikeFilter(&quot;getName&quot;, name + &quot;%&quot;, false);
         return performSearch(filter);
     }
     @SuppressWarnings(&quot;unchecked&quot;)
     private List&lt;Commune&gt; performSearch(Filter filter) {
         Set&lt;Map.Entry&lt;Object, Commune&gt;&gt; entrySet=cacheCommunes
                 .entrySet(filter);
         List&lt;Commune&gt; result = new ArrayList&lt;Commune&gt;(entrySet.size());
         for (Map.Entry&lt;Object, Commune&gt; e : entrySet) {
             result.add(e.getValue());
         }
         return result;
     }
}
</pre><p>Appliquons le même benchmark.</p><div
id="attachment_3005" class="wp-caption aligncenter" style="width: 613px"><img
src="http://blog.xebia.fr/wp-content/uploads/2009/10/coherence-filter.png" alt="Résultat du benchmark Coherence avec Filtre" title="Résultat du benchmark Coherence avec Filtre" width="603" height="428" class="size-full wp-image-3005" /><p
class="wp-caption-text">Résultat du benchmark Coherence avec Filtre</p></div><p>Le temps de réponse du service est meilleur (autour de 500 ms) mais constant. Il y a donc un gain par rapport aux requêtes qui retournent beaucoup d&#8217;éléments (A,B,C,L,S,..) mais une perte sur les requêtes qui retournent peu d&#8217;éléments. Donc plus le filtre sera sélectif, moins la recherche dans le cache sera efficace.</p><p>Ceci se comprend mieux si on affine l&#8217;étude de l&#8217;API Coherence. L&#8217;interface <a
href="http://download.oracle.com/otn_hosted_doc/coherence/350/com/tangosol/util/Filter.html" title="Filter" >Filter</a> définit une seule méthode: <code>evaluate</code></p><pre class="brush: java; title: ; notranslate">
package com.tangosol.util;
public abstract interface Filter
{
  public abstract boolean evaluate(Object paramObject);
}
</pre><p>Donc une recherche dans le cache par filtre se résume à parcourir l&#8217;ensemble des entrées de la <code>Map</code> et à appliquer le filtre passé en paramètre.</p><h4><a
name="Encoreplusrapideavecunindex"></a>&#8230;Encore plus rapide avec un index</h4><p>Si on examine de plus près le filtre utilisé <a
href="http://download.oracle.com/otn_hosted_doc/coherence/350/com/tangosol/util/filter/LikeFilter.html" title="<code>LikeFilter</code>" ><code>LikeFilter</code></a>, on peut noter qu'il implémente l'interface <a
href="http://download.oracle.com/otn_hosted_doc/coherence/350/com/tangosol/util/filter/IndexAwareFilter.html" title="IndexAwareFilter" ><code>IndexAwareFilter</code></a>. Il est donc possible d'indexer le contenu d'un cache Coherence. Le code ci-dessous ajoute un index au cache "IndexedCommune": pour chaque entrée ajoutée au cache, il va extraire et indexer la valeur de la propriété "Name" (getName()).</p><pre class="brush: java; title: ; notranslate">
NamedCache cache = CacheFactory.getCache(&quot;IndexedCommune&quot;);
cache.addIndex(new ReflectionExtractor(&quot;getName&quot;), true, null);
</pre><p>Appliquons le benchmark.</p><div
id="attachment_3006" class="wp-caption aligncenter" style="width: 632px"><img
src="http://blog.xebia.fr/wp-content/uploads/2009/10/coherence-indexed-filter.png" alt="Benchmark Coherence avec filtre indexé" title="Benchmark Coherence avec filtre indexé" width="622" height="427" class="size-full wp-image-3006" /><p
class="wp-caption-text">Benchmark Coherence avec filtre indexé</p></div><p>Avec l'ajout de l'index, le temps de réponse du service a encore nettement chuté et reste proportionnel au nombre de communes retourné. Donc si le filtre est sélectif, le temps de réponse sera très bon.</p><p>En moyenne, la première solution a divisé le temps de réponse par 5, la seconde par 80. Cependant il faut garder à l'esprit qu'un accès à une valeur par son index (<code>cache.get(key)</code>) reste beaucoup plus performant que l'utilisation des <code>Filters</code>. Leurs utilisations doivent rester des exceptions.</p><h4><a
name="Conclusion"></a>Conclusion</h4><p>Les solutions de "Data Grid" modernes comme Oracle Coherence offrent maintenant des services de haut niveau, semblables à ceux offerts par des SGBD, comme la gestion de la concurrence, des transactions, des indexs, du partitionnement, qui permettent d'améliorer nettement les performances d'une application J2EE.</p><h4><a
name="Sources"></a>Sources</h4><p>Vous retrouverez l'ensemble des sources présentées dans ce billet dans le <a
href="http://code.google.com/p/xebia-france/source/browse/trunk/grid/coherence-filter/" title="repository SVN de Xebia France" >repository SVN de Xebia France</a>.</p><h4><a
name="Rfrences"></a>Références</h4><ul><li><a
href="http://www.oracle.com/technology/products/coherence/index.html " title="Oracle Coherence" >Oracle Coherence</a> (Site Officiel)</li><li><a
href=" http://blog.xebia.fr/2009/08/26/les-caches-ces-armes-a-manipuler-avec-precaution/" title="Les caches ces armes  manipuler avec prcaution" >Les caches, ces armes à manipuler avec précaution</a></li><li><a
href=" http://blog.xebia.fr/2009/05/06/paris-jug-soiree-grid-computing-le-12-mai/ " title="Paris JUG  Soire Data Grid le 12 mai" >Paris JUG : Soirée Data Grid le 12 mai</a></li><li><a
href=" http://wiki.tangosol.com/display/COH/Oracle+Coherence+Knowledge+Base+Home " title="Oracle Coherence Knowledge Base Home " >Oracle Coherence Knowledge Base Home </a></li></ul><div
class="shr-publisher-2996"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F10%2F14%2Fbooster-vos-recherches-avec-oracle-coherence%2F' data-shr_title='Booster+vos+recherches+avec+Oracle+Coherence'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F10%2F14%2Fbooster-vos-recherches-avec-oracle-coherence%2F' data-shr_title='Booster+vos+recherches+avec+Oracle+Coherence'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/10/14/booster-vos-recherches-avec-oracle-coherence/feed/</wfw:commentRss> <slash:comments>4</slash:comments> </item> <item><title>Les caches, ces armes à manipuler avec précaution</title><link>http://blog.xebia.fr/2009/08/26/les-caches-ces-armes-a-manipuler-avec-precaution/</link> <comments>http://blog.xebia.fr/2009/08/26/les-caches-ces-armes-a-manipuler-avec-precaution/#comments</comments> <pubDate>Wed, 26 Aug 2009 05:28:32 +0000</pubDate> <dc:creator>Erwan Alliaume</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[bases de données]]></category> <category><![CDATA[cache]]></category> <category><![CDATA[cluster]]></category> <category><![CDATA[Ehcache]]></category> <category><![CDATA[JBoss Cache]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=2698</guid> <description><![CDATA[Il n&#8217;y a rien de plus simple qu&#8217;un framework de cache &#8230; enfin il paraît. La majorité d&#8217;entre eux fonctionne sur un même principe élémentaire, celui que vous décideriez probablement d&#8217;adopter si l&#8217;on vous demandait d&#8217;en développer un : une bonne vieille HashMap ! Logique puisqu&#8217;il ne s&#8217;agit finalement que d&#8217;organiser manuellement un index d&#8217;objets [...]]]></description> <content:encoded><![CDATA[<p>Il n&#8217;y a rien de plus simple qu&#8217;un framework de cache &#8230; enfin il paraît. La majorité d&#8217;entre eux fonctionne sur un même principe élémentaire, celui que vous décideriez probablement d&#8217;adopter si l&#8217;on vous demandait d&#8217;en développer un : une bonne vieille <code>HashMap</code> ! Logique puisqu&#8217;il ne s&#8217;agit finalement que d&#8217;organiser manuellement un index d&#8217;objets vous permettant d&#8217;accéder le plus rapidement possible à vos données plutôt que d&#8217;aller les piocher dans des sources de données plus gourmandes. Et pourtant, leur utilisation est soumise à un certain nombre de cas d&#8217;utilisations offrant de belles occasions de se planter en beauté ! Cet article décrit quelques-uns de ces problèmes, plus précisément les problèmes liés au cache L2 hibernate et caches distribués.</p><h3><a
name="Incohrencesdesdonnesestceunpro"></a>Incohérences des données, est-ce un problème ?</h3><p>C&#8217;est probablement l&#8217;une des phobies les plus répandues dans le monde informatique, partagées aussi bien par les développeurs, les architectes que les clients : l&#8217;incohérence des données. Phobie compréhensible puisque les données représentent la valeur ajoutée même de votre métier, sans elles, pas de transactions donc pas de rentrées d&#8217;argent. Et pourtant, nous constatons trop souvent que cette phobie est le point de départ de bien des problèmes. Combien d&#8217;usines à Shadocks ont été montées à tort ? Combien de fausses bonnes idées ont coulé des projets ? Ceci vient souvent d&#8217;une mauvaise interprétation des besoins du client : la perte ou l&#8217;incohérence des données est dans bien des cas acceptables. Alors, pourquoi s&#8217;obstiner à se rajouter systématiquement des aiguilles dans la poupée vaudou de votre projet.</p><p>En résumé, les problématiques liées à la cohérence des données d&#8217;un cache distribué sont les mêmes que celles d&#8217;une source de données partagée telle qu&#8217;une base de données : mises à jour concurrentes, échecs de mise à jour, fiabilité des contraintes&#8230; L&#8217;ajout d&#8217;un cache distribué n&#8217;est donc pas anodin, vous rajoutez avec lui une complexité complémentaire à votre système.</p><h3><a
name="Stratgiesdenotificationsmisesj"></a>Stratégies de notifications, mises à jour synchrones ou asynchrones</h3><p>En cas de modification locale d&#8217;un élément d&#8217;un des caches d&#8217;un cluster, deux solutions s&#8217;offrent à vous pour répercuter celle-ci sur les différents nœuds de votre cluster :</p><ul><li>par copie, vous envoyez un message contenant le nouvel objet (ou un différentiel de celui-ci)</li><li>par invalidation, vous envoyez une notification demandant aux autres membres du cluster d&#8217;effacer tout ou partie de leurs caches liés à cet élément.</li></ul><p>Si vous êtes le seul à connaître l&#8217;existence d&#8217;un élément (i.e. l&#8217;objet a été créé localement et n&#8217;est directement disponible dans aucune source de données), vous n&#8217;avez d&#8217;autre choix que de propager vos modifications par copie. Dans tous les autres cas, c&#8217;est à vous de choisir la meilleure option en fonction du type de vos données.</p><p>Il est souvent recommandé de privilégier les mises à jour par copie. Celles-ci évitent le rechargement complet des caches de votre cluster. Suivant le type de données, vider entièrement un cache peut s&#8217;avérer désastreux : l&#8217;invalidation peut provoquer une demande massive d&#8217;objets simultanée à partir des différents nœuds d&#8217;un cluster. Les caches regroupent souvent des données homogènes dont les objets sont liés les uns aux autres. Il est facile de noyer la base sous une pluie de requêtes gourmandes en ressources et simultanée. Le but premier de votre cache distribué n&#8217;était pas de limiter les accès à la base de données ? Cet effet est encore amplifié par la fréquence de mise à jour de vos données. Dernier conseil, une mise à jour par copie perd de son intérêt lorsque que la durée de vie maximale des objets de vos caches est faible, surveillez votre time-to-live.</p><p>Pourtant, la mise à jour par copie n&#8217;est pas sans risque, vous exposez vos objets à de potentielles désynchronisations d&#8217;états entre les différents nœuds de votre cluster. En effet, la majorité des mécanismes de mise à jour par copie n&#8217;assurent pas la réussite de celle-ci. Par exemple, si une micro coupure réseau intervient lors de la demande d&#8217;une mise à jour d&#8217;un objet entre 2 serveurs, il est courant de constater qu&#8217;au final les deux objets ne soient pas identiques. (il en est d&#8217;ailleurs le même pour les mécanismes d&#8217;invalidation). Si les mécanismes de copies asynchrones sont rapides, ils ne garantissent pas la bonne exécution de leur service. Au contraire, d&#8217;autres mécanismes synchrones le permettent, mais à quel prix pour vos utilisateurs ? Êtes-vous prêt à stopper l&#8217;activité de votre serveur en attendant d&#8217;obtenir les accusés de réception de l&#8217;ensemble des nœuds de votre cluster.</p><table
width="95%" align="center"><tr><th
width="50%"> Mise à jour Asynchrone VS Synchrone</th><th> Mise à jour par copie VS invalidation</th></tr><tr><td> Réponse rapide contre cohérence des données</td><td> Multiplicité des notifications contre rechargement massif de la base</td></tr></table><h3><a
name="AttentionauCacheLHibernate"></a>Attention au Cache L2 Hibernate</h3><p>Lorsque l&#8217;on sort le Cache L2 de la trousse à outils, on en attend souvent un résultat miraculeux. Pourtant, si cette solution est simple à mettre en place, elle n&#8217;est pas magique pour autant. Il est donc important d&#8217;en connaître les principales caractéristiques.</p><p>Les manipulations de données des caches s&#8217;effectuent le plus souvent par l&#8217;ajout ou la récupération <em>d&#8217;un seul et unique objet</em>. Les caches proposent tous une manipulation simple par le biais de ces simples méthodes : <code>cache.put( Element element )</code> pour l&#8217;ajout d&#8217;un objet dans le cache et <code>cache.get ( Object key )</code> pour la récupération. Et ce sont ces mêmes méthodes que le cache L2 Hibernate va utiliser. Ainsi, la mise à jour du cache, quelque soit son implémentation, va passer par une mise à jour objet par objet. Ceci s&#8217;avère peu performant lorsque le cache doit mettre à jour de volumineuses listes d&#8217;objets.</p><p>Vous l&#8217;avez compris, les effets peuvent vite devenir catastrophiques en cas de mauvaise utilisation des associations Hibernate. Il est parfois pertinent d&#8217;utiliser un système de cache externe sans utiliser le cache L2 Hibernate. Afin d&#8217;appuyer cela, je vous invite à lire le <a
href="http://faler.wordpress.com/2009/03/23/caching-observations-ehcache-with-hibernate-vs-ehcache-without-hibernate/" title="billet de blog suivant" >billet de blog suivant</a> dans lequel l&#8217;auteur effectue une comparaison des performances en fonction des différentes utilisations du cache dont voici les résultats :<br
/> <em>Pour 50 objets chargés contenant chacun 2 relations One-To-Many</em></p><ul><li>Hibernate Simple sans cache : 192 secondes</li><li>Hibernate avec un cache L2 basé sur Ehcache : 60 secondes</li><li>Accès direct à Ehcache, utilisation d&#8217;Hibernate pour les objets non trouvés dans le cache : 20 secondes</li><li>Accès direct à Ehcache, utilisation d&#8217;Hibernate pour les objets non trouvés dans le cache et optimisation du nombre d&#8217;ouvertures de sessions : 1 seconde</li></ul><h3><a
name="Conclusionlecachingcenestpassi"></a>Le caching, ce n&#8217;est pas si simple</h3><p>Ce billet n&#8217;avait pas pour but de lister l&#8217;ensemble des problématiques liées aux caches distribués, j&#8217;en suis d&#8217;ailleurs incapable ; mais juste de mettre en lumière les principales problématiques liées au caching. Qu&#8217;il soit distribué ou non, la mise en place d&#8217;un cache ne doit pas s&#8217;effectuer à la légère. Si elle est censée améliorer les performances, elle en augmente grandement l&#8217;entropie de votre système. C&#8217;est pourquoi il est nécessaire d&#8217;avoir les moyens d&#8217;estimer le gain de performances lié à la mise en place de vos caches. La majorité des API proposent pour cela de la consultation des statistiques via JMX. Compter le nombre de <em>hits</em> (éléments tirés du cache) et de <em>misses</em> (éléments non trouvés dans la cache) vous permettra d&#8217;évaluer facilement le rendement de celui-ci.</p><p>Si vous ne deviez retenir qu&#8217;une chose, un cache c&#8217;est comme un pare-chocs de voiture pour une base de données :</p><ul><li>Mal placé, ça sert à rien</li><li>Mal configuré, c&#8217;est inefficace</li></ul><p>Attention aux accidents <img
src='http://blog.xebia.fr/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /></p><div
align="center"> <a
href="http://twitter.com/ealliaume"    ><br
/> <img
src="http://blog.xebia.fr/wp-content/uploads/2009/04/twitter4.png"     alt="twitter erwan alliaume" title="twitter erwan alliaume" border="0" /><br
/> </a></div><div
class="shr-publisher-2698"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F08%2F26%2Fles-caches-ces-armes-a-manipuler-avec-precaution%2F' data-shr_title='Les+caches%2C+ces+armes+%C3%A0+manipuler+avec+pr%C3%A9caution'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F08%2F26%2Fles-caches-ces-armes-a-manipuler-avec-precaution%2F' data-shr_title='Les+caches%2C+ces+armes+%C3%A0+manipuler+avec+pr%C3%A9caution'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/08/26/les-caches-ces-armes-a-manipuler-avec-precaution/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Exception synchronisée</title><link>http://blog.xebia.fr/2008/07/02/exception-synchronisee/</link> <comments>http://blog.xebia.fr/2008/07/02/exception-synchronisee/#comments</comments> <pubDate>Wed, 02 Jul 2008 06:00:33 +0000</pubDate> <dc:creator>Benoit Moussaud</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[exception]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/2008/07/02/exception-synchronisee/</guid> <description><![CDATA[Symptômes Lors d&#8217;un test de performance sur une application J2EE, je note que celle-ci a des soucis de montée en charge. Généralement une ou deux thread dumps peuvent mettre en évidence les points de contentions. Dans mon cas, rien de probant. Je repense alors à l&#8217;article publié sur notre blog Chroniques de la performance : [...]]]></description> <content:encoded><![CDATA[<h3><a
name="Symptmes"></a>Symptômes</h3><p>Lors d&#8217;un test de performance sur une application J2EE, je note que celle-ci a des soucis de montée en charge. Généralement une ou deux thread dumps peuvent mettre en évidence les points de contentions. Dans mon cas, rien de probant. Je repense alors à l&#8217;article publié sur notre blog <a
href="http://blog.xebia.fr/2007/11/29/chroniques-de-la-performance-a-propos-de-contentions/" title="Chroniques de la performance : À propos de contentions..." >Chroniques de la performance : À propos de contentions&#8230;</a>. Je récupère les sources de l&#8217;agent et l&#8217;installe sur le serveur d&#8217;application, Weblogic 8.1 &#8211; JVM 1.4.2. Lancement du tir&#8230;.</p><p>Dès le début de phase plateau, l&#8217;agent affiche régulièrement une partie du code que je n&#8217;aurais pas soupçonné: la bibliothèque <a
href="http://ibatis.apache.org" title="iBatis" >iBatis</a> qui gère l&#8217;accès aux données.</p><pre class="brush: java; title: ; notranslate">
[JTPROF] Contention report [id=-1250505672,thread=ExecuteThread: '14' for queue: 'weblogic.kernel.Default',blocked=210ms]
[JTPROF] Stack trace:
[JTPROF]         com.ibatis.sqlmap.engine.accessplan.EnhancedPropertyAccessPlan.&lt;init&gt; (EnhancedPropertyAccessPlan.java:29)
[JTPROF]         com.ibatis.sqlmap.engine.accessplan.AccessPlanFactory.getAccessPlan (AccessPlanFactory.java:62)
[JTPROF]         com.ibatis.sqlmap.engine.exchange.JavaBeanDataExchange.initialize (JavaBeanDataExchange.java:63)
[JTPROF]         com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMap.setParameterMappingList (BasicParameterMap.java:93)
[JTPROF]         com.ibatis.sqlmap.engine.builder.xml.SqlStatementParser.applyInlineParameterMap (SqlStatementParser.java:431)
[JTPROF]         com.ibatis.sqlmap.engine.builder.xml.SqlStatementParser.processSqlStatement (SqlStatementParser.java:215)
[JTPROF]         com.ibatis.sqlmap.engine.builder.xml.SqlStatementParser.parseGeneralStatement (SqlStatementParser.java:120)
</pre><p>Les temps de blocage affichés vont de 20ms à 500ms !</p><h3><a
name="Analyse"></a>Analyse</h3><p>A la lecture de cette pile d&#8217;appel, je me dis <em>&laquo;&nbsp;encore un bloc synchronisé mal placé dans <a
href="http://ibatis.apache.org" title="iBatis" >iBatis</a>&laquo;&nbsp;</em>. L&#8217;avantage avec l&#8217;open source, comme son nom l&#8217;indique, est que l&#8217;on a accès aux sources. J&#8217;ai donc ouvert la classe EnhancedPropertyAccessPlan qui, à ma grande déception, infirma ma 1ère intuition :</p><pre class="brush: java; title: ; notranslate">
27  EnhancedPropertyAccessPlan(Class clazz, String[] propertyNames) {
28    super(clazz, propertyNames);
29    bulkBean = BulkBean.create(clazz, getGetterNames(propertyNames), getSetterNames(propertyNames), getTypes(propertyNames));
30  }
</pre><p>La ligne #29 indique l&#8217;appel à une méthode statique de la classe &laquo;&nbsp;BulkBean&nbsp;&raquo; qui appartient à la bibliothèque <a
href="http://cglib.sourceforge.net" title="cgLib" >cgLib</a>, bien connue pour accélérer efficacement la création de beans Proxy . Idem: cette méthode n&#8217;est pas &#8216;synchronized&#8217;. Alors pourquoi l&#8217;agent m&#8217;indique cette méthode ?<br
/> Les grands moyens : injection de traces manuelles dans le code d&#8217;iBatis afin de comprendre ce qu&#8217;il se trame. Après de nombreux allers-retours de type &#8216;essais-erreurs&#8217;, je finis par trouver l&#8217;origine du problème : chaque appel à la méthode <em>BulkBean.create()</em> engendre une levée d&#8217;exception <em>NoClassDefFoundError</em>.<br
/> En effet, le packaging de l&#8217;ear est incomplet : <em>cglib.jar</em> est bien présente mais il manque l&#8217;une de ses dépendances : <a
href="http://asm.objectweb.org/" title="asm" >asm</a>. Or le code de la méthode <em>BulkBean.create()</em> s&#8217;appuie essentiellement sur l&#8217;API d&#8217;asm.<br
/> Cependant le packaging n&#8217;est pas le seul coupable, iBatis est également fautive ! La méthode <a
href="http://ibatis.apache.org/docs/java/dev/com/ibatis/sqlmap/engine/accessplan/AccessPlanFactory.html" title="AccessPlanFactory.getAccessPlan" >AccessPlanFactory.getAccessPlan</a> est extrêmement défensive : l&#8217;appel à EnhancedPropertyAccessPlan est gardé par un bloc <em>try&#8230;catch(Throwable)</em>. L&#8217;ajout d&#8217;un message de log de type &laquo;&nbsp;Erreur&nbsp;&raquo; aurait été le bienvenue, au moins la première fois.</p><pre class="brush: java; title: ; notranslate">
60:       if (bytecodeEnhancementEnabled) {
61:        try {
62:          plan = new EnhancedPropertyAccessPlan(clazz, propertyNames);
63:        } catch (Throwable t) {
64:          try {
65:            plan = new PropertyAccessPlan(clazz, propertyNames);
66:         } catch (Throwable t2) {
67:            plan = new ComplexAccessPlan(clazz, propertyNames);
68:          }
69:        }
</pre><h3><a
name="Explications"></a>Explications</h3><p>La levée d&#8217;une exception dans une méthode oblige la JVM à rendre l&#8217;appel synchronisé afin de garantir un traitement par le <em>catch</em> cohérent. Il ne faudrait pas que les données (attributs, paramètres, variables) aient été modifiées par un autre thread entre la levée de l&#8217;exception et son éventuel traitement.</p><p>Pour se convaincre de ce phénomène, il suffit d&#8217;écrire une simple classe de test : 10 threads, chaque thread appelle une méthode qui suivant un paramètre lève une <a
href="http://java.sun.com/javase/6/docs/api/java/lang/Exception.html" title="Exception" >Exception</a>, une <a
href="http://java.sun.com/javase/6/docs/api/java/lang/Error.html" title="Error" >Error</a> ou ne fait rien, et ceci 1 000 000 de fois. Le résultat :</p><ul><li>lorsque la méthode ne lève aucune Exception ou Erreur : Temps de réponse : 89 ms</li><li>lorsque la méthode lève une exception : Temps de réponse 5892 ms, 66 fois plus lent !</li></ul><p>Règle: <em>La levée d&#8217;exception doit rester un cas exceptionnel et ne dois en aucun cas devenir un design pattern, c&#8217;est même un<strong> anti-pattern</strong></em>.</p><pre class="brush: java; title: ; notranslate">
public class AntiPattern {
	class NotEvenException extends Exception {
	}
	boolean isEven(int nb) {
		try {
			if (nb % 2 &gt; 0)
				throw new NotEvenException();
			return true;
		} catch (NotEvenException e) {
			return false;
		}
	}
}
</pre><p>Note : Une fois le packaging complet, l&#8217;agent <em>jtprof</em> ne mentionne plus du tout cette zone de l&#8217;application.</p><div
class="shr-publisher-393"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2008%2F07%2F02%2Fexception-synchronisee%2F' data-shr_title='Exception+synchronis%C3%A9e+'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2008%2F07%2F02%2Fexception-synchronisee%2F' data-shr_title='Exception+synchronis%C3%A9e+'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2008/07/02/exception-synchronisee/feed/</wfw:commentRss> <slash:comments>7</slash:comments> </item> <item><title>Chroniques de la performance : À propos de contentions&#8230;</title><link>http://blog.xebia.fr/2007/11/29/chroniques-de-la-performance-a-propos-de-contentions/</link> <comments>http://blog.xebia.fr/2007/11/29/chroniques-de-la-performance-a-propos-de-contentions/#comments</comments> <pubDate>Thu, 29 Nov 2007 22:15:31 +0000</pubDate> <dc:creator>Guillaume Bodet</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/2007/11/29/chroniques-de-la-performance-a-propos-de-contentions/</guid> <description><![CDATA[J&#8217;ai été, il y a peu, confronté à un problème de performances que l&#8217;on peut qualifier d&#8217;intéressant &#8211; dans la bouche d&#8217;un expert technique, ce mot a généralement tendance à provoquer une bouffée de panique chez les plus chevronnés des managers. Je vous explique. Le programme consiste à appliquer massivement un traitement identique à un [...]]]></description> <content:encoded><![CDATA[<p>J&#8217;ai été, il y a peu, confronté à un problème de performances que l&#8217;on peut qualifier d&#8217;<em>intéressant</em> &#8211; dans la bouche d&#8217;un expert technique, ce mot a généralement tendance à provoquer une bouffée de panique chez les plus chevronnés des managers.</p><p>Je vous explique.</p><p>Le programme consiste à appliquer massivement un traitement identique à un volume important de données – bref, c’est un batch. Objectif opérationnel : assurer la capacité du système à traiter 50000 dossiers par heure.<br
/> L’architecture d’exécution de ce batch est relativement classique : un contrôleur est chargé d’obtenir auprès d’un service métier une liste de dossiers à traiter, de segmenter cette liste en lots, puis de soumettre les lots à un pool  de threads qui vont réaliser les traitements en parallèle – chaque lot est traité dans une transaction distincte. Le traitement unitaire d’un dossier est relativement long, de l’ordre de 2 secondes ; les lots sont donc petits – 4 dossiers – pour limiter la durée des transactions.</p><p>Au-delà de son rôle de segmentation et de répartition des lots, le contrôleur fournit un ensemble de services de pilotage, qui n’ont pas vraiment de relation avec notre problème, mais que je mentionne pour information : état d’avancement du traitement, interruption, reprise, calcul de statistiques variées, rapports d’erreurs, etc.</p><p>Typiquement, avec une telle architecture, le débit total du système est une fonction du temps de traitement unitaire et du nombre de threads simultanés :</p><p
style="text-align: center"><code>Débit Horaire = (3600 / Temps Unitaire) * Nombre de threads</code></p><p>Pour mon batch, le calcul théorique est simple : le traitement de chaque dossier demandant 2 secondes, un thread peut traiter 1800 dossiers par heure. Le débit cible étant de 50000 dossiers par heure il est donc théoriquement nécessaire de démarrer un pool de 30 threads.<br
/> Ce calcul cependant part d’une hypothèse audacieuse : il suppose que les temps de traitement unitaire resteront stables quel que soit le nombre de threads. En somme, que la montée en charge du système est parfaitement linéaire.</p><p>Or les tests grandeur réelle réalisés en pré-production montrent un comportement assez éloigné de notre équation platonicienne :</p><p
style="text-align: center"><img
src="http://blog.xebia.fr/wp-content/uploads/2007/11/tu_initial.png" alt="Temps unitaire par dossier selon le nombre de threads" /></p><p>Exprimé sous forme de débit, ce même graphe montre une pente inquiétante :</p><p
style="text-align: center"><img
src="http://blog.xebia.fr/wp-content/uploads/2007/11/debit_initial.png" alt="Débit réel comparé au débit théorique" /></p><p>Le débit horaire s’écarte de plus en plus de la valeur théorique idéale et tend vers une valeur désespérément éloignée du débit cible. Pire, il aurait tendance à se dégrader lorsque le nombre de threads devient trop élevé. Pas de panique, cependant, ce comportement ne saurait déstabiliser le briscard de la performance que je suis : de telles courbes révèlent simplement que le système atteint une limite qui interdit la montée en charge. Reste à déterminer quel composant physique ou logiciel en est à l’origine.</p><p>La première réaction est naturellement de vérifier qu’aucun composant physique n’arrive à saturation. Les outils <em>ad hoc</em> sont utilisés pour contrôler la consommation CPU, l’overhead du GC, le paging, la bande passante, les I/O disque, etc., je vous épargne le détail. Deux éléments intéressants sont tirés de cette analyse : premièrement, aucun composant physique n’approche ses limites de capacité ; deuxièmement, leur niveau de charge épouse presque parfaitement l’évolution du débit présenté dans la figure 2. En d&#8217;autres termes, l’usage des ressources physiques, par exemple la charge moyenne des processeurs, présente la même évolution que le débit : leur montée en charge est freinée et s’écarte inexorablement de la progression théorique linéaire.<br
/> Une nouvelle fois, ce sont des caractéristiques relativement communes des systèmes parallélisés : cela signifie que les threads d’exécution entrent en compétition pour obtenir certains verrous, ou pour accéder à certaines sections critiques ; plus le nombre de threads augmente et plus la compétition devient serrée : il faut de plus en plus de temps pour acquérir les verrous.</p><p>Dans notre système, deux composants sont susceptibles de créer ces conditions :</p><ul><li>la base de données, qui gère des verrous à différents niveaux</li><li>le code java, au travers de blocs synchronisés</li></ul><p>Quiconque a déjà travaillé sur un système transactionnel fortement parallélisé sait que les contentions sur la base de données en sont le principal écueil. Pour assurer l’isolation des transactions, les SGBD posent des verrous en lecture et/ou en écriture sur des lignes, des pages ou des tables – en cas de très forte charge, la granularité des verrous est parfois modifiée dynamiquement, passant par exemple de la ligne (ROW LOCK) à la page (PAGE LOCK).<br
/> Notre système batch a été conçu en conséquence : la base est partitionnée selon des axes fonctionnels stricts, les opérations de lecture et d’écriture ont été soigneusement séquencées, les verrous sont posés au niveau des pages et le contrôleur sait exploiter certaines caractéristiques du stockage physique pour calculer et répartir les segments entre les différents threads. Une analyse des contentions sur la base de données a démontré l’efficacité de ces stratégies : le niveau de contention reste remarquablement bas, et n’explique en aucun cas la forte dégradation observée lors de la montée en charge.</p><p>Reste une seule explication : des contentions dans les couches d’exécution Java. Et une question : comment identifier l’origine de ces contentions, et les corriger ?</p><p>Un premier test est réalisé pour valider l’hypothèse de contentions applicatives dans le code java : il consiste à démarrer 5 processus dotés chacun d’un pool de 4 threads – un total de 20 threads, donc, permettant d’atteindre un taux de parallélisation qui dans nos tests précédents mettaient fortement en exergue la dégradation des temps de traitements unitaires. Ce test est concluant : distribués sur 5 processus distincts, les threads ne sont plus soumis à une compétition mortifère, et la montée en charge se réalise de façon satisfaisante.</p><p>Une solution envisageable serait d’adopter cette architecture, et de distribuer les traitements sur plusieurs processus. Le contrôleur, cependant, n’a pas été conçu pour coordonner plusieurs processus. L’évolution la plus simple, consistant à séparer le contrôleur des composants métiers – par exemple au moyen d’EJBs – implique d’introduire une couche de distribution qui nous semble d’autant moins souhaitable que le contrôleur est en charge du pilotage des transactions : le séparer des traitements signifie distribuer les transactions, et tous les petits soucis que cette décision implique généralement. Cela signifie aussi probablement l’introduction d’un serveur d’applications dans l’architecture de batch, avec les difficultés afférentes en terme de déploiement et d’exploitation. D’autres évolutions plus massives sont envisageables : par exemple s’appuyer sur des tables techniques pour stocker les segments, et découpler complètement une phase de pré-processing – consistant à calculer les lots – et une phase de traitement – consistant à piocher des lots dans la base et à les traiter. On peut même imaginer des solutions plus exotiques, à base de files JMS&#8230; Mais pour tout dire, nous aimons la compacité de notre architecture initiale, et ne sommes pas prêts à l’abandonner sans résister un peu. La question reste donc entière : comment débusquer l&#8217;origine de nos contentions aux fins de les liquider ?</p><p>L’analyse statique du code n’a rien donné : le contrôleur, à l’instar des composants métiers, utilise un bon zillion de bibliothèques tierces, plus ou moins open source et au flot d’exécution volontiers cryptique. Impossible dans ces conditions de déterminer l’origine exacte des contentions par simple consultation des sources : une analyse <em>runtime</em> est nécessaire.</p><p>Reste à trouver le bon outil dans la sacoche du plombier java. Même avec l&#8217;aide gracieuse de Google, la récolte reste maigre en matière d&#8217;outillage&#8230;</p><p>Autant l’offre est pléthorique lorsqu’il s’agit de profiler la consommation CPU ou mémoire des applications Java, autant l’analyse des contentions reste une discipline peu outillée. Certes les profilers java offrent pour la plupart un module d’analyse de threads ; mais leur overhead est tel qu’il est difficile, voire impossible d’instrumenter un traitement fortement multi-threadé comme notre batch : au-delà de 3 ou 4 threads, les informations collectées perdent de leur pertinence, et les temps unitaires s’allongent tellement que toute tentative d’analyse relève de l’acrobatie la plus pure.<br
/> Tordons rapidement le cou à hprof, le profiler intégré au JDK – le notre, en l’occurrence, est un JDK IBM 1.4.2 SR8 ; la documentation indique une option « monitor=y », qui, je cite, « tells hprof to generate information on contention monitors used to synchronize the work of multiple threads » (je vous laisse traduire). Bigre, nous voilà sauvés ! Pas tout à fait&#8230; Outre que le faire fonctionner a demandé une montée de version du JDK – la version que nous utilisions à l’origine générait un très joli core lors de l’activation de hprof -, les informations obtenues se sont révélées d’une rare inutilité (fondamentalement, un état des moniteurs java au moment de la sortie du processus. Aucun intérêt !).<br
/> Exit hprof, donc.<br
/> Autre approche : générer de façon répétée des Thread Dump à l’aide de l’instruction <code>kill -3</code>, puis comparer les différents dumps à l’aide d’un outil <em>ad hoc</em> (en l’occurrence un utilitaire disponible sur le site alphaWorks, et dont je donne le nom complet pour souligner le sens du marketing des ingénieurs IBM : <a
href="http://www.alphaworks.ibm.com/tech/jca">IBM Thread and Monitor Dump Analyzer for Java Technology</a>). Bien que prometteuse, cette solution n’a une nouvelle fois pas donné de résultat définitif : elle nous a permis d’identifier quelques méthodes candidates, mais sans qu’il fût possible de quantifier leurs responsabilités respectives.</p><p>Reste une solution : retrousser ses manches et écrire un profiler spécialisé en s’appuyant sur JVMPI.<br
/> JVMPI (pour Java Virtual Machine Profiling Interface) est, comme son nom le suggère, une API native de profilage de la JVM (remplacée par JVMTI à partir de Java 5, mais c&#8217;est une autre histoire). L’API fonctionne sur un système de callback : l’agent (c’est ainsi que l’on nomme le programme s’appuyant sur l’API) s’enregistre auprès de la JVM en précisant les types d’événements dont il souhaite être notifié – vous aurez probablement reconnu le pattern Observer.<br
/> Ces événements concernent la plupart des opérations techniques de bas niveau réalisées par la JVM : chargement d’une classe, allocation mémoire, exécution d’une méthode, démarrage d’un thread, etc. Parmi ces événements, deux retiennent particulièrement notre attention : <code>MONITOR_CONTENDED_ENTER</code> et <code>MONITOR_CONTENDED_ENTERED</code>. Le premier indique qu&#8217;un thread souhaite exécuter un bloc synchronisé, et tente d&#8217;acquérir un moniteur à cette fin (pour mémoire, la notion de moniteur en java est très proche de celle de verrou dans le reste du monde); le second indique que le thread a obtenu le moniteur en question et entame l&#8217;exécution du bloc synchronisé. L&#8217;intervalle de temps entre les deux événements correspond par conséquent à la durée totale de l&#8217;attente – autrement dit à la durée de la contention.<br
/> Munis de ces rudiments de JVMPI, il est possible de formuler les spécifications exhaustives de notre petit outil de profilage : la durée de toutes les contentions rencontrées par le programme est mesurée. Si cette durée est supérieure à un certain seuil (disons 5 millisecondes), le nom de la méthode correspondante est loggué dans un fichier, ainsi qu’une pile d’appels simplifiée.</p><p>Bien. Il ne reste plus qu&#8217;à coder.</p><p>Le point d&#8217;entrée d&#8217;un agent JVMPI est la méthode JVM_OnLoad. C&#8217;est dans cette méthode que l&#8217;on va informer le sous-système JVMPI des événements que l&#8217;on souhaite activer (<code>EnableEvent</code>), et de la méthode callback qui sera invoquée lors des occurrences de ces événements (<code>NotifyEvent</code>) :</p><pre class="brush: cpp; title: ; notranslate">
JNIEXPORT jint JNICALL _JVM_OnLoad(JavaVM *vm, char *options, void *reserved)
{
    ...
    /* Register callback method */
    jvmpi-&gt;NotifyEvent = jtprof_notify_event;
    /* Enable events */
    jvmpi-&gt;EnableEvent(JVMPI_EVENT_JVM_SHUT_DOWN, NULL);
    jvmpi-&gt;EnableEvent(JVMPI_EVENT_CLASS_LOAD, NULL);
    jvmpi-&gt;EnableEvent(JVMPI_EVENT_CLASS_UNLOAD, NULL);
    jvmpi-&gt;EnableEvent(JVMPI_EVENT_MONITOR_CONTENDED_ENTER, NULL);
    jvmpi-&gt;EnableEvent(JVMPI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
    jvmpi-&gt;EnableEvent(JVMPI_EVENT_THREAD_START, NULL);
    jvmpi-&gt;EnableEvent(JVMPI_EVENT_THREAD_END, NULL);
    ...
    return JNI_OK;
}
</pre><p>La méthode <em>callback</em>, <code>jtprof_notify_event</code>, se contente de déterminer la nature de l&#8217;événement et de déclencher un <em>handler</em> spécialisé :</p><pre class="brush: cpp; title: ; notranslate">
static void jtprof_notify_event(JVMPI_Event *event)
{
    switch(event-&amp;gt;event_type) {
        case JVMPI_EVENT_JVM_SHUT_DOWN:
            handle_jvm_shut_down_event();
            return;
        ...
        case JVMPI_EVENT_THREAD_START:
            handle_thread_started_event(event);
            return;
        case JVMPI_EVENT_THREAD_END:
            handle_thread_end_event(event);
            return;
        case JVMPI_EVENT_MONITOR_CONTENDED_ENTER:
            handle_monitor_contented_enter(event);
            return;
        case JVMPI_EVENT_MONITOR_CONTENDED_ENTERED:
            handle_monitor_contented_entered(event);
            return;
        ...
    }
}
</pre><p>Les choses semblent relativement simples. L&#8217;API JVMPI offre même un système de stockage <em>thread local</em> (méthode <code>GetThreadLocalStorage</code>), permettant de conserver une structure de données quelconque dédiée à chaque thread. Je vous épargne les détails de la création et de la destruction de cette structure de données – les curieux pourront jeter un oeil sur le code source. Sachez simplement qu&#8217;elle est créée lors de l&#8217;événement THREAD_START, détruite lors de l&#8217;événement THREAD_END, et qu&#8217;elle permet notamment de conserver la date de la demande d&#8217;acquisition du moniteur par le thread.</p><p>Au final, le code permettant de mesurer la durée d&#8217;acquisition d&#8217;un moniteur est relativement trivial :</p><pre class="brush: cpp; title: ; notranslate">
static void handle_monitor_contented_enter(JVMPI_Event *event){
    thread_local_context *ctx = (thread_local_context*)jvmpi-&gt;GetThreadLocalStorage(event-&gt;env_id);
    //Error handling code
    ....
    ctx-&gt;timer = system_current_time_millis();
}
static void handle_monitor_contented_entered(JVMPI_Event *event){
    long finish = system_current_time_millis();
    long total;
    thread_local_context *ctx = (thread_local_context*)jvmpi-&gt;GetThreadLocalStorage(event-&gt;env_id);
    //Error handling code
    ....
    total = finish – ctx-&gt;timer;
    ctx-&gt;timer = 0;
    if (total &gt; __contention_threshold){
        //Log contention details
        ....
    }
}
</pre><p>Les choses, bien sûr, sont en réalité un poil plus complexes – fallait pas rêver, non plus.<br
/> Par souci d&#8217;efficacité, en effet, la structure de données <code>JVMPI_Event</code> ne contient, pour chaque événement, qu&#8217;un jeu minimal d&#8217;informations. En pratique, cela signifie que le nom de la méthode invoquée n&#8217;est pas disponible sous forme littérale, mais sous la forme d&#8217;un identifiant interne créé lors du chargement de la classe correspondante.<br
/> Logguer cet identifiant ne serait bien sûr pas d&#8217;un grand intérêt. Il faut pouvoir l&#8217;associer au nom qualifié de la méthode. Pour cela, l&#8217;événement <code>CLASS_LOAD</code> doit être traité. Cet événement fournit la définition complète de la classe et de toutes ses méthodes – y compris leur nom littéral. Notre programme conserve donc ces informations dans un tableau associatif (dont le code source est très largement inspiré de celui de hprof). Ce tableau peut ensuite être consulté lors du traitement d&#8217;une contention afin de déterminer le nom de la méthode appelante à partir de son identifiant. Une technique similaire est mise en oeuvre pour expliciter la pile d&#8217;appels. Je vous laisse consulter <a
href="http://blog.xebia.fr/wp-content/uploads/2007/11/jtprof.zip" title="jtprof.zip">le code source</a> pour les détails&#8230;</p><p>Le programme doit être compilé sous forme de bibliothèque dynamique (extension <code>.dll</code> sous Windows, <code>.so</code> sous Unix), inclu dans le LIB_PATH (ou son équivalent) et intégré à la JVM grâce à l&#8217;option <code>-Xrunjtprof</code> (jtprof est le nom donné à la bibliothèque). Voici le type de sorties obtenues :</p><pre class="brush: java; title: ; notranslate">
[JTPROF] Contention report [id=-2002923824,thread=Contention-Thread-4,blocked=305ms]
[JTPROF] Stack trace:
[JTPROF]	 org.test.Contentions.blockABitMore (Contentions.java:36)
[JTPROF]	 org.test.Contentions.run (Contentions.java:25)
[JTPROF]	 java.lang.Thread.run (Thread.java:595)
...
[JTPROF] Thread end [id=-2002912512, name=Contention-Thread-6, duration=1519ms, blocked=1416ms]
</pre><p>Une fois mis au point, cet outil s&#8217;est révélé très précieux. Son overhead est très faible – les événements les plus gourmands, comme les sites d&#8217;allocation mémoire ou la consommation CPU des méthodes, ne sont pas traités. Il nous a fourni un état très précis du niveau de contention, et de la localisation de celles-ci. Une douzaine de méthodes ont été corrigées (la plupart des contentions étaient de très courte durée &#8211; rarement plus de 50ms &#8211; mais leur fréquence et leur durée avaient tendance à augmenter).<br
/> Au terme de ces optimisations, la courbe des débits se présente comme suit :</p><p
style="text-align: center"><img
src="http://blog.xebia.fr/wp-content/uploads/2007/11/debit_final.png" alt="Débit réel comparé au débit théorique" /></p><p>Il reste un léger décrochage au-delà de 25 threads, mais cette fois-ci, son origine ne fait pas de doute : notre machine de test est simplement saturée, et la contention, cette fois-ci, porte sur l&#8217;accès aux processeurs.</p><p>Ceux qui ont suivi depuis le début se souviennent peut-être de l&#8217;équation présentée plus haut dans cet article :</p><p
style="text-align: center"><code>Débit Horaire = (3600 / Temps Unitaire) * Nombre de threads</code></p><p>S&#8217;ils n&#8217;ont pas complètement oublié le programme de mathématiques du Brevet des Collèges, ils auront probablement compris que l&#8217;augmentation du nombre de threads n&#8217;est pas le seul levier du débit : réduire le temps de traitement unitaire en est un autre. Mais ceci est une autre histoire&#8230;</p><div
class="shr-publisher-143"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2007%2F11%2F29%2Fchroniques-de-la-performance-a-propos-de-contentions%2F' data-shr_title='Chroniques+de+la+performance+%3A+%C3%80+propos+de+contentions...'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2007%2F11%2F29%2Fchroniques-de-la-performance-a-propos-de-contentions%2F' data-shr_title='Chroniques+de+la+performance+%3A+%C3%80+propos+de+contentions...'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2007/11/29/chroniques-de-la-performance-a-propos-de-contentions/feed/</wfw:commentRss> <slash:comments>6</slash:comments> </item> <item><title>Top ten des problèmes de performances des applications J2EE (4 &amp; 3)</title><link>http://blog.xebia.fr/2007/10/04/top-ten-des-problemes-de-performances-des-applications-j2ee-4-3/</link> <comments>http://blog.xebia.fr/2007/10/04/top-ten-des-problemes-de-performances-des-applications-j2ee-4-3/#comments</comments> <pubDate>Thu, 04 Oct 2007 06:44:11 +0000</pubDate> <dc:creator>Guillaume Bodet</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[J2EE]]></category> <category><![CDATA[vidéo]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/2007/10/04/top-ten-des-problemes-de-performances-des-applications-j2ee-4-3/</guid> <description><![CDATA[Nous vous proposons aujourd&#8217;hui la quatrième d&#8217;une série de cinq vidéos consacrées aux problèmes de performances des applications java / J2EE. Nous y déroulons le top 10 des problèmes de performances en environnement java&#160;/ J2EE en les illustrant par des cas concrets et en proposant pour chacun des mesures permettant de s&#8217;en prémunir. Cette vidéo [...]]]></description> <content:encoded><![CDATA[<p>Nous vous proposons aujourd&#8217;hui la quatrième d&#8217;une série de cinq vidéos consacrées aux problèmes de performances des applications java / J2EE.<br
/> Nous y déroulons <a
href="http://blog.xebia.fr/2007/05/03/le-top-10-des-problemes-de-performances-des-applications-j2ee/">le top 10 des problèmes de performances en environnement java&nbsp;/ J2EE</a> en les illustrant par des cas concrets et en proposant pour chacun des mesures permettant de s&#8217;en prémunir.</p><p>Cette vidéo traite des numéros&nbsp;:</p><ul><li><strong>04&nbsp;: Les bibliothèques tierces</strong></li><li><strong>03&nbsp;: Mauvais usage de la concurrence</strong></li></ul><div
align="center"> <object
width="700" height="350"><param
name="movie" value="http://www.vcasmo.com/swf/vcasmo.swf"></param><param
name="flashvars" value="pid=621"></param><param
name="allowFullScreen" value="true"></param> <embed
src="http://www.vcasmo.com/swf/vcasmo.swf" flashvars="pid=621" allowFullScreen="true" type="application/x-shockwave-flash" width="700" height="350"></embed></object></div><div
class="shr-publisher-114"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2007%2F10%2F04%2Ftop-ten-des-problemes-de-performances-des-applications-j2ee-4-3%2F' data-shr_title='Top+ten+des+probl%C3%A8mes+de+performances+des+applications+J2EE+%284+%26+3%29'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2007%2F10%2F04%2Ftop-ten-des-problemes-de-performances-des-applications-j2ee-4-3%2F' data-shr_title='Top+ten+des+probl%C3%A8mes+de+performances+des+applications+J2EE+%284+%26+3%29'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2007/10/04/top-ten-des-problemes-de-performances-des-applications-j2ee-4-3/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Top ten des problèmes de performances des applications J2EE (6 &amp; 5)</title><link>http://blog.xebia.fr/2007/09/27/top-ten-des-problemes-de-performances-des-applications-j2ee-6-5/</link> <comments>http://blog.xebia.fr/2007/09/27/top-ten-des-problemes-de-performances-des-applications-j2ee-6-5/#comments</comments> <pubDate>Thu, 27 Sep 2007 06:33:06 +0000</pubDate> <dc:creator>Guillaume Bodet</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[J2EE]]></category> <category><![CDATA[vidéo]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/2007/09/27/top-ten-des-problemes-de-performances-des-applications-j2ee-6-5/</guid> <description><![CDATA[Nous vous proposons aujourd&#8217;hui la troisième d&#8217;une série de cinq vidéos consacrées aux problèmes de performances des applications java / J2EE. Nous y déroulerons le top 10 des problèmes de performances en environnement java&#160;/ J2EE en les illustrant par des cas concrets et en proposant pour chacun des mesures permettant de s&#8217;en prémunir. Cette vidéo [...]]]></description> <content:encoded><![CDATA[<p>Nous vous proposons aujourd&#8217;hui la troisième d&#8217;une série de cinq vidéos consacrées aux problèmes de performances des applications java / J2EE.<br
/> Nous y déroulerons <a
href="http://blog.xebia.fr/2007/05/03/le-top-10-des-problemes-de-performances-des-applications-j2ee/">le top 10 des problèmes de performances en environnement java&nbsp;/ J2EE</a> en les illustrant par des cas concrets et en proposant pour chacun des mesures permettant de s&#8217;en prémunir.</p><p>Cette vidéo traite des numéros&nbsp;:</p><ul><li><strong>06&nbsp;: Utilisation impropre des caches</strong></li><li><strong>05&nbsp;: Utilisation excessive de la mémoire</strong></li></ul><div
align="center"> <object
width="700" height="350"><param
name="movie" value="http://www.vcasmo.com/swf/vcasmo.swf"></param><param
name="flashvars" value="pid=620"></param><param
name="allowFullScreen" value="true"></param> <embed
src="http://www.vcasmo.com/swf/vcasmo.swf" flashvars="pid=620" allowFullScreen="true" type="application/x-shockwave-flash" width="700" height="350"></embed></object></div><div
class="shr-publisher-107"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2007%2F09%2F27%2Ftop-ten-des-problemes-de-performances-des-applications-j2ee-6-5%2F' data-shr_title='Top+ten+des+probl%C3%A8mes+de+performances+des+applications+J2EE+%286+%26+5%29'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2007%2F09%2F27%2Ftop-ten-des-problemes-de-performances-des-applications-j2ee-6-5%2F' data-shr_title='Top+ten+des+probl%C3%A8mes+de+performances+des+applications+J2EE+%286+%26+5%29'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2007/09/27/top-ten-des-problemes-de-performances-des-applications-j2ee-6-5/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Top ten des problèmes de performances des applications J2EE (8 &amp; 7)</title><link>http://blog.xebia.fr/2007/09/19/top-ten-des-problemes-de-performances-des-applications-j2ee-8-7/</link> <comments>http://blog.xebia.fr/2007/09/19/top-ten-des-problemes-de-performances-des-applications-j2ee-8-7/#comments</comments> <pubDate>Wed, 19 Sep 2007 06:44:57 +0000</pubDate> <dc:creator>Guillaume Bodet</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[J2EE]]></category> <category><![CDATA[vidéo]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/2007/09/19/top-ten-des-problemes-de-performances-des-applications-j2ee-8-7/</guid> <description><![CDATA[Nous vous proposons aujourd&#8217;hui la deuxième d&#8217;une série de cinq vidéos consacrées aux problèmes de performances des applications java / J2EE. Nous y déroulerons le top 10 des problèmes de performances en environnement java&#160;/ J2EE en les illustrant par des cas concrets et en proposant pour chacun des mesures permettant de s&#8217;en prémunir. Cette vidéo [...]]]></description> <content:encoded><![CDATA[<p>Nous vous proposons aujourd&#8217;hui la deuxième d&#8217;une série de cinq vidéos consacrées aux problèmes de performances des applications java / J2EE.<br
/> Nous y déroulerons <a
href="http://blog.xebia.fr/2007/05/03/le-top-10-des-problemes-de-performances-des-applications-j2ee/">le top 10 des problèmes de performances en environnement java&nbsp;/ J2EE</a> en les illustrant par des cas concrets et en proposant pour chacun des mesures permettant de s&#8217;en prémunir.</p><p>Cette vidéo traite des numéros&nbsp;:</p><ul><li><strong>08&nbsp;: Usage incorrect de Java EE</strong></li><li><strong>07&nbsp;: Utilisation abusive du XML</strong></li></ul><div
align="center"> <object
width="700" height="350"><param
name="movie" value="http://www.vcasmo.com/swf/vcasmo.swf"></param><param
name="flashvars" value="pid=619"></param><param
name="allowFullScreen" value="true"></param> <embed
src="http://www.vcasmo.com/swf/vcasmo.swf" flashvars="pid=619" allowFullScreen="true" type="application/x-shockwave-flash" width="700" height="350"></embed></object></div><div
class="shr-publisher-98"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2007%2F09%2F19%2Ftop-ten-des-problemes-de-performances-des-applications-j2ee-8-7%2F' data-shr_title='Top+ten+des+probl%C3%A8mes+de+performances+des+applications+J2EE+%288+%26+7%29'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2007%2F09%2F19%2Ftop-ten-des-problemes-de-performances-des-applications-j2ee-8-7%2F' data-shr_title='Top+ten+des+probl%C3%A8mes+de+performances+des+applications+J2EE+%288+%26+7%29'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2007/09/19/top-ten-des-problemes-de-performances-des-applications-j2ee-8-7/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> </channel> </rss>
