<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="http://blog.pwkf.org/feed/rss2/xslt" ?><rss version="2.0"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <title>Personal Workflow Blog</title>
  <link>http://blog.pwkf.org/</link>
  <atom:link href="http://blog.pwkf.org:82/feed/rss2" rel="self" type="application/rss+xml"/>
  <description>Some thoughts I encounter during my working day in the J2EE land. Originally a blog about PWKF, an easy-to-use workflow solution, but I have less time to work on PWKF that what I had before as real life kicked in !</description>
  <language>en</language>
  <pubDate>Fri, 24 May 2013 13:10:42 +0200</pubDate>
  <copyright>(c) 2006-2011 - Steve Schnepp</copyright>
  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  <generator>Dotclear</generator>
  
    
  <item>
    <title>Spinoffs in the munin ecosystem</title>
    <link>http://blog.pwkf.org/post/2013/04/Spinoffs-in-the-munin-ecosystem</link>
    <guid isPermaLink="false">urn:md5:440686798cf8dd47249c366d7dfd9b81</guid>
    <pubDate>Sat, 13 Apr 2013 14:42:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>ecosystem</category><category>munin</category><category>sysadmin</category>    
    <description>    &lt;h2&gt;KISS is the core design of Munin&lt;/h2&gt;
&lt;p&gt;Munin's greatest strength is its very KISS architecture. It therefore gets
many things right, such as a huge modularity.&lt;/p&gt;
&lt;p&gt;Each component (master/node/plugin) has a simple API to communicate with the
others.&lt;/p&gt;
&lt;h2&gt;Spin-offs ...&lt;/h2&gt;
&lt;p&gt;I admit that the master, even the node, have convoluted code. In fact some
rewrites already do exist.&lt;/p&gt;
&lt;h3&gt;... are welcomed ...&lt;/h3&gt;
&lt;p&gt;And they are a really good thing, as it enables rapid prototyping on things
that the stock munin has (currently) trouble to do.&lt;/p&gt;
&lt;p&gt;The stock munin is a piece of software that many depend upon, so it has to
move at a much slower pace than one does want, even me. As much as I really
want to add many many features to it, I still have to take extra care that it
doesn't break stuff, even the least known features.&lt;/p&gt;
&lt;p&gt;So I take munin off-springs very seriously and even offer as much help as I
can in order for them to succeed.&lt;/p&gt;
&lt;h3&gt;... because they are very valuable in the long term&lt;/h3&gt;
&lt;p&gt;In my opinion competition is only short bad in the short term, and in the
long term they usually add significant value to the whole ecosystem. That said,
there's always a risk to become slowly irrelevant, but I think that's the real
power of open-source's evolutionary paradigm : embrace them or become obsolete
and get replaced.&lt;/p&gt;
&lt;p&gt;Since, if someone takes the time to author a competitor that has a real
threat potential, it mostly means that there's a real itch to scratch and that
many things are to be learnt.&lt;/p&gt;
&lt;h2&gt;Different layers of spin-offs&lt;/h2&gt;
&lt;p&gt;The munin ecosystem is divided in 3 main categories, obviously related to
the 3 main components of munin : master, node &amp;amp; plugin.&lt;/p&gt;
&lt;h3&gt;Plugins&lt;/h3&gt;
&lt;p&gt;That's the most obvious part as custom plugins are the real &lt;em&gt;bread and
butter&lt;/em&gt; of munin.&lt;/p&gt;
&lt;p&gt;Stock plugins are mostly written in Perl or POSIX shell, as Perl is munin's
own language and POSIX shell is ubiquitous. That fact is acknowledged by the
fact that core munin provides 2 libraries (Perl &amp;amp; Shell) to help plugin
authoring.&lt;/p&gt;
&lt;p&gt;So, it's quite natural that each mainstream language has grown its own
plugin library. Some language even have &lt;a href=&quot;https://github.com/aouyar/PyMunin&quot; hreflang=&quot;en&quot;&gt;two&lt;/a&gt; of &lt;a href=&quot;https://github.com/samuel/python-munin&quot; hreflang=&quot;en&quot;&gt;them&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;C&lt;/h4&gt;
&lt;p&gt;Some plugins got even rewritten in plain C, as it was shown that shell
plugins do have a significant impact on very under-powered nodes, such as
embedded routers.&lt;/p&gt;
&lt;h3&gt;Node&lt;/h3&gt;
&lt;p&gt;This component is very simple. Yet, it has to be run on all the nodes that
one wants to monitor. It is currently written in Perl, and while that's not an
issue on UNIX-like systems, it can be quite problematic on embedded ones&lt;/p&gt;
&lt;h4&gt;Simple munin&lt;/h4&gt;
&lt;p&gt;The official package comes with a POSIX shell rewrite that has to be run
from inetd. It is quite useful for embedded routers like OpenWRT, but still
suffers from an hard dep on POSIX shell and inetd.&lt;/p&gt;
&lt;h4&gt;SNMP&lt;/h4&gt;
&lt;p&gt;SNMP is another way to monitor nodes. While it works really well, it mostly
suffers the fact that its configuration is quite different of the usual way, so
I guess some things will change on that side.&lt;/p&gt;
&lt;h4&gt;Win32 ports&lt;/h4&gt;
&lt;p&gt;Win32 has long been a very difficult OS to monitor, as it doesn't offer much
of the UNIX-esque features. Yet the number of win32 nodes that one wants to
monitor is quite high, as it makes munin one the few systems that can easily
monitor heterogeneous systems.&lt;/p&gt;
&lt;p&gt;Therefore, while you can install the stock munin-node, several projects
emerged. We decided to adopt &lt;a href=&quot;http://munin-monitoring.org/browser/munin-node-win32&quot; hreflang=&quot;en&quot;&gt;munin-node-win32&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Android&lt;/h4&gt;
&lt;p&gt;There's also a dedicated &lt;a href=&quot;https://github.com/silverchris/Android-Munin-Node&quot; hreflang=&quot;en&quot;&gt;node for
Android&lt;/a&gt;. It makes sense, given that the Android is yet Linux-derived, but
lacks Perl, and is a Java mostly platform. This node also has some basic
capabilities of pushing data to the master instead of the usual polling.&lt;/p&gt;
&lt;p&gt;This is specially interesting given the fact that Android nodes are usually
loosely connected, so the node spools values itself and pushes them when it
recovers connectivity.&lt;/p&gt;
&lt;p&gt;Note that this is specifically an aspect that is currently lacking in munin,
and I'm planning to address it in the 2.1 series. So thanks to its author for
showing a relevant use-case.&lt;/p&gt;
&lt;h4&gt;C&lt;/h4&gt;
&lt;p&gt;That's my last experiment. It started with a simple question : &lt;em&gt;how
difficult would it be to code a fairly portable version of the node ?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It turned out that it wasn't that difficult. I'm even asking myself about
eventually replacing the win32 specific port with this one, as the code is much
simpler. The win32 node has several plugin built-in mostly due to platform
specifics. I still have to find a way to work my way around it, but it's in
quite good shape.&lt;/p&gt;
&lt;p&gt;This post was originally done to promote it, but while writing it I noticed
that the ecosystem deserved a post on its own. So I'll write another one,
specific to the C port of munin-node and plugins.&lt;/p&gt;
&lt;h3&gt;Master&lt;/h3&gt;
&lt;p&gt;The master is the most complex component. So rewrites of it won't happen
as-is. They usually take the form of a bridge between the munin protocol and
another graphing system, such as Graphite.&lt;/p&gt;
&lt;h4&gt;Clients&lt;/h4&gt;
&lt;p&gt;There are also client libraries that are able to directly query munin nodes,
to be able to reuse the vast ecosystem. Languages are various, from the obvious
&lt;a href=&quot;http://julien.danjou.info/projects/pymunincli/&quot; hreflang=&quot;en&quot;&gt;Python&lt;/a&gt; to &lt;a href=&quot;https://github.com/sosedoff/munin-ruby&quot; hreflang=&quot;en&quot;&gt;Ruby&lt;/a&gt;, along with a quite modern &lt;a href=&quot;https://github.com/Redpill-Linpro/node-munin-client&quot;&gt;node.js&lt;/a&gt; one.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2013/04/Spinoffs-in-the-munin-ecosystem#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2013/04/Spinoffs-in-the-munin-ecosystem#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/729285</wfw:commentRss>
      </item>
    
  <item>
    <title>Do not fear git rebase : make snapshots !</title>
    <link>http://blog.pwkf.org/post/2013/04/Do-not-fear-git-rebase-%3A-make-snapshots-%21</link>
    <guid isPermaLink="false">urn:md5:a4b26960bf61185026fd6b59bcc9b18e</guid>
    <pubDate>Thu, 04 Apr 2013 20:48:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>programming</category>
        <category>backup</category><category>git</category><category>rebase</category>    
    <description>    &lt;p&gt;Git is a nice version system, but some commands are destructrive, such as
rebase.&lt;/p&gt;
&lt;p&gt;Here is a script to have a safety net, and free backups !&lt;/p&gt;
&lt;pre&gt;
#! /bin/sh
# Script to snaphot a git repo
SNAP_VERSION=$(date +%s)
BUNDLE_NAME=$(basename $( pwd )).${SNAP_VERSION}.git.bundle
git bundle create ../${BUNDLE_NAME} --all
git remote add snap-${SNAP_VERSION} ../${BUNDLE_NAME}
git fetch -p snap-${SNAP_VERSION}
&lt;/pre&gt;
&lt;p&gt;Usage is very easy. If you want to restore your current branch to the master
one you made earlier.&lt;/p&gt;
&lt;pre&gt;
git reset --hard snap-1365068411/master
&lt;/pre&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2013/04/Do-not-fear-git-rebase-%3A-make-snapshots-%21#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2013/04/Do-not-fear-git-rebase-%3A-make-snapshots-%21#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/727986</wfw:commentRss>
      </item>
    
  <item>
    <title>When having good relationships with package maintainers can also be a curse</title>
    <link>http://blog.pwkf.org/post/2013/02/good-relationships-maintainers-curse</link>
    <guid isPermaLink="false">urn:md5:1ee5de3b0be031a31b35b328f6af58d4</guid>
    <pubDate>Sun, 24 Feb 2013 13:23:00 +0100</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>packaging</category>    
    <description>    &lt;p&gt;I advise every user to &lt;strong&gt;only&lt;/strong&gt; use the &lt;strong&gt;packaged
version&lt;/strong&gt; of &lt;a href=&quot;http://munin-monitoring.org&quot; hreflang=&quot;en&quot;&gt;munin&lt;/a&gt;. Here's a short article to explain the background of my
reluctance to ask for users to directly use the official tarball.&lt;/p&gt;
&lt;p&gt;I have become upstream of &lt;a href=&quot;http://munin-monitoring.org&quot; hreflang=&quot;en&quot;&gt;munin&lt;/a&gt; a while ago now. As such, I'm in contact with package
maintainers. They take the official releases and cram it into their own
distribution of choice&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2013/02/#pnote-721204-1&quot; id=&quot;rev-pnote-721204-1&quot; name=&quot;rev-pnote-721204-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;I have to admit that the various epic war stories read throughout the web
about &lt;em&gt;upstream vs packagers&lt;/em&gt; are very far from the truth here. They are
a &lt;ins&gt;charm&lt;/ins&gt; to work with. Often challenging and demanding, but always
because there's a real need. And that's quite a good thing, as I'm still a
rookie in term of open source software management. Therefore I'm quite grateful
when they gently pinpoint my mistakes&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2013/02/#pnote-721204-2&quot; id=&quot;rev-pnote-721204-2&quot; name=&quot;rev-pnote-721204-2&quot;&gt;2&lt;/a&gt;]&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Yet, this nice team comes with a &lt;em&gt;price&lt;/em&gt;. Since we mostly hang out on
IRC together, there is way much inter-distro communication than on other
software. But I'm the &lt;em&gt;sole&lt;/em&gt; owner of the &lt;em&gt;tarball distro&lt;/em&gt; .&lt;/p&gt;
&lt;p&gt;Yet, as I don't like to build everything from source, I obviously use a
distro. There, since the packaging is very nicely done, I don't feel to take
the hassle of using my own &amp;quot;tarball&amp;quot; to test them. I just build a package for
my distro out of the release code.&lt;/p&gt;
&lt;p&gt;That's also a curse, as I admit that I although I test the &lt;em&gt;code&lt;/em&gt;, I
only seldom test the &lt;em&gt;packaging&lt;/em&gt;. This means that I cannot really advise
someone on using the tarball, nor directly git code as even I don't do it.&lt;/p&gt;
&lt;p&gt;But, that said, &lt;strong&gt;I still think I'm the luckiest upstream
around&lt;/strong&gt;. Thanks guys !&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2013/02/#rev-pnote-721204-1&quot; id=&quot;pnote-721204-1&quot; name=&quot;pnote-721204-1&quot;&gt;1&lt;/a&gt;] Be it linux-based like Gentoo, Redhat..., BSD-based as
FreeBSD, OpenBSD..., or even multi-kernel based as Debian&lt;/p&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2013/02/#rev-pnote-721204-2&quot; id=&quot;pnote-721204-2&quot; name=&quot;pnote-721204-2&quot;&gt;2&lt;/a&gt;] Defaulting to CGI graphics was a move that was way too
premature, end-user wise. So thanks to them, it defaults to cron again&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2013/02/good-relationships-maintainers-curse#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2013/02/good-relationships-maintainers-curse#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/721204</wfw:commentRss>
      </item>
    
  <item>
    <title>Avoid those milli-hits in Munin</title>
    <link>http://blog.pwkf.org/post/2013/02/Avoid-those-milli-hits-in-Munin</link>
    <guid isPermaLink="false">urn:md5:1cfbd4f11b7797cb82e1c534cd701530</guid>
    <pubDate>Fri, 01 Feb 2013 01:47:00 +0100</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>sysadmin</category>    
    <description>    &lt;p&gt;A recurring question on IRC is : &lt;q&gt;why do I have 500 million hit/s in my
graph ?&lt;/q&gt;.&lt;/p&gt;
&lt;p&gt;Turns out that they are really seeing &lt;code&gt;500m hit/s&lt;/code&gt;, and that
lower-case &lt;code&gt;m&lt;/code&gt; means &lt;em&gt;milli&lt;/em&gt;, and not &lt;em&gt;Mega&lt;/em&gt; as
specified in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Metric_prefix&quot; hreflang=&quot;en&quot;&gt;Metric system&lt;/a&gt;. This is automatically done by RRD.&lt;/p&gt;
&lt;p&gt;To avoid this you should just specify &lt;code&gt;graph_scale no&lt;/code&gt; as
&lt;a href=&quot;http://munin-monitoring.org/wiki/graph_scale&quot; hreflang=&quot;en&quot;&gt;specified&lt;/a&gt;.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2013/02/Avoid-those-milli-hits-in-Munin#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2013/02/Avoid-those-milli-hits-in-Munin#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/717685</wfw:commentRss>
      </item>
    
  <item>
    <title>Waiting for Munin 2.0 - Break the 5 minutes barrier !</title>
    <link>http://blog.pwkf.org/post/2012/07/Waiting-for-Munin-2.0-Break-the-5-minutes-barrier</link>
    <guid isPermaLink="false">urn:md5:f744e8b37a4da9119f7da6bbd840f083</guid>
    <pubDate>Thu, 12 Jul 2012 21:58:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
            
    <description>    &lt;p&gt;Every monitoring software has a polling rate. It is usually 5 min, because
it's the sweet spot that enables frequent updates yet still having a low
overhead.&lt;/p&gt;
&lt;p&gt;Munin is not different in that respect : it's data fetching routines
&lt;strong&gt;have&lt;/strong&gt; to be launched every 5 min, otherwise you'll face data
loss. And this 5 min period is deeply grained in the code. So changing it is
possible, but very tedious and error prone.&lt;/p&gt;
&lt;p&gt;But sometimes we need a very fine sampling rate. Every 10 seconds enables us
to track fast changing metrics that would be averaged out otherwise. Changing
the whole polling process to cope with a 10s period is very hard on hardware,
since now &lt;strong&gt;every&lt;/strong&gt; update has to finish in these 10 seconds.&lt;/p&gt;
&lt;p&gt;This triggered an extension in the plugin protocol, commonly known as
&lt;em&gt;supersampling&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Supersampling&lt;/h2&gt;
&lt;h3&gt;Overview&lt;/h3&gt;
&lt;p&gt;The basic idea is that fine precision should only be for selected plugins
only. It also cannot be triggered from the master, since the overhead would be
way too big.&lt;/p&gt;
&lt;p&gt;So, we just let the plugin sample itself the values at a rate it feels
adequate. Then each polling round, the master fetches all the samples since
last poll.&lt;/p&gt;
&lt;p&gt;This enables various constructions, mostly around &lt;em&gt;streaming&lt;/em&gt; plugins
to achieve highly detailed sampling with a very small overhead.&lt;/p&gt;
&lt;h5&gt;Notes&lt;/h5&gt;
&lt;p&gt;This protocol is currently completely transparent to
&lt;code&gt;munin-node&lt;/code&gt;, and therefore it means that it can be used even on
older (1.x) nodes. Only a 2.0 master is required.&lt;/p&gt;
&lt;h3&gt;Protocol details&lt;/h3&gt;
&lt;p&gt;The protocol itself is derived from the spoolfetch extension.&lt;/p&gt;
&lt;h4&gt;Config&lt;/h4&gt;
&lt;p&gt;A new directive is used, &lt;code&gt;update_rate&lt;/code&gt;. It enables the master to
create the rrd with an adequate step.&lt;/p&gt;
&lt;p&gt;Omitting it would lead to rrd averaging the supersampled values onto the
default 5 min rate. This means &lt;strong&gt;data loss&lt;/strong&gt;.&lt;/p&gt;
&lt;h5&gt;Notes&lt;/h5&gt;
&lt;p&gt;The heartbeat has always a 2 step size, so failure to send all the samples
will result with unknown values, as expected.&lt;/p&gt;
&lt;p&gt;The RRD file size is always the same in the default config, as all the RRA
are configured proportionally to the &lt;code&gt;update_rate&lt;/code&gt;. This means that,
since you'll keep as much data as with the default, you keep it for a shorter
time.&lt;/p&gt;
&lt;h4&gt;Fetch&lt;/h4&gt;
&lt;p&gt;When spoolfetching, the epoch is also sent in front of the value.
Supersampling is then just a matter of sending multiple epoch/value lines, with
monotonically increasing epoch. Note that since the epoch is an integer value
for rrdtool, the smallest granularity is 1 second. For the time being, the
protocol itself does also mandates integers. We can easily imagine that with
another database as backend, an extension could be hacked together.&lt;/p&gt;
&lt;h3&gt;Compatibility with 1.4&lt;/h3&gt;
&lt;p&gt;On older 1.4 masters, only the last sampled value gets into the rrd.&lt;/p&gt;
&lt;h3&gt;Sample implementation&lt;/h3&gt;
&lt;p&gt;The canonical sample implementation is multicpu1sec, a contrib plugin on
github. It is also a so-called streaming plugin.&lt;/p&gt;
&lt;h3&gt;Streaming plugins&lt;/h3&gt;
&lt;p&gt;These plugins fork a background process when called that streams a system
tool into a spool file. In multipcu1sec, it is the &lt;code&gt;mpstat&lt;/code&gt; tool
with a period of 1 second.&lt;/p&gt;
&lt;h2&gt;Undersampling&lt;/h2&gt;
&lt;p&gt;Some plugins are on the opposite side of the spectrum, as they only need a
lower precision.&lt;/p&gt;
&lt;p&gt;It makes sense when :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;data should be kept for a &lt;em&gt;very&lt;/em&gt; long time&lt;/li&gt;
&lt;li&gt;data is &lt;strong&gt;very&lt;/strong&gt; expensive to generate and it doesn't vary
fast.&lt;/li&gt;
&lt;/ul&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2012/07/Waiting-for-Munin-2.0-Break-the-5-minutes-barrier#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2012/07/Waiting-for-Munin-2.0-Break-the-5-minutes-barrier#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/613559</wfw:commentRss>
      </item>
    
  <item>
    <title>Enhance RRD I/O performance in Munin 1.4 and Scale</title>
    <link>http://blog.pwkf.org/post/2011/06/Enhance-RRD-I/O-performance-in-Munin-1.4-and-Scale</link>
    <guid isPermaLink="false">urn:md5:e375b97e3b545a1b4e856d09553193e4</guid>
    <pubDate>Mon, 20 Jun 2011 09:42:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>performance</category><category>rrd</category>    
    <description>    &lt;p&gt;As with most of the RRD-based monitoring software (Cacti, Ganglia, ...), it
is quite difficult to scale.&lt;/p&gt;
&lt;p&gt;The bad part is that &lt;strong&gt;updating&lt;/strong&gt; &lt;strong&gt;lots&lt;/strong&gt; of
small RRD files seems like &lt;strong&gt;pure random I/O to&lt;/strong&gt; the OS as stated
in there documentation.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;good part&lt;/strong&gt; is that we are not alone, and therefore the
&lt;strong&gt;RRD developers did tackle the issue&lt;/strong&gt; with &lt;a href=&quot;http://oss.oetiker.ch/rrdtool/doc/rrdcached.en.html&quot; hreflang=&quot;en&quot;&gt;rrdcached&lt;/a&gt;. It spools the updates, and flushs them to disk in a batched
manner, or when needed by a rrd read command such as graphing. That's why it is
&lt;strong&gt;scales&lt;/strong&gt; well when using &lt;strong&gt;CGI graphing&lt;/strong&gt;.
Otherwise, munin-graph will read every rrd, and therefore force a flush on all
the cache.&lt;/p&gt;
&lt;p&gt;And the icing on the cake is that, although it is only fully integrated to
munin 2.0, &lt;strong&gt;you can use it right away in the 1.4.x series&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You only need to define the environment variable
&lt;code&gt;RRDCACHED_ADDRESS&lt;/code&gt; while running the scripts accessing the
RRDs.&lt;/p&gt;
&lt;p&gt;Then, you have to remove the &lt;code&gt;munin-graph&lt;/code&gt; part of the
&lt;code&gt;munin-cron&lt;/code&gt; and run it on its own line. Usually only every hour or
so, to be able to accumulate data in &lt;code&gt;rrdcached&lt;/code&gt; before flushing it
all to disk when graphing.&lt;/p&gt;
&lt;p&gt;Updating to 2.0 is also an option to have a real CGI support. (CGI on 1.4 is
existing but has nowhere decent performance).&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2011/06/Enhance-RRD-I/O-performance-in-Munin-1.4-and-Scale#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2011/06/Enhance-RRD-I/O-performance-in-Munin-1.4-and-Scale#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/614814</wfw:commentRss>
      </item>
    
  <item>
    <title>Autovivification in Perl : Great Idea but also Huge Trap - Another Leaking Abstraction...</title>
    <link>http://blog.pwkf.org/post/2011/06/Autovivification-in-Perl-Great-Idea-Huge-Trap-Leaking-Abstraction</link>
    <guid isPermaLink="false">urn:md5:a3f3a669f2a289052af57b868d238497</guid>
    <pubDate>Thu, 16 Jun 2011 20:20:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>perl</category>
        <category>fail</category><category>perl</category>    
    <description>    &lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Autovivification&quot; hreflang=&quot;en&quot;&gt;Autovivification&lt;/a&gt; is one of Perl's really great design success.&lt;/p&gt;
&lt;p&gt;It all comes to &lt;em&gt;you don't need to worry about existence before
dereferencing something&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;That means, for setting a nested hash, you only need to write :&lt;/p&gt;
&lt;pre&gt;
$h-&amp;gt;{foo}{bar} = &amp;quot;value&amp;quot;;
&lt;/pre&gt;
&lt;p&gt;And that will work out of the box. Perl will happily create all the
data-structure for you.&lt;/p&gt;
&lt;p&gt;So, now a little coding test, what does the following code output ?&lt;/p&gt;
&lt;pre&gt;
my $a;

if ($a-&amp;gt;{foo}{bar}) {
   print &amp;quot;Found foo/bar\n&amp;quot;;
}

if ($a-&amp;gt;{foo}) {
   print &amp;quot;Found foo\n&amp;quot;;
}
&lt;/pre&gt;
&lt;p&gt;Naively, it shouldn’t output anything, right ?&lt;/p&gt;
&lt;p&gt;Not so fast. Upon a careful read of &lt;q&gt;Perl will happily create all the
data-structure for you&lt;/q&gt;, we can put some emphasis on one word : &lt;q&gt;Perl will
happily &lt;strong&gt;create&lt;/strong&gt; all the data-structure for you&lt;/q&gt;.&lt;/p&gt;
&lt;p&gt;That might be just perfect, except that Perl creates it whenever it needs
it, even if it is only for &lt;strong&gt;reading&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;And now you understand the catch : a &lt;strong&gt;read&lt;/strong&gt; operation can
result in a &lt;strong&gt;write&lt;/strong&gt; one.&lt;/p&gt;
&lt;p&gt;As Uncle Ben (from SpiderMan) said&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2011/06/#pnote-614219-1&quot; id=&quot;rev-pnote-614219-1&quot; name=&quot;rev-pnote-614219-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt; : &lt;q&gt;With Great
Power Comes Great Responsibility&lt;/q&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://search.cpan.org/~ilmari/&quot; hreflang=&quot;en&quot;&gt;Dagfinn Ilmari
Mannsåker&lt;/a&gt; showed me a nice &lt;a href=&quot;http://search.cpan.org/perldoc?autovivification&quot; hreflang=&quot;en&quot;&gt;autovivification&lt;/a&gt; module on CPAN that fixes this behavior, and enables
a fine tuning of this process.&lt;/p&gt;
&lt;p&gt;I really think the fact that creation also happen when querying the value is
a real bug in Perl itself, or at least a bug in the design of the feature.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2011/06/#rev-pnote-614219-1&quot; id=&quot;pnote-614219-1&quot; name=&quot;pnote-614219-1&quot;&gt;1&lt;/a&gt;] Voltaire, Franklin D. Roosevelt and other said
something very similar, but they are not as geeky.&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2011/06/Autovivification-in-Perl-Great-Idea-Huge-Trap-Leaking-Abstraction#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2011/06/Autovivification-in-Perl-Great-Idea-Huge-Trap-Leaking-Abstraction#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/614219</wfw:commentRss>
      </item>
    
  <item>
    <title>Waiting for Munin 2.0 - Keep more data with custom data retention plans</title>
    <link>http://blog.pwkf.org/post/2010/08/Waiting-for-Munin-2.0-Keep-more-data-with-custom-data-retention-plans</link>
    <guid isPermaLink="false">urn:md5:b528a73802a31e6004307ae6cb82e4d7</guid>
    <pubDate>Mon, 23 Aug 2010 18:47:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>munin20</category><category>sysadmin</category>    
    <description>    &lt;h2&gt;RRD is Munin's backbone.&lt;/h2&gt;
&lt;p&gt;Munin keeps its data in an &lt;a href=&quot;http://oss.oetiker.ch/rrdtool/&quot;&gt;RRD
database&lt;/a&gt;. It's a wonderful piece of software, designed for this very
purpose : keep an history of numeric data.&lt;/p&gt;
&lt;p&gt;All you need is to tell RRD for how long and the precision you want to keep
your data. RRD manages then all the underlying work : pruning old data,
averaging to decrease precision if needed, ...&lt;/p&gt;
&lt;p&gt;Munin automatically creates the RRD databases it needs.&lt;/p&gt;
&lt;h2&gt;1.2 - Only one set&lt;/h2&gt;
&lt;p&gt;In 1.2, every database creation was done with the same temporal &amp;amp;
precision parameters. Since the output parameters were constant (day, week,
month, year graphs), there were little need to have a different set of
parameters.&lt;/p&gt;
&lt;h2&gt;1.4 - 2 sets : normal &amp;amp; huge&lt;/h2&gt;
&lt;p&gt;In 1.4, various users showed their need to have different graphing outputs,
and began to hack around Munin's fixed graphing. It became rapidly obvious that
the 1.2 preset wasn't a fit for everyone.&lt;/p&gt;
&lt;p&gt;Therefore a &lt;code&gt;huge&lt;/code&gt; dataset was available to be able to extend the
finest precision (5min) to the whole Munin timeframe. This comes at a price
though : more space is required, and the graph generation is slower, specially
when generating the yearly one, since more data has to be read and
analysed.&lt;/p&gt;
&lt;p&gt;The switch is done for the whole munin installation by changing the
system-wide &lt;code&gt;graph_data_size&lt;/code&gt;, although already created rrd
databases aren't changed. It is then even possible for a user to pre-customize
the rrd file. Munin will then happily uses them transparently thanks to the RRD
layer.&lt;/p&gt;
&lt;h3&gt;Manual overriding&lt;/h3&gt;
&lt;p&gt;Altering the RRD files after it is created is possible, but not as simple.
Standard export &amp;amp; import from RRD take the structure with it. So data has
to be moved around with special tools. &lt;a href=&quot;http://code.google.com/p/pmptools/source/browse/trunk/rrd/rrdmove&quot;&gt;rrdmove&lt;/a&gt;
is my attempt to create such a tool. It copies data between 2 already existing
RRD files, even asking RRD to interpolate the data when needed.&lt;/p&gt;
&lt;h2&gt;2.0 - Full control&lt;/h2&gt;
&lt;p&gt;Starting with 2.0, the parameter &lt;code&gt;graph_data_size&lt;/code&gt; is per
service. It also has a special mode : &lt;code&gt;custom&lt;/code&gt;. &lt;a href=&quot;http://munin-monitoring.org/wiki/format-graph_data_size&quot;&gt;Its format&lt;/a&gt; is
very simple :&lt;/p&gt;
&lt;pre&gt;
 
graph_data_size custom FULL_NB, MULTIPLIER_1 MULTIPLIER_1_NB, ... MULTIPLIER_NMULTIPLIER_N_NB
graph_data_size custom 300, 15 1600, 30 3000
&lt;/pre&gt;
&lt;p&gt;The first number is the number of data at full resolution. Then usually it
comes gradually decreasing resolution.&lt;/p&gt;
&lt;p&gt;A decreasing resolution has 2 usages :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Limit the space consumption : keeping full resolution for the whole period
(default : 5min for 2 years) is sometime too precise.&lt;/li&gt;
&lt;li&gt;Increase performance : RRD will choose the best fitting resolution to
generate its graphs. Already aggregated data is faster to compute.&lt;/li&gt;
&lt;/ul&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/08/Waiting-for-Munin-2.0-Keep-more-data-with-custom-data-retention-plans#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/08/Waiting-for-Munin-2.0-Keep-more-data-with-custom-data-retention-plans#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/540984</wfw:commentRss>
      </item>
    
  <item>
    <title>Waiting for Munin 2.0 - Native SSH transport</title>
    <link>http://blog.pwkf.org/post/2010/07/Waiting-for-Munin-2.0-Native-SSH-transport</link>
    <guid isPermaLink="false">urn:md5:909601af6402cb869f7d9e2e3b0515ee</guid>
    <pubDate>Mon, 12 Jul 2010 14:11:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>http</category><category>munin</category><category>munin20</category><category>ssh</category><category>sysadmin</category>    
    <description>    &lt;p&gt;In the munin architecture, the munin-master has to connect to the munin-node
via a very simple protocol and plain TCP.&lt;/p&gt;
&lt;p&gt;This has several advantages :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Very&lt;/strong&gt; simple to manage &amp;amp; install&lt;/li&gt;
&lt;li&gt;Optional SSL since 1.4 enabling secure communications&lt;/li&gt;
&lt;li&gt;Quite simple firewall rules.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It has also some disadvantages :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A new listening service means a wider exposure&lt;/li&gt;
&lt;li&gt;The SSL option might add some administrative overhead (certificates
management, ...)&lt;/li&gt;
&lt;li&gt;A native protocol isn't always covered by all firewall solutions&lt;/li&gt;
&lt;li&gt;Some organisations only authorize a few protocols to simplify audits (ex:
only SSH &amp;amp; HTTPS)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Native SSH&lt;/h2&gt;
&lt;p&gt;Theses down points may be solved by &lt;a href=&quot;http://munin-monitoring.org/wiki/MuninSSHTunneling&quot; hreflang=&quot;en&quot;&gt;encapsulation over SSH&lt;/a&gt;, but it can be a tedious task to maintain if
the number of hosts increases.&lt;/p&gt;
&lt;p&gt;Therefore 2.0 introduces the concept of a &lt;strong&gt;native SSH&lt;/strong&gt;
transport. Its usage is dead simple : replace the address with an
&lt;code&gt;ssh://&lt;/code&gt; URL-like one.&lt;/p&gt;
&lt;p&gt;The node still has to be modified to communicate with
&lt;code&gt;stdin&lt;/code&gt;/&lt;code&gt;stdout&lt;/code&gt; instead of a network socket. For now,
only &lt;a href=&quot;http://blog.pwkf.org/post/2008/11/04/A-Poor-Man-s-Munin-Node-to-Monitor-Hostile-UNIX-Servers&quot;&gt;pmmn&lt;/a&gt;
and &lt;a href=&quot;http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Asynchronous-updates&quot;&gt;munin-async&lt;/a&gt;
are able to provide such a node.&lt;/p&gt;
&lt;h3&gt;Configuration&lt;/h3&gt;
&lt;p&gt;The URL is quite self-explanatory as shown in the example below :&lt;/p&gt;
&lt;pre&gt;
[old-style-host]
    address host.example.com

[new-style-host]
    address ssh://munin-node-user@host.example.com/path/to/stdio-enabled-node --params
&lt;/pre&gt;
&lt;h3&gt;Installation notes&lt;/h3&gt;
&lt;p&gt;Authentication should be done without password but via SSH keys. The
connection is from &lt;code&gt;munin-user@host-munin&lt;/code&gt; to
&lt;code&gt;munin-node-user@remote-node&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you use &lt;code&gt;munin-async&lt;/code&gt;, the user on the remote node might only
be a readonly one, since it only needs to read spooled data. This implies that
you use &lt;code&gt;--spoolfetch&lt;/code&gt; and not &lt;code&gt;--vectorfetch&lt;/code&gt; that
updates the spool repository.&lt;/p&gt;
&lt;h2&gt;Upcoming HTTP(S) transport in 3.0&lt;/h2&gt;
&lt;p&gt;And the sweetest part is that since all the work has been done for adding
another transport, adding a CGI-based HTTP transport one is possible (and
therefore done) for 3.0.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/07/Waiting-for-Munin-2.0-Native-SSH-transport#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/07/Waiting-for-Munin-2.0-Native-SSH-transport#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/532312</wfw:commentRss>
      </item>
    
  <item>
    <title>Waiting for Munin 2.0 - Performance - Asynchronous updates</title>
    <link>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Asynchronous-updates</link>
    <guid isPermaLink="false">urn:md5:e1957d01162a0736f5534140c4cbdd4e</guid>
    <pubDate>Sat, 26 Jun 2010 16:07:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>munin20</category><category>performance</category>    
    <description>    &lt;p&gt;&lt;code&gt;munin-update&lt;/code&gt; is &lt;strong&gt;the&lt;/strong&gt; fragile link in the munin
architecture. A &lt;strong&gt;missed execution&lt;/strong&gt; means that some &lt;strong&gt;data
is lost&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;The problem : updates are synchronous&lt;/h2&gt;
&lt;p&gt;In Munin 1.x, updates are synchronous : the value of each
service&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/#pnote-526512-1&quot; id=&quot;rev-pnote-526512-1&quot; name=&quot;rev-pnote-526512-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt; is the one that &lt;code&gt;munin-update&lt;/code&gt;
retrieves each scheduled run.&lt;/p&gt;
&lt;p&gt;The issue is that &lt;code&gt;munin-update&lt;/code&gt; has to ask every service on
every node for their values. Since the values are only computed when asked,
&lt;code&gt;munin-update&lt;/code&gt; has to wait quite some time for every value.&lt;/p&gt;
&lt;p&gt;This &lt;strong&gt;very simple design&lt;/strong&gt; enables munin to have the
&lt;strong&gt;simplest plugins&lt;/strong&gt; : they are completely
&lt;strong&gt;stateless&lt;/strong&gt;. While being one great strength of munin, it puts a
severe blow on scalability : more plugins/node means obviously a slower
retrieval.&lt;/p&gt;
&lt;h2&gt;Evolving Solutions&lt;/h2&gt;
&lt;h3&gt;1.4 : Parallel Fetching&lt;/h3&gt;
&lt;p&gt;1.4 addresses some of these scalability issues by implementing parallel
fetching. It takes into account that the &lt;strong&gt;most of the execution
time&lt;/strong&gt; of &lt;code&gt;munin-update&lt;/code&gt; is spent &lt;strong&gt;waiting for
replies&lt;/strong&gt;. In 1.4 &lt;code&gt;munin-update&lt;/code&gt; can ask
&lt;code&gt;max_processes&lt;/code&gt; nodes in parallel.&lt;/p&gt;
&lt;p&gt;Now, the I/O part is becoming the next limiting factor, since updating many
RRDs in &lt;strong&gt;parallel&lt;/strong&gt; is the same as &lt;strong&gt;random I/O&lt;/strong&gt;
access for the underlying munin-master OS. Serializing &amp;amp; grouping the
updates will be possible with the new RRDp interface from rrdtool version 1.4
and on-demand graphing. Tomas Zvala even offered &lt;a href=&quot;http://sourceforge.net/mailarchive/message.php?msg_name=4BEDB877.9050004%40zvala.cz&quot; hreflang=&quot;en&quot;&gt;a patch for 1.4 RRDp&lt;/a&gt; on the ML. It is very promising, but
doesn't address the root defect in this design : a hard dependence of regular
&lt;code&gt;munin-update&lt;/code&gt; runs.&lt;/p&gt;
&lt;h3&gt;2.0 : Stateful plugins&lt;/h3&gt;
&lt;p&gt;2.0 provides a way for plugins to be stateful. They might schedule their
polling themselves, and then when &lt;code&gt;munin-update&lt;/code&gt; runs, only emit
collect already computed values. This way, a &lt;strong&gt;missed run&lt;/strong&gt; isn't
as dramatic as it is in the 1.x series, since &lt;strong&gt;data isn't lost&lt;/strong&gt;.
The data collection is also &lt;strong&gt;much faster&lt;/strong&gt; because the real
computing is done &lt;strong&gt;ahead of time&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;2.0 : Asynchronous proxy node&lt;/h3&gt;
&lt;p&gt;But &lt;strong&gt;changing plugins&lt;/strong&gt; to be &lt;strong&gt;stateful&lt;/strong&gt; and
self-polled is &lt;strong&gt;difficult&lt;/strong&gt; and tedious. &lt;strong&gt;It even works
against of one of the real strength of munin&lt;/strong&gt; : having simple &amp;amp;
stateless plugins.&lt;/p&gt;
&lt;p&gt;To address this concern, an experimental proxy node is created. For 2.0 it
takes the form of a couple of processes : &lt;code&gt;munin-async-server&lt;/code&gt; and
&lt;code&gt;munin-sync-client&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;The proxy node in detail (&lt;code&gt;munin-async&lt;/code&gt;)&lt;/h2&gt;
&lt;h3&gt;Overview&lt;/h3&gt;
&lt;p&gt;These 2 processes form an asynchronous proxy between
&lt;code&gt;munin-update&lt;/code&gt; and &lt;code&gt;munin-node&lt;/code&gt;. This avoids the need to
change the plugins or upgrade &lt;code&gt;munin-node&lt;/code&gt; on all nodes.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;munin-async-server&lt;/code&gt; should be installed on the same host than
the proxied &lt;code&gt;munin-node&lt;/code&gt; in order to avoid any network issue. It is
the process that will poll regularly &lt;code&gt;munin-node&lt;/code&gt;. The I/O issue of
&lt;code&gt;munin-update&lt;/code&gt; is here non-existent, since &lt;code&gt;munin-async&lt;/code&gt;
stores all the values by simply appending them in a text file without any
further processing. This file is later read by the client's
&lt;code&gt;munin-update&lt;/code&gt;, and it will be processed there.&lt;/p&gt;
&lt;h3&gt;Specific update rates&lt;/h3&gt;
&lt;p&gt;Having one proxy per node enables a polling of all the services there with a
specific update rate.&lt;/p&gt;
&lt;p&gt;To achieve this, &lt;code&gt;munin-async-server&lt;/code&gt; forks into multiple
processes, one for each proxied service. This way each service is completely
isolated from the other, and therefore is able to have its own update rate, is
safe from other plugins slowdowns, and it does even completely parallelize the
information gathering.&lt;/p&gt;
&lt;h3&gt;SSH transport&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;munin-async-client&lt;/code&gt; uses the new SSH native transport of 2.0. It
permits a very simple install of the async proxy.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/#rev-pnote-526512-1&quot; id=&quot;pnote-526512-1&quot; name=&quot;pnote-526512-1&quot;&gt;1&lt;/a&gt;] in 1.2 it's the same as plugin, but since 1.4 and the
introduction of &lt;ins&gt;multigraph&lt;/ins&gt;, one plugin can provide multiple
&lt;ins&gt;services&lt;/ins&gt;.&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Asynchronous-updates#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Asynchronous-updates#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/526512</wfw:commentRss>
      </item>
    
  <item>
    <title>CGI on steroids with FastCGI, but on a CGI-only server - The FastCGI wrapper</title>
    <link>http://blog.pwkf.org/post/2010/06/CGI-on-steroids-with-FastCGI%2C-but-on-a-CGI-only-server-The-FastCGI-wrapper</link>
    <guid isPermaLink="false">urn:md5:ba5366e894e1d3032bccad18415143b6</guid>
    <pubDate>Mon, 21 Jun 2010 22:22:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>sysadmin</category>
        <category>design</category><category>performance</category><category>perl</category>    
    <description>    &lt;h2&gt;FastCGI is really &lt;em&gt;CGI on steroids&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;FastCGI is very common way to increase performance of a CGI installation. It
is based on the fact that usually the startup of CGI scripts is slow, whereas
the response is quite fast.&lt;/p&gt;
&lt;p&gt;So if you have a persistent process, you only have to take care of the
startup once, and you then experience a real speedup.&lt;/p&gt;
&lt;h3&gt;FastCGI vs mod_perl (or mod_python, ...)&lt;/h3&gt;
&lt;p&gt;Once a big fan of &lt;code&gt;mod_perl&lt;/code&gt;, I'm converted to FastCGI since.
&lt;code&gt;mod_perl&lt;/code&gt; was for a long time &lt;strong&gt;the&lt;/strong&gt; answer for
speeding up Perl CGI scripts. It has a very good track record of stability and
has real hooks deep in the Apache processing requests.&lt;/p&gt;
&lt;p&gt;FastCGI focuses on a different feature set that is more actual than
&lt;code&gt;mod_perl&lt;/code&gt;&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/#pnote-527747-1&quot; id=&quot;rev-pnote-527747-1&quot; name=&quot;rev-pnote-527747-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is much simpler to install and configure, especially when having
multiple applications.&lt;/li&gt;
&lt;li&gt;Able to connect to a distant server (running as a different UID, chrooted
or even on a remote host)&lt;/li&gt;
&lt;li&gt;Able to mix scripting languages without any need to compile some other
apache modules.&lt;/li&gt;
&lt;li&gt;Able to be used with several webservers, even closed-source ones : FastCGI
is a protocol, not an API.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;But steroids do have some side effects&lt;/h2&gt;
&lt;h3&gt;CGI issues&lt;/h3&gt;
&lt;p&gt;One downside is that your CGI script should be adapted to FastCGI and the
fact that the script doesn't end with the end of the request.&lt;/p&gt;
&lt;p&gt;In the real world that's quite easy. Every language that is commonly used
for CGI offers &lt;a href=&quot;http://www.fastcgi.com/drupal/node/5&quot; hreflang=&quot;en&quot;&gt;CGI-wrapper libraries&lt;/a&gt; that works in a FastCGI context as well as a
plain CGI one.&lt;/p&gt;
&lt;h3&gt;Webserver issues&lt;/h3&gt;
&lt;p&gt;Another issue can also come from the webserver. Since CGI is dead simple to
implement even the micro-webserver &lt;a href=&quot;http://www.acme.com/software/thttpd/&quot; hreflang=&quot;en&quot;&gt;thttpd&lt;/a&gt; implements
it.&lt;/p&gt;
&lt;p&gt;FastCGI on the other hand is a little more difficult to implement, since the
webserver needs to create a container that monitors and calls the
FastCGI-enabled script.&lt;/p&gt;
&lt;h3&gt;A standalone FastCGI container&lt;/h3&gt;
&lt;p&gt;Fortunately, the FastCGI team provided us with a ready-to-use container and
a very simple client that acts a plain CGI script, but proxies it to a
full-blown container.&lt;/p&gt;
&lt;p&gt;Since the plain CGI part is a very small native executable its overhead is
negligible compared to the reply time, even without comparison with the startup
time of the whole script.&lt;/p&gt;
&lt;p&gt;Its installation is also quite straightforward. I just installed the
&lt;code&gt;libfcgi&lt;/code&gt; package on Debian : it provides
&lt;code&gt;/usr/bin/cgi-fcgi&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I created a simple CGI wrapper for my previous &lt;a href=&quot;http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-FastCGI&quot;&gt;munin
benchmarking&lt;/a&gt; needs :&lt;/p&gt;
&lt;pre&gt;
#! /bin/sh

exec /usr/bin/cgi-fcgi -connect /tmp/munin-cgi.sock \
     /usr/lib/cgi-bin/munin-cgi-graph
&lt;/pre&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/#rev-pnote-527747-1&quot; id=&quot;pnote-527747-1&quot; name=&quot;pnote-527747-1&quot;&gt;1&lt;/a&gt;] who really need deep apache hooks ?&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/06/CGI-on-steroids-with-FastCGI%2C-but-on-a-CGI-only-server-The-FastCGI-wrapper#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/06/CGI-on-steroids-with-FastCGI%2C-but-on-a-CGI-only-server-The-FastCGI-wrapper#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/527747</wfw:commentRss>
      </item>
    
  <item>
    <title>Waiting for Munin 2.0 - Performance - FastCGI</title>
    <link>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-FastCGI</link>
    <guid isPermaLink="false">urn:md5:68c4f27314364d8247cef0bd2bb372fc</guid>
    <pubDate>Wed, 16 Jun 2010 23:25:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>munin20</category>    
    <description>    &lt;p&gt;1.2 has CGI, it is slow, unsupported, but &lt;a href=&quot;http://munin-monitoring.org/wiki/CgiHowto&quot; hreflang=&quot;en&quot;&gt;it does
exist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;1.4 has even an &lt;a href=&quot;http://munin-monitoring.org/wiki/CgiHowto#FastCGI&quot; hreflang=&quot;en&quot;&gt;experimental FastCGI&lt;/a&gt; install mode.&lt;/p&gt;
&lt;p&gt;Quoting from this page :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is more a proof of concept than a recommended - it's slow. Also we do
not test it before every release&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In 2.0 lots of work has been done to take this experimental CGI mode into a
supported one. It might even be the primary way of using munin since, when an
install has a certain size, CGI becomes mandatory.&lt;/p&gt;
&lt;p&gt;That's because &lt;code&gt;munin-graph&lt;/code&gt; doesn't have time to finish its job
when the next one is launched, and the new one doesn't run. It is not as
dramatic as a missed &lt;code&gt;munin-update&lt;/code&gt; execution, since the graphs will
still be generated on the later round, but there will be random graph lags and
it will put quite some stress on the CPU &amp;amp; I/O subsystem. This will slow
&lt;code&gt;munin-update&lt;/code&gt; down since it also uses the I/O subsystem much, and
that's to be avoided at all costs.&lt;/p&gt;
&lt;p&gt;Mainstream CGI has some consequences :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Only the FastCGI wrapper remained : the plain CGI one is dropped.
&lt;ul&gt;
&lt;li&gt;The CPAN module &lt;code&gt;CGI::Fast&lt;/code&gt; is compatible when launched as a
normal CGI.&lt;/li&gt;
&lt;li&gt;Almost all HTTP servers support plain CGI, and with the &lt;a href=&quot;http://www.fastcgi.com/devkit/doc/cgi-fcgi.1&quot; hreflang=&quot;en&quot;&gt;cgi-fcgi&lt;/a&gt;
wrapper from the FastCGI devkit (Debian package &lt;code&gt;libfcgi&lt;/code&gt;), you can
have the best of both worlds (a custom HTTP server &amp;amp; FastCGI). I even
posted on how to have a working &lt;a href=&quot;http://blog.pwkf.org/post/2010/06/CGI-on-steroids-with-FastCGI%2C-but-on-a-CGI-only-server-The-FastCGI-wrapper&quot;&gt;
thttpd with FastCGI&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The old process limit mechanism is dropped also. The FastCGI server
configuration is a much better way to control it. The old code was based on
System V semaphores and was not 100% reliable.&lt;/li&gt;
&lt;li&gt;A caching system has to be implemented, in order for each graph to be
generated only once for its lifetime.&lt;/li&gt;
&lt;li&gt;The CGI process is launched with the HTTP server user. Since it doesn't
only read now, but also writes log files and images files, there is an extra
step when installing it. But it's already described in the &lt;a href=&quot;http://munin-monitoring.org/wiki/CgiHowto&quot; hreflang=&quot;en&quot;&gt;Munin CGI&lt;/a&gt; page
given previously.&lt;/li&gt;
&lt;li&gt;Since the process is launched only once, for now it read only once the
config. So if some part of the config change, the FastCGI container MUST be
restarted.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Some benchmarks&lt;/h2&gt;
&lt;p&gt;Now, the sweet part : I'm putting up some micro-benchmarks.&lt;/p&gt;
&lt;p&gt;They should be taken with caution as every benchmark should be, but I think
the general idea is conveyed. For the sake of simplicity I'm only doing 1
request in parallel and disabled IMS caching.&lt;/p&gt;
&lt;h3&gt;Basic 1.2 CGI&lt;/h3&gt;
&lt;pre&gt;
$ httperf --num-conns 10  --add-header='Cache-Control: no-cache\n' \
    --uri  /cgi-bin/munin-cgi-graph/localdomain/localhost.localdomain/cpu-day.png

Total: connections 10 requests 10 replies 10 test-duration 27.939 s

Connection rate: 0.4 conn/s (2793.9 ms/conn, &amp;lt;=1 concurrent connections)
Connection time [ms]: min 1653.9 avg 2793.9 max 5217.0 median 1912.5 stddev 1487.8
Connection time [ms]: connect 0.0
Connection length [replies/conn]: 1.000

Request rate: 0.4 req/s (2793.9 ms/req)
Request size [B]: 131.0
&lt;/pre&gt;
&lt;h3&gt;1.4 FastCGI&lt;/h3&gt;
&lt;p&gt;The munin-fastcgi-graph is only loaded once, but the munin-graph is reloaded
each time.&lt;/p&gt;
&lt;pre&gt;
$ httperf --num-conns 10  --add-header='Cache-Control: no-cache\n' \
    --uri  /cgi-bin/munin-fastcgi-graph/localdomain/localhost.localdomain/cpu-day.png

Total: connections 10 requests 10 replies 10 test-duration 13.807 s

Connection rate: 0.7 conn/s (1380.7 ms/conn, &amp;lt;=1 concurrent connections)
Connection time [ms]: min 1141.3 avg 1380.7 max 1636.1 median 1381.5 stddev 173.7
Connection time [ms]: connect 0.0
Connection length [replies/conn]: 1.000

Request rate: 0.7 req/s (1380.7 ms/req)
&lt;/pre&gt;
&lt;p&gt;The response time is cut almost in half. That's expected, since only the top
half of the processing isn't reloaded.&lt;/p&gt;
&lt;h3&gt;2.0 FastCGI&lt;/h3&gt;
&lt;p&gt;Here everything is loaded once.&lt;/p&gt;
&lt;pre&gt;
$ httperf --num-conns 10  --add-header='Cache-Control: no-cache\n' \
    --uri  /cgi-bin/munin-cgi-graph-2.0/localdomain/localhost.localdomain/cpu-day.png

Total: connections 10 requests 10 replies 10 test-duration 1.668 s

Connection rate: 6.0 conn/s (166.8 ms/conn, &amp;lt;=1 concurrent connections)
Connection time [ms]: min 123.0 avg 166.8 max 513.4 median 127.5 stddev 121.9
Connection time [ms]: connect 0.0
Connection length [replies/conn]: 1.000

Request rate: 6.0 req/s (166.8 ms/req)
&lt;/pre&gt;
&lt;p&gt;Now response time is cut almost by a ten factor ! That's quite good news,
since it goes 20 times faster that the original CGI.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-FastCGI#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-FastCGI#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/525792</wfw:commentRss>
      </item>
    
  <item>
    <title>Waiting for Munin 2.0 - Performance - Architecture</title>
    <link>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Introduction-Architecture</link>
    <guid isPermaLink="false">urn:md5:08010319781f7bf88a099f0de8c8960e</guid>
    <pubDate>Thu, 10 Jun 2010 03:48:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>munin20</category>    
    <description>    &lt;h2&gt;A little intro/refresh on munin's architecture on the master&lt;/h2&gt;
&lt;p&gt;Munin has a very simple architecture on the master : &lt;code&gt;munin-cron&lt;/code&gt;
is launched via cron every 5 minutes. Its only job is to launch in order
&lt;code&gt;munin-update&lt;/code&gt;, &lt;code&gt;munin-graph&lt;/code&gt;, &lt;code&gt;munin-html&lt;/code&gt;
&amp;amp; &lt;code&gt;munin-limits&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;The various processes&lt;/h2&gt;
&lt;h3&gt;munin-update&lt;/h3&gt;
&lt;p&gt;This process retrieves the values from the various nodes and to update the
rrd files. This one should never take more than 5 minutes to run, otherwise
there will be gaps since the next update will not be launched
(lockfile-protected runs).&lt;/p&gt;
&lt;p&gt;This process stresses the I/O on the master, and depends on the plugins
execution time on the various nodes. On 1.4 the retrieval is
multi-threaded&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/#pnote-525782-1&quot; id=&quot;rev-pnote-525782-1&quot; name=&quot;rev-pnote-525782-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;, so an slow node doesn't impact too much the
whole process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.0 proposes asynchronous updates and vectorized
updates.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;munin-graph&lt;/h3&gt;
&lt;p&gt;This process generates all the image files from the rrd files.&lt;/p&gt;
&lt;p&gt;It is usually a process that is quite CPU-bound, it generates also a fair
load of I/O. Since 1.4 there might also be a parallel graphing generation in
order to take advantage of multiple CPU / multiple I/O paths.&lt;/p&gt;
&lt;p&gt;A simple optimization is to generate only needed graphs instead of all of
them each time. This leads to CGI-generation of graphs. 1.2 &amp;amp; 1.4 took a
first step in this direction, but it's quite a hack since it's only a very
basic script that calls &lt;code&gt;munin-update&lt;/code&gt; with the correct
parameters.&lt;/p&gt;
&lt;p&gt;A FastCGI port of the wrapper (&lt;code&gt;munin-cgi-graph&lt;/code&gt;) removes the
overhead of starting the wrapper for each call, but in 1.4 the code is quite
experimental and has some serious bugs that would need extensive patching to be
fixed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.0 completes the integration of CGI graphing with removing the
overhead of calling &lt;code&gt;munin-graph&lt;/code&gt; and does this extensive patching
for bugs fixing&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;munin-html&lt;/h3&gt;
&lt;p&gt;This process generates all the html files from the rrd files. This one is
quite fast for now.&lt;/p&gt;
&lt;h3&gt;munin-limits&lt;/h3&gt;
&lt;p&gt;This process checks the limits to see if there is a warning/alert to send
via mail or nagios. This one is also quite fast for now.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/#rev-pnote-525782-1&quot; id=&quot;pnote-525782-1&quot; name=&quot;pnote-525782-1&quot;&gt;1&lt;/a&gt;] more multi-process actually&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Introduction-Architecture#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Introduction-Architecture#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/525782</wfw:commentRss>
      </item>
    
  <item>
    <title>Waiting for Munin 2.0 - Introduction</title>
    <link>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Introduction</link>
    <guid isPermaLink="false">urn:md5:bb2170b02e8c57e4f5118071419e8e6a</guid>
    <pubDate>Tue, 08 Jun 2010 22:30:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>munin20</category>    
    <description>    &lt;p&gt;This is the first article of a series about the coming version 2.0 of
&lt;a href=&quot;http://munin-monitoring.org/&quot; hreflang=&quot;en&quot;&gt;Munin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The idea came from the series &lt;a href=&quot;http://www.depesz.com/index.php/2009/07/03/waiting-for-8-5-lets-start/&quot; hreflang=&quot;en&quot;&gt;Waiting from 8.5&lt;/a&gt; about PostgreSQL.&lt;/p&gt;
&lt;p&gt;The ironic part is that their 8.5 release has become a 9.0, just like our
1.5 will be a 2.0.&lt;/p&gt;
&lt;p&gt;I'll post several small articles about new or enhanced-enough features. They
will all be tagged &lt;a href=&quot;http://blog.pwkf.org/tag/munin20&quot;&gt;munin20&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Planned summary :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Introduction-Architecture&quot;&gt;Performance
- Architecture context&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/Using-FastCGI-with-a-CGI-only-server-The-FastCGI-wrapper&quot;&gt;Performance
- FastCGI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Asynchronous-updates&quot;&gt;Performance
- Asynchronous updates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Performance - Misc&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.pwkf.org/post/2010/07/Waiting-for-Munin-2.0-Native-SSH-transport&quot;&gt;Native
SSH transport&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.pwkf.org/post/2010/08/Waiting-for-Munin-2.0-Keep-more-data-with-custom-data-retention-plans&quot;&gt;
Custom data retention plans (keep more data)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dynamic zooming&lt;/li&gt;
&lt;/ol&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Introduction#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Introduction#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/525488</wfw:commentRss>
      </item>
    
  <item>
    <title>Don't use Excerpt... At least with DotClear.</title>
    <link>http://blog.pwkf.org/post/2010/04/Do-not-use-Excerpt-At-least-with-DotClear</link>
    <guid isPermaLink="false">urn:md5:5e310276dfa3d044fb0f767f3527a814</guid>
    <pubDate>Thu, 01 Apr 2010 08:00:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>general</category>
            
    <description>    &lt;p&gt;DotClear automatically generates a &lt;code&gt;meta description&lt;/code&gt; tag from
the blog entry, but it doesn't take the excerpt into account.&lt;/p&gt;
&lt;p&gt;It just takes the beginning of the article &lt;strong&gt;content&lt;/strong&gt;. Since
the excerpt is also shown at the beginning of the article, I cannot just write
2 times the same content.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;meta description&lt;/code&gt; is quite interesting since it is usually used
for the little snipped under a search result in usual search engines, so having
the beginning of the post in here is very nice.&lt;/p&gt;
&lt;p&gt;This fact annihilates the &lt;a href=&quot;http://blog.pwkf.org/post/2009/05/Are-Excerpts-a-Good-Thing&quot;&gt;good point of having
excerpts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I'm now falling back to removing progressively all the excerpts on my
posts...&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/04/Do-not-use-Excerpt-At-least-with-DotClear#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/04/Do-not-use-Excerpt-At-least-with-DotClear#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/504880</wfw:commentRss>
      </item>
    
  <item>
    <title>API Design: Avoid hidden costs of simple features</title>
    <link>http://blog.pwkf.org/post/2010/03/API-Design%3A-Hidden-costs-of-simple-features</link>
    <guid isPermaLink="false">urn:md5:8ea72e6386e7410474ce3ece000deda1</guid>
    <pubDate>Wed, 31 Mar 2010 21:00:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>programming</category>
        <category>api</category><category>design</category><category>performance</category>    
    <description>    &lt;p&gt;&lt;strong&gt;Programmers&lt;/strong&gt; are usually like water : they &lt;strong&gt;always
use&lt;/strong&gt; the &lt;strong&gt;path of least resistance&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Let's see how to use this fact to predict the usage of an API when you
design it.&lt;/p&gt;
&lt;h2&gt;Initial API&lt;/h2&gt;
&lt;p&gt;Consider the very simple DB API that consumes a connected ResultSet and
presents a disconnected version of it.&lt;/p&gt;
&lt;pre&gt;
class DisconnectedResultSet{
        public DisconnectedResultSet (ResultSet rs);
        public boolean next();
        public Object getObject(int col_idx);
}
&lt;/pre&gt;
&lt;p&gt;It's usage is quite easy :&lt;/p&gt;
&lt;pre&gt;
while (drs.next()) {
        int col_idx = 1;
        drs.getObject(col_idx++); // Do something w/ 1st col
        drs.getObject(col_idx++); // Do something w/ 2st col
        //...
}
&lt;/pre&gt;
&lt;h2&gt;Just a &lt;em&gt;little&lt;/em&gt; evolution...&lt;/h2&gt;
&lt;p&gt;Since the &lt;code&gt;DisconnectedResultSet&lt;/code&gt; is &lt;em&gt;disconnected&lt;/em&gt;, we
can imagine that it should implement a &lt;code&gt;rewind()&lt;/code&gt; method in order to
use it several times without running the initial query again. We now have an
updated class :&lt;/p&gt;
&lt;pre&gt;
class DisconnectedResultSet{
        public DisconnectedResultSet (ResultSet rs);
        public boolean next();
        public Object getObject(int col_idx);   
        public void rewind(); // Be able to rewind it
}
&lt;/pre&gt;
&lt;p&gt;And its classical usage :&lt;/p&gt;
&lt;pre&gt;
while (drs.next()) {
        // do stuff...
}
// ...
drs.rewind();
while (drs.next()) {
        // do something else with the same data...
}
// ...
drs.rewind();
while (drs.next()) {
        // do something else with the same data...
}
// ...
&lt;/pre&gt;
&lt;h2&gt;A new need comes&lt;/h2&gt;
&lt;p&gt;A new need comes : see if the &lt;code&gt;DisconnectedResultSet&lt;/code&gt; is empty or
not in order to avoid sending header.&lt;/p&gt;
&lt;p&gt;The usual way is to send them once when iterating like :&lt;/p&gt;
&lt;pre&gt;
boolean is_headers_sent = false;
while (drs.next()) {
        if (! is_headers_sent) { 
                send_headers(); 
                is_headers_sent = true;
        }
        // do something else with the same data...
}
&lt;/pre&gt;
&lt;p&gt;But since there is a nice &lt;code&gt;rewind()&lt;/code&gt;method, just waiting to be
used, the code might become :&lt;/p&gt;
&lt;pre&gt;
if (drs.next()) {
        send_headers(); 
}
drs.rewind();
while (drs.next()) {
        // do something else with the same data...
}
&lt;/pre&gt;
&lt;p&gt;Now, this code isn't generic anymore to accommodate a connected
ResultSet.&lt;/p&gt;
&lt;p&gt;So, as John Carmack said :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The cost of adding a feature isn't just the time it takes to code it. The
cost also includes the addition of an obstacle to future expansion.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's really true when you design &lt;strong&gt;APIs&lt;/strong&gt; since their purpose
is to &lt;strong&gt;last long&lt;/strong&gt; and to &lt;strong&gt;be extended&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So, &lt;strong&gt;think twice when you propose an extension &amp;quot;just in
case&amp;quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;The &lt;em&gt;little&lt;/em&gt; evolution, revisited...&lt;/h2&gt;
&lt;p&gt;To solve this case, don't propose a &lt;code&gt;rewind()&lt;/code&gt; method, but offer
a &lt;code&gt;duplicate()&lt;/code&gt; one. It offers the same functionality, just in a new
object.&lt;/p&gt;
&lt;p&gt;The usage will be almost the same as shown below, but since it feels more
performance-sensitive, it won't be used as lightly : the &lt;code&gt;boolean
is_headers_sent&lt;/code&gt; pattern has now more chances to be used.&lt;/p&gt;
&lt;pre&gt;
while (drs.next()) {
        // do stuff...
}
// ...
drs = drs.duplicate();
while (drs.next()) {
        // do something else with the same data...
}
// ...
drs = drs.duplicate();
while (drs.next()) {
        // do something else with the same data...
}
// ...
&lt;/pre&gt;
&lt;p&gt;It's an other example that &lt;a href=&quot;http://blog.pwkf.org/post/2007/12/03/Use-immutable-objects-to-avoid-synchronisation&quot;&gt;immutable
objects are the way to go&lt;/a&gt;, but for a different reason this time.&lt;/p&gt;
&lt;p&gt;Note: Just finished my March 2010 article, even &lt;strong&gt;on time&lt;/strong&gt;...
I'm still trying to keep at least a one article per month blogging rate. So far
so good for 2010, still 9 months to go !&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/03/API-Design%3A-Hidden-costs-of-simple-features#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/03/API-Design%3A-Hidden-costs-of-simple-features#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/475523</wfw:commentRss>
      </item>
    
  <item>
    <title>Free Exception lunch : Use unchecked exceptions, but still announce which ones you might throw.</title>
    <link>http://blog.pwkf.org/post/2010/02/You-Shall-Declare-The-Unchecked-Exceptions-You-Might-Throw</link>
    <guid isPermaLink="false">urn:md5:03e06c61165fcdfa2d6e0d529dfbeb36</guid>
    <pubDate>Sat, 20 Feb 2010 16:01:00 +0100</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>java</category>
            
    <description>    &lt;p&gt;In a previous article I choosed my side : &lt;a href=&quot;http://blog.pwkf.org/post/2009/07/Checked-or-Unchecked-Exceptions-for-Legacy-Code&quot;&gt;Unchecked
Exceptions are much simpler to use&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But, on the other side of this great division, there is a very valid point :
&lt;strong&gt;You usually declare checked exceptions&lt;/strong&gt;. Sure it's possible to
only declare to throw &lt;code&gt;Exception&lt;/code&gt;, but that would defeat the whole
purpose of using checked exceptions.&lt;/p&gt;
&lt;p&gt;The nicest thing is that you can also have a custom exception hierarchy, but
based on &lt;code&gt;RuntimeException&lt;/code&gt; instead of a plain
&lt;code&gt;Exception&lt;/code&gt;. This way it's like in C++. Everything might be thrown,
and you don't &lt;strong&gt;need&lt;/strong&gt; to handle them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Declaring them&lt;/strong&gt;, on the other side, is very interesting
because you are &lt;strong&gt;documenting your interface&lt;/strong&gt; for almost
&lt;strong&gt;free&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So, use unchecked exceptions to free yourself of the checked catch-slavery,
but still declare the custom ones you might throw.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/02/You-Shall-Declare-The-Unchecked-Exceptions-You-Might-Throw#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/02/You-Shall-Declare-The-Unchecked-Exceptions-You-Might-Throw#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/436982</wfw:commentRss>
      </item>
    
  <item>
    <title>Immutability of an URL</title>
    <link>http://blog.pwkf.org/post/2010/02/Immutability-of-an-URL</link>
    <guid isPermaLink="false">urn:md5:d309c7c0d59a5f7e7cbcd5c896b3f2cd</guid>
    <pubDate>Sat, 20 Feb 2010 15:18:00 +0100</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>general</category>
            
    <description>    &lt;p&gt;In the pure spirit of &lt;a href=&quot;http://www.javapractices.com/topic/TopicAction.do?Id=211&quot; hreflang=&quot;en&quot;&gt;Data
is King&lt;/a&gt; I think that URL should &lt;strong&gt;never&lt;/strong&gt; change. Even the W3C
agrees with their &lt;a href=&quot;http://www.w3.org/Provider/Style/URI.html&quot; hreflang=&quot;en&quot;&gt;Cool URIs don't change&lt;/a&gt; article.&lt;/p&gt;
&lt;p&gt;But we all know that in IT &lt;em&gt;never&lt;/em&gt; is only &lt;em&gt;not in the foreseen
future&lt;/em&gt;. So URL &lt;strong&gt;do&lt;/strong&gt; change, at least after a while, and
usually for technical reasons&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/02/#pnote-397657-1&quot; id=&quot;rev-pnote-397657-1&quot; name=&quot;rev-pnote-397657-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Since you can update your website to update the URLs, but the inbound link
cannot be easily updated. To handle this need, the HTTP protocol has specified
the 301 response code.&lt;/p&gt;
&lt;p&gt;The solution is that the site should remember all the urls that it generated
and redirects accordingly. This way you'll never loose a potential reader to
the infamous 404 (this page does not exist).&lt;/p&gt;
&lt;p&gt;Some sites even try to approximate the page on a custom 404 page. That's
another reason to have user-friendly urls : to be able to hint your reader to
appropriate pages in case you don't find his initial destination.&lt;/p&gt;
&lt;p&gt;Sadly, this redirect behavior isn't supported by my blog engine
(dotclear)... That's for the &lt;a href=&quot;http://en.wikipedia.org/wiki/Eating_one%27s_own_dog_food&quot; hreflang=&quot;en&quot;&gt;eat
your own dog's food&lt;/a&gt;, but I'm looking forward to do it on my current
blogging platform.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/02/#rev-pnote-397657-1&quot; id=&quot;pnote-397657-1&quot; name=&quot;pnote-397657-1&quot;&gt;1&lt;/a&gt;] upgrade to another blog engine...&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/02/Immutability-of-an-URL#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/02/Immutability-of-an-URL#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/397657</wfw:commentRss>
      </item>
    
  <item>
    <title>Avoid the Preprocessor : Use ''Compile-Time Polymorphism'' for Cross-platform Development</title>
    <link>http://blog.pwkf.org/post/2009/12/Avoid-the-Preprocessor-Use-Compile-Time-Polymorphism-for-Cross-platform-Development</link>
    <guid isPermaLink="false">urn:md5:ac68468a97cc5a2146661e506b24a7c2</guid>
    <pubDate>Fri, 11 Dec 2009 23:00:00 +0100</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>c++</category>
            
    <description>&lt;p&gt;When writing portable cross-platform code, don't litter your code with
preprocessor macros, use &lt;em&gt;compile-time polymorphism&lt;/em&gt; instead.&lt;/p&gt;
&lt;p&gt;A flexible build system will enable you to use advanced OOP-like
compile-time polymorphism. That way you can hide all the specifics of the
different platform behind an interface firewall. It is the usual way that most
cross-platform toolkits and frameworks (such as QT, GTK or wxWidgets) are
designed.&lt;/p&gt;    &lt;p&gt;We'll take a very simple file I/O subsystem here as an example
(&lt;code&gt;open&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt;). We'll also only take Linux and
Windows, since that's usually the 2 most common platforms people want to
develop for&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/12/#pnote-467153-1&quot; id=&quot;rev-pnote-467153-1&quot; name=&quot;rev-pnote-467153-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;.&lt;/p&gt;
&lt;h2&gt;The usual abstraction with the preprocessor&lt;/h2&gt;
&lt;p&gt;Usually preprocessor &lt;code&gt;#ifdef&lt;/code&gt;s are used to compile specific parts
for the underlying OS.&lt;/p&gt;
&lt;p&gt;The file &lt;code&gt;fileiosys.cpp&lt;/code&gt; looks&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/12/#pnote-467153-2&quot; id=&quot;rev-pnote-467153-2&quot; name=&quot;rev-pnote-467153-2&quot;&gt;2&lt;/a&gt;]&lt;/sup&gt; like the one below
:&lt;/p&gt;
&lt;pre&gt;
fileiosys_filedesc open(char* filename) {
#ifdefine __WIN32__
    return OpenFile(
        filename, 
        GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_READ | FILE_SHARE_WRITE, 
        NULL,
    );  
#else // UNIX
    return open(filename, O_READ | O_WRITE, 0666);
#endif
}

int close (fileiosys_filedesc fd) {
#ifdefine __WIN32__
    return CloseHandle(fd) ? 0 : -1;
#else // UNIX
    return close(fd);
#endif
}
&lt;/pre&gt;
&lt;p&gt;The header &lt;code&gt;fileiosys.h&lt;/code&gt; looks then like :&lt;/p&gt;
&lt;pre&gt;
// Define a custom file descriptor
#ifdefine __WIN32__
    #define fileiosys_filedesc HANDLE
#else // UNIX
    #define fileiosys_filedesc int
#endif

fileiosys_filedesc open(char* filename); 
int close(fileiosys_filedesc fd); 
&lt;/pre&gt;
&lt;h2&gt;Avoid the preprocessor Compile-time polymorphism&lt;/h2&gt;
&lt;p&gt;As the previous little example, the code isn't really easy to read. You have
to always think which environnement you are in. All the specifics are
multiplexed in the same file, and the programmer has to always demultiplex it
in real time each time he reads the code.&lt;/p&gt;
&lt;p&gt;The last part of the interface file is quite simple to read since it's
already abstracted away. Now let's completely demultiplex the implementation in
several implementation files.&lt;/p&gt;
&lt;h3&gt;The header file is the common interface&lt;/h3&gt;
&lt;p&gt;The interface is the most important part of the design. It should be
high-level enough to mask the differences between the plateforms you want to
support, but not too high-level, otherwise you'll end up duplicating to much
code.&lt;/p&gt;
&lt;p&gt;So, for our file I/O subsystem, we'll just abstract the usual syscalls
&lt;code&gt;open&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt; in the same way as before.&lt;/p&gt;
&lt;p&gt;The parameters that are passed through the interface are also very
important. You cannot usually leak a platform-specific structure. So here all
the file descriptors are just an opaque handle, represented by a pointer to a
structure defined only as a forward declaration in the header. This pattern,
sometimes called the &lt;a href=&quot;http://en.wikipedia.org/wiki/Opaque_pointer&quot; hreflang=&quot;en&quot;&gt;pimpl idiom&lt;/a&gt;, enables use to really share the representation
while implementing it differently.&lt;/p&gt;
&lt;p&gt;The header file is preserved as &lt;code&gt;fileiosys.h&lt;/code&gt;, whereas the
implementation is in the files &lt;code&gt;linux/fileiosys.cpp&lt;/code&gt; and
&lt;code&gt;win32/fileiosys.cpp&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;&lt;code&gt;fileiosys.h&lt;/code&gt;&lt;/h4&gt;
&lt;pre&gt;
// Define the forward declaration
struct fis_filedesc;
fis_filedesc* open(char* filename); 
int close(fileiosys_filedesc* fd); 
&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;win32/fileiosys.cpp&lt;/code&gt;&lt;/h4&gt;
&lt;pre&gt;
struct fis_filedesc {
    HANDLE handle;
};

fis_filedesc* open(char* filename) {
    fis_filedesc* fd = new fis_filedesc();
    fd-&amp;gt;handle = OpenFile(
        filename, 
        GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_READ | FILE_SHARE_WRITE, 
        NULL,
    );  

    return fd;
}

int close (fis_filedesc* fd) {
    int retval = CloseHandle(fd-&amp;gt;handle) ? 0 : -1;
    delete(fd);
    return retval;
}
&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;linux/fileiosys.cpp&lt;/code&gt;&lt;/h4&gt;
&lt;pre&gt;
struct fis_filedesc {
    int file_descriptor;
};

static fis_filedesc[32];

fis_filedesc* open(char* filename) {
    fis_filedesc* fd = new fis_filedesc();
    fd-&amp;gt;file_descriptor = open(filename, O_READ | O_WRITE, 0666);
    return fd;
}

int close (fis_filedesc* fd) {
    int retval = close(fd);
    delete(fd);
    return retval;
}
&lt;/pre&gt;
&lt;h4&gt;The build system : &lt;code&gt;Makefile&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;The makefile should take into account the different platforms, and only
compile the needed implementation file. All the gluing magic will then be done
at linking time instead of preprocessor time.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The interest of have multiple implementation files is obvious. It is
&lt;strong&gt;much&lt;/strong&gt; more straightforward to read and only marginally harder
to write. But since most of the time code is read and not written, the choose
is quite a no-brainer.&lt;/p&gt;
&lt;p&gt;The nicest part is that all this is possible even without the expensive
run-time polymorphism and RTTI, since the choose is done at compile-time.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/12/#rev-pnote-467153-1&quot; id=&quot;pnote-467153-1&quot; name=&quot;pnote-467153-1&quot;&gt;1&lt;/a&gt;] actually when targeting Linux, you usually target all
Unix-like systems since they already have POSIX as a common abstraction&lt;/p&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/12/#rev-pnote-467153-2&quot; id=&quot;pnote-467153-2&quot; name=&quot;pnote-467153-2&quot;&gt;2&lt;/a&gt;] The code is not real, it has been sweetened&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2009/12/Avoid-the-Preprocessor-Use-Compile-Time-Polymorphism-for-Cross-platform-Development#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2009/12/Avoid-the-Preprocessor-Use-Compile-Time-Polymorphism-for-Cross-platform-Development#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/467153</wfw:commentRss>
      </item>
    
  <item>
    <title>Native SSH transport for Munin</title>
    <link>http://blog.pwkf.org/post/2009/11/Native-SSH-transport-for-Munin</link>
    <guid isPermaLink="false">urn:md5:9850ae8f77d67536a24ea8c5e21b723e</guid>
    <pubDate>Thu, 26 Nov 2009 22:00:00 +0100</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>ssh</category>    
    <description>&lt;p style=&quot;color:red&quot;&gt;&lt;b&gt;Update&lt;/b&gt;: This page is obsolete, since it has been
merged in the &lt;a&gt;2.0 version of Munin&lt;/a&gt;. The syntax is a little bit
different, but the idea is the same.&lt;/p&gt;
&lt;p&gt;I &lt;a href=&quot;http://blog.pwkf.org/post/2008/11/04/A-Poor-Man-s-Munin-Node-to-Monitor-Hostile-UNIX-Servers&quot;&gt;blogged&lt;/a&gt;
about the &lt;a href=&quot;http://munin.projects.linpro.no/&quot; hreflang=&quot;en&quot;&gt;munin
monitoring system&lt;/a&gt; a while ago.&lt;/p&gt;
&lt;p&gt;The fact the Munin team did quite a remarkable job in cleaning up the 1.2
code for the 1.4 release enabled me to add a native SSH transport for Munin,
and made be able to get rid of all SSH tunnels.&lt;/p&gt;    &lt;p&gt;Actually the tunnel won't disappear, but they will be launched only when
needed and, most importantly configured in &lt;code&gt;munin.conf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://blog.pwkf.org/public/direct_ssh_transport.diff&quot; hreflang=&quot;en&quot;&gt;native ssh for
munin patch&lt;/a&gt; should applies quite cleanly on revision 3101 of the svn
trunk.&lt;/p&gt;
&lt;p&gt;Its use is quite straightforward : in &lt;code&gt;/etc/munin/munin.conf&lt;/code&gt;,
you just migrate address to the new configuration directive
&lt;code&gt;remote_connection_cmd&lt;/code&gt; that take the whole &lt;code&gt;ssh&lt;/code&gt; command
to launch a stdio munin-node such as pmmn.&lt;/p&gt;
&lt;p&gt;If we take the examples from the previous post, it becomes clear it's
&lt;strong&gt;much&lt;/strong&gt; easier to configure.&lt;/p&gt;
&lt;h3&gt;munin.conf snippet - Inetd version&lt;/h3&gt;
&lt;pre&gt;
[server1]
    address localhost
    port 7001
[server2]
    address localhost
    port 7002
&lt;/pre&gt;
&lt;h3&gt;munin.conf snippet - Native SSH transport version&lt;/h3&gt;
&lt;p&gt;Right now, the &lt;code&gt;address&lt;/code&gt; directive is still mandatory, but
ignored when connecting.&lt;/p&gt;
&lt;pre&gt;
[server1]
    address dummy
    remote_connection_cmd /usr/bin/ssh -- supusr@server1 /home/suprusr/pmmn/pmmn.pl
[server2]
    address dummy
    remote_connection_cmd /usr/bin/ssh -- supusr@server2 /home/suprusr/pmmn/pmmn.pl
&lt;/pre&gt;
&lt;h3&gt;Warning&lt;/h3&gt;
&lt;p&gt;Beware that the &lt;code&gt;ssh&lt;/code&gt; process will now be launched by the
&lt;code&gt;munin&lt;/code&gt; user, so you have to update the key-based SSH authentication
accordingly.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2009/11/Native-SSH-transport-for-Munin#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2009/11/Native-SSH-transport-for-Munin#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/462735</wfw:commentRss>
      </item>
    
</channel>
</rss>