Yelp / zygote

A Python HTTP process management utility.
http://opensource.yelp.com/
Apache License 2.0
40 stars 15 forks source link

add HTTP keep-alive support #4

Open eklitzke opened 13 years ago

eklitzke commented 13 years ago

Right now the HTTP server runs with Keep-Alive disabled. Making Keep-Alive work is going to be really annoying, because the Tornado HTTPServer is too smart for its own good and knows how to overlap requests.

One thing to note here is that if you're using HAProxy in front of your web application, you can just have HAProxy do the Keep-Alive support itself. The way this works is a client (say, a browser) connects to HAProxy with Keep-Alive, and on the backend HAProxy uses Connection: close with the backend servers it talks to. So this limitation is not as bad as it seems if you are lucky enough to be using HAProxy.

eskil commented 11 years ago

Fun fact. Running a tornado http server with keepalive spends 30-40ms getting the POST body versus no keep alive.

no keep alive

25062 1350614772.256471 recvfrom(6, "POST /status HTTP/1.1\r\nUser-Agent: Mozilla/5.0 (compatible; pycurl)\r\nHost: localhost:9000\r\nAccept: */*\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 59\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n", 4096, 0, N
25062 1350614772.256848 select(7, [3 5 6], [], [3 5 6], {0, 200000}) = 1 (in [6], left {0, 199995}) <0.000021>
25062 1350614772.256977 recvfrom(6, "{\"foo\": \"bar\", \"foo1\": \"bar\", \"foo2\": \"bar\", \"foo3\": \"bar\"}", 4096, 0, NULL, NULL) = 59 <0.000016>
25062 1350614772.257215 uname({sys="Linux", node="dev19", ...}) = 0 <0.000012>
25062 1350614772.257403 write(1, "HELLO FHATS\n", 12) = 12 <0.000018>
25062 1350614772.257485 open("/proc/25062/statm", O_RDONLY) = 8 <0.000021>
25062 1350614772.257543 fstat(8, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 <0.000011>
25062 1350614772.257607 fstat(8, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 <0.000011>
25062 1350614772.257663 lseek(8, 0, SEEK_CUR) = 0 <0.000011>
25062 1350614772.257704 fstat(8, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 <0.000012>
25062 1350614772.257760 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f19f8cf6000 <0.000014>
25062 1350614772.257806 lseek(8, 0, SEEK_CUR) = 0 <0.000011>
25062 1350614772.257854 read(8, "22181 5216 964 541 0 4242 0\n", 8192) = 28 <0.000015>
25062 1350614772.257905 read(8, "", 7168) = 0 <0.000011>
25062 1350614772.257958 close(8)        = 0 <0.000015>
25062 1350614772.258003 munmap(0x7f19f8cf6000, 4096) = 0 <0.000017>
25062 1350614772.258102 uname({sys="Linux", node="dev19", ...}) = 0 <0.000011>
25062 1350614772.258957 sendto(7, "\0\0\2\246\0\0\0\3Log\1\0\0\0\0\17\0\1\f\0\0\0\1\v\0\1\0\0\0\21tmp_service_cleat\v\0\2\0\0\2q{\"hostname\": \"dev19\", \"request\": {\"headers\": {\"Content-Length\": \"59\", \"Accept-Encoding\": \"gzip,deflate\", \"Accept\": \"*/*\", \"
25062 1350614772.259107 recvfrom(7, "\0\0\0\24", 4, 0, NULL, NULL) = 4 <0.000036>
25062 1350614772.259202 recvfrom(7, "\0\0\0\3Log\2\0\0\0\0\10\0\0\0\0\0\0\0", 20, 0, NULL, NULL) = 20 <0.000014>
25062 1350614772.259466 select(7, [3 5], [6], [3 5 6], {0, 200000}) = 1 (out [6], left {0, 199995}) <0.000017>
25062 1350614772.259581 sendto(6, "HTTP/1.1 200 OK\r\nContent-Length: 47\r\nContent-Encoding: gzip\r\nContent-Type: application/json\r\nServer: TornadoServer/1.1\r\n\r\n\37\213\10\0\364\276\200P\2\377\253VJ\313\317W\262RPJJ,R\322Q\0\361\fQ\271F\250\\c\30\267\226\v\0\276b\
25062 1350614772.259857 close(6)        = 0 <0.000035>
25062 1350614772.259981 select(6, [3 5], [], [3 5], {0, 200000}) = 1 (in [5], left {0, 197865}) <0.002153>
25062 1350614772.262239 accept(5, {sa_family=AF_INET, sin_port=htons(56271), sin_addr=inet_addr("127.0.0.1")}, [16]) = 6 <0.000030>
25062 1350614772.262355 fcntl(6, F_GETFL) = 0x2 (flags O_RDWR) <0.000011>
25062 1350614772.262441 fcntl(6, F_SETFL, O_RDWR|O_NONBLOCK) = 0 <0.000011>
25062 1350614772.262556 accept(5, 0x7fffe96105d0, [16]) = -1 EAGAIN (Resource temporarily unavailable) <0.000021>
25062 1350614772.262677 select(7, [3 5 6], [], [3 5 6], {0, 200000}) = 1 (in [6], left {0, 199995}) <0.000021>

keep alive

28261 1350614952.393343 recvfrom(6, "POST /status HTTP/1.1\r\nUser-Agent: Mozilla/5.0 (compatible; pycurl)\r\nHost: localhost:9000\r\nAccept: */*\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 59\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n", 4096, 0, NULL, NULL) = 206 <0.000013>
28261 1350614952.393667 select(7, [3 5 6], [], [3 5 6], {0, 200000}) = 1 (in [6], left {0, 156202}) <0.043877>
28261 1350614952.437728 recvfrom(6, "{\"foo\": \"bar\", \"foo1\": \"bar\", \"foo2\": \"bar\", \"foo3\": \"bar\"}", 4096, 0, NULL, NULL) = 59 <0.000205>
28261 1350614952.438235 uname({sys="Linux", node="dev19", ...}) = 0 <0.000050>
28261 1350614952.438625 write(1, "HELLO FHATS\n", 12) = 12 <0.000165>
28261 1350614952.438996 open("/proc/28261/statm", O_RDONLY) = 8 <0.000028>
28261 1350614952.439073 fstat(8, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 <0.000011>
28261 1350614952.439151 fstat(8, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 <0.000015>
28261 1350614952.439221 lseek(8, 0, SEEK_CUR) = 0 <0.000010>
28261 1350614952.439263 fstat(8, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 <0.000010>
28261 1350614952.439315 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9fe7b04000 <0.000012>
28261 1350614952.439357 lseek(8, 0, SEEK_CUR) = 0 <0.000009>
28261 1350614952.439405 read(8, "22179 5214 964 541 0 4240 0\n", 8192) = 28 <0.000014>
28261 1350614952.439450 read(8, "", 7168) = 0 <0.000009>
28261 1350614952.439498 close(8)        = 0 <0.000012>
28261 1350614952.439536 munmap(0x7f9fe7b04000, 4096) = 0 <0.000013>
28261 1350614952.439622 uname({sys="Linux", node="dev19", ...}) = 0 <0.000010>
28261 1350614952.440594 sendto(7, "\0\0\2\240\0\0\0\3Log\1\0\0\0\0\17\0\1\f\0\0\0\1\v\0\1\0\0\0\21tmp_service_cleat\v\0\2\0\0\2k{\"hostname\": \"dev19\", \"request\": {\"headers\": {\"Content-Length\": \"59\", \"Accept-Encoding\": \"gzip,deflate\", \"Accept\": \"*/*\", \"User-Agent\": \"Mozilla/5.0 (compatible; pycurl)\", \"Host\": \"localhost:9000\", \"Co"..., 676, 0, NULL, 0) = 676 <0.000036>
28261 1350614952.440727 recvfrom(7, "\0\0\0\24", 4, 0, NULL, NULL) = 4 <0.000128>
28261 1350614952.440902 recvfrom(7, "\0\0\0\3Log\2\0\0\0\0\10\0\0\0\0\0\0\0", 20, 0, NULL, NULL) = 20 <0.000013>
28261 1350614952.441148 select(7, [3 5], [6], [3 5 6], {0, 189537}) = 1 (out [6], left {0, 189533}) <0.000015>
28261 1350614952.441243 sendto(6, "HTTP/1.1 200 OK\r\nContent-Length: 47\r\nContent-Encoding: gzip\r\nContent-Type: application/json\r\nServer: TornadoServer/1.1\r\n\r\n\37\213\10\0\250\277\200P\2\377\253VJ\313\317W\262RPJJ,R\322Q\0\361\fQ\271F\250\\c\30\267\226\v\0\276b\252w<\0\0\0", 169, 0, NULL, 0) = 169 <0.000094>
28261 1350614952.441517 select(7, [3 5 6], [], [3 5 6], {0, 189176}) = 1 (in [6], left {0, 187943}) <0.001251>