<?xml version="1.0" encoding="UTF-8"?>

    <feed xmlns="http://www.w3.org/2005/Atom">
        <title>@kgriffs</title>
        
        <link rel="alternate" href="http://blog.kgriffs.com/" />
        <link rel="self" href="http://blog.kgriffs.com/feed.xml" type="application/atom+xml" />
        <id>http://blog.kgriffs.com/</id>
        <updated>2019-04-08T19:38:55Z</updated>
        
        <author>
            <name>Kurt Griffiths</name>
            <email>mail@kgriffs.com</email>
            <uri>http://blog.kgriffs.com/</uri>
        </author>
        
        
            <entry>
                <title>GraphQL vs. REST</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2017/08/29/graphql-vs-rest.html" type="text/html" />
                <id>http://blog.kgriffs.com/2017/08/29/graphql-vs-rest.html</id>
                <updated>2017-08-29T21:09:00Z</updated>
                
                
                    <summary type="html">Comparing GraphQL to REST is like comparing apples and oranges. But let&#39;s do it anyway.</summary>
                
                
                <content type="html">&lt;p&gt;Since kicking off a new project for my startup, I&amp;rsquo;ve been looking into GraphQL vs. REST.&lt;/p&gt;

&lt;p&gt;First of all, it&amp;rsquo;s important to note that REST is a comprehensive &lt;em&gt;architectural style&lt;/em&gt;, not a protocol. And I don&amp;rsquo;t think this is really a debate about whether to use one or the other. We&amp;rsquo;ll need both for the foreseeable future.&lt;/p&gt;

&lt;p&gt;GraphQL really shines only as long as you are only talking about rich read-only data APIs. It really can be quite elegant. GraphQL does support mutations as well, but they are essentially just a way of tacking on RPC calls. Some devs think this is the bee&amp;rsquo;s knees, but that&amp;rsquo;s because they never really understood REST in the first place. They&amp;rsquo;ve never moved past thinking in terms of RPC or CRUD, but just using HTTP verbs instead of method names. &lt;/p&gt;

&lt;p&gt;Case in point: we tend to write RPC-style clients for REST APIs, and then proceed to complain about REST not being a useful architectural style. It&amp;rsquo;s a self-fulfilling prophecy.&lt;/p&gt;

&lt;p&gt;So of course they are excited to have somewhere else to go. &lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s not to say GraphQL is devoid of attractive qualities. Especially if you don&amp;rsquo;t try to use it to mutate state. &lt;/p&gt;

&lt;p&gt;With GraphQL you can potentially reduce the number of calls to your API, conserve bandwidth, and improve client responsiveness. On the other hand, GraphQL may make it harder for the server to effectively cache responses, since different clients can query for wildly different data sets.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://githubengineering.com/the-github-graphql-api/&#34;&gt;GitHub makes some reasonable justifications&lt;/a&gt; for moving to GraphQL in the latest version of their API. On the other hand, note how they appeal to their own authority as API experts to convince you that you should trust them. Maybe. Just remember, do your own homework. &lt;strong&gt;#youarenotgithub&lt;/strong&gt; &lt;strong&gt;#youarenotfacebook&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can do some things in REST to alleviate the pain points that GitHub mentions (ala OData, API Chaining). But the GraphQL declarative style is perhaps more elegant. On the other hand, if REST clients and APIs were to make better use (or any use at all) of caching headers and &lt;a href=&#34;https://github.com/mikestowe/cphl&#34;&gt;HATEOS&lt;/a&gt;, this would be less of an issue. Performance would be improved, and REST clients would become far less brittle. &lt;/p&gt;

&lt;p&gt;Anyway, we are still climbing the hype curve on this one. We&amp;rsquo;ll see how it turns out.&lt;/p&gt;

&lt;p&gt;Further reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://graphql.org&#34;&gt;GraphQL (Official Site)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://githubengineering.com/the-github-graphql-api/&#34;&gt;The GitHub GraphQL API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.programmableweb.com/news/just-because-github-has-graphql-api-doesn%E2%80%99t-mean-you-should-too/analysis/2016/09/21&#34;&gt;Just Because Github Has a GraphQL API Doesn’t Mean You Should Too&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gist.github.com/skanev/f3468e8b85a3d6bc16c7aa493229eda7&#34;&gt;I Like GraphQL (Gist)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
            </entry>
        
            <entry>
                <title>Falcon Web Framework: What&#39;s New?</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2016/10/27/falcon-web-framework-whats-new-1.x.html" type="text/html" />
                <id>http://blog.kgriffs.com/2016/10/27/falcon-web-framework-whats-new-1.x.html</id>
                <updated>2016-10-27T21:09:00Z</updated>
                
                
                    <summary type="html">Version 1.1 of the Falcon WSGI framework is now available, thanks to all the hard work put in by our growing team of awesome contributors. Extra special thanks to everyone who joined us at the PyCon 2015 and 2016 sprints to work on 1.0 and 1.1!</summary>
                
                
                <content type="html">&lt;p&gt;&lt;img class=&#34;right&#34; src=&#34;http://blog.kgriffs.com/assets/images/pycon-2016-falcon-web-framework-sprint-1.jpg&#34; width=&#34;160px&#34; alt=&#34;Falcon web framework sprint at PyCon 2016&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Earlier this year the Falcon community celebrated the web framework&amp;rsquo;s landmark 1.0 release. It takes a surprising amount of effort to make something simple and elegant, and I want to personally thank the many people who have helped us reach this point through their generous support and contributions to the project over the past few years.&lt;/p&gt;

&lt;p&gt;When it comes to web development, there are many options to choose from within the Python community. This is actually a good problem to have, since it gives you a better chance of finding the right tool for the job. We&amp;rsquo;ve worked hard to make Falcon a useful, complementary addition to any Python web developer&amp;rsquo;s toolbox. &lt;/p&gt;

&lt;p&gt;Some web developers choose Falcon when the job calls for high performance. For example, they may develop a performance-sensitive microservice in Falcon to complement their Django app. Falcon also works great for developing high-throughput cloud services, microservices, and app backends.&lt;/p&gt;

&lt;p&gt;Other web developers choose Falcon when they need low-level control over the way requests are processed. They appreciate how Falcon embraces HTTP instead of paving over it. Falcon makes it easier to reason about the application and to diagnose errors, which is especially helpful in large-scale production deployments.&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;left&#34; src=&#34;http://blog.kgriffs.com/assets/images/pycon-2016-falcon-web-framework-sprint-3.jpg&#34; width=&#34;180px&#34; alt=&#34;Falcon web framework sprint at PyCon 2016&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Finally, web developers choose Falcon due to its clean, well-documented source code. We&amp;rsquo;ve worked hard to make it easy to understand the code and to contribute improvements and add-ons. Developers have noted the educational aspects of the Falcon framework; reading its source is a great way to learn more about WSGI, HTTP, Python programming idioms, and performance tuning. &lt;/p&gt;

&lt;p&gt;No tool is perfect, and Falcon is certainly no exception. But the framework has already come a long way and I&amp;rsquo;m excited to see what the future will bring. If you&amp;rsquo;d like to help us create that future, please consider &lt;a href=&#34;https://github.com/falconry/falcon/blob/master/CONTRIBUTING.md&#34;&gt;joining the discussion&lt;/a&gt; and contributing a PR or two. Or, if you&amp;rsquo;ve created an add-on please consider listing it &lt;a href=&#34;https://github.com/falconry/falcon/wiki/Add-on-Catalog&#34;&gt;on our wiki&lt;/a&gt;. Thanks!&lt;/p&gt;

&lt;p&gt;Recently we released version 1.1 of the Falcon web framework. Many thanks to everyone in the community who contributed to the 1.0 and 1.1 releases! &lt;/p&gt;

&lt;p&gt;Here are some highlights:&lt;/p&gt;
&lt;h2&gt;New in Falcon 1.0&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Please note: For a complete list of changes, including breaking changes and bug fixes, please see the &lt;a href=&#34;http://falcon.readthedocs.io/en/stable/changes/1.0.0.html&#34;&gt;changelog for version 1.0&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Code of Conduct&lt;/h3&gt;
&lt;p&gt;A &lt;a href=&#34;https://github.com/falconry/falcon/blob/master/CODEOFCONDUCT.md&#34;&gt;code of conduct&lt;/a&gt; was added to solidify our community&amp;rsquo;s commitment to sustaining a welcoming, respectful culture. This was not done in response to a specific incident, but rather as a proactive measure to nip any potential problems in the bud as our community grows.&lt;/p&gt;
&lt;h3&gt;Routing Improvements&lt;/h3&gt;
&lt;p&gt;Path segments with multiple field expressions can now be defined at the same level as path segments having only a single field expression. For example, this now works:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;api.add_route(&amp;#x27;&amp;#x2F;files&amp;#x2F;{name}&amp;#x27;, resource_1)
api.add_route(&amp;#x27;&amp;#x2F;files&amp;#x2F;{name}.{ext}&amp;#x27;, resource_2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note, however, that using different field names will still cause a conflict:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;api.add_route(&amp;#x27;&amp;#x2F;files&amp;#x2F;{id}&amp;#x27;, resource_1)
api.add_route(&amp;#x27;&amp;#x2F;files&amp;#x2F;{name}&amp;#x2F;ext&amp;#x27;, resource_2)  # Raises ValueError
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Falcon 1.0 also improves support for custom router implementations. &lt;code&gt;API.add_route()&lt;/code&gt; now accepts additional parameters via &lt;code&gt;*args&lt;/code&gt;, &lt;code&gt;**kwargs&lt;/code&gt;. These parameters are passed through to the router&amp;rsquo;s own &lt;code&gt;add_route()&lt;/code&gt; method. Also, &lt;code&gt;falcon.routing.compile_uri_template()&lt;/code&gt; now supports templates that contain digits and underscores.&lt;/p&gt;
&lt;h3&gt;Request and Response Improvements&lt;/h3&gt;
&lt;p&gt;New &lt;code&gt;access_route&lt;/code&gt; and &lt;code&gt;remote_addr&lt;/code&gt; properties were added to the &lt;code&gt;Request&lt;/code&gt; class for getting upstream IP addresses:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;client_ip = req.access_route[0]
last_hop_ip = req.remote_addr
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Response&lt;/code&gt; class was given a &lt;code&gt;get_header()&lt;/code&gt; method to give apps a way to check if a header has already been set:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;request_id = resp.get_header(&amp;#x27;X-Request-ID&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also, as of Falcon 1.0 both the &lt;code&gt;Request&lt;/code&gt; and &lt;code&gt;Response&lt;/code&gt; classes support range header units other than bytes:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;# Per RFC 7233, the server must ignore a Range header field
# that contains a range unit that it does not understand.
use_range = (req.range_unit == &amp;#x27;blocks&amp;#x27;)

# Content-Range: blocks 0-63&amp;#x2F;64
resp.content_range = (0, 63, 64, &amp;#x27;blocks&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;HTTP Error and Status Features&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;HTTP_422&lt;/code&gt;, &lt;code&gt;HTTP_428&lt;/code&gt;, &lt;code&gt;HTTP_429&lt;/code&gt;, &lt;code&gt;HTTP_431&lt;/code&gt;, &lt;code&gt;HTTP_451&lt;/code&gt;, and &lt;code&gt;HTTP_511&lt;/code&gt; were added to the &lt;code&gt;falcon&lt;/code&gt; module. We also added three additional error classes, namely &lt;code&gt;HTTPUnprocessableEntity&lt;/code&gt;, &lt;code&gt;HTTPTooManyRequests&lt;/code&gt;, and 
&lt;code&gt;HTTPUnavailableForLegalReasons&lt;/code&gt;. (The fact that some developers need that last one makes me sad, but unfortunately this is the world we live in.)&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;HTTPStatus&lt;/code&gt; class is now available directly under the &lt;code&gt;falcon&lt;/code&gt; module, and has been properly documented. Furthermore, support for HTTP redirections was added via a set of &lt;code&gt;HTTPStatus&lt;/code&gt; subclasses to avoid the problem of hooks and responder methods possibly overriding the redirect. Raising an instance of one of these new redirection classes will short-circuit request processing, similar to raising an instance of &lt;code&gt;HTTPError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also, the default 404 responder now raises an instance of &lt;code&gt;HTTPError&lt;/code&gt; instead of manipulating the response object directly. This makes it possible to customize the response body using a custom error handler or serializer.&lt;/p&gt;
&lt;h3&gt;New Testing Framework&lt;/h3&gt;
&lt;p&gt;A new testing framework was added that should be more intuitive to use than the old one. The new testing framework performs &lt;code&gt;wsgiref&lt;/code&gt; validation on all requests. &lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;from falcon import testing
import myapp


class MyTestCase(testing.TestCase):
    def setUp(self):
        super(MyTestCase, self).setUp()

        # Assume the hypothetical `myapp` package has a
        # function called `create()` to initialize and
        # return a `falcon.API` instance.
        self.app = myapp.create()


class TestMyApp(MyTestCase):
    def test_get_message(self):
        doc = {u&amp;#x27;message&amp;#x27;: u&amp;#x27;Hello world!&amp;#x27;}

        result = self.simulate_get(&amp;#x27;&amp;#x2F;messages&amp;#x2F;42&amp;#x27;)
        self.assertEqual(result.json, doc)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Please note that the previous testing framework is now deprecated and will be removed in a future release. Several of Falcon&amp;rsquo;s own tests have been ported to use the new framework, with the remainder to be ported in subsequent releases.&lt;/p&gt;
&lt;h3&gt;Breaking Changes in 1.0&lt;/h3&gt;
&lt;p&gt;Since 1.0 was a major release, we took the opportunity to clean up a few rough edges. Rather than list all the breaking changes here, I&amp;rsquo;ll just highlight one in particular. &lt;/p&gt;

&lt;p&gt;In 1.0 an option was added to toggle automatic parsing of form params. Falcon will no longer automatically parse, by default, requests that have the content type &amp;ldquo;application/x-www-form-urlencoded&amp;rdquo;. This was done to avoid unintended side-effects that may arise from consuming the request stream. It also makes it more straightforward for applications to customize and extend the handling of form submissions. Applications that require this functionality must re-enable it explicitly, by setting a new request option that was added for that purpose:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;app = falcon.API()
app.req_options.auto_parse_form_urlencoded = True
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A full list of 1.0 breaking changes is included in &lt;a href=&#34;http://falcon.readthedocs.io/en/stable/changes/1.0.0.html&#34;&gt;the changelog&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;New in Falcon 1.1&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Please note: For a complete list of changes, including bug fixes, please see the &lt;a href=&#34;http://falcon.readthedocs.io/en/stable/changes/1.1.0.html&#34;&gt;changelog for version 1.1&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Request and Response Improvements&lt;/h3&gt;
&lt;p&gt;&lt;img class=&#34;right&#34; src=&#34;http://blog.kgriffs.com/assets/images/pycon-2016-falcon-web-framework-sprint-2.jpg&#34; width=&#34;160px&#34; alt=&#34;Falcon web framework sprint at PyCon 2016&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Three new properties were added to the &lt;code&gt;Request&lt;/code&gt; class. The new &lt;code&gt;bounded_stream&lt;/code&gt; property can be used in place of the &lt;code&gt;stream&lt;/code&gt; property to mitigate the blocking behavior of input objects used by some WSGI servers. Also, a &lt;code&gt;uri_template&lt;/code&gt; property was added to expose the template for the route corresponding to the path requested by the user agent. &lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;# Load the request body directly into msgpack
resource_representation = msgpack.unpack(req.bounded_stream, encoding=&amp;#x27;utf-8&amp;#x27;)

# Log the template that was matched for this request
logger.debug(req.uri_template)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In 1.1 we also added an &lt;code&gt;accept_ranges&lt;/code&gt; property for setting the Accept-Ranges header:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;# Tell the client that they should specify ranges in terms of &amp;quot;blocks&amp;quot;
resp.accept_ranges = &amp;#x27;blocks&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In addition to the new properties mentioned above, a &lt;code&gt;context&lt;/code&gt; property was implemented for the &lt;code&gt;Response&lt;/code&gt; class to mirror the same property that is already available on the &lt;code&gt;Request&lt;/code&gt; class. In addition, arbitrary custom attributes can now be attached to instances of both &lt;code&gt;Request&lt;/code&gt; and &lt;code&gt;Response&lt;/code&gt; as an alternative to adding values to the &lt;code&gt;context&lt;/code&gt; property or implementing custom subclasses:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;# Pass a &amp;quot;customer&amp;quot; resource representation to middleware via the context dict
resp.context[&amp;#x27;rr&amp;#x27;] = customer

# ...or use a custom attribute instead of the context dict
resp.rr = customer

# Also works with Request objects
resp.set_header(&amp;#x27;X-Request-ID&amp;#x27;, req.request_id)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other news, when working with query strings, you can now disable CSV-style parsing of query parameter values with the &lt;code&gt;auto_parse_qs_csv&lt;/code&gt; request option. JSON-encoded query parameter values can now be retrieved and decoded in a single step via &lt;code&gt;req.get_param_as_dict()&lt;/code&gt;. Also, &lt;code&gt;req.get_param_as_bool()&lt;/code&gt; now recognizes &amp;ldquo;on&amp;rdquo; and &amp;ldquo;off&amp;rdquo; in support of IE&amp;rsquo;s default checkbox values. &lt;/p&gt;
&lt;h3&gt;New and Improved Error Classes&lt;/h3&gt;
&lt;p&gt;In Falcon 1.1 we added two new error classes, &lt;code&gt;falcon.HTTPUriTooLong&lt;/code&gt; and &lt;code&gt;falcon.HTTPGone&lt;/code&gt;. All parameters are now optional for most error classes. When no title is specified for an error, it will default to the HTTP status text (e.g., &amp;ldquo;409 Conflict&amp;rdquo;).&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;# The target resource is no longer available at the 
# origin server and this condition is likely to be 
# permanent.
raise falcon.HTTPGone()

# All parameters are optional now, but note that you 
# can improve the user experience by specifying some 
# details.
raise HTTPForbidden()
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Better Testing&lt;/h3&gt;
&lt;p&gt;By popular demand, pytest support was added to Falcon&amp;rsquo;s testing framework:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;from falcon import testing
import pytest

import myapp


@pytest.fixture(scope=&amp;#x27;module&amp;#x27;)
def client():
    # Assume the hypothetical `myapp` package has a
    # function called `create()` to initialize and
    # return a `falcon.API` instance.
    return testing.TestClient(myapp.create())


def test_get_message(client):
    doc = {u&amp;#x27;message&amp;#x27;: u&amp;#x27;Hello world!&amp;#x27;}

    result = client.simulate_get(&amp;#x27;&amp;#x2F;messages&amp;#x2F;42&amp;#x27;)
    assert result.json == doc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Regardless of whether you use unittest or pytest, when simulating a request using Falcon&amp;rsquo;s testing framework, query string parameters can now be specified as a &lt;code&gt;dict&lt;/code&gt;, as an alternative to passing a raw query string.&lt;/p&gt;

&lt;p&gt;Also, the &lt;code&gt;falcon.testing.Cookie&lt;/code&gt; class was added to represent a cookie returned by a simulated request; &lt;code&gt;falcon.testing.Result&lt;/code&gt; now exposes a &lt;code&gt;cookies&lt;/code&gt; attribute for examining returned cookies. &lt;/p&gt;
&lt;h3&gt;Middleware Processing&lt;/h3&gt;
&lt;p&gt;Falcon&amp;rsquo;s middleware processing logic was revamped to improve performance and to fix a couple of edge cases.&lt;/p&gt;

&lt;p&gt;In addition, a &lt;code&gt;req_succeeded&lt;/code&gt; flag is now passed to the &lt;code&gt;process_request()&lt;/code&gt; middleware method to signal whether or not an exception was raised while processing the request:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;class ExampleMiddleware(object):
    def process_response(self, req, resp, resource, req_succeeded):
        if req_succeeded:
            # ...
        else:
            # ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Per our policy of not introducing breaking changes in point releases (not to mention never introducing undocumented breaking changes that can take you by surprise), we added shimming logic to avoid breaking existing middleware methods that do not yet accept this new parameter.&lt;/p&gt;
&lt;h3&gt;Other Goodies&lt;/h3&gt;
&lt;p&gt;A new CLI utility, &lt;code&gt;falcon-print-routes&lt;/code&gt;, was added that takes in a &lt;code&gt;module:callable&lt;/code&gt;, introspects the routes, and prints the results to &lt;code&gt;stdout&lt;/code&gt;. This utility is automatically installed along with the framework:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;bash&#34;&gt;    $ falcon-print-routes commissaire:api
    -&amp;gt; &amp;#x2F;api&amp;#x2F;v0&amp;#x2F;status
    -&amp;gt; &amp;#x2F;api&amp;#x2F;v0&amp;#x2F;cluster&amp;#x2F;{name}
    -&amp;gt; &amp;#x2F;api&amp;#x2F;v0&amp;#x2F;cluster&amp;#x2F;{name}&amp;#x2F;hosts
    -&amp;gt; &amp;#x2F;api&amp;#x2F;v0&amp;#x2F;cluster&amp;#x2F;{name}&amp;#x2F;hosts&amp;#x2F;{address}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, &lt;code&gt;falcon.get_http_status()&lt;/code&gt; was implemented to provide a way for apps to look up a full HTTP status line, given just a status code.&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;py&#34;&gt;status = falcon.get_http_status(719)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thanks again to all of our awesome contributors who have made these releases possible!&lt;/p&gt;

&lt;p&gt;@kgriffs&lt;/p&gt;
</content>
            </entry>
        
            <entry>
                <title>Falcon WSGI Framework: 0.3.0</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2015/06/15/falcon-wsgi-framework-highlights-0.3.html" type="text/html" />
                <id>http://blog.kgriffs.com/2015/06/15/falcon-wsgi-framework-highlights-0.3.html</id>
                <updated>2015-06-15T21:09:00Z</updated>
                
                
                    <summary type="html">Version 0.3 of the Falcon WSGI framework is now available, thanks to all the hard work put in by our growing team of stylish and talented contributors. Extra special thanks to everyone who joined us at the PyCon 2015 sprint in Montreal!</summary>
                
                
                <content type="html">&lt;p&gt;&lt;img class=&#34;left&#34; src=&#34;http://blog.kgriffs.com/assets/images/falcon-sprint-pycon-2015.jpg&#34; alt=&#34;Falcon web framework - PyCon 2015 sprint&#34; width=&#34;100&#34; height=&#34;75&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Version 0.3 of the Falcon WSGI framework is now available, thanks to all the hard work put in by our growing team of stylish and talented contributors. Extra special thanks to everyone who joined us at the PyCon 2015 sprint in Montreal!&lt;/p&gt;

&lt;p&gt;So what&amp;rsquo;s new in Falcon 0.3?&lt;/p&gt;
&lt;h2&gt;New Router&lt;/h2&gt;
&lt;p&gt;Thanks to &lt;a href=&#34;https://github.com/richardolsson&#34;&gt;Richard Olsson&lt;/a&gt; we now have a new engine that compiles routes into a decision tree. This improves lookup performance for large APIs, and will also allow us to more efficiently implement some new URI template features. As part of this work, we also made it easier to use &lt;a href=&#34;http://falcon.readthedocs.org/en/0.3.0/api/routing.html&#34;&gt;custom routing engines&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;right&#34; src=&#34;http://blog.kgriffs.com/assets/images/linear-router.png&#34; alt=&#34;Falcon web framework linear routing engine&#34; width=&#34;395&#34; height=&#34;305&#34; /&gt;&lt;/p&gt;

&lt;p&gt;In version 0.2, Falcon&amp;rsquo;s default router compiles each URI template to a regular expression. For each incoming request, Falcon iterates through this list of regexes, attempting to match each one, in turn, against the requested path. This means that the order in which routes are added can make a big difference in performance; when a path is requested for a route toward the back of the list, a bunch of regex match operations must be attempted before finding the correct route.&lt;/p&gt;

&lt;p&gt;The new engine, by contrast, takes a divide-and-conquer approach to match a given request path to a resource. This works well because developers tend to organize APIs hierarchically. Richard and I started with a couple of prototypes that implemented a generic routing engine. This engine traversed a tree of nodes, with each node representing a single path segment in the URL namespace.&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;left&#34; src=&#34;http://blog.kgriffs.com/assets/images/tree-router.png&#34; alt=&#34;Falcon web framework tree-based routing engine&#34; width=&#34;278&#34; height=&#34;235&#34; /&gt;&lt;/p&gt;

&lt;p&gt;We found that the most efficient of the two prototypes ran slightly faster when looking up a long path with multiple segments. It wasn&amp;rsquo;t quite as fast for a simple path, but was still competitive. The order in which routes were added to the regex-based router also made a big difference; when looking up a route that was defined later in the router&amp;rsquo;s search list, the prototype&amp;rsquo;s divide-and-conquer approach easily won out.&lt;/p&gt;

&lt;div style=&#34;clear:both&#34;&gt;&lt;/div&gt;

&lt;p&gt;The final engine incorporated into Falcon 0.3 takes this strategy one step further. It generates a static decision tree, rather than running a generic traversal algorithm over an abstract tree. The generated code looks something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;def find(path, return_values, expressions, params):
    path_len = len(path)
    if path_len &amp;gt; 0:
        if path[0] == &amp;quot;parks&amp;quot;:
            if path_len &amp;gt; 1:
                params[&amp;quot;park_id&amp;quot;] = path[1]
                if path_len &amp;gt; 2:
                    if path[2] == &amp;quot;map&amp;quot;:
                        if path_len == 3:
                            return return_values[11]
                        return None
                    return None
                if path_len == 2:
                    return return_values[10]
                return None
            return None
        if path[0] == &amp;quot;libraries&amp;quot;:
            
            # ...

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This provides an extra boost of performance by avoiding looping constructs and dict lookups. It&amp;rsquo;s especially fast when JITed under PyPy.&lt;/p&gt;
&lt;h2&gt;New URI Template Feature&lt;/h2&gt;
&lt;p&gt;Also thanks to &lt;a href=&#34;https://github.com/richardolsson&#34;&gt;Richard Olsson&lt;/a&gt;, URI templates can now include multiple parameterized fields within a single path segment. For example, you might use this template to route a GH-style request:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;#x2F;repos&amp;#x2F;{org}&amp;#x2F;{repo}&amp;#x2F;compare&amp;#x2F;{usr0}:{branch0}...{usr1}:{branch1}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our new engine paves the way for implementing some other, long-overdue templating features as well. Stay tuned!&lt;/p&gt;
&lt;h2&gt;Cookie Support&lt;/h2&gt;
&lt;p&gt;Thanks to the tireless efforts of &lt;a href=&#34;https://github.com/tbug&#34;&gt;Henrik Tudborg&lt;/a&gt;, we now have support for reading and writing cookies. A cookie can be read from the request via the new &lt;code&gt;cookies&lt;/code&gt; property, which returns a simple &lt;code&gt;dict&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;cookies = req.cookies
my_cookie_value = cookies[&amp;#x27;my_cookie&amp;#x27;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also set cookies on a response with the new &lt;code&gt;set_cookie&lt;/code&gt; method:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;resp.set_cookie(&amp;quot;my_cookie&amp;quot;, &amp;quot;my cookie value&amp;quot;,
                max_age=600, domain=&amp;quot;example.com&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See also: &lt;a href=&#34;http://falcon.readthedocs.org/en/0.3.0/api/cookies.html&#34;&gt;http://falcon.readthedocs.org/en/0.3.0/api/cookies.html&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Jython 2.7 support&lt;/h2&gt;
&lt;p&gt;During the PyCon 2015 sprint, &lt;a href=&#34;https://github.com/csojinb&#34;&gt;Clara Bennett&lt;/a&gt; added support to Falcon for Jython 2.7. Now you can use Falcon along with &lt;a href=&#34;https://github.com/jimbaker/hellowsgi&#34;&gt;Clamp and Fireside&lt;/a&gt; (or ModJy) to create JVM-friendly web services in Python!&lt;/p&gt;
&lt;h2&gt;Other goodies&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The Request class gained a new helper, &lt;code&gt;get_param_as_date(...)&lt;/code&gt;, for getting a query param as a date.&lt;/li&gt;
&lt;li&gt;Date header values are now returned as &lt;code&gt;datetime&lt;/code&gt; objects, rather than raw string.&lt;/li&gt;
&lt;li&gt;Friendly constants for status codes were added, so that you can now say &lt;code&gt;falcon.HTTP_NO_CONTENT&lt;/code&gt; instead of &lt;code&gt;falcon.HTTP_204&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Query string parsing was made much more robust when decoding embedded documents, such as JSON.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See also the &lt;a href=&#34;http://falcon.readthedocs.org/en/0.3.0/changes/0.3.0.html&#34;&gt;changelog on RTD&lt;/a&gt;.&lt;/p&gt;
</content>
            </entry>
        
            <entry>
                <title>Security for Humans</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2015/04/07/security-for-humans.html" type="text/html" />
                <id>http://blog.kgriffs.com/2015/04/07/security-for-humans.html</id>
                <updated>2015-04-07T21:09:00Z</updated>
                
                
                    <summary type="html">Don&#39;t demonize your users. This only sets the stage for a security cold war. Instead, shift the burden to design-time. Find ways to defend against threats without hamstringing your users, and they will love you for it.</summary>
                
                
                <content type="html">&lt;p&gt;Lately I&amp;rsquo;ve been thinking about an interesting interplay between a person’s:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Desire to be productive (D)&lt;/li&gt;
&lt;li&gt;Appreciation for security (S)&lt;/li&gt;
&lt;li&gt;Faith in those who are implementing security measures (F)&lt;/li&gt;
&lt;li&gt;Pain threshold for said security measures (T)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where an individual&amp;rsquo;s security threshold is equal to some measure of the other three:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;T = S + F - D
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When designing any system, the amount of pain (degradation to the user&amp;rsquo;s experience) caused by security controls is simply the sum of the parts:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;P = sum(pain(c) for c in controls)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ideally, we want to create systems where the pain introduced by security controls does not exceed the threshold of its users:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;P &amp;lt;= T
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;rsquo;s tempting to become fixated on the right side of the equation, i.e., &amp;ldquo;the users are the problem.&amp;rdquo;  Why? Because reducing (P) is hard. It requires formal threat modeling, creative architecture, and sufficient funding.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t mean to say that working on (T) is completely wrong; in fact, you should absolutely strive to engender a healthy appreciation for security, and work to build relationships of trust between those implementing security measures and those affected by said measures. However, to be successful you&amp;rsquo;ll need to dig in and get to work on (P) as well. The problem with betting too much on (T) is that it lies in the realm of culture. Changing culture is a slow and difficult process. And it&amp;rsquo;s a process that can easily backfire.&lt;/p&gt;

&lt;p&gt;Don&amp;rsquo;t demonize your users. This only sets the stage for a security cold war. Instead, shift the burden to design-time. Find ways to defend against threats without hamstringing users, and they will love you for it.&lt;/p&gt;
</content>
            </entry>
        
            <entry>
                <title>A Better uuidgen</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2015/03/03/towards-a-better-uuidgen.html" type="text/html" />
                <id>http://blog.kgriffs.com/2015/03/03/towards-a-better-uuidgen.html</id>
                <updated>2015-03-03T21:09:00Z</updated>
                
                
                    <summary type="html">A humble suggestion for a better uuidgen that works consistently across platforms and is clipboard-friendly.</summary>
                
                
                <content type="html">&lt;p&gt;Recently, I put together some examples to use in a RESTful workshop, and needed to generate a bunch of UUIDs. &lt;/p&gt;

&lt;p&gt;On OS X I have a couple of options. First, there&amp;rsquo;s &lt;code&gt;uuidgen&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;bash&#34;&gt;$ uuidgen
E4B221B0-9466-4354-8A33-5B3EB5D3ABE3

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under OS X, this creates a DCE version 4 (random) UUID. However, under FreeBSD, &lt;code&gt;uuidgen&lt;/code&gt; always generates a version 1 UUID. And finally, under Linux, &lt;code&gt;uuidgen&lt;/code&gt; can create either version 1 or version 4 UUIDs, but defaults to a random UUID when a high-quality RNG is available.&lt;sup&gt;&lt;a name=&#34;id-1&#34; href=&#34;#id-1.ftn&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;/p&gt;

&lt;p&gt;The second option I have on my MBP is the OSSP &lt;code&gt;uuid&lt;/code&gt; tool. It&amp;rsquo;s also available on Linux and FreeBSD:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;bash&#34;&gt;$ uuid
1d98d052-c107-11e4-a360-6796fc8cedc1

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, &lt;code&gt;uuid&lt;/code&gt; returns a DCE version 1 (time + MAC) UUID. I can override this to get a random UUID, which is usually what you want:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;bash&#34;&gt;$ uuid -v 4
07158102-962d-4038-a3d6-fc6428b98313

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I have a cross-platform way to generate a version 4 UUID from the command line. Next I need to get that value into my clipboard.&lt;/p&gt;
&lt;h2&gt;Trailing newlines with uuidgen and uuid&lt;/h2&gt;
&lt;p&gt;Both &lt;code&gt;uuidgen&lt;/code&gt; and &lt;code&gt;uuid&lt;/code&gt; output a trailing newline character. Now, that&amp;rsquo;s fine when just displaying the UUID in a terminal, but is decidedly less helpful when piping the UUID somewhere, for example &lt;a href=&#34;http://stackoverflow.com/questions/749544/pipe-to-from-clipboard&#34;&gt;to the clipboard&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;bash&#34;&gt;$ uuidgen | pbcopy

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when I paste the copied text somewhere else, like into a JSON document, the newline messes up my formatting (yes, I know, this is all very sad.)&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;json&#34;&gt;{
    &amp;quot;uuid&amp;quot;: &amp;quot;07158102-962d-4038-a3d6-fc6428b98313
&amp;quot;
}

&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;A better uuidgen&lt;/h2&gt;
&lt;p&gt;Fortunately, the problems above are easily solved with a little bash magic. The systems where I run this have CPRNGs, so I&amp;rsquo;m comfortable with forcing version 4:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;bash&#34;&gt;#!&amp;#x2F;usr&amp;#x2F;bin&amp;#x2F;env bash

if [ -t 1 ]
then
    uuid -v 4
else
    uuid -v 4 | tr -d &amp;#x27;\n&amp;#x27;
fi

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script first tests whether output is attached to a terminal. If so, a version 4 UUID is output with a trailing newline. Otherwise, if we are piping the output, we&amp;rsquo;ll strip off the trailing newline character.&lt;/p&gt;

&lt;p&gt;Or, if you don&amp;rsquo;t want to depend on OSSP&amp;rsquo;s &lt;code&gt;uuid&lt;/code&gt; tool:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;#!&amp;#x2F;usr&amp;#x2F;bin&amp;#x2F;env python

import sys
import uuid

result = str(uuid.uuid4())
if sys.stdout.isatty():
    print(result)
else:
    sys.stdout.write(result)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Python &lt;code&gt;uuid.uuid4()&lt;/code&gt; function will use your operating system&amp;rsquo;s native &lt;code&gt;uuid_generate_random&lt;/code&gt; function call, if available, to generate the UUID. Failing that, it will use &lt;code&gt;os.urandom&lt;/code&gt;. Only if a CPRNG is unavailable will &lt;code&gt;uuid.uuid4()&lt;/code&gt; resort to using &lt;code&gt;random.randrange(256)&lt;/code&gt; like some kind of primitive animal.&lt;sup&gt;&lt;a name=&#34;id-2&#34; href=&#34;#id-2.ftn&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;/p&gt;

&lt;p&gt;Now I have a version of &lt;code&gt;uuidgen&lt;/code&gt; that works consistently across platforms, and is pipe-able. &lt;/p&gt;

&lt;p&gt;Hooray!&lt;/p&gt;

&lt;ul class=&#34;footnotes&#34;&gt;
    &lt;li&gt;
        &lt;sup&gt;&lt;a name=&#34;id-1.ftn&#34; href=&#34;#id-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;I suppose this makes some kind of sense, since a bad generator would be more likely to introduce collisions. You also don&amp;rsquo;t want to lull the user into a false sense of security (allowing them to assume their UUIDs are unpredicatable and opaque when they actually aren&amp;rsquo;t).
    &lt;/li&gt;
    &lt;li&gt;
        &lt;sup&gt;&lt;a name=&#34;id-2.ftn&#34; href=&#34;#id-2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;If you have to use such a platform, you have my sympathy.
    &lt;/li&gt;  
&lt;/ul&gt;
</content>
            </entry>
        
            <entry>
                <title>OpenStack Paris Summit Retrospective</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2014/12/17/openstack-paris-retrospective.html" type="text/html" />
                <id>http://blog.kgriffs.com/2014/12/17/openstack-paris-retrospective.html</id>
                <updated>2014-12-17T21:09:00Z</updated>
                
                
                    <summary type="html">During the week of the summit, I observed three important trends in the OpenStack ecosystem. First, private clouds are starting to take on the characteristics of public clouds. Second, design discussions and general interactions between various members of the community are becoming significantly more civil and constructive. And finally, interns are taking a greater role in delivering new features across various OpenStack projects.</summary>
                
                
                <content type="html">&lt;p&gt;A few weeks ago I attended the OpenStack Summit in Paris. For this next development cycle (&amp;ldquo;Kilo&amp;rdquo;) I decided to step down from the Program Technical Lead (PTL) role for Zaqar in order to give others the opportunity to lead, and to give myself more time to focus on a few other projects that have been demanding more and more of my attention. The new PTL, Flavio Percoco, is an amazing engineer and a good friend of mine; I know he is going to do a great job with Zaqar going forward. As any former or current PTL will tell you, it is far from an easy job, and I&amp;rsquo;m grateful to Flavio for stepping up to lead the program.&lt;/p&gt;

&lt;p&gt;During the week of the summit, I observed three important trends in the OpenStack ecosystem. First, private clouds are starting to take on the characteristics of public clouds. Second, design discussions and general interactions between various members of the community are becoming significantly more civil and constructive. And finally, interns are taking a greater role in delivering new features across various OpenStack projects.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://blog.kgriffs.com/assets/images/paris-summit-design-sessions.jpg&#34; alt=&#34;OpenStack Paris Design Summit&#34; /&gt;&lt;/p&gt;

&lt;p&gt;OpenStack is growing up. For anyone attending the Paris Summit, it was hard to miss the strong interest by banks, telcos and large enterprises in leveraging OpenStack within their data centers. The economics, flexibility, and control provided by OpenStack is (continuing) to attract some big players. It is my belief that as more organizations like BMW, BBVA, Bloomberg, Comcast/NBC, Time Warner, AT&amp;amp;T, Orange, Swisscom, and Huawei continue to adopt the open cloud in critical parts of their infrastructure, more and more private clouds will start looking like public clouds in terms of scale and other requirements. This will necessitate a dramatic improvement in the technical underpinnings of various projects, including performance, security, reliability, scale, and operability.&lt;/p&gt;

&lt;p&gt;In order to deliver on these challenging requirements, active technical contributors and community leaders will need to be more disciplined and efficient than ever before. At this past summit I was happy to discover that community members were spending less time arguing about &lt;em&gt;who&lt;/em&gt; is right, and more time discussing &lt;em&gt;what&lt;/em&gt; is right;
 with a tacit acceptance that the community will need to embrace multiple technologies and deployment options in order to cover all of our emerging use cases. &lt;/p&gt;

&lt;p&gt;Any creative endeavor of significance is the product of an extraordinary number of ideas; if we want to create a world-class open cloud solution, we must become incredibly efficient at farming great ideas and crafting them together. We must have a culture in which every voice is heard and valued, with individuals holding themselves accountable to create a constructive, positive community. &amp;ldquo;Seek first to understand,&amp;rdquo; as Stephen Covey would say. We aren&amp;rsquo;t simply building up software; we are &lt;a href=&#34;https://www.startwithwhy.com/Books.aspx&#34;&gt;building up people&lt;/a&gt;. Do that well, and the software will take care of itself.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://blog.kgriffs.com/assets/images/eiffel-tower-night.jpg&#34; class=&#34;left&#34; alt=&#34;OpenStack 
Paris Design Summit - Eiffel Tower at Night&#34; /&gt;&lt;/p&gt;

&lt;p&gt;One of the best sources of fresh ideas in the OpenStack community is our growing network of interns. During the summit in Paris I had the opportunity to spend time with several interns who are doing amazing work across a number of projects. These young professionals are our future leaders. They bring a fresh perspective to their respective teams, helping all of us challenge long-held assumptions and see the forest for the trees. I hope that we will continue to see more and more interns participating in OpenStack through such means as the GNOME Outreach Program for Women, Google Summer of Code, and general corporate sponsorships. &lt;/p&gt;

&lt;p&gt;OpenStack will have a bright future if we can strike while the iron&amp;rsquo;s hot. Let&amp;rsquo;s take the Big Private challenge head-on, focusing our development efforts on efficiency, security, reliability, usability and operability. Let&amp;rsquo;s continue creating a more constructive, positive software development culture. And finally, let&amp;rsquo;s continue to invest in our future leaders through mentoring and internship programs.&lt;/p&gt;
</content>
            </entry>
        
            <entry>
                <title>Redis Lua Scripting for Performance</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2014/11/19/redis-lua-scripting-performance.html" type="text/html" />
                <id>http://blog.kgriffs.com/2014/11/19/redis-lua-scripting-performance.html</id>
                <updated>2014-11-19T21:09:00Z</updated>
                
                
                    <summary type="html">NoSQL tends to force a lot of data model logic into the app layer, making it hard (or even impossible) to optimize certain types of operations. By supporting server-side Lua scripting, Redis provides a way to move some of that logic back into the data layer without having to add higher-order operations to the API.</summary>
                
                
                <content type="html">&lt;p&gt;Lately I&amp;rsquo;ve been working on &lt;a href=&#34;https://wiki.openstack.org/wiki/Zaqar&#34;&gt;Zaqar&amp;rsquo;s&lt;/a&gt; new Redis driver. Zaqar provides a stateless REST API for creating and consuming message feeds. When there are multiple observers AKA subscribers of a feed, each observer uses a marker to keep track of its own position in that feed. &lt;/p&gt;

&lt;p&gt;In this design, there is a race condition that emerges as a result of the interplay between producers and observers, that can cause observers to miss one or more messages. This issue manifests differently depending on which backend you use with Zaqar, but generally speaking, to avoid the condition you need to make sure a message with a higher marker is never &lt;em&gt;persisted&lt;/em&gt; before a message with a lower marker.&lt;/p&gt;

&lt;p&gt;The way we originally dealt with this in the Redis driver was to use the server&amp;rsquo;s support for transactions. To do this with Redis, you set a watch on a key (or set of keys) upon which the transaction depends, then prepare the transaction by creating a pipeline of commands, and finally attempt to execute that pipeline. An error will be raised if any of the watched keys have changed in the meantime, causing all commands to abort. &lt;/p&gt;

&lt;p&gt;Here is a version of the code in Zaqar that we originally used to post messages, edited for instructional purposes:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;with self._client.pipeline() as pipe:

    start_ts = timeutils.utcnow_ts()

    # NOTE(kgriffs): Retry the operation if another transaction
    # completes before this one, in which case it may have
    # posted messages with the same rank counter the current
    # thread is trying to use, which would cause messages
    # to get out of order and introduce the risk of a client
    # missing a message while reading from the queue.
    #
    # This loop will eventually time out if we can&amp;#x27;t manage to
    # post any messages due to other threads continually beating
    # us to the punch.

    # TODO(kgriffs): Add a backoff sleep between retries

    while (timeutils.utcnow_ts() - start_ts) &amp;lt; RETRY_POST_TIMEOUT:
        now = timeutils.utcnow_ts()
        prepared_messages = [
            Message(
                ttl=msg[&amp;#x27;ttl&amp;#x27;],
                created=now,
                client_uuid=client_uuid,
                claim_id=None,
                claim_expires=now,
                body=msg.get(&amp;#x27;body&amp;#x27;, {}),
            )

            for msg in messages
        ]

        try:
            # NOTE(kgriffs): Keep an eye on the side counter; if
            # it changes, we know another parallel request beat us
            # to the punch and we need to get a new starting
            # value for rank_counter.
            pipe.watch(counter_key)

            rank_counter = pipe.get(counter_key)
            rank_counter = int(rank_counter) if rank_counter else 0

            pipe.multi()

            for i, msg in enumerate(prepared_messages):
                msg.to_redis(pipe)
                pipe.zadd(msgset_key, rank_counter + i, msg.id)

            pipe.incrby(counter_key, len(keys))
            pipe.execute()

        except redis.exceptions.WatchError:
            continue
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, Zaqar uses an ordered set to index messages. It ranks the messages using a side counter. Elsewhere in the Redis driver, there is a method that lists messages. The client provides a marker which tells the server the position of the last message received by that client, and then the server is responsible for returning the next batch of messages for that client.&lt;/p&gt;

&lt;p&gt;In the Redis driver, the marker is simply the message ID. In order to return to the client a list of messages &lt;em&gt;after&lt;/em&gt; the specified marker, the service looks up the rank of that marker in the message index, then lists any subsequent messages, in rank order, up to a specified limit.&lt;/p&gt;

&lt;p&gt;This works, but the more concurrent requests served, the more frequent the counter collisions. The result is a lot of wasted CPU capacity spent on retrying the operation, and significantly higher per-request latency. There are strategies that can reduce the number of retries (on average) required, but they only offer marginal improvements. &lt;/p&gt;

&lt;p&gt;Fortunately, there&amp;rsquo;s a better way.&lt;/p&gt;

&lt;p&gt;Since version 2.6, Redis supports server-side execution of Lua scripts. This is analogous to stored procedures in the RDBMS world. However, only one Redis script may run at a time, and no other commands may run concurrently. In this way you can execute a batch of commands atomically, without having to use watch-abort-retry loops in the client. On the other hand, this also means scripts must finish quickly to avoid starving other incoming commands.&lt;sup&gt;&lt;a name=&#34;id-1&#34; href=&#34;#id-1.ftn&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Generally speaking, NoSQL tends to force a lot of data model logic into the app layer. By supporting server-side Lua scripting, Redis provides a way to move some of that logic back into the data layer without having to add higher-order operations to the API.&lt;/p&gt;

&lt;p&gt;All things considered, I had a hunch that moving the indexing logic to Lua would increase the performance of posting messages to the service. I was hoping for at least a moderate improvement over the transactional approach outlined above.&lt;/p&gt;

&lt;p&gt;The first thing I noticed was that by moving much of the logic to Lua, I was able to greatly simplify the Python code:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;with self._client.pipeline() as pipe:
    message_ids = []
    now = timeutils.utcnow_ts()

    with self._client.pipeline() as pipe:
        for msg in messages:
            prepared_msg = Message(
                ttl=msg[&amp;#x27;ttl&amp;#x27;],
                created=now,
                client_uuid=client_uuid,
                claim_id=None,
                claim_expires=now,
                body=msg.get(&amp;#x27;body&amp;#x27;, {}),
            )

            prepared_msg.to_redis(pipe)
            message_ids.append(prepared_msg.id)

        pipe.execute()

    # NOTE(kgriffs): If this call fails, we will return
    # an error to the client and the messages will be
    # orphaned, but Redis will remove them when they
    # expire, so we will just pretend they don&amp;#x27;t exist
    # in that case.
    self._index_messages(msgset_key, counter_key, message_ids)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;_index_messages&lt;/code&gt; method prepares the arguments, then passes them to the &lt;a href=&#34;https://github.com/andymccurdy/redis-py#lua-scripting&#34;&gt;cached Lua script&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;def _index_messages(self, msgset_key, counter_key, message_ids):
    # NOTE(kgriffs): A watch on a pipe could also be used to ensure
    # messages are inserted in order, but that would be less efficient.
    func = self._scripts[&amp;#x27;index_messages&amp;#x27;]

    arguments = [len(message_ids)] + message_ids
    func(keys=[msgset_key, counter_key], args=arguments)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Lua script then updates the message index using a single&lt;sup&gt;&lt;a name=&#34;id-2&#34; href=&#34;#id-2.ftn&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; ZADD call, then increments the side counter:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;lua&#34;&gt;-- Read params
local msgset_key = KEYS[1]
local counter_key = KEYS[2]

local num_message_ids = tonumber(ARGV[1])

-- Get next rank value
local rank_counter = tonumber(redis.call(&amp;#x27;GET&amp;#x27;, counter_key) or 1)

-- Add ranked message IDs
local zadd_args = {&amp;#x27;ZADD&amp;#x27;, msgset_key}
for i = 0, (num_message_ids - 1) do
    zadd_args[#zadd_args+1] = rank_counter + i
    zadd_args[#zadd_args+1] = ARGV[2 + i]
end

redis.call(unpack(zadd_args))

-- Set next rank value
return redis.call(&amp;#x27;SET&amp;#x27;, counter_key, rank_counter + num_message_ids)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since only one Lua script can run at a time, the counter is guaranteed to stay constant while updating the index. Consequently, after the ZADD call, the ordered set is guaranteed to end up with a run of unique rank values for each batch of messages.&lt;/p&gt;

&lt;p&gt;So how did it perform? &lt;/p&gt;

&lt;p&gt;I benchmarked both the old and new implementations using zaqar-bench, a simple python+gevent performance testing tool included with Zaqar. I ran the tool with 3,000 producer clients, posting messages to a minimal Zaqar deployment (1 web head running uWSGI and one DB box running a couple of Redis processes).&lt;/p&gt;
&lt;h2&gt;Before&lt;/h2&gt;
&lt;p&gt;Before the patch the results were decent. But, as you can see, some requests  took an inordinate amount of time. High contention for the side counter caused some requests to retry the transaction many times before finally succeeding.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;req&amp;#x2F;sec: 5223

ms&amp;#x2F;req (mean): 3.5 
ms&amp;#x2F;req (stdev): 7.7 
ms&amp;#x2F;req (99th): 42.1
ms&amp;#x2F;req (max): 186.5
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;After&lt;/h2&gt;
&lt;p&gt;After applying the Lua patch and re-running the benchmark, the stats not only smoothed out significantly, but throughput jumped by almost 60%. Hooray!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;req&amp;#x2F;sec: 8246

ms&amp;#x2F;req (mean): 2.4
ms&amp;#x2F;req (stdev): 1.7 
ms&amp;#x2F;req (99th): 10.7
ms&amp;#x2F;req (max): 54.6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&amp;rsquo;s still some work to do in order to get those outliers fully under control, but these initial results have me excited to see what else a little Lua love can do.&lt;/p&gt;

&lt;ul class=&#34;footnotes&#34;&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-1.ftn&#34; href=&#34;#id-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;Larger operations can typically be broken down into smaller ones in order to interleave multiple concurrent requests.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-2.ftn&#34; href=&#34;#id-2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;This should be faster than multiple ZADD calls, since the Redis code still treats Lua scripts as &lt;em&gt;clients&lt;/em&gt;, albeit ones that can bypass the network stack. However, I still need to do an A/B test to see if the difference in performance is significant.
  &lt;/li&gt;
&lt;/ul&gt;
</content>
            </entry>
        
            <entry>
                <title>Open Minds for Open Discussions</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2014/09/30/open-minds-open-discussions.html" type="text/html" />
                <id>http://blog.kgriffs.com/2014/09/30/open-minds-open-discussions.html</id>
                <updated>2014-09-30T21:09:00Z</updated>
                
                
                    <summary type="html">Mailing lists tend to dehumanize people, opening the door to subconscious (and conscious) social behaviors that are anything but constructive.</summary>
                
                
                <content type="html">&lt;p&gt;I&amp;rsquo;m thinking about setting up a mailing list for the &lt;a href=&#34;http://falconframework.org/&#34;&gt;Falcon web framework&lt;/a&gt;. This seems like a good way to bring more people into the conversation, and it should help capture tribal knowledge for posterity.&lt;/p&gt;

&lt;p&gt;But I have a concern. Mailing lists tend to dehumanize people, opening the door to subconscious (and conscious) social behaviors that are anything but constructive. I&amp;rsquo;ve seen this happen first-hand in other communities I&amp;rsquo;ve been a part of.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a rough list of ways to interact with people, from most human to least:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In-person visits&lt;/li&gt;
&lt;li&gt;Video conferencing&lt;/li&gt;
&lt;li&gt;Phone calls&lt;/li&gt;
&lt;li&gt;Instant messaging&lt;/li&gt;
&lt;li&gt;Mailing lists&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Don&amp;rsquo;t get me wrong; mailing lists can be (and have been) used for much good. It&amp;rsquo;s just that the further down you get on the list above, the more discipline is required to keep communications constructive. &lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;right&#34; src=&#34;http://blog.kgriffs.com/assets/images/prick.png&#34; width=&#34;300px&#34; height=&#34;80px&#34; alt=&#34;William Shakespeare, The Merchant of Venice, Act 3, Scene 1&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Part of the problem is that mailing lists (and other forums that facilitate open discussions) can sometimes lead to a culture of distrust or even become a tool for subversion. This happens when individuals humiliate, intimidate, or even bully others in the community. The more abstract and unaccountable the communications medium, the easier it is for those with good intentions to unconsciously use a poor choice of words. Not only that, but it also becomes easier for unscrupulous individuals to manipulate the community for personal gain.&lt;/p&gt;

&lt;p&gt;I have to hope that most of the time these sorts of communications (or mis-communications, as the case may be) happen unconsciously, perhaps due to a lack of shared context or as a failed attempt at humor. &lt;/p&gt;

&lt;p&gt;Regardless of whether the intent is actual or perceived, the damage to the community is the same, and must be dealt with immediately, before it festers into a community-crippling culture of enmity. We aren&amp;rsquo;t always going to agree on how this or that should be done. But we can agree to treat each other with trust and respect. &lt;/p&gt;

&lt;p&gt;We can agree to &lt;a href=&#34;https://www.stephencovey.com/7habits/7habits-habit5.php&#34;&gt;seek first to understand&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once the Falcon mailing list is live, it will be interesting to see how this plays out and how much moderation will be required. So far the community has been really cool and I don&amp;rsquo;t want to lose that. &lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m hoping people will for the most part moderate themselves, behaving professionally and being cognizant of the way their words may be perceived. If we can all do that, while also assuming good intent when on the receiving end, we&amp;rsquo;ll be well on our way to building a fantastic community around Falcon.&lt;/p&gt;
</content>
            </entry>
        
            <entry>
                <title>How to Win</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2014/06/18/how-to-win.html" type="text/html" />
                <id>http://blog.kgriffs.com/2014/06/18/how-to-win.html</id>
                <updated>2014-06-18T21:09:00Z</updated>
                
                
                    <summary type="html">In 1998 the Phantom Regiment did the impossible. You can too.</summary>
                
                
                <content type="html">&lt;p&gt;Allow me to share with you a personal experience.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s early summer, 1996. I am 16 years old, discovering muscles I never thought existed, holding a heavy baritone bugle in front of my body for interminable lengths of time. Every day, all day, I spend practicing with my corps, refining our field show for this year&amp;rsquo;s season. My fellow drum corps friends surround me as we perform our drills, practice our steps, and perfect our music under a hot blue sky.&lt;/p&gt;

&lt;p&gt;During breaks we gossip about our corps, and about the competition. We talk about how everyone&amp;rsquo;s shows are shaping up, speculating on who will rock the DCI finals at the end of the summer. As the season progresses, two junior drum and bugle corps begin to stand out.&lt;/p&gt;

&lt;p&gt;Everyone is talking about the Blue Devils and the Phantom Regiment.&lt;/p&gt;

&lt;p&gt;The Blue Devils are based in Concord, CA. To date, they have won more championships than any other DCI corps. The Blue Devils&amp;#39; center snare is nicknamed &amp;ldquo;Jesus&amp;rdquo; because &lt;em&gt;he never makes a mistake!&lt;/em&gt; They have a massive, tiered organization. Many of their musicians move out to California in late spring to practice and take private lessons in advance of the regular season.&lt;/p&gt;

&lt;p&gt;The Phantom Regiment hails from Rockford, Illinois. They have yet to win a single DCI championship. And things are not looking promising this year, either. In fact, the Phantom Regiment has not been placing particularly well in the early-season competitions. The critics deride the Regiment&amp;rsquo;s &amp;ldquo;boring&amp;rdquo; show, which eschews the flashy Broadway-esque style favored by many DCI corps over the past few seasons.&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;right&#34; src=&#34;http://blog.kgriffs.com/assets/images/phantom-regiment-win.png&#34; width=&#34;300px&#34; alt=&#34;Lessons Learned from the Phantom Regiment Drum and Bugle Corps.&#34; /&gt;&lt;/p&gt;

&lt;p&gt;But lately, we start to hear how the Phantom Regiment is placing higher and higher in competitions across the country, even taking first in some cases.&lt;/p&gt;

&lt;p&gt;Now, when people talk about the Phantom Regiment, they use words like &amp;ldquo;exciting&amp;rdquo;, &amp;ldquo;powerful&amp;rdquo; and &amp;ldquo;precise&amp;rdquo;. The corps is building a fervent fan base with a back-to-basics show that is&amp;mdash;somehow&amp;mdash;incredibly refreshing.&lt;/p&gt;

&lt;p&gt;Finally, at the end of the summer, when the Blue Devils and the Phantom Regiment meet in Florida for the DCI 1996 World Championships, they finish their individual shows to thunderous applause. It is clear to all of us that we have just seen something extraordinary.&lt;/p&gt;

&lt;p&gt;At the end of the competition, all of the finalists take the field to await the judge&amp;rsquo;s decision. Starting with 12th place, as each corps&amp;#39; score is announced, the tension slowly builds&amp;hellip; we are now waiting to hear who will be this year&amp;rsquo;s DCI World Champion&amp;hellip;&lt;/p&gt;

&lt;p&gt;In fourth place with a final score of 93.8&amp;hellip;the Cavaliers!&lt;/p&gt;

&lt;p&gt;In third place with a score of 96.9&amp;hellip;the Cadets of Bergen County!&lt;/p&gt;

&lt;p&gt;Then, a pause&amp;hellip; There are only two corps left. The crowd begins to buzz with speculation. Who will take second? Who has won the championship? And then the announcement comes&amp;hellip;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Ladies and gentlemen, with a score of 97.4, for the first time in DCI history, &lt;strong&gt;we have a tie&lt;/strong&gt; between the Blue Devils and the Phantom Regiment!&amp;rdquo;&lt;/p&gt;

&lt;p&gt;The crowd goes &lt;em&gt;absolutely insane&lt;/em&gt;.&lt;/p&gt;

&lt;div style=&#34;text-align:center&#34;&gt;❧&lt;/div&gt;

&lt;p&gt;In 1996 the Phantom Regiment won against all odds. You can too:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Set Audacious Goals.&lt;/strong&gt; Don&amp;rsquo;t settle for mediocrity. Dream big.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Es Sprit de Corps.&lt;/strong&gt; Don&amp;rsquo;t underestimate the importance of creating a positive, constructive culture. A culture where every individual&amp;rsquo;s contribution is valued. A culture of friendship, respect, and accountability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Obsess Over the Basics.&lt;/strong&gt; When you are the underdog, your only chance of winning is to become obsessed with the basics. Prioritize quality over quantity; substance over flash.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create Your Own Fans.&lt;/strong&gt; There is more than one way to win. Decide who you&amp;rsquo;re playing for, and then create something that blows them away. Play for your fans, not your competition.&lt;/li&gt;
&lt;/ol&gt;
</content>
            </entry>
        
            <entry>
                <title>Falcon WSGI Framework: 0.1.8</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2014/02/04/falcon-wsgi-framework-highlights-0.1.8.html" type="text/html" />
                <id>http://blog.kgriffs.com/2014/02/04/falcon-wsgi-framework-highlights-0.1.8.html</id>
                <updated>2014-02-04T21:09:00Z</updated>
                
                
                    <summary type="html">Thanks to the hard work of a growing community of contributors, we were able to ship several long-awaited goodies, including request sinks, improved URI decoding, and custom error handlers.</summary>
                
                
                <content type="html">&lt;p&gt;I&amp;rsquo;m quite proud of the new Falcon 0.1.8 release. Thanks to our growing community of talented contributors, we were able to ship several long-awaited goodies, including request sinks, improved URI decoding, and custom error handlers.&lt;/p&gt;

&lt;p&gt;Also, there was a ton of work done to improve performance in hot code paths, in order to offset the extra processing required by the new features landing in 0.1.8.&lt;/p&gt;
&lt;h2&gt;Custom Error Handlers&lt;/h2&gt;
&lt;p&gt;You can now DRY up your error code by registering global handlers. An error handler is just a callable that takes the exception that was raised, plus the standard req and resp args that were passed to the responder, along with the params dict that was passed as kwargs to the responder.&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;def handle_storage_error(ex, req, resp, params):
    # Log what happened

    # ...

    # Return an appropriate response explictly, or raise an
    # instance of HTTPError as shown here...

    description = (&amp;#x27;Sorry, couldn\&amp;#x27;t write your thing to the &amp;#x27;
                   &amp;#x27;database. It worked on my box.&amp;#x27;)

    raise falcon.HTTPError(falcon.HTTP_725,
                           &amp;#x27;Database Error&amp;#x27;,
                           description)


api = falcon.API()

# If a responder ever raised an instance of StorageError, pass control to
# the given handler.
api.add_error_handler(StorageError, handle_storage_error)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, you can define a handler on the error class itself. If you name it &lt;code&gt;handle&lt;/code&gt; then you don&amp;rsquo;t even need to specify the function in &lt;code&gt;add_error_handler&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;class StorageError(Exception):
    @staticmethod
    def handle(ex, req, resp, params):
        description = (&amp;#x27;Sorry, couldn\&amp;#x27;t write your thing to the &amp;#x27;
                       &amp;#x27;database. It worked on my box.&amp;#x27;)

        raise falcon.HTTPError(falcon.HTTP_725,
                               &amp;#x27;Database Error&amp;#x27;,
                               description)

# ...

# Falcon conveniently assumes the handler is defined as `StorageError.handle`
api.add_error_handler(StorageError)

&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Request Sinks&lt;/h2&gt;
&lt;p&gt;Request sinks is another handy new feature added in Falcon 0.1.8. What you do is add a regex-based route that slurps up anything that starts with the given pattern. You can make smart proxies with this, or anything else you like.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a ridiculously contrived example that drains any request paths that start
with either &amp;lsquo;/v1/charts&amp;rsquo; or &amp;lsquo;/v1/inventory&amp;rsquo;.&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;# Step 1: Define a sink using an extra Proxy thing just for fun
class Proxy(object):
    def forward(self, req):
        return falcon.HTTP_503


class SinkAdapter(object):

    def __init__(self):
        self._proxy = Proxy()

    def __call__(self, req, resp, **kwargs):
        resp.status = self._proxy.forward(req)
        self.kwargs = kwargs


# Step 2: Invoke some magic
app = falcon.API()

sink = SinkAdapter()
app.add_sink(sink, r&amp;#x27;&amp;#x2F;v1&amp;#x2F;[charts|inventory]&amp;#x27;)

# Step 3: Profit!

&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Case-Insensitive Headers&lt;/h2&gt;
&lt;p&gt;Previously, when you set response headers, the header name you used was case-sensitive. This wasn&amp;rsquo;t exactly intuitive in the world of HTTP, where clients and servers are supposed to treat header names as case-insensitive. Among other things, this created an unfortunate gotcha for folks who were trying to proxy requests to a backing service, and selectively overwrite some of the original header values.&lt;/p&gt;

&lt;p&gt;Now, when setting headers, their names are normalized to lowercase to avoid this problem. This approach is more performant than using some kind of case-insensitive dict under the covers, and well-behaved clients should be treating response headers they get back from the server as case-insensitive anyway.&lt;/p&gt;

&lt;p&gt;That being said, if some of your unit tests were asserting on specific header strings, they may break. If you are using &lt;code&gt;falcon.testing.StartResponseMock&lt;/code&gt;, you can work around this problem by reading headers via &lt;code&gt;headers_dict&lt;/code&gt; which is now implemented using a case-insensitive dict class borrowed from the stupendous Requests library.&lt;/p&gt;
&lt;h2&gt;Improved URL encoding/decoding&lt;/h2&gt;
&lt;p&gt;Percent-encoded characters in query strings are now properly decoded. Even encoded UTF-8 sequences work like a charm! See also &lt;a href=&#34;https://www.ietf.org/rfc/rfc3986.txt&#34;&gt;RFC 3986&lt;/a&gt; if you want to know how this is supposed to work and/or you are having trouble falling asleep.&lt;/p&gt;

&lt;p&gt;Also, you can now manually encode/decode URI things in your app if you&amp;rsquo;re crazy like that; just &lt;code&gt;from falcon.util import uri&lt;/code&gt; and you&amp;rsquo;re ready to rock.&lt;/p&gt;
&lt;h2&gt;Improved Python 3.3 Performance&lt;/h2&gt;
&lt;p&gt;All WSGI frameworks I&amp;rsquo;ve tested slow down when running under Python 3.3, relative to Python 2.7, but thanks to some serious voodoo, Falcon&amp;rsquo;s own performance gap has narrowed quite a bit as of 0.1.8. The difference is now just 12 μs/req. Check out the &lt;a href=&#34;http://falconframework.org/#Metrics&#34;&gt;latest benchmarks&lt;/a&gt; and see for yourself.&lt;/p&gt;

&lt;p&gt;Please, take &lt;a href=&#34;https://pypi.python.org/pypi/falcon/0.1.8&#34;&gt;0.1.8&lt;/a&gt; for a spin and tell me what you like, what you don&amp;rsquo;t, and what you would like to see in the next version. As always, you can find me on Freenode in &lt;strong&gt;#falconframework&lt;/strong&gt; and on Twitter &lt;strong&gt;@kgriffs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://pypi.python.org/pypi/falcon&#34;&gt;Get it while it&amp;rsquo;s hot.&lt;/a&gt;&lt;/p&gt;
</content>
            </entry>
        
            <entry>
                <title>Standardization Manifesto</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2014/01/08/software-standardization-manifesto.html" type="text/html" />
                <id>http://blog.kgriffs.com/2014/01/08/software-standardization-manifesto.html</id>
                <updated>2014-01-08T21:09:00Z</updated>
                
                
                    <summary type="html">Standardization is often promulgated as a worthy goal for teams and communities, but it must be recognized for what it is: a Platonic ideal.</summary>
                
                
                <content type="html">&lt;p&gt;Standardization is often promulgated as a worthy goal for teams and communities, but it must be recognized for what it is: a Platonic ideal. It is far more practical to simply constrain the number of options to a small number. Even then, you must be prepared to make an occasional exception simply to get the job done.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t think chaos is the answer, where you end up with everyone doing something different. However, I don&amp;rsquo;t think totalitarian standardization is the answer, either.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s important to use the right tool for the job. And if the tool doesn&amp;rsquo;t exist, who&amp;rsquo;s to say it shouldn&amp;rsquo;t be created?&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;center&#34; width=&#34;500px&#34;src=&#34;http://blog.kgriffs.com/assets/images/community-software-standardization.png&#34; alt=&#34;Total standardization within software communications is a fool&#39;s errand.&#34;/&gt;&lt;/p&gt;

&lt;p&gt;There are simply too many compromises&amp;mdash;both in terms of community dynamics and software functionality&amp;mdash;that have to be made in order to force everyone to use One Thing. In fact, the more code, people, and projects you have, the more compromises you will be forced to make.&lt;/p&gt;

&lt;p&gt;People often justify draconian standardization efforts by invoking the cliché &amp;ldquo;reinventing the wheel&amp;rdquo;. In reality, this is almost always a &lt;a href=&#34;http://goo.gl/1sRwkC&#34;&gt;false analogy&lt;/a&gt;. Can you imagine if we had stopped with &lt;a href=&#34;http://www.model-t-restore.com/images/wheel_3_lrg.jpg&#34;&gt;this design&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;When someone tells you &amp;ldquo;don&amp;rsquo;t reinvent the wheel,&amp;rdquo; they probably mean to say &amp;ldquo;don&amp;rsquo;t duplicate effort&amp;rdquo;, or &amp;ldquo;don&amp;rsquo;t repeat yourself&amp;rdquo; (&lt;a href=&#34;http://programmer.97things.oreilly.com/wiki/index.php/Don%27t_Repeat_Yourself&#34;&gt;DRY&lt;/a&gt;). The latter phrases avoid drawing a false analogy, but still have the problem of assuming that (1) duplicating effort is inherently bad, and (2) that the accused is guilty before being proven innocent.&lt;/p&gt;

&lt;p&gt;As for (1), sometimes duplicating effort is a perfectly reasonable thing to do. Students recreate other people&amp;rsquo;s work all the time in order to learn. And in the process, they sometimes discover even better ways of doing things. Or they may find that one way happens to be more productive for some people than another way, simply due to psychological differences among individuals.&lt;/p&gt;

&lt;p&gt;Regarding (2), maybe the accused is guilty and maybe they aren&amp;rsquo;t, but it makes a big difference whether or not you decide in advance that the person has nothing of value to add beyond what already exists.&lt;/p&gt;

&lt;p&gt;Stephen Covey found in his research that highly successful people seek first to understand, and only &lt;em&gt;then&lt;/em&gt; to be understood:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you&amp;rsquo;re like most people, you probably seek first to be understood; you want to get your point across. And in doing so, you may ignore the other person completely, pretend that you&amp;rsquo;re listening, selectively hear only certain parts of the conversation or attentively focus on only the words being said, but miss the meaning entirely. So why does this happen? Because most people listen with the intent to reply, not to understand.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you seek to understand another&amp;rsquo;s point of view, it helps to recognize that different things &amp;ldquo;feel&amp;rdquo; right to different people. When you standardize on One Thing, you gain some advantages with respect to knowledge and code reuse, but those are often offset by the loss in productivity that is inevitable when you force a significant portion of your community to use something that doesn&amp;rsquo;t feel natural to their way of thinking.&lt;/p&gt;

&lt;p&gt;More importantly, by mandating One Thing, you dissuade people from experimenting with other things which may (or may not) some day prove to be better than the One Thing, or at least inform future revisions of the One Thing. I don&amp;rsquo;t pretend to know in advance what the Best Thing is, and neither should any other community member.&lt;/p&gt;

&lt;p&gt;Indeed, community leaders should see themselves more as moderators, and less as presidents or dictators.&lt;/p&gt;

&lt;p&gt;If you put Some Thing out there and let people try it, and you see, by its fruits, that it is Good, other teams will start picking it up. Before you know it, you&amp;rsquo;ll arrive at a natural standard. But this takes time. You must be patient. You must, as a community, experiment with Some Thing, pushing and prodding it from many different angles, discussing its merits and shortcomings. Not too much time; just enough to get an idea of Its practicality. Enough time to allow Darwin to do his job.&lt;/p&gt;

&lt;p&gt;It is common to think &amp;ldquo;me vs. them&amp;rdquo;, but the most effective community leaders think &amp;ldquo;we&amp;rdquo; or &amp;ldquo;us&amp;rdquo;. They seek first to understand. Consider: was the project made for the process, or the process made for the project? Was the leader made for the community, or the community made for the leader?&lt;/p&gt;

&lt;p&gt;If you have to push very hard to get people to adopt Your Thing, you are doing it wrong. You aren&amp;rsquo;t building the community; you are poisoning it.&lt;/p&gt;
</content>
            </entry>
        
            <entry>
                <title>Painless Py3K Unicode Magic</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2013/12/20/py3k-magic-string-methods.html" type="text/html" />
                <id>http://blog.kgriffs.com/2013/12/20/py3k-magic-string-methods.html</id>
                <updated>2013-12-20T21:09:00Z</updated>
                
                
                    <summary type="html">Implementing Python&#39;s magic string methods is tricky when it comes to Unicode characters and Py3K compatibility. I recently came across this problem in OpenStack, and wanted to share the strategy we are using to work around the issue.</summary>
                
                
                <content type="html">&lt;p&gt;Implementing Python&amp;rsquo;s magic string methods is tricky when it comes to Unicode characters and Py3K compatibility. If your strings contain non-ASCII characters, ostensibly innocent statements such as &lt;code&gt;str(thing)&lt;/code&gt; blow up without warning. I recently came across this problem in OpenStack, and wanted to share the strategy we are using to work around it.&lt;/p&gt;

&lt;p&gt;The first step is to standardize on wide strings throughout your code base, only converting to UTF-8 byte strings at the edges, when it is required to communicate with the outside world. This strategy minimizes the number of places text encoding bugs can hide.&lt;/p&gt;

&lt;p&gt;Next, once you have normalized your code to use &lt;code&gt;six.text_type&lt;/code&gt; in lieu of &lt;code&gt;str&lt;/code&gt;, find everywhere  you use string coercion. You will want to change all the expressions that look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;str(thing)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to this:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;six.text_type(thing)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, if you ever override the default magic string methods, you will need to do something like this (&lt;a href=&#34;https://gist.github.com/kgriffs/7951625&#34;&gt;gist&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;import six

class FooError(Exception):

    message = u&amp;#x27;An unknown exception occurred.&amp;#x27;

    # Called under both Py2 and Py3K for str(ex)
    def __str__(self):
        if six.PY3:
            return self.message

        # Avoid UnicodeDecodeError in py2 when the string
        # contains non-ASCII characters.
        return self.message.encode(&amp;#x27;utf-8&amp;#x27;)

    # Called under Py2 for unicode(ex) and ignored in Py3
    def __unicode__(self):
        return self.message


# elsewhere...

def do_something():
    raise FooError()

try:
    do_something()
except FooError as ex:
    # Returns a UTF-8 string in py2, and a wide string in py3,
    # both of type `six.text_type`, with no coercion. Normally you
    # would use `six.text_type` instead (see below)
    msg_a = str(ex)

    # Returns `unicode` in py2 and `str` in py3.
    msg_b = six.text_type(ex)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result of &lt;code&gt;__str__&lt;/code&gt; under Py2 is always coerced to &lt;code&gt;str&lt;/code&gt; when &lt;code&gt;unicode&lt;/code&gt; is returned, which results in an ugly &lt;code&gt;UnicodeDecodeError&lt;/code&gt; when the string contains non-ASCII code points:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;pycon&#34;&gt;&amp;gt;&amp;gt;&amp;gt; class BadLlama(object):
...     def __str__(self):
...         return u&amp;#x27;€&amp;#x27;
...
&amp;gt;&amp;gt;&amp;gt; badness = BadLlama()
&amp;gt;&amp;gt;&amp;gt; str(badness)
Traceback (most recent call last):
  File &amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;, line 1, in &amp;lt;module&amp;gt;
UnicodeEncodeError: &amp;#x27;ascii&amp;#x27; codec can&amp;#x27;t encode character u&amp;#x27;\u20ac&amp;#x27; in position 0: ordinal not in range(128)
&amp;gt;&amp;gt;&amp;gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Happy Hacking!&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
</content>
            </entry>
        
            <entry>
                <title>SHA Snake Oil</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2013/11/25/sha-snake-oil.html" type="text/html" />
                <id>http://blog.kgriffs.com/2013/11/25/sha-snake-oil.html</id>
                <updated>2013-11-25T21:09:00Z</updated>
                
                
                    <summary type="html">The SHA message-digest algorithm has its uses, but it&#39;s no cure-all.</summary>
                
                
                <content type="html">&lt;p&gt;Massive, highly-publicized security breaches of online services in recent years have exposed the inconvenient truth that many web services still use MD5-based password authentication, and some don&amp;rsquo;t even hash passwords in the first place.&lt;/p&gt;

&lt;p&gt;This is serious stuff, considering that people tend to reuse the same password everywhere they go. A weak service not only risks its own business and reputation, but also everyone else&amp;rsquo;s.&lt;/p&gt;
&lt;h1&gt;Naive Password Hashing&lt;/h1&gt;
&lt;p&gt;&lt;img class=&#34;right&#34; src=&#34;http://blog.kgriffs.com/assets/images/sha-digest-cure.gif&#34; width=&#34;80px&#34; alt=&#34;Message digest algorithms such as SHA don&#39;t solve everything.&#34; /&gt;&lt;/p&gt;

&lt;p&gt;In the wake of these attacks, a movement began&lt;sup&gt;&lt;a name=&#34;id-1&#34; href=&#34;#id-1.ftn&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; to stop storing passwords in such a blatantly insecure way. In some circles, using a simple salted SHA was promulgated as the &amp;ldquo;best practice&amp;rdquo; fix. While certainly better than storing passwords in plaintext, or hashing them with MD5, there are other, more appropriate algorithms we should be promoting instead.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the problem: SHA, just like MD5, is actually &lt;em&gt;optimized&lt;/em&gt; for speed. In other words, just like MD5, SHA was designed to generate a one-way hash &lt;em&gt;as quickly as possible&lt;/em&gt;. This is a good property to have in some cases, but when it comes to password hashing, the last thing you want is an efficient algorithm!&lt;/p&gt;

&lt;p&gt;Case in point: Today&amp;rsquo;s commodity GPUs can perform &lt;strong&gt;billions of hashes&lt;/strong&gt; per second&lt;sup&gt;&lt;a name=&#34;id-2&#34; href=&#34;#id-2.ftn&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. Armed with a few video cards (or an EC2 account) and some knowledge of how humans typically choose passwords&lt;sup&gt;&lt;a name=&#34;id-3&#34; href=&#34;#id-3.ftn&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, it becomes trivial for an attacker to crack large numbers of passwords in a surprisingly short amount of time.&lt;/p&gt;
&lt;h1&gt;Use the Right Tool&lt;/h1&gt;
&lt;p&gt;What we as a community &lt;em&gt;should&lt;/em&gt; be promoting, instead, is the use of strong key derivation functions (KDFs).&lt;/p&gt;

&lt;p&gt;KDFs comprise a family of algorithms for generating password hashes. They can be used for password verification, as well as for deriving limited-use keys from a master secret. Unlike message-digest algorithms, such as MD5 and SHA, KDFs are designed to be &lt;em&gt;inefficient&lt;/em&gt;. Proper use of a KDF goes a long way toward making brute-force attacks impractical to execute, in terms of both cost and time.&lt;/p&gt;

&lt;p&gt;When asking people to move away from plaintext and MD5, we should be encouraging them to use a proper KDF, not some kind of home-grown, salted SHA digest.&lt;/p&gt;

&lt;p&gt;That way, we make the black hats sad.&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;center&#34; src=&#34;http://blog.kgriffs.com/assets/images/digest-vs-kdf.gif&#34; width=&#34;400px&#34; alt=&#34;Use a KDF to turn a happy black hat into a sad one.&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Here are my (current) go-to KDFs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;PBKDF2.&lt;/strong&gt; This RSA-developed, NIST-recommended algorithm has been widely used and vetted by cryptographers. You can find it in anything from LastPass to Django, OS X to Android. PBKDF2 is a good choice if an scrypt library is not available for your programming language of choice.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;scrypt.&lt;/strong&gt; This KDF is relatively new and not as battle-tested as some older algorithms, but has the advantage of requiring lots of memory to go fast, which mitigates attacks that rely on specialized hardware.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;We must do better&lt;/h1&gt;
&lt;p&gt;Everyone has a responsibility to the broader community to defend their portion of the web. Let&amp;rsquo;s ensure we are promoting &lt;em&gt;real&lt;/em&gt; best practices as we work to raise the bar on computer security.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Caveat emptor: While I care deeply about computer security and have a working knowledge of the same, I&amp;rsquo;m no cryptographer. You should definitely invest some time into making your own evaluation of KDFs, including consulting with experts in the field to fully understand their proper use.&lt;/em&gt;&lt;/p&gt;

&lt;ul class=&#34;footnotes&#34;&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-1.ftn&#34; href=&#34;#id-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;It&amp;rsquo;s about time our industry got a wake up call.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-2.ftn&#34; href=&#34;#id-2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;With appropriate software, i.e. &lt;a href=&#34;http://hashcat.net/oclhashcat-plus/&#34;&gt;hashcat&lt;/a&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-3.ftn&#34; href=&#34;#id-3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;See also this &lt;a href=&#34;http://www.troyhunt.com/2011/06/brief-sony-password-analysis.html&#34;&gt;password analysis&lt;/a&gt;.
  &lt;/li&gt;
&lt;/ul&gt;
</content>
            </entry>
        
            <entry>
                <title>An Unladen Web Framework</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2013/07/02/python-fast-web-service-framework.html" type="text/html" />
                <id>http://blog.kgriffs.com/2013/07/02/python-fast-web-service-framework.html</id>
                <updated>2013-07-02T21:09:00Z</updated>
                
                
                    <summary type="html">Falcon is a new web framework for building efficient cloud APIs and stirring up controversy.</summary>
                
                
                <content type="html">&lt;p&gt;When measuring the performance of a web service, I like to find out how quickly the service responds to requests (latency), and how much horsepower is required to serve each request (efficiency).&lt;/p&gt;

&lt;p&gt;Efficiency is important because it allows me to serve large numbers of customers at a reasonable cost (both to them and to myself). Latency is also important to me, because it correlates with usability; if an API responds faster, then apps using that API respond faster, and by extension the people using
&lt;img class=&#34;left&#34; src=&#34;http://blog.kgriffs.com/assets/images/web-framework-performance.gif&#34; width=&#34;240px&#34; height=&#34;127px&#34; alt=&#34;Web Framework Performance: Latency and Efficiency&#34; /&gt; those apps are happier, and more likely to spend more time with those apps. Yay!&lt;/p&gt;

&lt;p&gt;Of course, there are many factors that influence web service latency and efficiency; one area that often gets overlooked or downplayed is the performance of the underlying web framework. Previously, I shared some performance testing results involving a queuing message service that used Rawr, a proprietary micro-framework I developed for Rackspace a few years back. Those results made it clear that even a small improvement in performance of the framework (in the case of Rawr, compiling it with Cython) can make a big difference in performance.&lt;/p&gt;

&lt;p&gt;Several of you asked about getting the code for Rawr, and so I&amp;rsquo;m happy to announce that it&amp;rsquo;s successor, Falcon, has been open-sourced, courtesy of your friendly neighborhood Rackspace. If nothing else, I hope contributing this framework to the community will raise the bar on Python web framework performance, providing a laboratory of sorts for experimentation in this space.&lt;/p&gt;
&lt;h2&gt;Introducing the Falcon Web Framework&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;http://blog.kgriffs.com/assets/images/falcon-no-perch.png&#34; width=&#34;159px&#34; height=&#34;176px&#34; alt=&#34;Falcon image courtesy of John O&#39;Neill.&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://falconframework.org&#34;&gt;Falcon&lt;/a&gt; is a new, high-performance web framework for building web services and cloud APIs with Python. It&amp;rsquo;s WSGI-based, and works great with Python 2.6, Python 2.7, Python 3.3, and PyPy, giving you a wide variety of deployment options. While &lt;a href=&#34;https://github.com/racker/falcon&#34;&gt;the project&lt;/a&gt; is still quite young (v0.1.6 at the time of this writing), it&amp;rsquo;s far enough along to be useful in real applications. In fact, we&amp;rsquo;re already trying it out in a few cloud projects at Rackspace.&lt;/p&gt;
&lt;h2&gt;Yet Another Web Framework&lt;/h2&gt;
&lt;p&gt;I didn&amp;rsquo;t particularly &lt;em&gt;want&lt;/em&gt; to write Falcon. It would have been far easier to take something off the shelf and just plug it in. However, a few things pushed me over the edge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python web frameworks often perform rather poorly under load. At high concurrency, using async IO, API servers can become CPU-bound. When that happens, every microsecond counts. I wondered if I could make something that could perform a little better than your average framework.&lt;/li&gt;
&lt;li&gt;Most web frameworks come with a lot of HTML-centric tooling that is fantastic if you are developing a web app, but quite useless for building an API. In that case, all they do is waste RAM, increase your chance of a security exploit, and generally make a nuisance of themselves.&lt;/li&gt;
&lt;li&gt;Many frameworks try too hard, in my opinion, to abstract away what&amp;rsquo;s going on under the hood, making it difficult to reason about the river of HTTP flowing in and out of your API. Magic is wonderful at development time, but a nightmare when it comes time to debug a hairy production issue.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How is Falcon different?&lt;/h2&gt;
&lt;p&gt;First, Falcon is already &lt;a href=&#34;http://falconframework.org/#Metrics&#34;&gt;pretty fast&lt;/a&gt;, and will be getting faster. When there is a conflict between saving the developer a few keystrokes and saving a few microseconds to serve a request, Falcon is strongly biased toward the latter.&lt;/p&gt;

&lt;p&gt;Second, Falcon is lean. It doesn&amp;rsquo;t try to be everything to everyone, focusing instead on a single use case: HTTP APIs. Falcon doesn&amp;rsquo;t include a template engine, form helpers, or an ORM. When you sit down to write a web service with Falcon, you choose your own adventure in terms of async I/O, serialization, data access, etc. In fact, the only dependency Falcon takes is on Six, to make it easier to support both Python 2 and 3.&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;block&#34; src=&#34;http://blog.kgriffs.com/assets/images/flight-silhouettes.gif&#34; width=&#34;580px&#34; alt=&#34;Falcon image courtesy of L. Shyamal and Wikipedia.&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Third, Falcon eschews magic. When you use the framework, it&amp;rsquo;s pretty obvious which inputs lead to which outputs. Also, it&amp;rsquo;s blatantly obvious where variables originate. All this makes it easier for you and your posterity to reason about your code, even months (or years) after you wrote it.&lt;/p&gt;
&lt;h2&gt;When would you use Falcon?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m not going to pretend that Falcon is the best choice for all projects, or even the majority of them. Here are a few things to consider when choosing a web framework for your next project:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reuse.&lt;/strong&gt; If you constantly go back and forth between web app and API development, you may want to choose a less-specialized framework than Falcon, so you don&amp;rsquo;t have to context-switch between two different environments all day long. That being said, many apps these days serve static assets and render everything in JS, in which case Falcon could be a nice way to build the backing API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features.&lt;/strong&gt; Falcon is a low-level framework, which gives you a lot of freedom, but also requires a little more elbow grease. If you just want to make a quick website or app, you might consider something with more bells and whistles than Falcon (e.g., Django, Pecan, or Flask)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maturity.&lt;/strong&gt; Falcon is still a young project and not as battle-tested as some other frameworks out there. Caveat emptor.&lt;/p&gt;
&lt;h2&gt;What does a Falcon-based web service look like?&lt;/h2&gt;
&lt;p&gt;Here is a simple example from Falcon&amp;rsquo;s README, showing how to get started writing an API:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;# things.py

# Let&amp;#x27;s get this party started
import falcon


# Falcon follows the REST architectural style, meaning (among
# other things) that you think in terms of resources and state
# transitions, which map to HTTP verbs.
class ThingsResource:
    def on_get(self, req, resp):
        &amp;quot;&amp;quot;&amp;quot;Handles GET requests&amp;quot;&amp;quot;&amp;quot;
        resp.status = falcon.HTTP_200  # This is the default status
        resp.body = (&amp;#x27;\nTwo things awe me most, the starry sky &amp;#x27;
                     &amp;#x27;above me and the moral law within me.\n&amp;#x27;
                     &amp;#x27;\n&amp;#x27;
                     &amp;#x27;    ~ Immanuel Kant\n\n&amp;#x27;)

# falcon.API instances are callable WSGI apps
app = api = falcon.API()

# Resources are represented by long-lived class instances
things = ThingsResource()

# things will handle all requests to the &amp;#x27;&amp;#x2F;things&amp;#x27; URL path
api.add_route(&amp;#x27;&amp;#x2F;things&amp;#x27;, things)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can run the above example using any WSGI server, such as uWSGI
or Gunicorn. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;bash&#34;&gt;$ pip install gunicorn
$ gunicorn things:app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, in another terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;bash&#34;&gt;$ curl localhost:8000&amp;#x2F;things
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is a more involved example that demonstrates reading headers and query parameters, handling errors, and working with request and response bodies.&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;python&#34;&gt;
import json
import logging
from wsgiref import simple_server

import falcon


class StorageEngine:
    pass


class StorageError(Exception):
    pass


def token_is_valid(token, user_id):
    return True  # Suuuuuure it&amp;#x27;s valid...


def auth(req, resp, params):
    # Alternatively, do this in middleware
    token = req.get_header(&amp;#x27;X-Auth-Token&amp;#x27;)

    if token is None:
        raise falcon.HTTPUnauthorized(&amp;#x27;Auth token required&amp;#x27;,
                                      &amp;#x27;Please provide an auth token &amp;#x27;
                                      &amp;#x27;as part of the request&amp;#x27;,
                                      &amp;#x27;http:&amp;#x2F;&amp;#x2F;docs.example.com&amp;#x2F;auth&amp;#x27;)

    if not token_is_valid(token, params[&amp;#x27;user_id&amp;#x27;]):
        raise falcon.HTTPUnauthorized(&amp;#x27;Authentication required&amp;#x27;,
                                      &amp;#x27;The provided auth token is &amp;#x27;
                                      &amp;#x27;not valid. Please request a &amp;#x27;
                                      &amp;#x27;new token and try again.&amp;#x27;,
                                      &amp;#x27;http:&amp;#x2F;&amp;#x2F;docs.example.com&amp;#x2F;auth&amp;#x27;)


def check_media_type(req, resp, params):
    if not req.client_accepts_json:
        raise falcon.HTTPUnsupportedMediaType(
            &amp;#x27;Media Type not Supported&amp;#x27;,
            &amp;#x27;This API only supports the JSON media type.&amp;#x27;,
            &amp;#x27;http:&amp;#x2F;&amp;#x2F;docs.examples.com&amp;#x2F;api&amp;#x2F;json&amp;#x27;)


class ThingsResource:

    def __init__(self, db):
        self.db = db
        self.logger = logging.getLogger(&amp;#x27;thingsapi.&amp;#x27; + __name__)

    def on_get(self, req, resp, user_id):
        marker = req.get_param(&amp;#x27;marker&amp;#x27;) or &amp;#x27;&amp;#x27;
        limit = req.get_param_as_int(&amp;#x27;limit&amp;#x27;) or 50

        try:
            result = self.db.get_things(marker, limit)
        except Exception as ex:
            self.logger.error(ex)

            description = (&amp;#x27;Aliens have attacked our base! We will &amp;#x27;
                           &amp;#x27;be back as soon as we fight them off. &amp;#x27;
                           &amp;#x27;We appreciate your patience.&amp;#x27;)

            raise falcon.HTTPServiceUnavailable(
              &amp;#x27;Service Outage&amp;#x27;,
              description,
              30)

        resp.set_header(&amp;#x27;X-Powered-By&amp;#x27;, &amp;#x27;Donuts&amp;#x27;)
        resp.status = falcon.HTTP_200
        resp.body = json.dumps(result)

    def on_post(self, req, resp, user_id):
        try:
            raw_json = req.stream.read()
        except Exception:
            raise falcon.HTTPError(falcon.HTTP_748,
                                   &amp;#x27;Read Error&amp;#x27;,
                                   &amp;#x27;Could not read the request body. Must be &amp;#x27;
                                   &amp;#x27;them ponies again.&amp;#x27;)

        try:
            thing = json.loads(raw_json, &amp;#x27;utf-8&amp;#x27;)
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_753,
                                   &amp;#x27;Malformed JSON&amp;#x27;,
                                   &amp;#x27;Could not decode the request body. The &amp;#x27;
                                   &amp;#x27;JSON was incorrect.&amp;#x27;)

        try:
            proper_thing = self.db.add_thing(thing)

        except StorageError:
            raise falcon.HTTPError(falcon.HTTP_725,
                                   &amp;#x27;Database Error&amp;#x27;,
                                   &amp;quot;Sorry, couldn&amp;#x27;t write your thing to the &amp;quot;
                                   &amp;#x27;database. It worked on my machine.&amp;#x27;)

        resp.status = falcon.HTTP_201
        resp.location = &amp;#x27;&amp;#x2F;%s&amp;#x2F;things&amp;#x2F;%s&amp;#x27; % (user_id, proper_thing.id)

wsgi_app = api = falcon.API(before=[auth, check_media_type])

db = StorageEngine()
things = ThingsResource(db)
api.add_route(&amp;#x27;&amp;#x2F;{user_id}&amp;#x2F;things&amp;#x27;, things)

app = application = api

# Useful for debugging problems in your API; works with pdb.set_trace()
if __name__ == &amp;#x27;__main__&amp;#x27;:
  httpd = simple_server.make_server(&amp;#x27;127.0.0.1&amp;#x27;, 8000, app)
  httpd.serve_forever()

&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;What&amp;rsquo;s next?&lt;/h2&gt;
&lt;p&gt;I need your help! Take Falcon for a test drive and tell me what you think.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get Involved!&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contribute &lt;a href=&#34;https://github.com/racker/falcon/issues/15&#34;&gt;some docs&lt;/a&gt; and/or write a blog post&lt;/li&gt;
&lt;li&gt;Improve the router&amp;rsquo;s support of &lt;a href=&#34;https://github.com/racker/falcon/issues/35&#34;&gt;URI templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Create an &lt;a href=&#34;https://github.com/racker/falcon/issues/134&#34;&gt;optimized alternative&lt;/a&gt; to urllib.quote&lt;/li&gt;
&lt;li&gt;Add more &lt;a href=&#34;https://github.com/racker/falcon/issues/151&#34;&gt;scenarios&lt;/a&gt; and frameworks to the benchmarking suite&lt;/li&gt;
&lt;li&gt;Or choose your own &lt;a href=&#34;https://github.com/racker/falcon/issues/milestones&#34;&gt;adventure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
            </entry>
        
            <entry>
                <title>The Face of the Cloud</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2013/02/05/the-face-of-the-cloud.html" type="text/html" />
                <id>http://blog.kgriffs.com/2013/02/05/the-face-of-the-cloud.html</id>
                <updated>2013-02-05T21:09:00Z</updated>
                
                
                    <summary type="html">It&#39;s no coincidence that cloud computing and post-PC devices became popular at the same time. But why didn&#39;t all this happen years ago when tech heavyweights were pushing thin clients?</summary>
                
                
                <content type="html">&lt;p&gt;Lately I&amp;rsquo;ve been thinking about how it&amp;rsquo;s no coincidence that cloud computing and post-PC devices became popular at the same time. When Steve Jobs introduced Apple&amp;rsquo;s iPhone and it&amp;rsquo;s accompanying App Store, he kicked off a revolution in the way software was built and delivered. Jobs succeeded where others had failed by simply focusing on the user experience and letting the rest take care of itself. &lt;/p&gt;

&lt;p&gt;The iPhone was only the beginning. Apple later introduced the iPad, and Google teamed up with cell phone manufacturers to deliver this new way of computing to the masses. In the past few years, we&amp;rsquo;ve also seen the wild success of Internet entertainment devices such as the Roku, fueled in large part by Netflix and Pandora. You can hardly find a game console, Blu-ray player or TV for sale that doesn&amp;rsquo;t use the Internet in some way. Combined, all these trends are pushing the concept of post-PC devices into ubiquity. &lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://blog.kgriffs.com/assets/images/cloud-post-pc-device.png&#34; alt=&#34;Post-PC Device and Cloud Computing&#34; /&gt;&lt;/p&gt;

&lt;p&gt;With millions of these devices sold and used every day around the world, it&amp;rsquo;s no wonder cloud computing has become such a hot topic. Post-PC devices crave content; they are portals to the world&amp;rsquo;s information, the world&amp;rsquo;s people, and the world&amp;rsquo;s markets. The cloud connects all of these things together and makes them accessible to anyone with an Internet connection.&lt;/p&gt;

&lt;p&gt;But why didn&amp;rsquo;t all this happen years ago when tech heavyweights&amp;mdash; Oracle, Sun, Novell and IBM, among others&amp;mdash;were pushing thin client solutions? After all, aren&amp;rsquo;t post-PC devices just thin clients?&lt;/p&gt;

&lt;p&gt;First, thin client solutions were designed with the IT department in mind, not the poor schmucks who would actually have to use the things for hours on end, day after day. The goal was to make the system administrator&amp;rsquo;s job easier while at the same time growing the market for Big Iron. This naturally led to clients that were too thin, too constrained, and too utilitarian. If you contrast thin clients with the iPhone and iPad, the Galaxy Note, even the MacBook Air, you start to understand the power of good design and &lt;em&gt;capable&lt;/em&gt; hardware, working in tandem.&lt;/p&gt;

&lt;p&gt;Second, thin-clients failed to create a revolution in computing because they were not mobile, and were sandboxed within corporate networks. The infrastructure simply wasn&amp;rsquo;t there. The Internet was immature, and cell phone networks barely had enough bandwidth for transmitting voices, let alone data. You simply can&amp;rsquo;t deliver a good experience over 56k.&lt;/p&gt;

&lt;p&gt;Third, applications were too hard to use, too hard to write, and too expensive to buy. Thin clients didn&amp;rsquo;t solve any of these problems; the only thing they did was make IT Bob&amp;rsquo;s life a little easier than before; with thin clients, he didn&amp;rsquo;t have to go around manually installing and updating software on everyone&amp;rsquo;s machines. Contrast that situation with the democratized development and distribution of modern software. &lt;/p&gt;

&lt;p&gt;Free, extremely productive development tools and online documentation make it easy for anyone to get started writing apps. App stores take the pain out of deploying, updating, and charging for software. Backend services are hosted on pay-as-you-go clouds (which often have free tiers), so that even cash-strapped college kids can create apps with a compelling online experience. These apps are generally more specialized than their dinosaur ancestors, making modern software both easier to use, and less expensive. &lt;/p&gt;

&lt;p&gt;The cloud is a vital part of the post-PC world. Cloud computing is essential not only for democratizing software development, but also for freeing the world&amp;rsquo;s information. Let&amp;rsquo;s have more of that.&lt;/p&gt;
</content>
            </entry>
        
            <entry>
                <title>uWSGI vs. Gunicorn, or How to Make Python Go Faster than Node</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2012/12/18/uwsgi-vs-gunicorn-vs-node-benchmarks.html" type="text/html" />
                <id>http://blog.kgriffs.com/2012/12/18/uwsgi-vs-gunicorn-vs-node-benchmarks.html</id>
                <updated>2012-12-18T21:09:00Z</updated>
                
                
                    <summary type="html">In which I pit uWSGI against Gunicorn and stumble upon a Python stack that leaves Node.js begging for mercy.</summary>
                
                
                <content type="html">&lt;p&gt;It seems I&amp;rsquo;ve finally arrived at the end of my quest to discover a fast, reliable Python stack for serving web APIs that can compete favorably with Node. The funny thing is, I didn&amp;rsquo;t even know it was my quest until I started looking at the surprising results from this latest round of performance testing, in which I pitted uWSGI against Gunicorn. &lt;/p&gt;

&lt;p&gt;When it comes to deploying web APIs, my preference is to use something lean-n-mean for managing local sockets and WSGI workers, leaving macro load balancing, SSL termination, rate limiting and general HTTP heavy-lifting to the big guns (e.g., Stingray, Nginx, HAProxy, Stud).  &lt;/p&gt;

&lt;p&gt;Gunicorn has been my go-to WSGI server for hosting web APIs in production, due to its simplicity, performance, and manageability. Recently I re-discovered uWSGI and was pleasantly surprised to find how far it has come in the past couple of years. I was particularly impressed by uWSGI&amp;rsquo;s high configurability, including lots of production-friendly options. &lt;/p&gt;

&lt;p&gt;Considering that uWSGI and Gunicorn are both pre-forking&lt;sup&gt;&lt;a name=&#34;id-1&#34; href=&#34;#id-1.ftn&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; WSGI servers, and given other design similarities, I couldn&amp;rsquo;t help but wonder how each would perform in the ring.  &lt;/p&gt;
&lt;h2&gt;Teh Contenders&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;http://uwsgi-docs.readthedocs.org/en/latest&#34;&gt;uWSGI (1.4.2).&lt;/a&gt;&lt;/strong&gt; Here we have what appears to be a devops dream-come-true. Lots of production-friendly configuration options and a pluggable architecture for customizing stats reporting and anything else you can dream up (LZ4 compression, anyone?). uWSGI has matured quite a bit over the past couple of years, and now supports a plethora of languages and deployment options. Nginx supports the uwsgi protocol natively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;http://gunicorn.org&#34;&gt;Gunicorn (0.16.1).&lt;/a&gt;&lt;/strong&gt; My go-to WSGI server. Like uWSGI, Gunicorn supports different worker types. IMHO, Gunicorn provides a good balance between performance and usability. It&amp;rsquo;s been performing like a champ for me in production for the better part of a year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;http://gevent.org/&#34;&gt;Gevent (1.0rc1).&lt;/a&gt;&lt;/strong&gt; This little green machine is mostly about coroutine-based async networking, but includes a pretty decent WSGI server, providing a good baseline that helps put uWSGI and Gunicorn&amp;rsquo;s performance into perspective.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;http://nodejs.org/&#34;&gt;Node.js (0.8.14).&lt;/a&gt;&lt;/strong&gt; I rewrote my event queuing service in JavaScript ala Node to further put uWSGI and Gunicorn&amp;rsquo;s performance into perspective, and to find out how well a Python-based app could compete with one running on the highly-optimized, V8-backed Node platform.&lt;/p&gt;
&lt;h2&gt;Setup&lt;/h2&gt;
&lt;p&gt;The performance testing setup this time around was identical to the one I used previously to &lt;a href=&#34;http://blog.kgriffs.com/2012/12/12/gevent-vs-tornado-benchmarks.html&#34;&gt;benchmark Gevent, Tornado, Cython, and PyPy&lt;/a&gt;. I brought forward the Cythonized version of my Rawr web framework for this latest round of tests. The Gevent and Node.js numbers you&amp;rsquo;ll see in the charts below were simply carried forward from my previous posts.&lt;/p&gt;

&lt;p&gt;All tests involved a single worker and were either self-hosted (in the case of Gevent and Node.js), or used an external WSGI server (in the case of uWSGI and Gunicorn). Workers were configured to use gevent, so they would play nice with my app, which relies on greenlets ala &lt;code&gt;gevent.monkey.patch_all()&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;As before, I tested a series of requests to a single event channel which was primed with ~1K of JSON-encoded data (i.e., the httperf workers had to read a little more than 1K per transaction). Keep-alive was not used, modeling the worst-case scenario in which every transaction involved negotiating a new TCP/IP connection.&lt;/p&gt;

&lt;p&gt;I used the following command to run uWSGI:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;bash&#34;&gt;uwsgi --http :8890 --file rse.py --gevent 2000 -l 1000 -p 1 -L
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;rsquo;s the command I used to run Gunicorn:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&#34;bash&#34;&gt;gunicorn \
  -b :8091 -w 1 -k gevent --worker-connections=2000 \
  --backlog=1000 -p gunicorn.pid --log-level=critical rse:app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that I disabled request logging in both cases.&lt;/p&gt;
&lt;h2&gt;Results&lt;/h2&gt;
&lt;p&gt;Throughput (req/sec)
&lt;div id=&#34;graph-1-rps&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Response Time (ms)
&lt;div id=&#34;graph-1-rt&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Errors
&lt;div id=&#34;graph-1-errors&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Standard Deviation for Throughput (req/sec)
&lt;div id=&#34;graph-1-stdev&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;
&lt;h2&gt;Q.E.D.&lt;/h2&gt;
&lt;p&gt;uWSGI looks like the Python app server to beat, although it&amp;rsquo;s performance did become a bit erratic under high load. Not only is it ridiculously fast, but judging by the docs, uWSGI gives you a lot of great options for production tuning. &lt;/p&gt;

&lt;p&gt;But what&amp;rsquo;s more, with an optimized web framework and uWSGI on your side, it looks like Python apps can hold their own against Node. &lt;/p&gt;

&lt;p&gt;Now that&amp;rsquo;s something to think about.&lt;/p&gt;

&lt;ul class=&#34;footnotes&#34;&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-1.ftn&#34; href=&#34;#id-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; The term &lt;em&gt;pre-forking&lt;/em&gt;, as used here, simply means that sockets are created before forking child processes, and that those sockets are inherited by the child processes so that they can directly bind to them, saving an extra hop.
  &lt;/li&gt;  
&lt;/ul&gt;

&lt;p&gt;&lt;script type=&#34;text/javascript&#34; src=&#34;http://blog.kgriffs.com/assets/js/uwsgi-vs-gunicorn.js&#34; /&gt;&lt;/p&gt;
 </content>
            </entry>
        
            <entry>
                <title>Tornado vs. Gevent - Benchmarks</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2012/12/12/gevent-vs-tornado-benchmarks.html" type="text/html" />
                <id>http://blog.kgriffs.com/2012/12/12/gevent-vs-tornado-benchmarks.html</id>
                <updated>2012-12-12T21:09:00Z</updated>
                
                
                    <summary type="html">In this latest round of performance testing, I take the Tornado web framework for a spin (heh, couldn&amp;rsquo;t help myself), and also play around with Cython. </summary>
                
                
                <content type="html">&lt;p&gt;In this latest round of performance testing, I take the Tornado web framework for a spin (heh, couldn&amp;rsquo;t help myself), and also play around with Cython. &lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;right&#34; src=&#34;http://blog.kgriffs.com/assets/images/python-tornado.png&#34; width=&#34;300px&#34; height=&#34;300px&#34; alt=&#34;Poor Cloud Ideas (Thrown Away)&#34; /&gt;&lt;/p&gt;

&lt;p&gt;After FriendFeed was acquired several years ago, &lt;a href=&#34;http://www.tornadoweb.org&#34;&gt;Tornado&lt;/a&gt; stagnated a bit, but this past year the community has been hard at work. Version 2.0 came out this past June, and the framework is now at 2.4.1 (at the time of this writing).&lt;/p&gt;

&lt;p&gt;Unlike Gevent, Tornado works on &lt;a href=&#34;http://pypy.org/&#34;&gt;PyPy&lt;/a&gt;, making it possible to compare PyPy vs. CPython in terms of nonblocking sockets. While I was at it (famous last words), I also experimented with &lt;a href=&#34;http://cython.org/&#34;&gt;Cython&lt;/a&gt; to see if just compiling a few key modules would give a comparable performance boost to running the entire app under PyPy.&lt;/p&gt;

&lt;p&gt;My setup for these tests was identical to the one used in my last post exploring &lt;a href=&#34;http://blog.kgriffs.com/2012/11/13/python-vs-node-vs-pypy-benchmarks.html&#34;&gt;Python web api performance&lt;/a&gt;, with the exception that I also added the following to &lt;code&gt;/etc/sysctl.conf&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Let the networking stack reuse TIME_WAIT connections
# when it thinks it&amp;#x27;s safe to do so
net.ipv4.tcp_tw_reuse = 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I ported my message bus service to Tornado 2.4.1, with logging disabled via a noop function, and left Tornado&amp;rsquo;s debugging option turned off (the default). In order to make a fair comparison between the Tornado and Gevent implementations, I used Motor (@ab024028f2) instead of pymongo in the Tornado code base so that the DB drivers were non-blocking in both implementations.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://emptysquare.net/motor/&#34;&gt;Motor&lt;/a&gt; is a non-blocking fork of pymongo, designed to play nice with Tornado. In the Gevent implementation, I simply used &lt;code&gt;gevent.monkey.patch_all()&lt;/code&gt; to make pymongo non-blocking.&lt;/p&gt;

&lt;p&gt;For all tests, only one request was performed per connection (no keep-alive or pipelining this time around). &lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Protip:&lt;/strong&gt; You can view and play with the raw result data by downloading the &lt;a type=&#34;text/javascript&#34; download=&#34;&#34; href=&#34;http://blog.kgriffs.com/assets/js/gevent-vs-tornado.js&#34;&gt;Flot data file&lt;/a&gt; that I used to draw the graphs below.&lt;/em&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;Gevent vs. Tornado&lt;/h2&gt;
&lt;p&gt;In this test I compared the performance of a Gevent-based implementation of my event bus service to one based on Tornado, the latter being implemented with the callback async style (no tornado.gen). Since Tornado comes with its own micro web framework, I used that in lieu of my own (Rawr).&lt;/p&gt;

&lt;p&gt;As mentioned elsewhere, I used a non-blocking MongoDB driver in both implementations. Also noteworthy is that both implementations were self-hosted using each frameworks&amp;#39; native web server (gevent.wsgi in the case of Gevent). &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Throughput (req/sec)&lt;/strong&gt;
&lt;div id=&#34;graph-1-rps&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Response Time (ms)&lt;/strong&gt;
&lt;div id=&#34;graph-1-rt&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Errors&lt;/strong&gt;
&lt;div id=&#34;graph-1-errors&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Standard Deviation, Throughput (req/sec)&lt;/strong&gt;
&lt;div id=&#34;graph-1-stdev&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;
&lt;h2&gt;Cython vs. CPython vs. Node.js&lt;/h2&gt;
&lt;p&gt;In this benchmark, I tested the performance of Cython 0.17.2 running under CPython 2.7.3, by compiling a few core modules with Cython and comparing the application&amp;rsquo;s performance with those vs. the regular *.pyc ones. &lt;/p&gt;

&lt;p&gt;In the graph keys shown below, CyRawr denotes a run where only my custom web framework, Rawr, was compiled with Cython. CyHandler indicates that the message request handler was also compiled with Cython before executing the application.&lt;/p&gt;

&lt;p&gt;I also included my &lt;a href=&#34;http://blog.kgriffs.com/2012/11/13/python-vs-node-vs-pypy-benchmarks.html&#34;&gt;previous Node.js benchmarks&lt;/a&gt; to help put these results in context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Throughput (req/sec)&lt;/strong&gt;
&lt;div id=&#34;graph-4-rps&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Response Time (ms)&lt;/strong&gt;
&lt;div id=&#34;graph-4-rt&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Errors&lt;/strong&gt;
&lt;div id=&#34;graph-4-errors&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Standard Deviation, Throughput (req/sec)&lt;/strong&gt;
&lt;div id=&#34;graph-4-stdev&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;
&lt;h2&gt;Tornado: Cython vs. CPython&lt;/h2&gt;
&lt;p&gt;This benchmark was similar to the one performed above, except it tested Cython-compiled modules running under the Tornado framework and web server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Throughput (req/sec)&lt;/strong&gt;
&lt;div id=&#34;graph-2-rps&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Response Time (ms)&lt;/strong&gt;
&lt;div id=&#34;graph-2-rt&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Errors&lt;/strong&gt;
&lt;div id=&#34;graph-2-errors&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Standard Deviation, Throughput (req/sec)&lt;/strong&gt;
&lt;div id=&#34;graph-2-stdev&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;
&lt;h2&gt;Tornado: PyPy vs. CPython&lt;/h2&gt;
&lt;p&gt;Unlike Gevent, Tornado is mostly compatible with PyPy, so I was able to benchmark Tornado running under CPython 2.7.3 vs. PyPy 2.0beta1-1.&lt;/p&gt;

&lt;p&gt;Unfortunately, I wasn&amp;rsquo;t able to test Tornado&amp;rsquo;s performance running under PyPy with request attempts over ~660/sec. Tornado crashed&lt;sup&gt;&lt;a name=&#34;id-1&#34; href=&#34;#id-1.ftn&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; with a buffer overflow error several times in a row at this load. I verified that this crash wasn&amp;rsquo;t caused by a PyPy 2.x bug, by running a quick test under 1.9 and observing identical behavior. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Throughput (req/sec)&lt;/strong&gt;
&lt;div id=&#34;graph-3-rps&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Response Time (ms)&lt;/strong&gt;
&lt;div id=&#34;graph-3-rt&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Errors&lt;/strong&gt;
&lt;div id=&#34;graph-3-errors&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Standard Deviation, Throughput (req/sec)&lt;/strong&gt;
&lt;div id=&#34;graph-3-stdev&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Gevent is very fast, with a good ecosystem, plus a ridiculously simple async programming model&amp;ndash;all thanks to the magic of greenlets, libev and monkey-patching.&lt;/p&gt;

&lt;p&gt;Tornado is not as fast as Gevent, and is hampered by the immature Motor library. Perhaps owing to the fact that Tornado was originally written to handle large numbers of &lt;em&gt;persistent&lt;/em&gt; connections, the framework was never optimized for frequent connection negotiations, making it lag behind Gevent for this use case. Note, however, that Tornado did seem to handle large numbers of connection requests more gracefully than did Gevent, as indicated by the former&amp;rsquo;s consistently low error rate (under CPython).&lt;/p&gt;

&lt;p&gt;Surprisingly, PyPy did not significantly speed up my Tornado-based implementation. I suspect the lackluster performance of greenlets (used by Motor) under PyPy, which may have caused the app to bottleneck at the DB library.&lt;/p&gt;

&lt;p&gt;All things considered, Gevent + Cython appears to be the best choice of platform for building a Python-based web api, particularly if you&amp;rsquo;re using MongoDB. Gevent provides fast, non-blocking sockets and an elegant synchronous-on-asynchronous programming model that is officially supported by pymongo, while Cython compensates well for Gevent&amp;rsquo;s incompatibility with PyPy. &lt;/p&gt;

&lt;p&gt;In my next post, I&amp;rsquo;ll share results from testing Gevent&amp;rsquo;s web server against uWSGI, Gunicorn, and Node. Stay tuned&amp;hellip;&lt;/p&gt;

&lt;ul class=&#34;footnotes&#34;&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-1.ftn&#34; href=&#34;#id-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; Judging by the stack trace, there was a native module/ctypes issue, related to &lt;em&gt;tornado.stack_context._StackContextWrapper&lt;/em&gt;. It may have been related to Motor, but I can&amp;rsquo;t say for sure pending further investigation.
  &lt;/li&gt;  
&lt;/ul&gt;

&lt;p&gt;&lt;script type=&#34;text/javascript&#34; src=&#34;http://blog.kgriffs.com/assets/js/gevent-vs-tornado.js&#34; /&gt;&lt;/p&gt;
 </content>
            </entry>
        
            <entry>
                <title>Stand back... I&#39;m going to try science!</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2012/11/13/python-vs-node-vs-pypy-benchmarks.html" type="text/html" />
                <id>http://blog.kgriffs.com/2012/11/13/python-vs-node-vs-pypy-benchmarks.html</id>
                <updated>2012-11-13T21:09:00Z</updated>
                
                
                    <summary type="html">Check out these results from a round of rigorous performance testing comparing Python, PyPy and Node.js</summary>
                
                
                <content type="html">&lt;p&gt;The majority of benchmarks posted on the web are derived from testing simple &amp;ldquo;hello world&amp;rdquo; apps. Although certainly better than nothing, these tests tell us little about real-world performance. Ideally, one would compare multiple implementations of a non-trivial application, but this takes a lot of time that is often hard to justify in the face of dogged competition and looming deadlines. Occasionally, however, the stars &lt;em&gt;do&lt;/em&gt; align, and one has the chance to conduct such an experiment.&lt;/p&gt;

&lt;p&gt;Lately, I&amp;rsquo;ve been researching the various merits of Python vs. JavaScript (ala Node.js), in terms of developing web-scale cloud services. In the course of my work, I ported an internal HTTP-based event queuing service from Python (currently running in production) to JavaScript. In a &lt;a href=&#34;http://blog.kgriffs.com/2012/10/23/python-vs-node-vs-pypy.html&#34;&gt;previous post&lt;/a&gt;, I shared the results from some informal performance testing of these implementations.  &lt;/p&gt;

&lt;p&gt;In this post, I&amp;rsquo;d like to share my results from a second round of more rigorous performance testing, during which the test environment and variables were tightly controlled&lt;sup&gt;&lt;a name=&#34;id-1&#34; href=&#34;#id-1.ftn&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. I switched from &lt;a href=&#34;https://en.wikipedia.org/wiki/ApacheBench&#34;&gt;ApacheBench&lt;/a&gt; to &lt;a href=&#34;http://www.xenoclast.org/autobench/&#34;&gt;Autobench&lt;/a&gt;/&lt;a href=&#34;http://www.hpl.hp.com/research/linux/httperf/&#34;&gt;Httperf&lt;/a&gt;, in order to generate a more consistent, realistic load. I also &lt;a href=&#34;http://api.mongodb.org/python/current/examples/gevent.html&#34;&gt;monkey-patched PyMongo&lt;/a&gt; this time around, so that both Python and Node implementations would use non-blocking I/O all the way through.&lt;/p&gt;
&lt;h2&gt;Testing Environment&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Servers&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.rackspace.com/cloud/public/servers/techdetails/&#34;&gt;Rackspace Cloud&lt;/a&gt; Virtual Machines

&lt;ul&gt;
&lt;li&gt;4GB RAM&lt;/li&gt;
&lt;li&gt;2 vCPUs&lt;/li&gt;
&lt;li&gt;Next Generation Platform&lt;/li&gt;
&lt;li&gt;Chicago Region (ORD)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Arch Linux (2012.08) 

&lt;ul&gt;
&lt;li&gt;x86_64&lt;/li&gt;
&lt;li&gt;Full system upgrade (pacman -Syu)&lt;/li&gt;
&lt;li&gt;linux-3.6.5-1&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Tuning

&lt;ul&gt;
&lt;li&gt;Set nofile to 10000 in /etc/security/limits.conf&lt;/li&gt;
&lt;li&gt;Updated &lt;a href=&#34;https://gist.github.com/4027835&#34;&gt;/etc/sysctl.conf&lt;/a&gt; to handle a large number of TCP requests and socket churn&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Network&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;200 Mbps, per server&lt;/li&gt;
&lt;li&gt;Internal network interface (10.x.x.x)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Python&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPython 2.7.3&lt;/li&gt;
&lt;li&gt;PyPy 1.9.0 &lt;/li&gt;
&lt;li&gt;Gevent 1.0rc1&lt;/li&gt;
&lt;li&gt;PyMongo 2.3&lt;/li&gt;
&lt;li&gt;WebOb 1.2.3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Node.js&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 0.8.14&lt;/li&gt;
&lt;li&gt;Connect 2.5.0&lt;/li&gt;
&lt;li&gt;node-mongodb-native 1.1.11&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Other&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MongoDB 2.2&lt;/li&gt;
&lt;li&gt;Autobench 2.1.2&lt;/li&gt;
&lt;li&gt;Httperf 0.9.0 (&lt;a href=&#34;http://gom-jabbar.org/articles/2009/02/04/httperf-and-file-descriptors&#34;&gt;recompiled&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Actors&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Cloud Servers&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3 Autobench hosts&lt;/li&gt;
&lt;li&gt;1 API server&lt;/li&gt;
&lt;li&gt;1 DB server &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Implementations&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node.js&lt;/strong&gt;: V8 + Node.js + Connect&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gevent&lt;/strong&gt;: CPython + &lt;a href=&#34;http://www.gevent.org/gevent.wsgi.html&#34;&gt;gevent.wsgi&lt;/a&gt; + &lt;a href=&#34;http://www.gevent.org/gevent.monkey.html&#34;&gt;gevent.monkey.patch_all()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WsgiRef&lt;/strong&gt;: CPython + WSGI Reference Implementation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WsgiRef-PyPy&lt;/strong&gt;: PyPy + WSGI Reference Implementation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Benchmarks&lt;/h2&gt;
&lt;p&gt;As in my previous experiment, I benchmarked retrieving a fixed set of events from an event queuing service backed by MongoDB, with alternative service implementations in Python and JavaScript. Unfortunately, I was not able to directly compare PyPy to both CPython &lt;em&gt;and&lt;/em&gt; Node.js, since Gevent is currently incompatible with PyPy, and I did not have the luxury of reimplementing the queuing service a third time (using a non-blocking framework that works with PyPy, such as Tornado).&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update:&lt;/strong&gt; See my followup post on &lt;a href=&#34;http://blog.kgriffs.com/2012/12/12/gevent-vs-tornado-benchmarks.html&#34;&gt;Tornado, Gevent, PyPy and Cython&lt;/a&gt;, in which I share my results from running my app with Tornado on PyPy.&lt;/em&gt;&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;For each test, I ran Autobench directly against a single message bus implementation. I set &lt;em&gt;min_rate&lt;/em&gt; and &lt;em&gt;max_rate&lt;/em&gt; to 20 and 2000, respectively, in order to test a wide range of requests per second&lt;sup&gt;&lt;a name=&#34;id-2&#34; href=&#34;#id-2.ftn&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. The x axes on the graphs below represent the range of req/sec attempted.&lt;/p&gt;

&lt;p&gt;I carried out all benchmarks against a single instance of each implementation; no clustering or load balancing solutions were employed (i.e., HAProxy, Gunicorn, Node&amp;rsquo;s &lt;em&gt;Cluster&lt;/em&gt; module, etc.). Although this setup does not model production deployments, it removes variability in the results, making them easier to verify and interpret.&lt;/p&gt;

&lt;p&gt;For those implementations that supported HTTP/1.1 Keep-Alive&lt;sup&gt;&lt;a name=&#34;id-3&#34; href=&#34;#id-3.ftn&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, I ran each test twice, once with 1 GET&lt;sup&gt;&lt;a name=&#34;id-4&#34; href=&#34;#id-4.ftn&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; per connection, and once again with 10 GETs per connection. I denoted this in the results by appending the number of requests per connection to each implementation name, as in &lt;em&gt;Gevent (1)&lt;/em&gt; and &lt;em&gt;Gevent (10)&lt;/em&gt;. The results of the latter test may be especially instructive regarding web apps, since browsers typically perform several requests per connection.&lt;/p&gt;

&lt;p&gt;Each request to the message bus returned an identical set of JSON-encoded events (shallow objects, ~1K of text). I also tested &lt;em&gt;Gevent (10)&lt;/em&gt; and &lt;em&gt;Node.js (10)&lt;/em&gt; against a larger result set containing ~64K of events, and against an empty result set (where the server responded to every request with &lt;em&gt;204 No Content&lt;/em&gt;). &lt;/p&gt;
&lt;h2&gt;Results&lt;/h2&gt;
&lt;p&gt;Except where noted, only the results from testing the 1K data set appear in the graphs below. I used &lt;a href=&#34;http://www.flotcharts.org/&#34;&gt;Flot&lt;/a&gt; to visualize the raw data (see also the &lt;a type=&#34;text/javascript&#34; download=&#34;&#34; href=&#34;http://blog.kgriffs.com/assets/js/python-vs-node-vs-pypy-benchmarks.js&#34;&gt;JavaScript file&lt;/a&gt; accompanying this post).&lt;/p&gt;

&lt;p&gt;Now, I&amp;rsquo;ll step aside for a moment and let the data speak for itself&amp;hellip;&lt;/p&gt;
&lt;h2&gt;Gevent vs. Node.js&lt;/h2&gt;
&lt;p&gt;Throughput (req/sec)
&lt;div id=&#34;graph-1-rps&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Response Time (ms)
&lt;div id=&#34;graph-1-rt&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Errors
&lt;div id=&#34;graph-1-errors&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Standard Deviation (req/sec)
&lt;div id=&#34;graph-1-stdev&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;
&lt;h2&gt;Sync vs. Async&lt;/h2&gt;
&lt;p&gt;Throughput (req/sec)
&lt;div id=&#34;graph-5-rps&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Response Time (ms)
&lt;div id=&#34;graph-5-rt&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Errors
&lt;div id=&#34;graph-5-errors&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;
&lt;h2&gt;PyPy vs. CPython&lt;/h2&gt;
&lt;p&gt;Throughput (req/sec)
&lt;div id=&#34;graph-4-rps&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Response Time (ms)
&lt;div id=&#34;graph-4-rt&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Errors
&lt;div id=&#34;graph-4-errors&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;
&lt;h2&gt;0 KiB vs. 1 KiB vs. 64 KiB&lt;/h2&gt;
&lt;p&gt;Throughput (req/sec)
&lt;div id=&#34;graph-2-rps&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Response Time (ms)
&lt;div id=&#34;graph-2-rt&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Errors
&lt;div id=&#34;graph-2-errors&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Standard Deviation (req/sec)
&lt;div id=&#34;graph-2-stdev&#34; class=&#34;flot&#34;&gt;&lt;/div&gt;&lt;/p&gt;
&lt;h2&gt;Q.E.D.&lt;/h2&gt;
&lt;p&gt;Node.js outperforms Gevent significantly in terms of latency and error rates for small data transfers (~1K). However, in the case of larger response bodies (~64K), the difference between the two platforms is more subtle. Overall, the best-case scenario for Node.js appears to be serving large numbers of concurrent requests for small chunks of data, over a persistent connection.&lt;/p&gt;

&lt;p&gt;PyPy performs only slightly better than CPython when using Python&amp;rsquo;s WSGI reference implementation. More work is needed to determine whether PyPy would perform similarly to Node.js given a compatible, non-blocking Python web framework &lt;em&gt;and&lt;/em&gt; a non-blocking MongoDB driver.&lt;/p&gt;

&lt;p&gt;Finally, regarding blocking vs. non-blocking I/O frameworks, Gevent certainly outperforms WsgiRef in terms of throughput and response time, although not by as much as one might expect.&lt;/p&gt;

&lt;p&gt;The plot thickens&amp;hellip;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks&lt;/strong&gt; to June Rich for reading drafts of this.&lt;/p&gt;

&lt;ul class=&#34;footnotes&#34;&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-1.ftn&#34; href=&#34;#id-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; Admittedly, the test environment I used was not perfectly controlled due to my use of virtual machines on a shared network. This was a trade-off I was willing to make in order to test application performance in a production cloud hosting environment, which is how many web apps are deployed these days. 
  &lt;/li&gt;  
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-2.ftn&#34; href=&#34;#id-2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; The &lt;a href=&#34;http://www.xenoclast.org/autobench/&#34;&gt;Autobench website&lt;/a&gt; has a good description of these and other options, and how they translate to Httperf parameters.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-3.ftn&#34; href=&#34;#id-3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; HTTP/1.0 did not document any support for persistent connections, although some servers support it via the Keep-Alive header.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-4.ftn&#34; href=&#34;#id-4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; Although not tested, I suspect the relative performance between the different implementations would be similar when executing both GET and POST requests, assuming the database is able to keep up with the load. In mixed workloads, the database&amp;rsquo;s write performance is more likely than the application to be a factor in any difference in performance between GET and POST, and my intent in this exercise was to test the app layer, not the DB.
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;script type=&#34;text/javascript&#34; src=&#34;http://blog.kgriffs.com/assets/js/python-vs-node-vs-pypy-benchmarks.js&#34; /&gt;&lt;/p&gt;
 </content>
            </entry>
        
            <entry>
                <title>Python vs. Node vs. PyPy</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2012/10/23/python-vs-node-vs-pypy.html" type="text/html" />
                <id>http://blog.kgriffs.com/2012/10/23/python-vs-node-vs-pypy.html</id>
                <updated>2012-10-23T21:09:00Z</updated>
                
                
                    <summary type="html">After playing around with recent versions of PyPy and Node.js, I&#39;ve discovered some things that may surprise you.</summary>
                
                
                <content type="html">&lt;p&gt;OpenStack has proven that you can build robust, scalable cloud services with Python. On the other hand, startups like Voxer are doing brilliant things with Node.js. That made me curious, so I took some time to learn Node, then ported a web-scale message bus project of mine from Python to JavaScript. &lt;/p&gt;

&lt;p&gt;With Python and Node implementations in hand, I compared the two in terms of performance, community, developer productivity, etc. I also took the opportunity to test-drive PyPy; it seemed appropriate, given that both PyPy and V8&lt;sup&gt;&lt;a name=&#34;id-1&#34; href=&#34;#id-1.ftn&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; rely on JIT compilation to boost performance. &lt;/p&gt;

&lt;p&gt;In this particular post, I&amp;rsquo;d like to share my discoveries concerning Python vs. Node performance. &lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update:&lt;/strong&gt; See my followup post on &lt;a href=&#34;http://blog.kgriffs.com/2012/11/13/python-vs-node-vs-pypy-benchmarks.html&#34;&gt;Python vs. Node&lt;/a&gt;, in which I share my results from a more formal, rigorous round of performance testing.&lt;/em&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;Testing Methodology&lt;/h2&gt;
&lt;p&gt;For each test, I executed 5,000 GETs with ApacheBench (ab). I ran each benchmark 3 times from localhost&lt;sup&gt;&lt;a name=&#34;id-2&#34; href=&#34;#id-2.ftn&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; on a 4-core Rackspace Cloud Server&lt;sup&gt;&lt;a name=&#34;id-3&#34; href=&#34;#id-3.ftn&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, retaining only the numbers for the best-performing iteration&lt;sup&gt;&lt;a name=&#34;id-4&#34; href=&#34;#id-4.ftn&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;All stacks were configured to spawn 4 worker processes, backed by a single, local mongod&lt;sup&gt;&lt;a name=&#34;id-5&#34; href=&#34;#id-5.ftn&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; for storage. The DB was primed so that each GET resulted in a non-empty response body of about 420 bytes&lt;sup&gt;&lt;a name=&#34;id-6&#34; href=&#34;#id-6.ftn&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;~ Insert obligatory benchmark disclaimer here. ~&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Teh Contenders&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;CPython (Sync Worker)&lt;/strong&gt; 
Python v2.7 + Gunicorn&lt;sup&gt;&lt;a name=&#34;id-7&#34; href=&#34;#id-7.ftn&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; v0.14.6 + Rawr&lt;sup&gt;&lt;a name=&#34;id-8&#34; href=&#34;#id-8.ftn&#34;&gt;8&lt;/a&gt;&lt;/sup&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CPython (Eventlet Worker)&lt;/strong&gt; 
Python v2.7 + Gunicorn v0.14.6 + Eventlet v0.9.17 + Rawr&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PyPy (Sync worker)&lt;/strong&gt; 
PyPy 1.8 + Gunicorn v0.14.6 + Rawr&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PyPy (Tornado Worker)&lt;/strong&gt; 
Gunicorn v0.14.6 + Tornado&lt;sup&gt;&lt;a name=&#34;id-9&#34; href=&#34;#id-9.ftn&#34;&gt;9&lt;/a&gt;&lt;/sup&gt; + Rawr&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node v0.8.11&lt;/strong&gt; 
Node v0.8.11 + Cluster + Connect&lt;sup&gt;&lt;a name=&#34;id-10&#34; href=&#34;#id-10.ftn&#34;&gt;10&lt;/a&gt;&lt;/sup&gt; v2.6.0&lt;/p&gt;
&lt;h2&gt;Throughput Benchmarks&lt;/h2&gt;
&lt;p&gt;In terms of throughput, Node.js is hard to beat. It&amp;rsquo;s almost twice as fast as CPython/Eventlet workers. Interestingly, Node.js spanks Eventlet even while serving a single request at a time. It&amp;rsquo;s obvious that Node&amp;rsquo;s async framework is far more efficient than Eventlet&amp;rsquo;s.&lt;/p&gt;

&lt;p&gt;PyPy comes to the rescue, demonstrating the power of a good JIT compiler. The big surprise here is how well the PyPy/Sync workers perform. But there&amp;rsquo;s more to the story&amp;hellip; &lt;/p&gt;

&lt;p&gt;Not shown in the graph (below) are a few informal tests I ran to see what would happen at even higher levels of concurrency. At 5,000 concurrent requests, PyPy/Tornado and Node.js exhibited the best performance at ~4100 req/sec, followed closely by PyPy/Sync at ~3800 req/sec, then CPython/Sync at ~2200 req/sec. I couldn&amp;rsquo;t get CPython/Eventlet to finish all 5,000 requests without ab giving up due to socket errors.&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;block&#34; src=&#34;http://blog.kgriffs.com/assets/images/node-bench/throughput.png&#34; alt=&#34;Python vs. PyPy vs. Node.js - Throughput Benchmark&#34; /&gt;&lt;/p&gt;
&lt;h2&gt;Latency Benchmarks&lt;/h2&gt;
&lt;p&gt;CPython/Eventlet demonstrates high per-request overhead, turning around requests about 30% slower (in the worst case) than non-evented CPython workers. &lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;block&#34; src=&#34;http://blog.kgriffs.com/assets/images/node-bench/latency.png&#34; alt=&#34;Python vs. PyPy vs. Node.js - Latency Benchmark&#34; /&gt;&lt;/p&gt;
&lt;h2&gt;Stability Benchmarks&lt;/h2&gt;
&lt;p&gt;With a high number of concurrent connections, PyPy&amp;rsquo;s performance is very consistent. CPython/Sync also does well in this regard. &lt;/p&gt;

&lt;p&gt;Node is less consistent than I expected, given its finely-tuned event loop. It&amp;rsquo;s possible that node-mongodb-native is to blame&amp;mdash;but that&amp;rsquo;s pure conjecture on my part.&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;block&#34; src=&#34;http://blog.kgriffs.com/assets/images/node-bench/stability.png&#34; alt=&#34;Python vs. PyPy vs. Node.js - Stability Benchmark&#34; /&gt;&lt;/p&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Node&amp;rsquo;s &lt;a href=&#34;http://blog.kgriffs.com/2012/09/18/demystifying-async-io.html&#34;&gt;asynchronous&lt;/a&gt; subsystem incurs far less overhead than Eventlet, and is slightly faster than Tornado running under PyPy. However, it appears that for moderate numbers of concurrent requests, the overhead inherent in any async framework simply isn&amp;rsquo;t worthwhile&lt;sup&gt;&lt;a name=&#34;id-11&#34; href=&#34;#id-11.ftn&#34;&gt;11&lt;/a&gt;&lt;/sup&gt;. I.e., async only makes sense in the context of serving several thousand concurrent requests per second.&lt;/p&gt;

&lt;p&gt;CPython&amp;rsquo;s lackluster performance makes a strong case for migrating to PyPy for existing projects, and for considering Node.js as a viable alternative to Python for new projects. That being said, PyPy is not nearly as battle-tested as CPython; caveat emptor!&lt;/p&gt;

&lt;ul class=&#34;footnotes&#34;&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-1.ftn&#34; href=&#34;#id-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; Node uses Google&amp;rsquo;s V8 JavaScript engine under the hood. 
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-2.ftn&#34; href=&#34;#id-2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; Running ab on the same box as the server avoids networking anomalies that could bias test results.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-3.ftn&#34; href=&#34;#id-3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; CentOs 5.5, 8 GB RAM, ORD region, first-generation cloud server platform.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-4.ftn&#34; href=&#34;#id-4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; What can I say? I&amp;rsquo;m an insufferable optimist.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-5.ftn&#34; href=&#34;#id-5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; A lot of FUD has gone around re MongoDB. I&amp;rsquo;m convinced that most bad experiences with Mongo are due to one or more of the following: (1) Developers consciously (or subconsciously) expecting MongoDB to act like an RDBMS, (2) the perpetuation of the myth that MongoDB is not durable, and (3) trying to run MongoDB on servers with slow disks and/or insufficient RAM.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-6.ftn&#34; href=&#34;#id-6&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; The response body was chosen as an example of a typical JSON document that might be returned from the message bus service.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-7.ftn&#34; href=&#34;#id-7&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; Gunicorn is a very fast WSGI worker proxy, similar to Node&amp;rsquo;s Cluster module. Gunicorn supports running various worker types, including basic synchronous workers, Eventlet workers, and Tornado workers.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-8.ftn&#34; href=&#34;#id-8&#34;&gt;8&lt;/a&gt;&lt;/sup&gt; Based on extensive benchmarking, I ended up writing a custom micro web-services framework. Protip: Don&amp;rsquo;t use webob for parsing requests; it&amp;rsquo;s dog-slow.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-9.ftn&#34; href=&#34;#id-9&#34;&gt;9&lt;/a&gt;&lt;/sup&gt; Used in lieu of Eventlet, since Eventlet was extremely slow under PyPy in my  benchmarks.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-10.ftn&#34; href=&#34;#id-10&#34;&gt;10&lt;/a&gt;&lt;/sup&gt; Connect adds virtually no overhead; I wanted to use a framework that was fast, yet mainstream.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-11.ftn&#34; href=&#34;#id-11&#34;&gt;11&lt;/a&gt;&lt;/sup&gt; Warning: Don&amp;rsquo;t expose sync processes to the Internet; run behind a non-blocking server such as Nginx to guard against not only malicious attacks (ala Slowloris), but also against the Thundering Herd.
  &lt;/li&gt;
&lt;/ul&gt;
</content>
            </entry>
        
            <entry>
                <title>Cloud Security Manifesto</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2012/10/02/cloud-security-manifesto.html" type="text/html" />
                <id>http://blog.kgriffs.com/2012/10/02/cloud-security-manifesto.html</id>
                <updated>2012-10-02T21:09:00Z</updated>
                
                
                    <summary type="html">We need to build a cloud that people can trust.</summary>
                
                
                <content type="html">&lt;p&gt;When folks consider public cloud hosting, security is one of their biggest hangups. Given this overwhelming demand for more secure products, &lt;strong&gt;it&amp;rsquo;s surprising&lt;/strong&gt; how few developers take the time to learn and apply security best practices. I have no doubt the market will reward SaaS and IaaS developers who take their customer&amp;rsquo;s privacy seriously.&lt;/p&gt;

&lt;p&gt;People are understandably concerned about ceding control of their data. Frankly, I&amp;rsquo;m tickled pink customers are holding our feet to the fire on this issue. Software development has had a long history of &lt;strong&gt;embarrassing security breaches&lt;/strong&gt;. We can do better. We &lt;em&gt;must&lt;/em&gt; do better. In the über-connected, post-PC era, attacks on cloud apps and services will only become more common, as more and more people live their lives online.&lt;/p&gt;

&lt;p&gt;First, we need to promote &lt;strong&gt;Computer Security&lt;/strong&gt; as a first-class citizen, joining the likes of &lt;em&gt;Agile Development&lt;/em&gt;, &lt;em&gt;Quality Engineering&lt;/em&gt;, &lt;em&gt;DevOps&lt;/em&gt;, and &lt;em&gt;Continuous Integration&lt;/em&gt;. Each team should have at least one security geek; not necessarily a Bruce Schnier, but someone who is&amp;mdash;at a minimum&amp;mdash;enthusiastic about the subject. Someone who will champion security best practices in the team, and keep up with the state of the art.&lt;/p&gt;

&lt;p&gt;Second, project managers should ensure that &lt;strong&gt;security is never compromised&lt;/strong&gt; in deference to shipping new features. Rock-solid security &lt;em&gt;is&lt;/em&gt; a feature. Your customer&amp;rsquo;s trust is something you can&amp;rsquo;t afford to loose. In fact, shipping security as a feature of your product is a great way to differentiate your company. If I have to choose between Cloud App X and Cloud App Y, I&amp;rsquo;m probably going to choose the one built by a team that takes my privacy seriously.&lt;/p&gt;

&lt;p&gt;In order to grow the cloud services market, &lt;strong&gt;we must build a cloud that people trust&lt;/strong&gt;. It&amp;rsquo;s not just about avoiding the inevitable PR and legal nightmares that spring from major security breaches. It&amp;rsquo;s about embracing and nurturing the implicit trust that people put in our code, in our networks, and in our profession.&lt;/p&gt;

&lt;p&gt;After all, they deserve nothing less.&lt;/p&gt;
</content>
            </entry>
        
            <entry>
                <title>How Async I/O Works</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2012/09/18/demystifying-async-io.html" type="text/html" />
                <id>http://blog.kgriffs.com/2012/09/18/demystifying-async-io.html</id>
                <updated>2012-09-18T21:09:00Z</updated>
                
                
                    <summary type="html">Async I/O can be your best friend, or your worst enemy. The devil&#39;s in the details.</summary>
                
                
                <content type="html">&lt;p&gt;Five Guys sells awesome burgers and fries. Each patty is hand-formed, grilled to order, and piled high with crazy toppings like A1, bacon, and green peppers. Ordering at Five Guys goes something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://blog.kgriffs.com/assets/images/hacking-table.png&#34; width=&#34;100px&#34; alt=&#34;Hacking @ Five Guys&#34; /&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You tell Nice Person at the counter what you want to eat.&lt;/li&gt;
&lt;li&gt;Nice Person hands you a receipt with a number on it.&lt;/li&gt;
&lt;li&gt;You take a seat and do something productive, like hack on some code.&lt;/li&gt;
&lt;li&gt;Nice Person takes more orders, sending them to Cook.&lt;/li&gt;
&lt;li&gt;Cook adds patties to the grill as the orders come in, keeping himself busy.&lt;/li&gt;
&lt;li&gt;Nice Person calls your number when your order is ready.&lt;/li&gt;
&lt;li&gt;You pick up your order, return to your seat, and get down to business.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Async I/O works in a similar way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Thread tells Kernel what I/O work it wants done (i.e., &amp;ldquo;please read from this socket&amp;rdquo; or &amp;ldquo;please write to this file&amp;rdquo;).&lt;/li&gt;
&lt;li&gt;Kernel provides a handle to the thread for monitoring the request.&lt;/li&gt;
&lt;li&gt;Kernel adds the request to a list of items to babysit.&lt;/li&gt;
&lt;li&gt;Thread continues on with life, periodically checking&lt;sup&gt;&lt;a name=&#34;id-1&#34; href=&#34;#id-1.ftn&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; the I/O handle for events.&lt;/li&gt;
&lt;li&gt;Kernel posts an event to the I/O handle whenever something interesting happens.&lt;/li&gt;
&lt;li&gt;Thread grabs each event, processing it and checking for more events until the requested operation is complete.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here&amp;rsquo;s an illustration to help visualize what&amp;rsquo;s happening:&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;center&#34; src=&#34;http://blog.kgriffs.com/assets/images/async-io.png&#34; width=&#34;300px&#34; alt=&#34;Async I/O - Illustration&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Here we have a (very simplified) execution thread and a fancy box representing the operating system. The thread issues I/O request (1), but since the request is asynchronous, the thread continues working while it waits for the results from (1). In the meantime, the thread issues a second I/O request (2). Eventually, (2) completes, followed closely by (1), generating two I/O events from the kernel. The thread acts on these event, reading the results from first (2), then (1).&lt;/p&gt;
&lt;h1&gt;Blocking I/O&lt;/h1&gt;
&lt;p&gt;When a thread uses blocking I/O calls, the process looks something like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Thread tells Kernel what I/O work is needed.&lt;/li&gt;
&lt;li&gt;Kernel adds the request to a list of items to babysit.&lt;/li&gt;
&lt;li&gt;Kernel pauses Thread.&lt;/li&gt;
&lt;li&gt;Kernel wakes up Thread when the I/O request is complete.&lt;/li&gt;
&lt;li&gt;Thread grabs the results.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, contrast the blocking I/O illustration below with the one for async I/O:&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;center&#34; src=&#34;http://blog.kgriffs.com/assets/images/blocking-io.png&#34; width=&#34;300px&#34; alt=&#34;Blocking I/O - Illustration&#34; /&gt;&lt;/p&gt;

&lt;p&gt;The thread sits idle after issuing I/O request (1). When (1) completes, the thread is allowed to continue its work and issue request (2). Again, this pauses the thread, and the operating system only allows the thread to continue when (2) is complete.&lt;/p&gt;

&lt;p&gt;Although blocking I/O is super-simple to use and understand (hooray!), it prevents the thread from doing anything useful whenever an I/O request is pending (booh!). This is &lt;strong&gt;really bad&lt;/strong&gt;; compared to reading and writing RAM, I/O on devices such as HDDs and NICs is excruciatingly slow. Blocking on I/O forces threads into hibernation for &lt;a href=&#34;http://i.imgur.com/X1Hi1.gif&#34; title=&#34;I/O Latency - Visualized&#34;&gt;millions of CPU-years&lt;/a&gt; on every request.&lt;/p&gt;

&lt;p&gt;One way of solving the problem is to spawn several worker threads&lt;sup&gt;&lt;a name=&#34;id-2&#34; href=&#34;#id-2.ftn&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. For example, you might create two threads, which I&amp;rsquo;ll cleverly name &lt;em&gt;Thread A&lt;/em&gt; and &lt;em&gt;Thread B&lt;/em&gt;. These threads listen for incoming HTTP requests. When Client A connects to Thread A, Thread A blocks while it waits for the kernel to read data from the NIC. Meanwhile, Thread B accepts a connection from Client B and starts servicing it. Now that both threads are busy, what happens when a third client wants to talk? Tragically, the kernel is forced to hold the third request in a queue until one of the threads is free. If too many requests pile up, they will time out before they reach the other end of the queue. Worse, if requests continue to arrive faster than they can be processed, the kernel&amp;rsquo;s queue will eventually fill up, causing the system to block all new connections to the box.&lt;/p&gt;

&lt;p&gt;This would be like Five Guys forcing me to stand in line while every single order, for every single person in front of me, is cooked and bagged. Sure, I can check Facebook on my iPhone while I wait, but that hardly counts as being productive. Eventually, I may get so frustrated at waiting that I give up and walk out. This is not good for business (unless you happen to manage the restaurant next door).&lt;/p&gt;

&lt;p&gt;In situations like these, asynchronous I/O is exactly what you need. In the above scenario, async functions allow each thread to continue accepting requests, while waiting for bits to travel over the wire. In this way, requests are multiplexed across individual threads of execution, so they spend a lot less time sitting idle, and a lot more time warming the CPU. More clients are served more quickly, with lower latency.&lt;/p&gt;

&lt;p&gt;But all is not roses and puppy dogs, my friend.&lt;/p&gt;
&lt;h1&gt;I/O Bound vs. CPU Bound&lt;/h1&gt;
&lt;p&gt;If your app spends most&lt;sup&gt;&lt;a name=&#34;id-3&#34; href=&#34;#id-3.ftn&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; of its time waiting on disk or network I/O, an asynchronous design will usually improve CPU utilization and reduce latency vs. a synchronous model. I say &lt;em&gt;usually&lt;/em&gt;, because async I/O doesn&amp;rsquo;t help much when your app is only processing a few concurrent tasks. Indeed, some async frameworks come with a significant performance tax that can actually cause higher per-request latency vs. more traditional, synchronous frameworks. This tax only makes sense when you are trying to &lt;a href=&#34;http://blog.kgriffs.com/2012/09/06/painless-scaling-in-the-cloud.html&#34; title=&#34;Painless Scaling in the Cloud&#34;&gt;scale up&lt;/a&gt; to thousands of simultaneous, &lt;a href=&#34;https://en.wikipedia.org/wiki/I/O_bound&#34; title=&#34;I/O Bound - Definition&#34;&gt;I/O bound&lt;/a&gt; tasks. Under heavy load,  multiplexing requests across a small number&lt;sup&gt;&lt;a name=&#34;id-4&#34; href=&#34;#id-4.ftn&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; of processes drastically increases the maximum number of concurrent requests a box can handle. Each process can jump back and forth between servicing different requests while waiting for I/O operations to complete in the background.&lt;/p&gt;

&lt;p&gt;Some apps, on the other hand, spend most of their time running algorithms and crunching numbers (e.g., audio processing, data categorization, scientific computing, etc.). When a task is &lt;a href=&#34;https://en.wikipedia.org/wiki/CPU_bound&#34; title=&#34;CPU Bound - Definition&#34;&gt;CPU bound&lt;/a&gt;, async I/O certainly won&amp;rsquo;t buy you anything, and is likely to make things worse. If a thread is spending most of its time crunching data, you might as well use blocking-IO and avoid paying any per-request performance tax&lt;sup&gt;&lt;a name=&#34;id-5&#34; href=&#34;#id-5.ftn&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h1&gt;Trade-offs&lt;/h1&gt;
&lt;p&gt;Hardware limits us on what we can achieve using blocking I/O in a single thread of execution, so we have to invent ways of simulating concurrent execution. No approach is perfect; it&amp;rsquo;s important to realize this, and research the trade-offs involved in each approach, so that we can make better design decisions.&lt;/p&gt;

&lt;ul class=&#34;footnotes&#34;&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-1.ftn&#34; href=&#34;#id-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; Some operating systems use a push model instead, i.e., the kernel interrupts the
    thread when data is ready or more data is required.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-2.ftn&#34; href=&#34;#id-2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; Multiprocessing is a common alternative to multi-threading on POSIX systems.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-3.ftn&#34; href=&#34;#id-3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; All applications require CPU time, which is why it can be helpful to run multiple threads (or processes) if you&amp;rsquo;ve got the cores.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-4.ftn&#34; href=&#34;#id-4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; Running only one thread or process per CPU minimizes expensive context-switching.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;sup&gt;&lt;a name=&#34;id-5.ftn&#34; href=&#34;#id-5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; For this reason, servers that need to perform non-trivial processing on a request should hand off that processing to a worker pool.
  &lt;/li&gt;

&lt;/ul&gt;
</content>
            </entry>
        
            <entry>
                <title>Painless Scaling in the Cloud</title>
                <link rel="alternate" href="http://blog.kgriffs.com/2012/09/06/painless-scaling-in-the-cloud.html" type="text/html" />
                <id>http://blog.kgriffs.com/2012/09/06/painless-scaling-in-the-cloud.html</id>
                <updated>2012-09-06T21:09:00Z</updated>
                
                
                    <summary type="html">Scaling your web app or service is a nice problem to have, but just because you may never need to do it, doesn&#39;t mean you shouldn&#39;t plan for it.</summary>
                
                
                <content type="html">&lt;p&gt;Scaling your app or service is often described by startup veterans as &amp;ldquo;a nice problem to have,&amp;rdquo; something that &amp;ldquo;you should worry about later, if/when your app takes off&amp;rdquo;. People love to hear epic war stories about just-in-time scaling; how suddenly widg.it went viral at 3 am on a Sunday morning, and the team only had a few hours to rewrite half their system, switch data centers, and shard their database to stop it from crashing every ten minutes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://blog.kgriffs.com/assets/images/cloud-scaling-talk.png&#34; alt=&#34;Cloud Scaling Talk&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Stories like this can fool you into thinking there&amp;rsquo;s no other way to get to web-scale. That&amp;rsquo;s just plain silly. With a little less procrastination, and a little more foresight, you can enjoy a relatively painless experience scaling your cloud app or service.&lt;/p&gt;

&lt;p&gt;(Mostly) painless scaling is possible; I&amp;rsquo;ve experienced it first-hand. Sadly, such experiences simply aren&amp;rsquo;t sensational enough to make the front page of Hacker News. That&amp;rsquo;s a real shame. Sleepless nights and Rockstar-fueled hackathons &lt;strong&gt;should not be the norm&lt;/strong&gt;, but the exception. &lt;/p&gt;

&lt;p&gt;Survival by accident isn&amp;rsquo;t something we should be proud of. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The general who wins a battle makes many calculations in his temple ere the battle is fought. The general who loses a battle makes but few calculations beforehand. Thus do many calculations lead to victory, and few calculations to defeat: how much more no calculation at all! It is by attention to this point that I can foresee who is likely to win or lose.&lt;/p&gt;

&lt;p&gt;~ Sun Tzu &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Eventually, we software developers will discover elegant solutions to the problem of scaling cloud apps, making knee-jerk, duct-tape engineering obsolete. In the meantime, we can avoid a lot of pain by investing more time up-front in proving ideas, carefully choosing a hosting provider, and putting continuous integration and deployment at the heart of everything we do.&lt;/p&gt;
&lt;h1&gt;Web-scale Architecture: Build one to Throw Away&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;If you know the enemy and know yourself, you need not fear the result of a hundred battles If you know yourself but not the enemy, for every victory gained you will also suffer a defeat. If you know neither the enemy nor yourself, you will succumb in every battle.&lt;/p&gt;

&lt;p&gt;~ Sun Tzu &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Architectural awesomeness requires patience, humility and experimentation. What trade-offs are you making, and why? How far will your initial design take you? What will you do if usage spikes? Pushing and prodding early iterations of your app until they break&amp;mdash;then picking up the pieces and putting them back together again&amp;mdash;will help you avoid a lot of nasty surprises. At the very least, you will know what you are getting yourself into.&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;left&#34; src=&#34;http://blog.kgriffs.com/assets/images/poor-cloud-ideas.png&#34; alt=&#34;Poor Cloud Ideas (Thrown Away)&#34; /&gt;&lt;/p&gt;

&lt;p&gt;You don&amp;rsquo;t need to create a massively scalable system right out of the gate; even if you wanted to, you probably can&amp;rsquo;t afford it. On the other hand, you need only barter a few days&amp;#39; work to become reasonably familiar with the limitations&amp;mdash;in terms of scalability, reliability and efficiency&amp;mdash;inherent in the various components of your toolbox. How well do you grok your programming language, web framework, operating system, or database server?&lt;/p&gt;

&lt;p&gt;Experiment. Don&amp;rsquo;t simply choose the first design, the first platform, or the first algorithm that comes to mind. &lt;strong&gt;Challenge yourself to think of something better.&lt;/strong&gt; Some things I do to test ideas early and often:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Prototype ideas.&lt;/strong&gt; Bring them into the real world. Make ideas stand up and dance to reveal their true nature. Second-hand anecdotes are inferior to taking something for a test drive yourself. Speculation is dangerous; avoid it. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conduct fire drills.&lt;/strong&gt; Break software before users do. Watermark system performance and reliability, and take a few minutes to consider (a) what simple adjustments can be made to raise that watermark, and (b) whether your design affords scaling, without having to re-architect major components.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitor early, often.&lt;/strong&gt; Monitoring helps you anticipate scaling problems so that you can fix them while the sun&amp;rsquo;s still shining. These days, there are &lt;a href=&#34;https://github.com/etsy/statsd&#34;&gt;plenty&lt;/a&gt; of &lt;a href=&#34;http://www.rackspace.com/cloud/public/monitoring/&#34;&gt;ways&lt;/a&gt; to quickly add &lt;a href=&#34;http://aws.amazon.com/cloudwatch/&#34;&gt;monitoring&lt;/a&gt; to your servers, daemons and databases. It doesn&amp;rsquo;t take long to whip up a simple &lt;a href=&#34;http://graphite.wikidot.com/&#34;&gt;dashboard&lt;/a&gt; containing a few graphs and statistics. Set up a few alerts so everyone knows when boxes are running hot, when connections are dropped, and when daemons crash.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Certainly, you can&amp;rsquo;t anticipate everything. Trying is a waste of time. What you &lt;em&gt;can&lt;/em&gt; do is create a flexible architecture and anticipate your system&amp;rsquo;s limitations. By doing these two things, you equip yourself to more effectively overcome scaling challenges, giving yourself a better chance at making it home in time for dinner at the end of the day.&lt;/p&gt;
&lt;h1&gt;Cloud Hosting: An Intimate Relationship&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;We cannot enter into alliances until we are acquainted with the designs of our neighbors.&lt;/p&gt;

&lt;p&gt;~ Sun Tzu&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Data center migrations are the last thing you want on your mind in the middle of a scaling crisis. When evaluating hosting providers, choose a good home for your app. The ideal hosting provider not only has expertise in your tech stack, but also offers services which scale from a single virtual machine in one DC, to 1000 boxes hosted around the world.&lt;/p&gt;

&lt;p&gt;If you find yourself implementing silly and outrageous workarounds for deficiencies in your hosting platform, your cloud provider is doing it wrong. You should demand reliability and solid performance for your money. IaaS is not only an abstraction of physical hardware, but also an abstraction of physical durability. The less these abstractions leak, the better.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://blog.kgriffs.com/assets/images/cloud-borg.png&#34; alt=&#34;Hybrid Cloud Hosting, ala The Borg&#34; /&gt;&lt;/p&gt;

&lt;p&gt;For some parts of your system, running on a virtualized platform is the wrong approach. While it&amp;rsquo;s certainly &lt;em&gt;possible&lt;/em&gt; to run highly-trafficked cloud services on Amazon&amp;rsquo;s EC2 instances or Rackspace&amp;rsquo;s Cloud Servers, &lt;strong&gt;it isn&amp;rsquo;t always wise&lt;/strong&gt;. A bare-metal server can be a less painful&amp;mdash;and less costly&amp;mdash;way to scale parts of your system. For example, 37signals runs their DB cluster on custom boxes. This approach frees them to scale Basecamp and other popular apps geometrically (&lt;em&gt;up&lt;/em&gt;, as well as &lt;em&gt;out&lt;/em&gt;). Need more RAM? A faster disk? How about a 10g nic? No problem.&lt;/p&gt;

&lt;p&gt;Personally, I prefer hosting companies that offer hybrid solutions, so that I can provision dedicated boxes and appliances that inter-operate with my cloud servers. I don&amp;rsquo;t need to do this out of the gate; cloud servers will do the job. But there will come a time when that&amp;rsquo;s no longer the case. The I/O tax and cost structure for virtual machines doesn&amp;rsquo;t work out well when scaling certain components beyond a certain point (e.g., an RDBMS).&lt;/p&gt;

&lt;p&gt;Generally speaking, if you spend a little more time up front researching the best &lt;strong&gt;long-term&lt;/strong&gt; host for your project, you will save yourself a significant amount of grief when it comes time to scale your system.&lt;/p&gt;
&lt;h1&gt;Continuous Integration: Trust Your Code&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Thus it is that in war the victorious strategist only seeks battle after the victory has been won, whereas he who is destined for defeat, first fights, and afterwards looks for victory.&lt;/p&gt;

&lt;p&gt;~ Sun Tzu&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Continuous integration and delivery (CI) belongs at the heart of cloud software development&amp;mdash;even for small, two-person startups. CI engenders trust in your code base, allowing you and your team to quickly roll out new features and optimizations. This ability is an absolute lifesaver during emergencies.&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;center&#34; src=&#34;http://blog.kgriffs.com/assets/images/cloud-continuous-integration.png&#34; alt=&#34;Hybrid Cloud Hosting, ala The Borg&#34; /&gt;&lt;/p&gt;

&lt;p&gt;A good CI system will break your code before the customer does. This is what you want. The earlier in your development process that you find and fix problems, the cheaper (and less embarrassing) it is to take care of those problems.&lt;/p&gt;

&lt;p&gt;Some tips for making your CI awesome:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Employ peer code reviews&lt;/strong&gt; as the first line of defense. Code reviews are surprisingly effective at catching bugs and suboptimal designs when they are the cheapest to fix.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run unit, integration, and security tests.&lt;/strong&gt; Break your own software, rather than forcing users to do it for you. Quality is &lt;em&gt;your&lt;/em&gt; job, not theirs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run static analysis tools.&lt;/strong&gt; Even the most skilled programmers in the world still make stupid mistakes. There&amp;rsquo;s an app for that.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run simple, fast tests&lt;/strong&gt; before complex, slow ones. E.g., there&amp;rsquo;s no sense in running expensive tests when the code doesn&amp;rsquo;t even compile.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enforce a consistent coding style.&lt;/strong&gt; Developers spend a lot more time reading code than writing it. Make your code easy to grok, and you will thank yourself later.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Include multiple environments&lt;/strong&gt;, such as &lt;em&gt;dev&lt;/em&gt;, &lt;em&gt;test&lt;/em&gt;, &lt;em&gt;staging&lt;/em&gt; and &lt;em&gt;production&lt;/em&gt;. The &lt;em&gt;staging&lt;/em&gt; environment mirrors &lt;em&gt;production&lt;/em&gt; as close as possible, making &lt;em&gt;staging&lt;/em&gt; ideal for smoke-testing, watermarking, and benchmarking. The &lt;em&gt;test&lt;/em&gt; environment provides a reasonably stable deployment suitable for integration testing, while &lt;em&gt;dev&lt;/em&gt; is an inherently unstable environment used to prove freshly-minted code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pipeline stages&lt;/strong&gt;. Build 5142 can be running in &lt;em&gt;dev&lt;/em&gt; while build 5141 is in &lt;em&gt;test&lt;/em&gt;. At the same time, build 5140 can be in &lt;em&gt;staging&lt;/em&gt;, where it is vetted before deployment to &lt;em&gt;production&lt;/em&gt;. This approach requires more build servers, but delivers feedback earlier and more often.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You don&amp;rsquo;t need to invest a lot of time and money setting up your CI pipeline. Start small with only a few automated tests and two environments; one for development, and one for production. Use a free CI system such as BuildBot, CruseControl.NET, or Jenkins. Then, take a few hours each week to tweak and improve your process until you are no longer nervous about shipping code on the same day it&amp;rsquo;s written.&lt;/p&gt;
&lt;h1&gt;Q.E.D.&lt;/h1&gt;
&lt;p&gt;By spending a little more time planning ahead, and by putting in place a trustworthy continuous integration and deployment pipeline, you have a good chance at avoiding sleepless nights and shattered relationships when your app blows up&amp;mdash;and I sincerely hope it does.&lt;/p&gt;

&lt;p&gt;After all, that&amp;rsquo;s a nice problem to have.&lt;/p&gt;
</content>
            </entry>
        
    </feed>
