Sunday, December 1, 2013

[HTTP Benchmark] Apache ab and HTTP 1.0 KeepAlive against node.js express

Apache ab allows you to specify '-k' to use the HTTP KeepAlive feature

We had to simulate some activity on our servers that use this keep alive extensively (thousands of requests through the same connexion), but couldn't make it happen using ab against our node.js/express application.

Using 'ab -v 2', we could confirm that every http request was closed, forcing the next one to create a new connexion :

---
POST /testroute HTTP/1.0
Connection: Keep-Alive
Content-length: 700
Content-type: text/plain
Host: app1
User-Agent: ApacheBench/2.3
Accept: */*

---
LOG: header received:
HTTP/1.1 200 OK
X-Powered-By: Express
Date: Sun, 01 Dec 2013 18:36:36 GMT
Connection: close

This is where we had the intuition that express was not implementing the 'non official' keepAlive http 1.0;

To confirm this, we tried calling express with curl using http1.1 and http1.0

- Using HTTP 1.1 :

curl -v http://app1/testroute

> POST /testroute HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: app1
> Accept: */*
> Connection: Keep-Alive
> Content-Length: 674
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Date: Sun, 01 Dec 2013 18:44:35 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked

- Using HTTP 1.0 and the keepAlive header : 

curl -v --http1.0 -H 'Connection: Keep-Alive' http://app1/testroute

> POST /testroute HTTP/1.0
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: app1
> Accept: */*
> Connection: Keep-Alive
> Content-Length: 674
> Content-Type: application/x-www-form-urlencoded
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Date: Sun, 01 Dec 2013 18:44:20 GMT
< Connection: close

Tada !! Our problem was confirmed:

  - apache ab is using HTTP 1.0
  - express don't care about the keepAlive header and close each connexion made with HTTP 1.0

---

After some googling we found some sources for ab and a quick look into them confirmed a quick hack was possible.

Here is what we did :

# Install dependencies :
yum install apr-devel.x86_64 apr-util-devel.x86_64 -y

# Get the sources :
wget https://apachebench-standalone.googlecode.com/files/ab-standalone-0.1.tar.bz2

# Unzip :
bzip2 -d ab-standalone-0.1.tar.bz2
tar xvf ab-standalone-0.1.tar

# Modify sources to force HTTP 1.1 :
cd ab-standalone
vi ab.c
# START ---------------
(...)
            "%s %s HTTP/1.1\r\n"
(...)
            "POST %s HTTP/1.1\r\n"
(...)
# END   ---------------

# Compile :
make apr-skeleton
make ab
chmod +x ./ab

# Alias ab to new newly compiled binary :
alias ab=/zbo/operations/ab-standalone/ab

# Confirm that keepAlive now works :
ab -v 2 -n 1 -c 1 -k http://app1/testroute

---
POST /testroute HTTP/1.1
Connection: Keep-Alive
Content-length: 700
Content-type: text/plain
Host: 192.168.0.161:8080
User-Agent: ApacheBench/2.3
Accept: */*

---
LOG: header received:
HTTP/1.1 200 OK
X-Powered-By: Express
Date: Sun, 01 Dec 2013 19:23:25 GMT
Connection: keep-alive
Transfer-Encoding: chunked


Use at your own risk :)


No comments: