Category: Networking

Articles on networking, client/server architectures, TCP/IP, UDP, networking services (i.e. dns, dhcp, http etc.), cluster management etc.

  • Loomiere: a post-mortem of my favorite code

    Loomiere: a post-mortem of my favorite code

    Fifteen years ago I wrote the code I’m still proudest of, for a product category that no longer exists. This is its story, told now that I’ve finally given the repo a dignified closing README instead of letting it rot quietly.

    2010, when video was hard

    If you’re younger than the problem, here’s the world: web video meant Flash players doing progressive download over plain HTTP — and I do mean your own Flash player, because every video site had to write one; there was no HTML5 <video> coming to your help. Seeking worked by asking the server for the file from an offset (?start=). There was no HLS, no DASH, no adaptive bitrate; CDNs existed but were priced for companies with sales departments.

    If you ran a video site, bandwidth was your business model — every wasted byte was money, and every rebuffer was a lost viewer.

    I ran into this the honest way. My company operated peteava.ro, a Romanian video-sharing site (now defunct, like most of that era), and I had already written one streamer for it — psstream, a PHP extension from 2008. It did the job until it didn’t: none of our servers could hold more than about 150 simultaneous streams without the machine practically freezing.

    That wall is where Loomiere begins.

    First pass: the micro-streamers

    The first Loomiere (0.x) was an exercise in minimalism: a set of tiny micro-streamers — one per format — written in C against dietlibc, statically linked, the MP4 streamer weighing about 21 KB on disk and 120 KB in memory, spawned one-process-per-request under ipsvd/runit.

    It entered production on all of peteava’s streaming servers on Friday, January 29, 2010, at 14:31 (some moments you write down). The same day, a random check on the most strained server showed 653 simultaneous clients where the old streamer had managed 150 — and total bandwidth had dropped by roughly a third, because of the throttle I’ll get to in a moment.

    Two months thinking, two weeks writing

    The 0.x design had a ceiling — one process per connection is honest but profligate — so I rebuilt it. I spent about two months just thinking about Loomiere 2.0’s internals before writing it, and then wrote the whole thing in about two weeks.

    Think long, write short — not always possible, but I’ve been trying to work like that ever since; the thinking is the work, the typing is transcription.

    What I remember from those two months isn’t code at all: it’s the old whiteboard, so full of sketches that at some point I was defending it with my own body from the cleaning lady’s sponge. Improbably, a photo of it survives — the exact spot where the Lua and C universes cross inside the code, coroutines yielding on one side of the line, the event loop deciding on the other:

    What came out: a C core on libev with SMP worker threads (“the hardware should be the only limit”), an in-memory cache, and — the part I’d still defend in any design review — Lua as the configuration and scripting surface. Virtual hosts, URL routing, rewrite logic: all Lua, so wiring Loomiere into an existing site was an afternoon, not a migration.

    And that whiteboard sketch is exactly the machinery being born: each stream lived as a Lua coroutine — a blocking operation yielded it across the line to the C event loop and resumed it on readiness — with spinlocks at the few seams where worker threads had to touch. Thousands of streams juggled in parallel on one machine, in 2010, when Node.js was a year-old curiosity and the async-everything movement it would ignite hadn’t happened yet. It was, and I say this with the full bias of authorship, truly beautiful.

    The throttle (the part worth stealing)

    The economics lived in one mechanism: the VBR-aware bandwidth-conservation throttle. Serve at full speed only until the client holds N seconds of playback ahead of the play-head (default: 20), then pace delivery to the stream’s own bitrate. The subtlety is “seconds”: with variable-bitrate video a byte target is wrong at exactly the moments that matter, so the buffer was tracked in playback time, not bytes. Smooth playback, instant seeks, and — since most viewers don’t finish most videos — dramatically less bandwidth bought for content nobody watched.

    On day one it cut peteava’s streaming bandwidth from roughly 1300 to 900 megabits while serving more clients.

    The numbers

    The run I still grin about was a single SSD-based machine in January 2011 — a 3 GHz Core i7, 12 GB RAM, six 256 GB SSDs, three gigabit NICs:

    6500+ active concurrent streams, 2841 Mbps of traffic, with the SSDs under 20% load.

    Cacti graph from January 2011: 2771.71 Mbps effective bandwidth
    2771.71 Mbps effective bandwidth — the original Cacti capture.
    Monitoring graph from January 2011: 6500+ active concurrent streams
    6500+ active concurrent streams on one machine.

    At that point we hit a wall that wasn’t Loomiere: somewhere between the I/O path and the sockets — interrupts, kernel, mainboard — the CPU saturated while memory and disks idled. \

    My note from that night reads, in its entirety: “Hmm… this is a deep one.” I never did get to the bottom of it; the wall was comfortably above what any single machine needed to do.

    CPU activity graph showing saturation while memory and disks idled
    The wall: CPU saturating while everything else idled. “Hmm… this is a deep one.”

    In steady production the fleet told the real story: Loomiere 2.0 served all of peteava.ro’s video — about 800 TB every month, from 14 servers — and did so for over five years in total.

    And none of it ran in a cloud, because there was no cloud worth the name: every one of those servers was physical iron that someone had to rack, cable, and keep alive (shout-out to Bogdan, who has since turned that craft into his own hosting business).

    Even the best things end

    Loomiere stood on libev, whose documentation contains a section titled — beautifully — “ev_cleanup — even the best things end”. Somewhere in those docs (I’ve never managed to find the exact passage again, but never managed to forget it either) its author left a thought along these lines: you always have the API to kill whatever needs killing — but there is something about a program written so well that, at end-time, all its threads close gracefully on their own… something close to perfect.

    Loomiere delivered on that spectacularly: at one point it ran for three years without a restart — no leaks, and no creeping memory fragmentation either, which at that kind of uptime stops being an implementation detail and becomes a discipline.

    And when asked to stop, it stopped the way the docs dreamed: every watcher, every worker, every connection closing in order, all the way down.

    And the child in me will forever cherish that.

    What happened

    The category was absorbed, the way categories are. nginx shipped its mp4/flv modules and pseudo-streaming became a config flag on a server everyone already ran. Then adaptive streaming (HLS, DASH) and CDNs finished the job. Loomiere’s last release was December 2011 — right about when the ground finished moving.

    Could I revive it? No. The industry has advanced enormously and I’d be fighting monsters — nginx, CDNs, twenty years of protocol evolution — over territory nobody disputes anymore. Reviving it would honor the code less than closing it well does.

    What it left behind

    Three things survived the product, all of them still in use:

    The method: think long, write short. Not always possible — but I’ve been trying ever since, and Krbn, the pencil-rendering engine I released recently, was built exactly that way, fifteen years later.

    The taste: performance as a design property, not an optimization pass; the conviction that software’s job is to get out of the hardware’s way.

    And the lesson I’d offer anyone building infrastructure products: a product built on a protocol era ends with the era. Platforms absorb categories. If your product is a feature of the platform’s future self, your moat is time — spend it accordingly.

    The repo is preserved at github.com/vpalos/loomiere, readable and honest about what it is. Start with options.lua — the whole design philosophy fits in its comments.

    Rest well, old friend. You were fast.

  • Loomiere 2.0.1-beta finally out!

    All right! I finally got around to releasing this code to the public. I won’t say much now (since I’m tired) but I will say that this software has been functioning in production environment for over 1 year and a half serving all the video content available on the romanian website http://peteava.ro (about 800 TB of data each month out of 14 servers).

    Some (old) statistics showing it’s power can be found here.

    Source code: https://github.com/valeriupalos/loomiere.

    Warning:
    Any software downloaded from this website is *never* to be associated in any form with pornographic or erotic content! I.E. “Loomiere” must *never* be used to stream pornographic or erotic videos! There are plenty alternatives if you can’t help it.

  • “Loomiere 2.0 teaser” reloaded

    UPDATE: http://vpalos.com/1165/loomiere-2-0-1-beta-finally-out/

    «Update… Today this machine reached 6500+ active concurrent connections for a total traffic of 2841.19 Mbps (2778.1 output + 63.09 input) while the SSD’s were still below 20% load. Now that’s what I call serious FUN! 😀 Here are some pictures…

    …end!»

    Since my last post about describing the performance of Loomiere in production, quite a few things have happened. I tested a lot and found many things I would like to improve or add, I tried many hardware configurations to see what goes well with what. In short, I have a whole list of things I want to implement as soon as possible and the most important item on this list is to actually launch Loomiere to the public as soon as possible! 🙂

    However, here is a quick update on the performance of Loomiere, but this time with a nice twist: it’s running on a SSD-based machine! Here are some specs:

    • Intel Core I7 3GHz
    • 12 GB RAM
    • 6 x 256GB SSD Kingston
    • 3 x 1 Gigabit Ethernet cards
    • Ubuntu Lucid Lynx with 2.6.37-12-server kernel

    And here are the results after only a few hours from launch (graphs follow):

    • 4500+ active oncurrent connections (streams)
    • 300+ MB/s of throughput (aprox. 2500 Gbps)

    However, at this point we hit a wall: the mainboard or the kernel. I have to dig into this problem further, but from what I could gather so far, it seems that the mainboard or the Linux kernel can’t handle more punishment. Following are the CPU and memory graphs; it is clear that while the memory has no worries, the CPU is hogging! The problem lies somewhere between the I/O operations and the actual sending of data to the sockets (interrupts maybe?). More testing will follow regarding this issue.

    Hmm… this is a deep one.

    So, that’s it for now, I’m going to sleep. Good night :).

  • Loomiere 2.0 teaser

    UPDATE: http://vpalos.com/1165/loomiere-2-0-1-beta-finally-out/

    This article is a quick peek into how Loomiere 2.0 is (currently) serving close to 3k active streams from a single server in production which is restricted to 1.6 Gbps of bandwidth (we are currently negotiating with our ISP to raise this limitation). All these statistics represent a single machine, in real time, over a period of 12 hours, equipped as follows:

    • 2 x Xeon Dual Core (with HyperThreading) at 3.2GHz
    • 16 GB RAM
    • 15 x 1TB HDD (7200rpm)
    • 4 x 1GB NIC’s
    • This system runs on Ubuntu 10.04.1 LTS.

    OK so here are the graphs:

    The graphs may not yet be as stable as I would wish at the moment since I am still testing this setup as well as Loomiere itself, but I think soon I will have a more stable configuration and also some time to comment on these graphs.

    Enjoy! 🙂

  • Loomiere/Stream: Revived!

    UPDATE: /1165/loomiere-2-0-1-beta-finally-out/

    OK folks, things have settled down and we are good to go. After some considerations the legal concerns for Loomiere/Stream are now cleared and gone. The source is now released and will be available indefinitely. Again, this streamer (minimally customized) has already been serving all the video content at http://peteava.ro for 3 full months (for those seeking a demo).

    Source code: loomiere-0.2.1-tar.gz

    Warning:
    Any software downloaded from this website is *never* to be associated in any form with pornographic or erotic content! I.E. “Loomiere/Stream” must *never* be used to stream pornographic or erotic videos! There are plenty alternatives if you can’t help it.

    Just a teaser:
    Fighting the video-streaming problem has taught me very many things which, in turn, led me to realize that I might be able to use a substantially different streaming approach to achieve a massive amount of optimization in this field. So quite soon, I think I’ll have ready a brand new (and far more powerful) streamer that aims at making it possible for a single server to serve many thousands (I am still testing this) of streams simultaneously using commodity hardware. I am not yet settled on whether this project will be commercial, open-sourced or both but I hope to clear this aspect soon as well. Real-world streaming (i.e. before and after) statistics will be made available on release.

    Stay tuned! 🙂

  • First impressions on Loomiere/Stream performance

    UPDATE: http://vpalos.com/1165/loomiere-2-0-1-beta-finally-out/

    As promised, here are some of the first monitoring statistics of Loomiere/Stream in a production environment after moving away from psstream. Only one server is considered, a Quad-core Xeon with 8GB RAM (not that they are used anymore).

    This shows the memory usage over one week (the switch was made on the 29th as is obvious).

    (more…)

  • Loomiere/Stream – A high performance streaming server

    UPDATE: http://vpalos.com/1165/loomiere-2-0-1-beta-finally-out/

    The Loomiere (0.2.1) code is now freely available under GPLv3.
    Please see this post for an update.

    Are you killing psstream?

    Well, yes! I am sure that many of you already know about psstream (the PHP streaming extension I made a while back). Well, many things happened since then and I came to realize I could do better; a whole lot better actually. As of now the ‘psstream’ project is officially no longer developed (see below). It will remain on the website for some time to come for archiving purposes but that is it.

    But wait, why did you do it?

    For some time now I have be looking into improving the streaming mechanism for a large video-sharing project run by my company. PSStream was a first effort, and it did the job but soon ran into problems. None of our servers was able to properly stream more than 150 clients simultaneously and the resources were grossly wasted, hence, Loomiere/Stream. (more…)

  • Bash URI parser using SED

    Warning! This version is now obsolete!
    Check out the new and improved version (using only Bash built-ins) here!

    Here is a command-line (bash) script that uses sed to split the segments of an URI into usable variables. It also validates the given URI since malformed strings produce the text “ERROR” which can be handled accordingly:

    # Assembling a sample URI (including an injection attack)
    uri_1='http://user:pass@www.example.com:19741/dir1/dir2/file.php'
    uri_2='?param=some_value&array[0]=123¶m2=\`cat /etc/passwd\`'
    uri_3='#bottom-left'
    uri="$uri_1$uri_2$uri_3"
    
    # Parse URI
    op=`echo "$uri" | sed -nrf "uri.sed"`
    
    # Handle invalid URI
    [[ $op == 'ERROR' ]] && { echo "Invalid URI!"; exit 1; }
    
    # Execute assignments
    eval "$op"
    
    # ...work with URI components...
    

    Notice the "uri.sed" file given to sed?
    (more…)