HTTP

Some time ago I had the requirement to limit the number of requests per IP to a CouchDB-instance. I couldn’t find an option for CouchDB to achieve that, but as communication with CouchDB is based on HTTP-requests I thought that it should be possible to use nginx as reverse proxy with rate-limiting capabilities for CouchDB. The CouchDB-wiki lists some basic steps how to use nginx as reverse proxy, but rate limiting isn’t mentioned there.

Beside the actual rate limiting I noticed that nginx won’t work, because it doesn’t support chunked request-bodies out of the box, which CouchDB seems to rely onto. But to the rescue there is a nginx module called ngx_chunkin, which adds chunkin support to nginx. To get that module in Debian you need to install nginx-extras from the repository (available since squeeze-backports). The configuration of that module is straight forward as described on the wiki page. All you have to do is to put the following code snippet into the server-context of your nginx configuration:

        chunkin on;

        error_page 411 = @my_411_error;
        location @my_411_error {
                chunkin_resume;
        }

Having solved that issue, doing the actual rate limiting was the next step. Therefore nginx ships the module ngx_http_limit_req_module. All I had to do was to configure a zone for the limited requests in the http-context of the configuration:

limit_req_zone $binary_remote_addr zone=couchdb_write:10m rate=10r/s;

and the logic what to rate limit (writing requests in my case) into the server-context:

        location / {
                # POST, PUT, DELETE ... requests will get rate limiting
                if ($request_method !~* GET) {
                        rewrite ^(.*)$ /throttled$1 last;
                }

                proxy_pass       http://127.0.0.1:5985;
                proxy_buffering  off;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location /throttled {
                internal;
                limit_req        zone=couchdb_write burst=10000;
                rewrite /throttled(.*) $1 break;
                proxy_pass       http://127.0.0.1:5985;
                proxy_buffering  off;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

So if you put together the chunkin support and the rate limiting, you’ll get the following piece of configuration for a server which does rate limiting of writing CouchDB-requests using nginx:

limit_req_zone $binary_remote_addr zone=couchdb_write:10m rate=10r/s;

server {
        listen 5984;

        chunkin on;

        error_page 411 = @my_411_error;
        location @my_411_error {
                chunkin_resume;
        }

        location / {
                # POST, PUT, DELETE ... requests will get rate limiting
                if ($request_method !~* GET) {
                        rewrite ^(.*)$ /throttled$1 last;
                }

                proxy_pass       http://127.0.0.1:5985;
                proxy_buffering  off;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location /throttled {
                internal;
                limit_req        zone=couchdb_write burst=10000;
                rewrite /throttled(.*) $1 break;
                proxy_pass       http://127.0.0.1:5985;
                proxy_buffering  off;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

I really enjoyed figuring that out, because it was a lot of fun to be able to use a great tool (nginx) to extend another great tool (CouchDB), because they’re using the same protocol (HTTP).

die geladenen Elemente auf der "Microsite" von IKEA PAXAuf der deutschen IKEA-Webseite gibt es aktuell eine PAX-“Microsite”. Diese ist echt schick. So bekommt man beispielsweise durch scrollen verschiedene Schrankkombinationen und Befüllungen innerhalb desselben Bildes angezeigt. Auch werden moderne Technologien, wie zum Beispiel jQuery und Modernizr, benutzt.
Was mich dann aber doch etwas staunend zurück ließ ist die Tatsache, dass beim Aufruf der Seite über 1500 HTTP-Requests ausgelöst werden und die damit angeforderten Daten eine Gesamtgröße von über 35MB haben? Srsly? Das geht doch auch besser.

Also ich weiß zwar nicht warum, aber ich weiß auf jeden Fall das Opera 9.0 irgendwelche Probleme hat. Zumindest sagen mir das meine Serverlogs. Ich habe einen Server mit einer IP und mehreren Domains. Für alle habe ich getrennte Access-Logs. Beim durchschauen des Accesslogs für die direkte IP fiel mir nun auf, dass dort Zugriffe verzeichnet sind, die ich anhand der Parameter eindeutig einer der Domains zuordnen kann. Sie haben also bei der IP nichts zu suchen. Ich weiß ebenso, dass es keinerlei falsche Zieladresse ist, bei der statt der Domain bei einem Link einfach die IP steht. Dafür kommen die Zugriffe von zu vielen verschiedenen Unterseiten von verschiedenen Domains.
Und wie schon erwähnt scheint der einzige Client der das macht Opera 9.0 zu sein. Na ja, im Endeffekt kann’s mir egal sein. Es passiert ja nicht viel mehr als das mein Server solche Anfragen mit einem 417er HTTP-Statuscode beantwortet.