<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.masterzen.fr/~d/styles/itemcontent.css"?><rss 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:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Masterzen's Blog</title>
	
	<link>http://www.masterzen.fr</link>
	<description>Journey in a software world...</description>
	<lastBuildDate>Sat, 31 Jul 2010 15:48:27 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.masterzen.fr/masterzen" /><feedburner:info uri="masterzen" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>The definitive recipe for Wordpress Gengo to WPML conversion</title>
		<link>http://feeds.masterzen.fr/~r/masterzen/~3/8-djGIxqfuA/</link>
		<comments>http://www.masterzen.fr/2010/07/31/the-definitive-recipe-for-wordpress-gengo-to-wpml-conversion/#comments</comments>
		<pubDate>Sat, 31 Jul 2010 15:48:27 +0000</pubDate>
		<dc:creator>masterzen</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[System Administration]]></category>
		<category><![CDATA[War stories]]></category>
		<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[gengo]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[wpml]]></category>

		<guid isPermaLink="false">http://www.masterzen.fr/?p=204</guid>
		<description><![CDATA[The Days of Wonder News Center is running Wordpress which until a couple of days used Gengo for multilingual stuff. Back when we started using Wordpress for our news, we wanted to be able to have those in three (and maybe more) languages.
At that time (in 2007, wordpress 2.3), only Gengo was available.
During the last [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://blog.daysofwonder.com" onclick="javascript:pageTracker._trackPageview('/outbound/article/blog.daysofwonder.com');">Days of Wonder News Center</a> is running <a href="http://wordpress.org" onclick="javascript:pageTracker._trackPageview('/outbound/article/wordpress.org');">Wordpress</a> which until a couple of days used <a href="http://wordpress.org/extend/plugins/gengo/" onclick="javascript:pageTracker._trackPageview('/outbound/article/wordpress.org');">Gengo</a> for multilingual stuff. Back when we started using <em>Wordpress</em> for our news, we wanted to be able to have those in three (and maybe more) languages.</p>
<p>At that time (in 2007, wordpress 2.3), only <em>Gengo</em> was available.<br />
During the last years, <em>Gengo</em> was unfortunately not maintained anymore, and it was difficult to upgrade Wordpress to new versions.</p>
<p>Recently we took the decision to upgrade our <em>Wordpress</em> installation, and at the same time ditch <em>Gengo</em> and start over using <a href="http://wpml.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/wpml.org');">WPML</a>, which is actively maintained (and looks superior to Gengo).</p>
<p>So, I started thinking about the conversion, then looked on the web and  found how to convert posts, with the help of those two blog posts:</p>
<ul>
<li><a href="http://www.bernawebdesign.ch/byteblog/2009/08/15/migrating-wordpress-from-gengo-to-wpml/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.bernawebdesign.ch');">Migrating Wordpress from Gengo to WPML</a></li>
<li><a href="http://www.pietvanoostrum.com/en/wordpress/converting-wordpress-from-gengo-to-wpml/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.pietvanoostrum.com');">Converting Wordpress from Gengo to WPML &#8211; part 1</a></li>
</ul>
<p>Those two posts were invaluable for the conversion of posts, but unfortunately nobody solved the conversion of translated categories&#8230; until I did <img src='http://www.masterzen.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>So here is the most complete recipe to convert from Gengo 2.5 to WPML 1.8, with updated and working SQL requests.</p>
<h2>Pre-requisites</h2>
<p>You might want to stop the traffic to your blog during all this procedure. One way to do that is to return an HTTP error code 503 by modifying your Apache/Nginx/Whatever configuration.</p>
<ol>
<li>Log-in as an administrator in the Wordpress back-end, and deactivate Gengo.</li>
<li>Install WPML 1.8, and activates it to create the necessary tables. I had to massage WPML a little bit to let it create the tables, YMMV.</li>
<li>In the WPML settings, define the same languages as in Gengo (in my case English (primary), French and German)</li>
<li>Finish the WPML configuration.</li>
<li>If you had a <strong>define(WP_LANG,&#8230;)</strong> in your wordpress config, get <em>rid of it</em>.</li>
</ol>
<h2>Converting Posts</h2>
<p>Connect to your MySQL server and issue the following revised SQL requests (thanks for the above blog posts for them):</p>
<p><script src="http://gist.github.com/502282.js?file=Convert%20Posts%20from%20Gengo%20to%20WPML.sql"></script></p>
<h2>Converting Pages</h2>
<p>This is the same procedure, except we track &#8216;post_page&#8217; instead of &#8216;post_post&#8217;:<br />
 <script src="http://gist.github.com/502282.js?file=Convert%20Pages%20from%20Gengo%20to%20WPML.sql"></script></p>
<h2>Category conversion</h2>
<p>This part is a little bit tricky. In Gengo, we translated the categories without creating new categories, but in WPML we have to create new categories that would be translations of a primary category.<br />
To do this, I created the following SQL procedure that simplifies the creation of a translated category:</p>
<p><script src="http://gist.github.com/502282.js?file=SQL%20Procedure%20to%20create%20a%20translated%20category.sql"></script> Then we need to create translated categories with this procedure (this can be done with the Wordpress admin interface, but if you have many categories it is simpler to do this with a bunch of SQL statements):  <script src="http://gist.github.com/502282.js?file=Convert%20some%20categories.sql"></script></p>
<h2>Bind translated categories to translated posts</h2>
<p>And this is the last step, we need to make sure our posts translations have the correct translated categories (for the moment they use the English primary categories).</p>
<p>To do this, I created the following SQL request:</p>
<p><script src="http://gist.github.com/502282.js?file=Bind%20French%20posts%20translations%20to%20French%20categories.sql"></script></p>
<p>The request is in two parts. The first one will list all the French translations posts IDs that we will report in the second request to update the categories links.</p>
<div class="feedflare">
<a href="http://feeds.masterzen.fr/~ff/masterzen?a=8-djGIxqfuA:ohP8nPQHHSc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=8-djGIxqfuA:ohP8nPQHHSc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/masterzen?i=8-djGIxqfuA:ohP8nPQHHSc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=8-djGIxqfuA:ohP8nPQHHSc:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=8-djGIxqfuA:ohP8nPQHHSc:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/masterzen?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=8-djGIxqfuA:ohP8nPQHHSc:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/masterzen?i=8-djGIxqfuA:ohP8nPQHHSc:gIN9vFwOqvQ" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.masterzen.fr/2010/07/31/the-definitive-recipe-for-wordpress-gengo-to-wpml-conversion/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.masterzen.fr/2010/07/31/the-definitive-recipe-for-wordpress-gengo-to-wpml-conversion/</feedburner:origLink></item>
		<item>
		<title>More Puppet Offloading</title>
		<link>http://feeds.masterzen.fr/~r/masterzen/~3/x71qXOlDfyU/</link>
		<comments>http://www.masterzen.fr/2010/03/21/more-puppet-offloading/#comments</comments>
		<pubDate>Sun, 21 Mar 2010 15:56:58 +0000</pubDate>
		<dc:creator>masterzen</dc:creator>
				<category><![CDATA[Nginx]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Puppet]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[System Administration]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[offloading]]></category>
		<category><![CDATA[puppet]]></category>
		<category><![CDATA[puppetmaster]]></category>

		<guid isPermaLink="false">http://www.masterzen.fr/?p=186</guid>
		<description><![CDATA[Puppet really shines at configuration management, but there are some things it is not good at, for instance file sourcing of large files, or managing deep hierarchies.
Fortunately, most of this efficiency issues will be addressed in a subsequent major version (thanks to some of my patches and other refactorings).
Meanwhile it is interesting to work-around those [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://reductivelabs.com/products/puppet/" onclick="javascript:pageTracker._trackPageview('/outbound/article/reductivelabs.com');">Puppet</a> really shines at configuration management, but there are some things it is not good at, for instance file sourcing of large files, or managing deep hierarchies.</p>
<p>Fortunately, most of this efficiency issues will be addressed in a subsequent major version (thanks to <a href="http://projects.reductivelabs.com/issues/3396" onclick="javascript:pageTracker._trackPageview('/outbound/article/projects.reductivelabs.com');">some of</a> <a href="http://projects.reductivelabs.com/issues/2929" onclick="javascript:pageTracker._trackPageview('/outbound/article/projects.reductivelabs.com');">my patches</a> and other refactorings).</p>
<p>Meanwhile it is interesting to work-around those bugs. Since most of us are running our masters as part of a more complete stack and not isolated, we can leverage the power of this stack to address some of the issues.</p>
<p>In this article, I&#8217;ll expose two techniques to help your overloaded masters to serve more and more clients.</p>
<h2>Offloading file sourcing</h2>
<p>I already talked about offloading file sourcing in a <a href="http://www.masterzen.fr/2010/01/28/puppet-memory-usage-not-a-fatality/" >previous blog post about puppet memory consumption</a>. Here the idea is to prevent our puppetmasters to read the whole content of files in memory at once to serve them. Most of the installation of puppetmasterd out there are behind an http reverse proxy of some sort (ie Apache or Nginx).</p>
<p>The idea is that file serving is an activity that a small static server is better placed to do than puppet itself (that might change when <a href="http://projects.reductivelabs.com/issues/3373" onclick="javascript:pageTracker._trackPageview('/outbound/article/projects.reductivelabs.com');">#3373</a> will be fully addressed). Note: I produced <a href="http://groups.google.com/group/puppet-dev/t/f9ffe87357c2ba38" onclick="javascript:pageTracker._trackPageview('/outbound/article/groups.google.com');">an experimental patch pending review</a> to stream puppet file sourcing on the client side, which this tip doesn&#8217;t address.</p>
<p>So I did implement this in <a href="http://www.nginx.org" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.nginx.org');">Nginx</a> (which is my favorite http server of course, but that can be ported to any other webserver quite easily, which is an exercise left to the reader):</p>
<script src="http://gist.github.com/339342.js"></script><noscript><code class="gist"><pre></p>
<pre>server {
    listen 8140;

    ssl                     on;
    ssl_session_timeout     5m;
    ssl_certificate         /var/lib/puppet/ssl/certs/master.pem;
    ssl_certificate_key     /var/lib/puppet/ssl/private_keys/master.pem;
    ssl_client_certificate  /var/lib/puppet/ssl/ca/ca_crt.pem;
    ssl_crl                 /var/lib/puppet/ssl/ca/ca_crl.pem;
    ssl_verify_client       optional;

    root                    /etc/puppet;

    # make sure we serve everything
    # as raw
    types { }
    default_type application/x-raw;

    # those locations are for the "production" environment
    # update according to your configuration

    # serve static file for the [files] mountpoint
    location /production/file_content/files/ {
        # it is advisable to have some access rules here
        allow   172.16.0.0/16;
        deny    all;

        alias /etc/puppet/files/;
    }

    # serve modules files sections
    location ~ /production/file_content/[^/]+/files/ {
        # it is advisable to have some access rules here
        allow   172.16.0.0/16;
        deny    all;

        root /etc/puppet/modules;

        # rewrite /production/file_content/module/files/file.txt
        # to /module/file.text
        rewrite ^/production/file_content/([^/]+)/files/(.+)$  $1/$2 break;
    }

    # ask the puppetmaster for everything else
    location / {
        proxy_pass          http://puppet-production;
        proxy_redirect      off;
        proxy_set_header    Host             $host;
        proxy_set_header    X-Real-IP        $remote_addr;
        proxy_set_header    X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_set_header    X-Client-Verify  $ssl_client_verify;
        proxy_set_header    X-SSL-Subject    $ssl_client_s_dn;
        proxy_set_header    X-SSL-Issuer     $ssl_client_i_dn;
        proxy_buffer_size   16k;
        proxy_buffers       8 32k;
        proxy_busy_buffers_size    64k;
        proxy_temp_file_write_size 64k;
        proxy_read_timeout  65;
    }
}</pre>
<p></pre></code></noscript>
<p>And if you use multiple module paths (for instance to separate common modules to other modules), it is still possible to use this trick with some use of <a href="http://wiki.nginx.org/NginxHttpCoreModule#try_files" onclick="javascript:pageTracker._trackPageview('/outbound/article/wiki.nginx.org');">nginx try_files</a> directive.</p>
<p>The try_files directive allows puppet to try several physical path (the first matching one will be served), and if none match you can use the generic location that proxies to the master which certainly will know what to do.</p>
<p>Something that can be useful would be to create a small script to generate the nginx config from your fileserver.conf and puppet.conf. Since mine is pretty easy, I did it manually.</p>
<h2>Optimize Catalog Compilation</h2>
<p>The normal process of puppet is to contact the <em>puppetmaster</em> at some time interval asking for a catalog. The catalog is a byproduct of the compilation of the parsed manifests in which are injected the node facts. This operation takes some times depending on the manifest complexity and the server capacity or current load.</p>
<p>Most of the time an host requires a catalog while the <em>manifests didn&#8217;t change at all</em>. In my own infrastructure I rarely change my manifests once a kind of host become stable (I might do a change every week at most when in production).</p>
<p>Since 0.25, puppet is now fully <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer" onclick="javascript:pageTracker._trackPageview('/outbound/article/en.wikipedia.org');">RESTful</a>, that means to get a catalog <em>puppetd</em> contacts the master under its SSL protected links and asks for this url:</p>
<script src="http://gist.github.com/339348.js"></script><noscript><code class="gist"><pre></p>
<pre>/production/catalog/node.daysofwonder.com?facts=&lt;encodedfacts&gt;&amp;facts_format=b64_zlib_yaml</pre>
<p></pre></code></noscript>
<p>In return the puppetmaster responds by a json-encoded catalog.<br />
The actual compilation of a catalog for one of my largest host takes about 4s (excluding storeconfigs). During this 4s one ruby thread inside the master is using the CPU. And this is done once every 30 minutes, even if the manifests don&#8217;t change.</p>
<p>What if we could compile only when something changes? This would really free our masters!</p>
<p>Since puppet uses HTTP, it is easy to add a front-most HTTP cache in front of our master to actually cache the catalog the first time it is compiled and serve this one on the subsequent requests.</p>
<p>Although we can do it with any HTTP Cache (ie Varnish), this is really easy to add this with Nginx (which is already running in my own stack):</p>
<script src="http://gist.github.com/339353.js"></script><noscript><code class="gist"><pre></p>
<pre># define a proxy cache called 'puppetcache'
# with an in-memory zone of 10MiB (increase this number if you want to be able to cache
# more keys)
# the cache disk path should be on the same filesystem as the proxy_temp_path
proxy_cache_path  /var/cache/nginx/cache  levels=1:2   keys_zone=puppetcache:10m;

server {

    ... normal nginx for puppet config...

    proxy_set_header    Host             $host;
    proxy_set_header    X-Real-IP        $remote_addr;
    proxy_set_header    X-Forwarded-For  $proxy_add_x_forwarded_for;
    proxy_set_header    X-Client-Verify  $ssl_client_verify;
    proxy_set_header    X-SSL-Subject    $ssl_client_s_dn;
    proxy_set_header    X-SSL-Issuer     $ssl_client_i_dn;
    proxy_buffer_size   16k;
    proxy_buffers       8 32k;
    proxy_busy_buffers_size    64k;
    proxy_temp_file_write_size 64k;
    proxy_read_timeout  65;

    # we handle catalog differently
    # because we want to cache them
    location /production/catalog {
        proxy_pass          http://puppet-production;
        proxy_redirect      off;

        # it is a good thing to actually restrict who
        # can ask for a catalog (especially for cached
        # catalogs)
        allow 172.16.10.0/24;
        allow 127.0.0.0/8;
        deny all;

        # where to cache contents
        proxy_cache         puppetcache;

        # we cache content by catalog host
        # we could also use $args to take into account request
        # facts, but those change too often (ie uptime or memory)
        # to be really usefull
        proxy_cache_key     $uri;

        # define how long to cache response

        # normal catalogs will be cached 2 weeks
        proxy_cache_valid  200 302 301 2w;

        # errors are not cached long
        proxy_cache_valid  500 403 1m;

        # the rest is cached a little bit
        proxy_cache_valid  any 30m;
    }

    # catch all location for other terminii
    location / {
        proxy_pass          http://puppet-production;
        proxy_redirect      off;
    }
}</pre>
<p></pre></code></noscript>
<p>Puppet currently doesn&#8217;t return any http caching headers (ie Cache-Control or Expires), so we use nginx ability to cache despite it (see proxy_cache_valid). Of course I have a <a href="http://github.com/masterzen/puppet/tree/features/http-catalog-cache" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">custom puppet branch</a> that introduces a new parameter called <em>&#8211;catalog_ttl</em> which allows puppet to set those cache headers.</p>
<p>One thing to note is that the <em>cache expiration won&#8217;t coincide with when you change your manifests</em>. So we need some ways to purge the cache when you deploy new manifests.</p>
<p>With Nginx this can be done with:</p>
<ul>
<li>removing the nginx cache directory: rm -rf /var/cache/nginx/cache &amp;&amp; killall -HUP nginx</li>
<li>selectively purge with: the <a href="http://github.com/FRiCKLE/ngx_cache_purge" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">Nginx proxy cache purge module</a>.</li>
</ul>
<p>It&#8217;s easy to actually add one of those methods to any <em>svn hook</em> or <em>git post-receive hook</em> so that deploying manifests actually purge the cache.</p>
<p>Note: I think that ReductiveLabs has some plan to add catalog compilation caching directly to Puppet (which would make sense). This method is the way to go before this features gets added to Puppet. I have no doubt that caching inside Puppet will be much better than outside caching, mainly because Puppet would be able to expire the cache when the manifests change.</p>
<p>There a few caveats to note:</p>
<ul>
<li>any host with a valid certificate can request another cached catalog, unlike with the normal puppetmaster which makes sure to serve catalogs only to the correct host. It&#8217;s something that can be a problem for some configurations</li>
<li>if your manifests rely on &#8220;dynamic&#8221; facts (like uptime or free memory), obviously you shouldn&#8217;t cache the catalog at all.</li>
<li>the above nginx configuration doesn&#8217;t include the facts as part of the cache key. That means the catalog won&#8217;t be re-generated when any facts change and the cached catalog will always be served. If that&#8217;s an issue, you need to purge the cache when the host itself change.</li>
</ul>
<p>I should also mention that caching is certainly not the panacea of reducing the master load.</p>
<p>Some other people are using clever methods to smooth out master load. One notable example is the <a href="http://www.devco.net/archives/2010/03/17/scheduling_puppet_with_mcollective.php" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.devco.net');">MCollective puppet scheduler</a>, <a href="http://twitter.com/ripienaar" onclick="javascript:pageTracker._trackPageview('/outbound/article/twitter.com');">R.I Pienaar</a> has written. In essence he wrote a <em>puppet run scheduler</em> running on top of <a href="http://code.google.com/p/mcollective/" onclick="javascript:pageTracker._trackPageview('/outbound/article/code.google.com');">MCollective</a> that schedule puppet runs (triggered through MCollective) when the master load is appropriate. This allows for the best use of the host running the master.</p>
<p>If you also have some tricks or tips for running puppet, do not hesitate to contact me (I&#8217;m masterzen on freenode&#8217;s #puppet or <a href="http://twitter.com/_masterzen_" onclick="javascript:pageTracker._trackPageview('/outbound/article/twitter.com');">@_masterzen_</a> on twitter).</p>
<div class="feedflare">
<a href="http://feeds.masterzen.fr/~ff/masterzen?a=x71qXOlDfyU:0hvz4JsY3tA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=x71qXOlDfyU:0hvz4JsY3tA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/masterzen?i=x71qXOlDfyU:0hvz4JsY3tA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=x71qXOlDfyU:0hvz4JsY3tA:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=x71qXOlDfyU:0hvz4JsY3tA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/masterzen?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=x71qXOlDfyU:0hvz4JsY3tA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/masterzen?i=x71qXOlDfyU:0hvz4JsY3tA:gIN9vFwOqvQ" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.masterzen.fr/2010/03/21/more-puppet-offloading/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.masterzen.fr/2010/03/21/more-puppet-offloading/</feedburner:origLink></item>
		<item>
		<title>Puppet Memory Usage – not a fatality</title>
		<link>http://feeds.masterzen.fr/~r/masterzen/~3/tVVnJ3c2cc0/</link>
		<comments>http://www.masterzen.fr/2010/01/28/puppet-memory-usage-not-a-fatality/#comments</comments>
		<pubDate>Thu, 28 Jan 2010 21:43:33 +0000</pubDate>
		<dc:creator>masterzen</dc:creator>
				<category><![CDATA[Nginx]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Puppet]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[System Administration]]></category>
		<category><![CDATA[allocator]]></category>
		<category><![CDATA[file serving]]></category>
		<category><![CDATA[heap]]></category>
		<category><![CDATA[jruby]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[memory]]></category>
		<category><![CDATA[memory consumption]]></category>
		<category><![CDATA[memory hog]]></category>
		<category><![CDATA[puppet]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[YAML]]></category>

		<guid isPermaLink="false">http://www.masterzen.fr/?p=168</guid>
		<description><![CDATA[As every reader of this blog certainly know, I&#8217;m a big fan of Puppet, using it in production on Days of Wonder servers, up to the point I used to contribute regularly bug fixes and new features (not that I stopped, it&#8217;s just that my spare time is a scarce resource nowadays).
Still, I think there [...]]]></description>
			<content:encoded><![CDATA[<p>As every reader of this blog certainly know, I&#8217;m a big fan of <a href="http://reductivelabs.com/products/" onclick="javascript:pageTracker._trackPageview('/outbound/article/reductivelabs.com');">Puppet,</a> using it in production on <a href="http://www.daysofwonder.com" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.daysofwonder.com');">Days of Wonder</a> servers, up to the point I used to contribute regularly bug fixes and new features (not that I stopped, it&#8217;s just that my spare time is a scarce resource nowadays).</p>
<p>Still, I think there are some issues in term of scalability or resource consumption (CPU or memory), for which we can find some workarounds or even fixes. Those issues are not a symptom bad programming or bad design. No, most of the issues come either from ruby itself or some random library issues.</p>
<p>Let&#8217;s review the things I have been thinking about lately.</p>
<h2>Memory consumption</h2>
<p>This is by far one of the most seen issues both on the client side and the server side. I&#8217;ve mainly seen this problem on the client side, up to the point that most people recommend running puppetd as cronjobs, instead of being a long lived process.</p>
<h3>Ruby allocator</h3>
<p>All boils down to the ruby (at least the the MRI 1.8.x version) allocator. This is the part in the ruby interpreter that deals with memory allocations. Like in many dynamic languages, the allocator manages a memory pool that is called a<a href="http://en.wikipedia.org/wiki/Dynamic_memory_allocation" onclick="javascript:pageTracker._trackPageview('/outbound/article/en.wikipedia.org');"> heap</a>. And like some other languages (among them Java), this heap can <strong>never shrink and always grows</strong> when more memory is needed. This is done this way because it is simpler and way faster. Usually applications ends using their nominal part of memory and no more memory has to be allocated by the kernel to the process, which gives faster applications.</p>
<p>The problem is that if the application needs transiently a high amount of memory that will be trashed a couple of millisecond after, the process will pay this penalty all its life, even though say 80% of the memory used by the process is free but not reclaimed by the OS.</p>
<p><em>And it&#8217;s even worst</em>. The ruby interpreter when it grows the heap, instead of allocating bytes per bytes (which would be really slow) does this by chunk. The whole question is what is the proper size of a chunk?</p>
<p>In the default implementation of MRI 1.8.x, a chunk is the size of the previous heap times 1.8. That means at worst a ruby process might end up allocating 1.8 times more than what it really needs at a given time. (This is a gross simplification, read the code if you want to know more).</p>
<h3>Yes but what happens in Puppet?</h3>
<p>So how does it apply to <em>puppetd</em>?</p>
<p>It&#8217;s easy, <em>puppetd</em> uses memory for two things (beside maintaining some core data to be able to run):</p>
<ol>
<li>the <strong>catalog</strong> (which contains all resources, along with all templates) as shipped by the <em>puppetmaster</em> (i.e. serialized) and live as ruby objects.</li>
<li>the <strong>content of the sourced</strong> files (one at a time, so it&#8217;s the biggest transmitted file that imposes it&#8217;s high watermark for <em>puppetd</em>). Of course this is still better than in 0.24 where the content was transmitted encoded in XMLRPC adding the penalty of escaping everything&#8230;</li>
</ol>
<p>Hopefully, <strong>nobody distributes large files with Puppet <img src='http://www.masterzen.fr/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </strong> If you&#8217;re tempted to do so, see below&#8230;</p>
<p>But again there&#8217;s more, as <em>Peter Meier</em> (known as duritong in the community) <a href="http://groups.google.com/group/puppet-dev/browse_thread/thread/17e901f2613b9c27/552469109dac1f91?lnk=gst&amp;q=+Possible+workaround+for+%232824#552469109dac1f91" onclick="javascript:pageTracker._trackPageview('/outbound/article/groups.google.com');">discovered a couple of month ago</a>: when <em>puppetd</em> gets its <em>catalog</em> (which by the way is transmitted in <a href="http://www.json.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.json.org');">json</a> nowadays), it also stores it as a local cache to be able to run if it can&#8217;t contact the master for a subsequent run. This operation is done by unserializing the catalog from json to ruby live objects, and then serializing the laters to <a href="http://www.yaml.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.yaml.org');">YAML</a>. Beside the <strong>evident loss of time</strong> to do that on large catalog, YAML is a real memory hog. Peter&#8217;s experience showed that about 200MB of live memory his <em>puppetd</em> process was using came from this final serialization!</p>
<p>So I had the following idea: why not store the serialized version of the catalog (the json one) since we already have it in a serialized form when we receive it from the master (it&#8217;s a little bit more complex than that of course). This way no need to serialize it again in YAML. This is what <a href="http://projects.reductivelabs.com/issues/2892" onclick="javascript:pageTracker._trackPageview('/outbound/article/projects.reductivelabs.com');">ticket #2892 is all about.</a> <a href="http://www.madstop.com/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.madstop.com');">Luke</a> is committed to have this enhancement in Rowlf, so there&#8217;s good hope!</p>
<h3>Some puppet solutions?</h3>
<p>So what can we do to help puppet not consume that many memory?</p>
<p>In <em>theory we could play on several factors</em>:</p>
<ul>
<li><strong>Transmit smaller catalogs</strong>. For instance get rid of all those templates you love (ok that&#8217;s not a solution)</li>
<li>Stream the serialization/deserialization with something like <a href="http://github.com/brianmario/yajl-ruby" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">Yajl-Ruby</a></li>
<li>Use another <strong>ruby interpreter with a better allocator</strong> (like for instance JRuby)</li>
<li>Use a <strong>different constant for resizing the heap</strong> (ie replace this 1.8 by 1.0 or less on line 410 of gc.c). This can be done easily when using Rails machine GC patches or Ruby Enterprise Edition, in which case setting the environment variable  <strong><tt>RUBY_HEAP_SLOTS_GROWTH_FACTOR</tt></strong> is enough. Check the <a href="http://www.rubyenterpriseedition.com/documentation.html#_garbage_collector_performance_tuning" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.rubyenterpriseedition.com');">documentation for more information</a>.</li>
<li><strong>Stream the sourced file on the server and the client</strong> (this way only a small buffer is used, and the total size of the file is never allocated). This one is hard.</li>
</ul>
<p>Note that the same issues apply to the master too (especially for the file serving part). But it&#8217;s usually easier to run a different ruby interpreter (like REE) on the master than on all your clients.</p>
<p>Streaming HTTP requests is promising but unfortunately would require large change to how Puppet deals with HTTP. Maybe it can be done only for file content requests&#8230; This is something I&#8217;ll definitely explore.</p>
<p>This file serving thing let me think about the following which I already discussed several time with Peter&#8230;</p>
<h2>File serving offloading</h2>
<p>One of the mission of the <em>puppetmaster</em> is to serve sourced file to its clients. We saw in the previous section that to do that the master has to read the file in memory. That&#8217;s <a href="http://reductivelabs.com/trac/puppet/wiki/PuppetScalability." onclick="javascript:pageTracker._trackPageview('/outbound/article/reductivelabs.com');">one reason it is recommended</a> to use a dedicated puppetmaster server to act as a <strong>pure fileserver</strong>.</p>
<p>But <strong>there&#8217;s a better way</strong>, provided you run puppet behind <a href="http://nginx.org/en/" onclick="javascript:pageTracker._trackPageview('/outbound/article/nginx.org');">nginx</a> or <a href="http://httpd.apache.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/httpd.apache.org');">apache</a>. Those two proxies are also static file servers: why not leverage what they do best to serve the sourced files and thus offload our puppetmaster?</p>
<p>This has some advantages:</p>
<ul>
<li>it frees lots of resources on the puppetmaster, so that they can serve more catalogs by unit time</li>
<li>the job will be done faster and by using less resources. Those static servers have been created to spoon-feed our puppet clients&#8230;</li>
</ul>
<p>In fact it was impossible in 0.24.x, but now that file content serving is <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer" onclick="javascript:pageTracker._trackPageview('/outbound/article/en.wikipedia.org');">RESTful</a> it becomes trivial.</p>
<p>Of course offloading would give its best if your clients requires lots of sourced files that change often, or if you provision lots of new hosts at the same time because we&#8217;re offloading only content, not file metadata. File content is served only if the client hasn&#8217;t the file or the file checksum on the client is different.</p>
<h3>An example is better than thousand words</h3>
<p>Imagine we have a standard manifest layout with:</p>
<ul>
<li> some globally sourced files under /etc/puppet/files and</li>
<li>some modules files under /etc/puppet/modules/&lt;modulename&gt;/files.</li>
</ul>
<p>Here is what would be the <em>nginx configuration</em> for such scheme:</p>
<pre class="syntax-highlight:bash">
server {
    listen 8140;

    ssl                     on;
    ssl_session_timeout     5m;
    ssl_certificate         /var/lib/puppet/ssl/certs/master.pem;
    ssl_certificate_key     /var/lib/puppet/ssl/private_keys/master.pem;
    ssl_client_certificate  /var/lib/puppet/ssl/ca/ca_crt.pem;
    ssl_crl                 /var/lib/puppet/ssl/ca/ca_crl.pem;
    ssl_verify_client       optional;

    root                    /etc/puppet;

    # those locations are for the &quot;production&quot; environment
    # update according to your configuration

    # serve static file for the [files] mountpoint
    location /production/file_content/files/ {
        # it is advisable to have some access rules here
        allow   172.16.0.0/16;
        deny    all;

        # make sure we serve everything
        # as raw
        types { }
        default_type application/x-raw;

        alias /etc/puppet/files/;
    }

    # serve modules files sections
    location ~ /production/file_content/[^/]+/files/ {
        # it is advisable to have some access rules here
        allow   172.16.0.0/16;
        deny    all;

        # make sure we serve everything
        # as raw
        types { }
        default_type application/x-raw;

        root /etc/puppet/modules;
        # rewrite /production/file_content/module/files/file.txt
        # to /module/file.text
        rewrite ^/production/file_content/([^/]+)/files/(.+)$  $1/$2 break;
    }

    # ask the puppetmaster for everything else
    location / {
        proxy_pass          http://puppet-production;
        proxy_redirect      off;
        proxy_set_header    Host             $host;
        proxy_set_header    X-Real-IP        $remote_addr;
        proxy_set_header    X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_set_header    X-Client-Verify  $ssl_client_verify;
        proxy_set_header    X-SSL-Subject    $ssl_client_s_dn;
        proxy_set_header    X-SSL-Issuer     $ssl_client_i_dn;
        proxy_buffer_size   16k;
        proxy_buffers       8 32k;
        proxy_busy_buffers_size    64k;
        proxy_temp_file_write_size 64k;
        proxy_read_timeout  65;
    }
}
</pre>
<p><strong>EDIT:</strong> the above configuration was missing the only content-type that nginx can return for Puppet to be able to actually receive the file content (that is raw).</p>
<p>I leave as an exercise to the reader the apache configuration.</p>
<p>It would also be possible to write some ruby/sh/whatever to generate the nginx configuration from the puppet fileserver.conf file.</p>
<p>And that&#8217;s all folks, stay tuned for more Puppet (or even different) content.</p>
<div class="feedflare">
<a href="http://feeds.masterzen.fr/~ff/masterzen?a=tVVnJ3c2cc0:powR--mT8BM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=tVVnJ3c2cc0:powR--mT8BM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/masterzen?i=tVVnJ3c2cc0:powR--mT8BM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=tVVnJ3c2cc0:powR--mT8BM:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=tVVnJ3c2cc0:powR--mT8BM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/masterzen?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=tVVnJ3c2cc0:powR--mT8BM:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/masterzen?i=tVVnJ3c2cc0:powR--mT8BM:gIN9vFwOqvQ" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.masterzen.fr/2010/01/28/puppet-memory-usage-not-a-fatality/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://www.masterzen.fr/2010/01/28/puppet-memory-usage-not-a-fatality/</feedburner:origLink></item>
		<item>
		<title>mysql-snmp 1.0 – SNMP monitoring for MySQL</title>
		<link>http://feeds.masterzen.fr/~r/masterzen/~3/vmgzAf77PHg/</link>
		<comments>http://www.masterzen.fr/2010/01/10/mysql-snmp-10-snmp-monitoring-for-mysql/#comments</comments>
		<pubDate>Sun, 10 Jan 2010 17:14:06 +0000</pubDate>
		<dc:creator>masterzen</dc:creator>
				<category><![CDATA[Monitoring]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[System Administration]]></category>
		<category><![CDATA[snmp]]></category>
		<category><![CDATA[monitoring]]></category>
		<category><![CDATA[net-snmp]]></category>
		<category><![CDATA[opennms]]></category>

		<guid isPermaLink="false">http://www.masterzen.fr/?p=149</guid>
		<description><![CDATA[I&#8217;m really proud to announce the release of the version 1.0 of mysql-snmp.
What is mysql-snmp?
mysql-snmp is a mix between the excellent MySQL Cacti Templates and a Net-SNMP agent. The idea is that combining the power of the MySQL Cacti Templates and any SNMP based monitoring would unleash a powerful mysql monitoring system. Of course this [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: left;">I&#8217;m really proud to announce the release of the version 1.0 of <a href="http://www.masterzen.fr/software-contributions/mysql-snmp-monitor-mysql-with-snmp/" >mysql-snmp</a>.</p>
<h2 style="text-align: left;">What is mysql-snmp?</h2>
<p style="text-align: left;"><strong>mysql-snmp</strong> is a mix between the excellent <a href="http://code.google.com/p/mysql-cacti-templates/" onclick="javascript:pageTracker._trackPageview('/outbound/article/code.google.com');">MySQL Cacti Templates</a> and a <a href="http://www.net-snmp.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.net-snmp.org');">Net-SNMP agent</a>. The idea is that combining the power of the <em>MySQL Cacti Templates</em> and any SNMP based monitoring would unleash a powerful mysql monitoring system. Of course this project favorite monitoring system is <a href="http://www.opennms.org/wiki/Main_Page" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.opennms.org');">OpenNMS</a>.</p>
<p style="text-align: left;"><strong>mysql-snmp</strong> is shipped with the necessary <a href="http://www.opennms.org/wiki/Main_Page" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.opennms.org');">OpenNMS</a> configuration files, but any other SNMP monitoring software can be used (provided you configure it).</p>
<p style="text-align: left;">To get there, you need to run a SNMP agent on each MySQL server, along with <strong>mysql-snmp</strong>. Then OpenNMS (or any SNMP monitoring software) will contact it and fetch the various values.</p>
<p style="text-align: left;">Mysql-snmp exposes a lot of useful values including but not limited to:</p>
<ul style="text-align: left;">
<li>SHOW STATUS values</li>
<li>SHOW ENGINE INNODB STATUS parsed values (MySQL 5.0, 5.1, XtraDB or Innodb plugin are supported)</li>
</ul>
<p style="text-align: left;">Here are some graph examples produced with OpenNMS 1.6.5 and mysql-snmp 1.0 on one of Days of Wonder MySQL server (running a MySQL 5.0 Percona build):</p>
<div id="attachment_152" class="wp-caption alignnone" style="width: 310px"><a href="http://www.masterzen.fr/wp-content/uploads/2010/01/commands.jpg" ><img class="size-medium wp-image-152 " title="MySQL command counters" src="http://www.masterzen.fr/wp-content/uploads/2010/01/commands-300x187.jpg" alt="commands" width="300" height="187" /></a><p class="wp-caption-text">This graph shows the number of SQL commands per unit of time</p></div>
<div id="attachment_155" class="wp-caption alignnone" style="width: 310px"><a href="http://www.masterzen.fr/wp-content/uploads/2010/01/mem.jpg" ><img class="size-medium wp-image-155   " title="Innodb Memory Usage" src="http://www.masterzen.fr/wp-content/uploads/2010/01/mem-300x163.jpg" alt="mem" width="300" height="163" /></a><p class="wp-caption-text">You can see the effect of MySQL bug #47991</p></div>
<p style="text-align: left;">
<p><a href="http://www.masterzen.fr/wp-content/uploads/2010/01/tmp.jpg" ><img class="size-medium wp-image-160 alignnone" title="tmp" src="http://www.masterzen.fr/wp-content/uploads/2010/01/tmp-300x145.jpg" alt="tmp" width="300" height="145" /></a><a href="http://www.masterzen.fr/wp-content/uploads/2010/01/innodbwrites.jpg" ><img class="alignnone size-medium wp-image-154" title="innodbwrites" src="http://www.masterzen.fr/wp-content/uploads/2010/01/innodbwrites-300x145.jpg" alt="innodbwrites" width="300" height="145" /></a></p>
<p style="text-align: left;"><a href="http://www.masterzen.fr/wp-content/uploads/2010/01/graph.jpg" ><img class="alignnone size-medium wp-image-153" title="graph" src="http://www.masterzen.fr/wp-content/uploads/2010/01/graph-300x145.jpg" alt="graph" width="300" height="145" /></a><a href="http://www.masterzen.fr/wp-content/uploads/2010/01/tablelocks.jpg" ><img class="alignnone size-medium wp-image-159" title="tablelocks" src="http://www.masterzen.fr/wp-content/uploads/2010/01/tablelocks-300x145.jpg" alt="tablelocks" width="300" height="145" /></a></p>
<h2 style="text-align: left;">Where to get it</h2>
<p>mysql-snmp is available in my <a href="http://github.com/masterzen/mysql-snmp" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">github repository</a>. The repository contains a spec file to build a RPM and what is needed to build a Debian package. Refer to the <a href="http://github.com/masterzen/mysql-snmp/blob/master/README" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">README</a> or the <a href="http://www.masterzen.fr/software-contributions/mysql-snmp-monitor-mysql-with-snmp/" >mysql-snmp page </a>for more information.</p>
<p>Thanks to gihub, it is possible to download the tarball instead of using Git:</p>
<p style="text-align: center;"><a href="http://github.com/masterzen/mysql-snmp/tarball/v1.0" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">Mysql-snmp v1.0 tarball</a></p>
<h2 style="text-align: left;">Changelog</h2>
<p>This lists all new features/options from the initial version v0.6:</p>
<ul>
<li>Spec file to build RPM</li>
<li>Use of configuration file for storing mysql password</li>
<li>Fix of slave handling</li>
<li>Fix for mk-heartbeat slave lag</li>
<li>Support of InnoDB plugin and Percona XtraDB</li>
<li>Automated testing of InnoDB parsing</li>
<li>Removed some false positive errors</li>
<li>OpenNMS configuration generation from MySQL Cacti Templates core files</li>
<li>64 bits computation done in Perl instead of (ab)using MySQL</li>
<li>More InnoDB values (memory, locked tables, &#8230;)</li>
</ul>
<h2 style="text-align: left;">Reporting Issues</h2>
<p>Please use <a href="http://github.com/masterzen/mysql-snmp/issues" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">Github issue system</a> to report any issues.</p>
<h2>Requirements</h2>
<p>There is a little issue here. <strong>mysql-snmp</strong> uses Net-Snmp. Not all versions of Net-Snmp are supported as some older versions have some bug for dealing with Counter64. <a href="http://sourceforge.net/projects/net-snmp/files/" onclick="javascript:pageTracker._trackPageview('/outbound/article/sourceforge.net');">Version 5.4.2.1</a> with <a href="http://sourceforge.net/tracker/?func=detail&amp;aid=2890931&amp;group_id=12694&amp;atid=312694" onclick="javascript:pageTracker._trackPageview('/outbound/article/sourceforge.net');">this patch</a> is known to work fine.</p>
<p>Also note that this project uses some Counter64, so make sure you configure your SNMP monitoring software to use SNMP v2c or v3 (SNMP v1 doesn&#8217;t support 64 bits values).</p>
<h2>Final words!</h2>
<p>I wish everybody an happy new year. Consider this new version as my Christmas present to the community <img src='http://www.masterzen.fr/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<div class="feedflare">
<a href="http://feeds.masterzen.fr/~ff/masterzen?a=vmgzAf77PHg:pm3r41AjALY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=vmgzAf77PHg:pm3r41AjALY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/masterzen?i=vmgzAf77PHg:pm3r41AjALY:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=vmgzAf77PHg:pm3r41AjALY:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=vmgzAf77PHg:pm3r41AjALY:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/masterzen?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=vmgzAf77PHg:pm3r41AjALY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/masterzen?i=vmgzAf77PHg:pm3r41AjALY:gIN9vFwOqvQ" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.masterzen.fr/2010/01/10/mysql-snmp-10-snmp-monitoring-for-mysql/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://www.masterzen.fr/2010/01/10/mysql-snmp-10-snmp-monitoring-for-mysql/</feedburner:origLink></item>
		<item>
		<title>Nginx upload progress module v0.8!</title>
		<link>http://feeds.masterzen.fr/~r/masterzen/~3/Hy6zV9cJNbU/</link>
		<comments>http://www.masterzen.fr/2009/12/19/nginx-upload-progress-module-v08/#comments</comments>
		<pubDate>Sat, 19 Dec 2009 19:46:42 +0000</pubDate>
		<dc:creator>masterzen</dc:creator>
				<category><![CDATA[C]]></category>
		<category><![CDATA[Nginx]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[System Administration]]></category>
		<category><![CDATA[nginx module]]></category>
		<category><![CDATA[nginx upload progress]]></category>

		<guid isPermaLink="false">http://www.masterzen.fr/?p=145</guid>
		<description><![CDATA[Yes, I know&#8230; I released v0.7 less than a month ago. But this release was crippled by a crash that could happen at start or reload.
Changes
Bonus in this new version, brought to you by Tizoc:

JSONP support
Long awaited fix for X-Progress-ID to be the last parameter in the request parameter

If you wonder what JSONP is (as [...]]]></description>
			<content:encoded><![CDATA[<p>Yes, I know&#8230; I <a href="http://www.masterzen.fr/2009/11/22/nginx-upload-progress-module-v07/" >released v0.7 less than a month ago</a>. But this release was <a href="http://github.com/masterzen/nginx-upload-progress-module/issues/closed/#issue/2" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">crippled by a crash</a> that could happen at start or reload.</p>
<h2>Changes</h2>
<p>Bonus in this new version, brought to you by <a href="http://github.com/tizoc" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">Tizoc</a>:</p>
<ul>
<li>JSONP support</li>
<li>Long awaited fix for X-Progress-ID to be the last parameter in the request parameter</li>
</ul>
<p>If you wonder what JSONP is (as I did when I got the merge request), you can check <a href="http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/" onclick="javascript:pageTracker._trackPageview('/outbound/article/bob.pythonmac.org');">the original blog post that lead to it</a>.</p>
<p>To activate JSONP you need:</p>
<ol>
<li>to use the upload_progress_jsonp_output in the progress probe location</li>
<li>declare the JSONP parameter with the upload_progress_jsonp_parameter</li>
</ol>
<p>This version has been tested with 0.7.64 and 0.8.30.</p>
<h2>How do you get it?</h2>
<p>Easy, download the tarball from the <a onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');" href="http://github.com/masterzen/nginx-upload-progress-module/downloads" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">nginx upload progress module github repository download section</a>.</p>
<p>If you want to report a bug, please use the <a href="http://github.com/masterzen/nginx-upload-progress-module/issues" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">Github issue section</a>.</p>
<div class="feedflare">
<a href="http://feeds.masterzen.fr/~ff/masterzen?a=Hy6zV9cJNbU:wAp-tW-nRu0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=Hy6zV9cJNbU:wAp-tW-nRu0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/masterzen?i=Hy6zV9cJNbU:wAp-tW-nRu0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=Hy6zV9cJNbU:wAp-tW-nRu0:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=Hy6zV9cJNbU:wAp-tW-nRu0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/masterzen?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=Hy6zV9cJNbU:wAp-tW-nRu0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/masterzen?i=Hy6zV9cJNbU:wAp-tW-nRu0:gIN9vFwOqvQ" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.masterzen.fr/2009/12/19/nginx-upload-progress-module-v08/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.masterzen.fr/2009/12/19/nginx-upload-progress-module-v08/</feedburner:origLink></item>
		<item>
		<title>Nginx upload progress module v0.7!</title>
		<link>http://feeds.masterzen.fr/~r/masterzen/~3/I9Q0mZTchPc/</link>
		<comments>http://www.masterzen.fr/2009/11/22/nginx-upload-progress-module-v07/#comments</comments>
		<pubDate>Sun, 22 Nov 2009 11:24:50 +0000</pubDate>
		<dc:creator>masterzen</dc:creator>
				<category><![CDATA[C]]></category>
		<category><![CDATA[Nginx]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[System Administration]]></category>
		<category><![CDATA[nginx module]]></category>
		<category><![CDATA[nginx upload progress]]></category>
		<category><![CDATA[release]]></category>

		<guid isPermaLink="false">http://www.masterzen.fr/?p=138</guid>
		<description><![CDATA[I&#8217;m proud to announce the release of Nginx Upload Progress module v0.7
This version sees a crash fix and various new features implemented by Valery Kholodkov (the author of the famous Nginx Upload Module).
This version has been tested with Nginx 0.7.64.
Changes

fixed segfault when uploads are aborted (thanks to Markus  Doppelbauer for his bug report)
session ID [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m proud to announce the release of <a href="http://github.com/masterzen/nginx-upload-progress-module" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">Nginx Upload Progress</a> module v0.7</p>
<p>This version sees a crash fix and various new features implemented by Valery Kholodkov (the author of the famous <a href="http://www.grid.net.ru/nginx/upload.en.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.grid.net.ru');">Nginx Upload Module</a>).</p>
<p>This version has been tested with Nginx 0.7.64.</p>
<h2>Changes</h2>
<ul>
<li>fixed segfault when uploads are aborted (thanks to Markus  Doppelbauer for his bug report)</li>
<li>session ID header name is now configurable (thanks to Valery Kholodkov)</li>
<li>Added directive to format output as pure json (thanks to Valery  Kholodkov)</li>
<li>Added directive to format output with configurable template (thanks  to Valery Kholodkov)</li>
<li>Added directive to set a probe response content-type (thanks to  Valery Kholodkov)</li>
<li>Added upload status variables (needs a status patch) (thanks to  Valery Kholodkov)</li>
</ul>
<h2>What&#8217;s now cool!</h2>
<p>What is cool is that now with only one directive (upload_progress_json_output) the responses are sent in pure Json and not in javascript mix as it was before.</p>
<p>Another cool feature is the possibility to use templates to send progress information. That means with a simple configuration change nginx can now return XML:</p>
<pre class="syntax-highlight:sh">
upload_progress_content_type &#039;text/xml&#039;;
upload_progress_template starting &#039;&lt;upload&gt;&lt;state&gt;starting&lt;/state&gt;&lt;/upload&gt;&#039;;
upload_progress_template uploading &#039;&lt;upload&gt;&lt;state&gt;uploading&lt;/state&gt;&lt;size&gt;$uploadprogress_length&lt;/size&gt;&lt;uploaded&gt;$uploadprogress_received&lt;/uploaded&gt;&lt;/upload&gt;&#039;;
upload_progress_template done &#039;&lt;upload&gt;&lt;state&gt;done&lt;/state&gt;&lt;/upload&gt;&#039;;
upload_progress_template error &#039;&lt;upload&gt;&lt;state&gt;error&lt;/state&gt;&lt;code&gt;$uploadprogress_status&lt;/code&gt;&lt;/upload&gt;&#039;;
</pre>
<p>Refer to the README in the distribution for more information.</p>
<h2>How do you get it?</h2>
<p>Easy, download the tarball from the <a href="http://github.com/masterzen/nginx-upload-progress-module/downloads" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">nginx upload progress module github repository download section</a>.</p>
<h2>How can I use it?</h2>
<p>Normally you have to use your own client code to display the progress bar and contact nginx to get the progress information.</p>
<p>But some nice people have created various javascript libraries doing this for you:</p>
<ul>
<li><a href="http://github.com/drogus/jquery-upload-progress" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">JQuery upload progress module</a></li>
</ul>
<ul>
<li><a href="http://github.com/edgarjs/prototype-nginx-upload-progress" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">Protoype upload progress module</a></li>
</ul>
<p>Happy uploads!</p>
<div class="feedflare">
<a href="http://feeds.masterzen.fr/~ff/masterzen?a=I9Q0mZTchPc:bGtGltsmlXM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=I9Q0mZTchPc:bGtGltsmlXM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/masterzen?i=I9Q0mZTchPc:bGtGltsmlXM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=I9Q0mZTchPc:bGtGltsmlXM:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=I9Q0mZTchPc:bGtGltsmlXM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/masterzen?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=I9Q0mZTchPc:bGtGltsmlXM:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/masterzen?i=I9Q0mZTchPc:bGtGltsmlXM:gIN9vFwOqvQ" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.masterzen.fr/2009/11/22/nginx-upload-progress-module-v07/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.masterzen.fr/2009/11/22/nginx-upload-progress-module-v07/</feedburner:origLink></item>
		<item>
		<title>MySQL InnoDB and table renaming don’t play well…</title>
		<link>http://feeds.masterzen.fr/~r/masterzen/~3/rp6dRg5sCcs/</link>
		<comments>http://www.masterzen.fr/2009/10/15/mysql-innodb-and-table-renaming-dont-play-well/#comments</comments>
		<pubDate>Thu, 15 Oct 2009 05:52:08 +0000</pubDate>
		<dc:creator>masterzen</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[System Administration]]></category>
		<category><![CDATA[War stories]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[memory]]></category>
		<category><![CDATA[memory leak]]></category>
		<category><![CDATA[mysql patch]]></category>
		<category><![CDATA[oom]]></category>
		<category><![CDATA[patch]]></category>
		<category><![CDATA[rename]]></category>

		<guid isPermaLink="false">http://www.masterzen.fr/?p=116</guid>
		<description><![CDATA[At Days of Wonder we are huge fans of MySQL (and since about a year of the various Open Query, Percona, Google or other community patches), up to the point we&#8217;re using MySQL for about everything in production.
But since we moved to 5.0, back 3 years ago our production databases which hold our website and [...]]]></description>
			<content:encoded><![CDATA[<p>At Days of Wonder we are huge fans of <a href="http://www.mysql.com/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.mysql.com');">MySQL</a> (and since about a year of the various <a href="http://ourdelta.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/ourdelta.org');">Open Query</a>, <a href="http://www.percona.com/percona-lab.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.percona.com');">Percona</a>, <a href="http://code.google.com/p/google-mysql-tools/wiki/Mysql5Patches" onclick="javascript:pageTracker._trackPageview('/outbound/article/code.google.com');">Google</a> or other community patches), up to the point we&#8217;re using MySQL for about everything in production.</p>
<p>But since we moved to 5.0, back 3 years ago our production databases which hold our website and online game systems has a unique issue: the mysqld process uses more and more RAM, up to the point where the <a href="http://linux-mm.org/OOM_Killer" onclick="javascript:pageTracker._trackPageview('/outbound/article/linux-mm.org');">kernel OOM</a> decide to kill the process.</p>
<p>You&#8217;d certainly think we are complete morons because we didn&#8217;t do anything in the last 3 years to fix the issue <img src='http://www.masterzen.fr/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Unfortunately, I never couldn&#8217;t replicate the issue in the lab, mainly because it is difficult to replicate the exact same load the production server sees (mainly because of the online games activity).</p>
<p>During those 3 years, I tried everything I could, from using other allocators, valgrind, debug builds and so on, without any success.</p>
<p>What is nice, is that we moved to an <a href="http://ourdelta.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/ourdelta.org');">OurDelta</a> build about a year ago, where <a href="http://www.innodb.com/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.innodb.com');">InnoDB</a> is able to print more memory statistics than the default MySQL version.</p>
<p>For instance it shows</p>
<pre>Internal hash tables (constant factor + variable factor)
    Adaptive hash index 1455381240      (118999688 + 1336381552)
    Page hash           7438328
    Dictionary cache    281544240       (89251896 + 192292344)
    File system         254712  (82672 + 172040)
    Lock system         18597112        (18594536 + 2576)
    Recovery system     0       (0 + 0)
    Threads             408056  (406936 + 1120)
    innodb_io_pattern   0       (0 + 0)</pre>
<p>Back several month ago, I analyzed this output just to see what figures were growing, and found that the <em>Dictionary Cache variable part </em>was increasing (slowly but definitely).</p>
<p>Sure fine MySQL experts would have been able to tell me exactly what, when and where the problem was, but since I&#8217;m not familiar with the code-base, I looked up what this number was and where it was increased (all in <em>dict0dict.c</em>) and added some logs each time it was increased.</p>
<p>I then installed this version for a quite long time (just to check it wouldn&#8217;t crash on production) on a slave server. But this server didn&#8217;t print anything interesting because it doesn&#8217;t see the exact same load the production masters.</p>
<p>A couple of months after that, I moved this code to one of the master and bingo! I found the operation and the tables exhibiting an increase:</p>
<pre class="syntax-highlight:sh">
mysqld[8131]: InnoDB: dict_table_rename_in_cache production/rank_tmp2 193330680 + 8112
mysqld[8131]: InnoDB: dict_table_rename_in_cache production/rank 193338792 + 8112
</pre>
<p>As soon as I saw the operation and table (ie rank), I found what the culprit is. We have a daemon that every 10s computes the player ranks for our online games.</p>
<p>To do this, we&#8217;re using the following pattern:</p>
<pre class="syntax-highlight:sql">
-- compute the ranks
SELECT NULL, playerID
FROM game_score as g
ORDER BY g.rankscore DESC
INTO OUTFILE &quot;/tmp/rank_tmp.tmp&quot;

-- load back the scores
LOAD DATA INFILE &quot;/tmp/rank_tmp.tmp&quot; INTO TABLE rank_tmp

-- swap tables so that clients see new ranks atomatically
RENAME TABLE rank TO rank_tmp2 , rank_tmp TO rank, rank_tmp2 TO rank_tmp

-- truncate the old ranks for a new pass
TRUNCATE TABLE rank_tmp

-- go back to the select above
</pre>
<p>You might ask why I&#8217;m doing a so much convoluted system, especially the SELECT INTO OUTFILE and the LOAD DATA. It&#8217;s just because INSERT &#8230; SELECT with innodb and binlog enabled can produce transactions abort (which we were getting tons of).</p>
<p>Back to the original issue, apparently the issue lies in the RENAME part of the daemon.</p>
<p>Looking at the <em>dict0dict.c dict_table_rename_in_cache</em> function we see:</p>
<pre class="syntax-highlight:php">
ibool
dict_table_rename_in_cache(...)
...
  old_name = mem_heap_strdup(table-&amp;gt;heap, table-&amp;gt;name);
  table-&amp;gt;name = mem_heap_strdup(table-&amp;gt;heap, new_name);
...
}
</pre>
<p>Looking to <em>mem_heap</em> stuff, I discovered that each table has a heap associated in which InnoDB allocates various things. This heap can only grow (by block of 8112 bytes it seems), since the allocator is not a real one. This is done for performance reasons.</p>
<p>So each time we rename a table, the old name (why? since it is already allocated) is duplicated, along with the new name. Each time.</p>
<p>This heap is freed when the table is dropped, so there is a possibility to reclaim the used memory. That means this issue is not a memory leak per-se.</p>
<p>By the way, I&#8217;ve <a href="http://bugs.mysql.com/?id=47991" onclick="javascript:pageTracker._trackPageview('/outbound/article/bugs.mysql.com');">filed this bug on mysql bug system</a>.</p>
<p>One work-around, beside fixing the code itself, would be to drop the rank table instead of truncating it. The issue with dropping/creating InnoDB table on a fast pace is that the dictionary cache itself will grow, because it can only grow as there is no way to purge it from old tables (except running one of the Percona patches). So the more tables we create the more we&#8217;ll use memory &#8211; back to square 0, but worst.</p>
<p>So right now, I don&#8217;t really have any idea on how to really fix the issue. Anyone having an idea, please do not hesitate to comment on this blog post <img src='http://www.masterzen.fr/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>And please, don&#8217;t tell me to move to MyISAM&#8230;</p>
<div class="feedflare">
<a href="http://feeds.masterzen.fr/~ff/masterzen?a=rp6dRg5sCcs:eRNbOgqWZ2k:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=rp6dRg5sCcs:eRNbOgqWZ2k:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/masterzen?i=rp6dRg5sCcs:eRNbOgqWZ2k:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=rp6dRg5sCcs:eRNbOgqWZ2k:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=rp6dRg5sCcs:eRNbOgqWZ2k:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/masterzen?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=rp6dRg5sCcs:eRNbOgqWZ2k:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/masterzen?i=rp6dRg5sCcs:eRNbOgqWZ2k:gIN9vFwOqvQ" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.masterzen.fr/2009/10/15/mysql-innodb-and-table-renaming-dont-play-well/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://www.masterzen.fr/2009/10/15/mysql-innodb-and-table-renaming-dont-play-well/</feedburner:origLink></item>
		<item>
		<title>My Puppet Camp slides appearing on the slideshare homepage!</title>
		<link>http://feeds.masterzen.fr/~r/masterzen/~3/j9bJ3QMweoY/</link>
		<comments>http://www.masterzen.fr/2009/10/13/my-puppet-camp-slides-appearing-on-the-slideshare-homepage/#comments</comments>
		<pubDate>Tue, 13 Oct 2009 21:48:53 +0000</pubDate>
		<dc:creator>masterzen</dc:creator>
				<category><![CDATA[Puppet]]></category>
		<category><![CDATA[System Administration]]></category>
		<category><![CDATA[pictures]]></category>
		<category><![CDATA[puppet]]></category>
		<category><![CDATA[puppetcamp]]></category>
		<category><![CDATA[puppetcamp09]]></category>
		<category><![CDATA[slideshare]]></category>

		<guid isPermaLink="false">http://www.masterzen.fr/?p=110</guid>
		<description><![CDATA[This morning I got the joy to see that my Puppet Camp 2009 slides had been selected by Slideshare to appear on their home page:
Waouh. For a surprise, that&#8217;s a surprise. I guess those stock photos I used are the underlying reason for this.
Still now that I talk about Puppet Camp again, I forgot to [...]]]></description>
			<content:encoded><![CDATA[<p>This morning I got the joy to see that my Puppet Camp 2009 slides had been selected by Slideshare to appear on their <a href="http://www.slideshare.net" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.slideshare.net');">home page</a>:</p>
<p>Waouh. For a surprise, that&#8217;s a surprise. I guess those stock photos I used are the underlying reason for this.</p>
<p>Still now that I talk about Puppet Camp again, I forgot to give the links to some pictures taken during the event:</p>
<ul>
<li><a href="http://www.flickr.com/photos/43103276@N07/sets/72157622370691217/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.flickr.com');">the ones taken by Glarizza</a> (sorry I don&#8217;t know your real name)</li>
</ul>
<p>and</p>
<ul>
<li><a href="http://www.flickr.com/photos/halliganfamily/tags/puppetcamp/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.flickr.com');">those from Michael Halligan</a></li>
</ul>
<div class="feedflare">
<a href="http://feeds.masterzen.fr/~ff/masterzen?a=j9bJ3QMweoY:lb48OzvDEoQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=j9bJ3QMweoY:lb48OzvDEoQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/masterzen?i=j9bJ3QMweoY:lb48OzvDEoQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=j9bJ3QMweoY:lb48OzvDEoQ:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=j9bJ3QMweoY:lb48OzvDEoQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/masterzen?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=j9bJ3QMweoY:lb48OzvDEoQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/masterzen?i=j9bJ3QMweoY:lb48OzvDEoQ:gIN9vFwOqvQ" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.masterzen.fr/2009/10/13/my-puppet-camp-slides-appearing-on-the-slideshare-homepage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.masterzen.fr/2009/10/13/my-puppet-camp-slides-appearing-on-the-slideshare-homepage/</feedburner:origLink></item>
		<item>
		<title>Puppet Camp 2009 debriefing time!</title>
		<link>http://feeds.masterzen.fr/~r/masterzen/~3/aw1M-QeleYM/</link>
		<comments>http://www.masterzen.fr/2009/10/05/puppet-camp-2009-debriefing-time/#comments</comments>
		<pubDate>Mon, 05 Oct 2009 01:42:52 +0000</pubDate>
		<dc:creator>masterzen</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Puppet]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[System Administration]]></category>
		<category><![CDATA[presentation]]></category>
		<category><![CDATA[puppet]]></category>
		<category><![CDATA[puppetcamp]]></category>
		<category><![CDATA[puppetcamp09]]></category>
		<category><![CDATA[storeconfigs]]></category>

		<guid isPermaLink="false">http://www.masterzen.fr/?p=105</guid>
		<description><![CDATA[I attended Puppet Camp 2009 in San Francisco last week. It was a wonderful event and I could meet a lot of really smart developers and sysadmins from a lot of different countries (US, Australia, Europe and even Singapore).
The format of the event (an unconference with some scheduled talks in the morning) was really great. [...]]]></description>
			<content:encoded><![CDATA[<p>I attended <a href="http://reductivelabs.com/home/community/puppetcamp/" onclick="javascript:pageTracker._trackPageview('/outbound/article/reductivelabs.com');">Puppet Camp 2009</a> in San Francisco last week. It was a wonderful event and I could meet a lot of really smart developers and sysadmins from a lot of different countries (US, Australia, Europe and even Singapore).</p>
<p>The format of the event (an unconference with some scheduled talks in the morning) was really great. Everybody got a chance to enter or propose a discussion topic they care about. I could attend some development sessions about the Ruby DSL vs Parser DSL, Code smells, Puppet Provider/Type developments, <a href="http://augeas.net/" onclick="javascript:pageTracker._trackPageview('/outbound/article/augeas.net');">Augeas</a>, and so on&#8230;</p>
<p>Morning talks were awesome. I was presenting a talk about storeconfigs, called &#8220;All About Storeconfigs&#8221;. Puppet Storeconfigs is a feature where you can store nodes configuration and export/collect resources between nodes with the help of a database. I already talked about this in a couple of posts:</p>
<ul>
<li><a title="Permanent Link to Storeconfigs (advanced) use cases" rel="bookmark" href="../2009/08/08/storeconfigs-use-cases/">Storeconfigs (advanced) use cases</a></li>
<li><a title="Permanent Link to OMG!! storedconfigs killed my database!" rel="bookmark" href="../2009/03/18/omg-storedconfigs-killed-my-database/">OMG!! storedconfigs killed my database!</a></li>
<li><a title="Permanent Link to All about Puppet storeconfigs" rel="bookmark" href="../2009/03/08/all-about-puppet-storeconfigs/">All about Puppet storeconfigs</a></li>
</ul>
<p>You can enjoy <a href="http://coursestream.sfsu.edu/ess/feed?id=e723afa9-1748-43c7-8231-180d2a7f7d3e&amp;type=MP3" onclick="javascript:pageTracker._trackPageview('/outbound/article/coursestream.sfsu.edu');">the recording of the session</a> (event though they cut the first part which is not that good), and have closer look to my slides here:</p>
<div id="__ss_2123814" style="width: 425px; text-align: left;"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" title="All About Storeconfigs" href="http://www.slideshare.net/masterzen/all-about-storeconfigs-2123814" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.slideshare.net');">All About Storeconfigs</a><object width="425" height="355" data="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=storeconfigs-091004202239-phpapp02&amp;stripped_title=all-about-storeconfigs-2123814" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowScriptAccess" value="always" /><param name="src" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=storeconfigs-091004202239-phpapp02&amp;stripped_title=all-about-storeconfigs-2123814" /><param name="allowfullscreen" value="true" /></object></p>
<div style="font-size: 11px; font-family: tahoma,arial; height: 26px; padding-top: 2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.slideshare.net');">documents</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/masterzen" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.slideshare.net');">Brice Figureau</a>.</div>
</div>
<p>What&#8217;s great with those conferences in foreign countries is that you usually finish at the pub with some local people to continue to share Puppet (or not) experiences. Those parties were plenty of fun, so thank you everybody for this.</p>
<p>So thanks everybody and Reductive Labs team (especially Andrew who organized everything) for this event, and thanks to <a href="http://www.daysofwonder.com" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.daysofwonder.com');">Days of Wonder</a> for funding my trip!</p>
<div class="feedflare">
<a href="http://feeds.masterzen.fr/~ff/masterzen?a=aw1M-QeleYM:riDdqO60Dss:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=aw1M-QeleYM:riDdqO60Dss:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/masterzen?i=aw1M-QeleYM:riDdqO60Dss:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=aw1M-QeleYM:riDdqO60Dss:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=aw1M-QeleYM:riDdqO60Dss:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/masterzen?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=aw1M-QeleYM:riDdqO60Dss:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/masterzen?i=aw1M-QeleYM:riDdqO60Dss:gIN9vFwOqvQ" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.masterzen.fr/2009/10/05/puppet-camp-2009-debriefing-time/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://www.masterzen.fr/2009/10/05/puppet-camp-2009-debriefing-time/</feedburner:origLink></item>
		<item>
		<title>Inexpensive but Powerful Photo Geotagging</title>
		<link>http://feeds.masterzen.fr/~r/masterzen/~3/jRRArR_Vb9w/</link>
		<comments>http://www.masterzen.fr/2009/09/06/inexpensive-but-powerful-photo-geotagging/#comments</comments>
		<pubDate>Sun, 06 Sep 2009 16:31:22 +0000</pubDate>
		<dc:creator>masterzen</dc:creator>
				<category><![CDATA[Photography]]></category>
		<category><![CDATA[geotag]]></category>
		<category><![CDATA[geotagging]]></category>
		<category><![CDATA[gps]]></category>
		<category><![CDATA[gpx]]></category>
		<category><![CDATA[igotu]]></category>
		<category><![CDATA[macosx]]></category>

		<guid isPermaLink="false">http://www.masterzen.fr/?p=94</guid>
		<description><![CDATA[It&#8217;s a long time since I blogged about photography, but I&#8217;m coming back from 2 weeks vacation in Sicily armed with my Nikon D700, so it&#8217;s the perfect time to talk about this hobby.
Since I sold my soul to our digital overlord (and ditched my slide scanner at the same time), I now have access [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s <a href="http://www.masterzen.fr/2009/02/01/no-more-slides-welcome-to-our-digital-overlords/" >a long time since I blogged about photography</a>, but I&#8217;m coming back from 2 weeks vacation in Sicily armed with my Nikon D700, so it&#8217;s the perfect time to talk about this hobby.</p>
<p>Since I sold my soul to our digital overlord (and ditched my slide scanner at the same time), I now have access to all the options digital photography can give me. And one that is very cool is <a href="http://en.wikipedia.org/wiki/Geotagging" onclick="javascript:pageTracker._trackPageview('/outbound/article/en.wikipedia.org');">geotagging</a>.</p>
<p>When I purchased my <a href="http://imaging.nikon.com/products/imaging/lineup/digitalcamera/slr/d700/index.htm" onclick="javascript:pageTracker._trackPageview('/outbound/article/imaging.nikon.com');">D700</a> back in last December, I had this whole geotagging idea back in my mind. Unfortunately at that time I couldn&#8217;t find any inexpensive but powerful geotagging system.</p>
<p>Sure you can use almost any GPS logger for this task, but the current models at that time were heavy and expensive and more directed to sports than photography.</p>
<p>Sure Nikon is selling the <a href="http://www.nikonusa.com/Find-Your-Nikon/Product/Miscellaneous/25396/GP-1-GPS-Unit.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.nikonusa.com');">GP-1 GPS module</a> you can attach on the camera, unfortunately it is expensive, large and doesn&#8217;t seem to be available in France.</p>
<p>But a couple of month ago, my father send me a link about a damn small GPS logger called: <a href="http://www.i-gotu.com/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.i-gotu.com');">I got U</a> GTS-120.</p>
<div id="attachment_95" class="wp-caption aligncenter" style="width: 160px"><img class="size-thumbnail wp-image-95" title="I got U - GTS 120" src="http://www.masterzen.fr/wp-content/uploads/2009/09/igotu2-150x150.jpg" alt="I got U - GTS 120" width="150" height="150" /><p class="wp-caption-text">I got U - GTS 120</p></div>
<p style="text-align: center;">
<p>The device is just a <a href="http://en.wikipedia.org/wiki/GPS_tracking" onclick="javascript:pageTracker._trackPageview('/outbound/article/en.wikipedia.org');">GPS logger</a>, it doesn&#8217;t have any display (except a blue and red led), and is not linked to the camera in anyway (it records a position every few seconds, this interval can be customized, mine is take a point every 30s).</p>
<p>The thing is really cool:</p>
<ul>
<li>it is as small as 2 (French sized) sugar cubes and weights only 20g.</li>
<li>it has a large autonomy (it covered my 2 weeks vacation with intermittent usage without charging it). You can charge it connected on a computer or with any USB charger (I&#8217;m using an ipod one).</li>
<li>it can capture 65000 waypoints. The frequency of acquisition can be controlled, and the 6s default one seems a little bit fast for me. I&#8217;m using comfortably 30s.</li>
<li>it is cheap, about 50 EUR in France.</li>
<li>it seems to work while in the pocket <img src='http://www.masterzen.fr/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </li>
</ul>
<p>The device is sold with an USB cable for charging and data access, and software. This software can be used to setup the device, display your trips, and associates photos to waypoints.</p>
<p>The main drawback of the system is that it is lacking a Mac OS X application. But that&#8217;s not a big deal, since there&#8217;s a GPL Mac OS X/Linux tool to download the waypoints called <a href="https://launchpad.net/igotu2gpx" onclick="javascript:pageTracker._trackPageview('/outbound/article/launchpad.net');">igotu2gpx</a>. Once launched, this tool auto-detects the device. Then you can grab the waypoints and save them as GPX for future use.</p>
<p>But we&#8217;ve done only half of the way to geotagging the photos. Here comes another (free) tool: <a href="http://www.earlyinnovations.com/gpsphotolinker/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.earlyinnovations.com');">GPS Photolinker</a> which can automatically batch geotagging tons of photos. This tool knows how to read most of the RAW photo formats, including Nikon NEF.</p>
<p><em>Geotagging</em> is done by matching the date and time of the photo (which is stored somewhere in the EXIF data) with one of the waypoint, so it works for NEF and JPG formats.</p>
<p>If no waypoint date and time match, the software assigns either the closest matching waypoint (up to a configurable time difference) or a linear interpolation between two consecutive waypoint. Of course you need your camera to have an accurate date and time (mine is synchronized each time I connect it to the Nikon transfer software). GPS Photolinker is able to apply a time shift if your camera clock wasn&#8217;t accurately set. One nice feature of GPS Photolinker is that it fills the City and Country fields of the IPTC data section with Google Maps information (which seems to be accurate).</p>
<p>Here is a sample of my Sicily geotagging efforts in Smugmug:</p>
<p><img class="aligncenter size-full wp-image-98" title="Geotagged photos appearing as pins in Smugmug" src="http://www.masterzen.fr/wp-content/uploads/2009/09/map.jpg" alt="Geotagged photos appearing as pins in Smugmug" width="400" height="290" /></p>
<p>Happy geotagging!</p>
<div class="feedflare">
<a href="http://feeds.masterzen.fr/~ff/masterzen?a=jRRArR_Vb9w:dvX2mg0Cw8E:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=jRRArR_Vb9w:dvX2mg0Cw8E:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/masterzen?i=jRRArR_Vb9w:dvX2mg0Cw8E:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=jRRArR_Vb9w:dvX2mg0Cw8E:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/masterzen?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=jRRArR_Vb9w:dvX2mg0Cw8E:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/masterzen?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.masterzen.fr/~ff/masterzen?a=jRRArR_Vb9w:dvX2mg0Cw8E:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/masterzen?i=jRRArR_Vb9w:dvX2mg0Cw8E:gIN9vFwOqvQ" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.masterzen.fr/2009/09/06/inexpensive-but-powerful-photo-geotagging/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.masterzen.fr/2009/09/06/inexpensive-but-powerful-photo-geotagging/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic Page Served (once) in 0.619 seconds --><!-- Cached page served by WP-Cache -->
