26
Gazelle Yokohama.pm #12 Masahiro Nagano (kazeburo) https://www.ickr.com/photos/ckindel/424610604/ Plack Handler for performance freaks

Gazelle - Plack Handler for performance freaks #yokohamapm

Embed Size (px)

Citation preview

Page 1: Gazelle - Plack Handler for performance freaks #yokohamapm

GazelleYokohama.pm #12

Masahiro Nagano (kazeburo)https://www.!ickr.com/photos/ckindel/424610604/

Plack Handler for performance freaks

Page 2: Gazelle - Plack Handler for performance freaks #yokohamapm

Me

• 長野雅広 (Masahiro Nagano)

• @kazeburo

• CPAN: KAZEBURO / github: kazeburo

• 横浜市西区在住• ISUCON 2013,2014 優勝

Page 3: Gazelle - Plack Handler for performance freaks #yokohamapm

Gazelle

Page 4: Gazelle - Plack Handler for performance freaks #yokohamapm

Gazelle #とは• Plack Handler / PSGI Server

• HTTP/1.0 Web Server

• Preforking Architecture

• Suitable for running application servers behind a reverse proxy

• Starlet compatible / hot deploy

• Fast Fast Fast

Page 5: Gazelle - Plack Handler for performance freaks #yokohamapm

“Hello World”

0

32,500

65,000

97,500

130,000

106,028

62,06933,300

127,462

req/

sec

nginx starman Starlet Gazelle

3x Faster!!than starman

Page 6: Gazelle - Plack Handler for performance freaks #yokohamapm

“counter.psgi”

0

27,500

55,000

82,500

110,000

hello world counter.psgi

42,285

106,028

28,292

62,069

20,10033,300

req/

sec

starman Starlet Gazelle

Page 7: Gazelle - Plack Handler for performance freaks #yokohamapm

ISUCON4 Quali!er

11,250

22,500

33,750

45,000

44,76442,81339,77637,808Scor

e

予選通過ライン starman Starlet Gazelle

「ISUCON4 予選でアプリケーションを変更せずに予選通過ラインを突破するの術」に若干変更を加えたバージョン

Page 8: Gazelle - Plack Handler for performance freaks #yokohamapm

Gazelle はなぜ速い• Only Support HTTP/1.0 and does not

support KeepAlive. It make code very simple

• Mostly written in XS

• Ultra fast HTTP processing using picohttpparser

• Use accept4(2)

• Use writev(2) for output responses

Page 9: Gazelle - Plack Handler for performance freaks #yokohamapm

Simple HTTP/1.0 GETaccept4(2)

read(2)

parse_headerpoll(2)

execute app

writev(2)poll(2)

close(2)

complete?

written?

OK

No

OK No

Page 10: Gazelle - Plack Handler for performance freaks #yokohamapm

Mostly written in XSaccept4(2)

read(2)

parse_headerpoll(2)

execute app

writev(2)poll(2)

close(2)

complete?

written?

OK

No

OK No

XS

XS

Page 11: Gazelle - Plack Handler for performance freaks #yokohamapm

Perl code using XS

while (1) { if ( my ($fd, $buf, $env) = accept_psgi( fileno($listen_sock), $timeout, $listen_sock_is_tcp, $host || 0, $port || 0 ) ) { my $guard = guard { close_client($fd) }; $res = Plack::Util::run_app $app, $env; my $status_code = $res->[0]; my $headers = $res->[1]; my $body = $res->[2]; write_psgi_response($fd, $timeout, $status_code, $headers, $body); }

Page 12: Gazelle - Plack Handler for performance freaks #yokohamapm

Perl code using XS

while (1) { if ( my ($fd, $buf, $env) = accept_psgi( fileno($listen_sock), $timeout, $listen_sock_is_tcp, $host || 0, $port || 0 ) ) { my $guard = guard { close_client($fd) }; $res = Plack::Util::run_app $app, $env; my $status_code = $res->[0]; my $headers = $res->[1]; my $body = $res->[2]; write_psgi_response($fd, $timeout, $status_code, $headers, $body); }

Page 13: Gazelle - Plack Handler for performance freaks #yokohamapm

picohttpparser

• created by kazuho-san

• used in H2O and HTTP::Parser::XS

Page 15: Gazelle - Plack Handler for performance freaks #yokohamapm

accept4(2)

• Required Linux >= 2.6.28

• Set FD_CLOEXEC and O_NONBLOCK in one system call

Page 16: Gazelle - Plack Handler for performance freaks #yokohamapm

accept4(2)

int_accept(int fileno, struct sockaddr *addr, unsigned int addrlen) { int fd;#ifdef SOCK_NONBLOCK fd = accept4(fileno, addr, &addrlen, SOCK_CLOEXEC|SOCK_NONBLOCK);#else fd = accept(fileno, addr, &addrlen); fcntl(fd, F_SETFD, FD_CLOEXEC); fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);#endif return fd;}

Page 17: Gazelle - Plack Handler for performance freaks #yokohamapm

accept4(2)13:51:26.755628 accept(4, {sa_family=AF_INET, sin_port=htons(42828), sin_addr=inet_addr("127.0.0.1")}, [16]) = 5

13:51:27.324951 fcntl(5, F_SETFD, FD_CLOEXEC) = 0

13:51:27.325014 fcntl(5, F_GETFL) = 0x2 (flags O_RDWR)

13:51:27.325067 fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 0

13:51:27.325117 read(5, "GET / HTTP/1.1\r\nUser-Agent:"..., 16384) = 155

13:51:27.325200 setsockopt(5, SOL_TCP, TCP_NODELAY, [1], 4) = 0

13:52:17.946622 accept4(4, {sa_family=AF_INET, sin_port=htons(42835), sin_addr=inet_addr("127.0.0.1")}, [16], SOCK_CLOEXEC|SOCK_NONBLOCK) = 5

13:52:18.505428 read(5, "GET / HTTP/1.1\r\nUser-Agent:”..., 16384) = 155

13:52:18.505519 setsockopt(5, SOL_TCP, TCP_NODELAY, [1], 4) = 0

Page 18: Gazelle - Plack Handler for performance freaks #yokohamapm

writev

• write multiple buffer to a fd in one system call

• reduce memory copy or system calls

Page 19: Gazelle - Plack Handler for performance freaks #yokohamapm

ex. memory copy#perlmy $header = ["Server"=>"gazelle","Content-Type"=>"text/plain",...];

#xschar buf[512];while ( i < av_len(headers) + 1 ) { key = SvPV_nolen(*av_fetch(headers,i++,0)); strcat(buf, key); strcat(buf, ": "); val = SvPV_nolen(*av_fetch(headers,i++,0)); strcat(buf, val); strcat(buf, "\r\n");}write(fd, buf, sizeof(buf)-1);

Too manymemory copycause system

overhead

Page 20: Gazelle - Plack Handler for performance freaks #yokohamapm

ex. write write write

#perlmy $header = ["Server"=>"gazelle","Content-Type"=>"text/plain"];

#xswhile ( i < av_len(headers) + 1 ) { key = SvPV(*av_fetch(headers,i++,0),&len); write(fd, key, len); write(fd, ": ", sizeof(“: ”) - 1); val = SvPV(*av_fetch(headers,i++,0),&len); write(fd, val, len); write(fd, "\r\n", sizeof(“\r\n”) - 1);}

Too manywrite(2)

increase latencyof network

Page 21: Gazelle - Plack Handler for performance freaks #yokohamapm

writev(2)#perlmy $header = ["Server"=>"gazelle","Content-Type"=>"text/plain"];#xsstruct iovec v[av_len(headers)+1)*2 + 10];iovcnt = 0;while ( i < av_len(headers) + 1 ) { key = SvPV(*av_fetch(headers,i++,0),&len); iovcnt++; v[iovcnt].iov_base = key; v[iovcnt].iov_len = len; iovcnt++; v[iovcnt].iov_base = “: ”; v[iovcnt].iov_len = sizeof(“: ”) - 1; ...}writev(fd, v, iovcnt);

no memory copyone system call

Page 22: Gazelle - Plack Handler for performance freaks #yokohamapm

writev(2)

plackup -s Gazelle -e 'sub{[200,["Content-Type"=>"text/plain"],

["xxx","xxx","yyy","yyy","zzzz","\n"]]}'

writev(5, [{"HTTP/1.0 200 OK\r\nConnection: close\r\nServer: gazelle\r

\n", 53}, {"Content-Type", 12}, {": ", 2}, {"text/plain", 10}, {"\r\n",

2}, {"Date: Fri, 28 Nov 2014 04:38:08 GMT\r\n\r\n", 39}, {"xxx", 3},

{"xxx", 3}, {"yyy", 3}, {"yyy", 3}, {"zzzz", 4}, {"\n", 1}], 12) = 135

Page 23: Gazelle - Plack Handler for performance freaks #yokohamapm

高速なサーバを書くには

• write XS, minimize Perl code

• reduce system calls

• Zero Copy

Page 24: Gazelle - Plack Handler for performance freaks #yokohamapm

高速なAppサーバって必要なの?

• ISUCON :)

• Social Games, AdTech, SNS

• High optimized applications

• few msec ~ few tens of msec

• Several hundreds of request/sec/host

• 1PVあたりの利益が小さいサービス

Page 25: Gazelle - Plack Handler for performance freaks #yokohamapm

Gazelleの実績

• livedoor Blog

• 2500万req/day/host

• Starletからの移行でCPU使用率1%~3%さがった

Page 26: Gazelle - Plack Handler for performance freaks #yokohamapm

ぜひお使い下さい

https://www.!ickr.com/photos/superformosa/9057428400/