How to build a High Performance PSGI/Plack Server

134
How to build a High Performance PSGI/Plack Server PSGI/PlackMonocerosで学ぶ ハイパフォーマンス Webアプリケーションサーバの作り方 YAPC::Asia 2013 Tokyo Masahiro Nagano / @kazeburo

description

How to build a High Performance PSGI/Plack Server PSGI/Plack・Monocerosで学ぶ ハイパフォーマンス Webアプリケーションサーバの作り方

Transcript of How to build a High Performance PSGI/Plack Server

Page 1: How to build a High Performance PSGI/Plack Server

How to build a High Performance PSGI/Plack Server

PSGI/Plack・Monocerosで学ぶハイパフォーマンス

Webアプリケーションサーバの作り方

YAPC::Asia 2013 TokyoMasahiro Nagano / @kazeburo

Page 2: How to build a High Performance PSGI/Plack Server

Me• 長野雅広 Masahiro Nagano

• @kazeburo

• PAUSE:KAZEBURO

• Operations Engineer, Site Reliability

• LINE Corp. Development support LINE Family, livedoor

Page 3: How to build a High Performance PSGI/Plack Server

livedoorBlogOne of the largest Blog Hosting Service in Japan

Page 4: How to build a High Performance PSGI/Plack Server

livedoorBlog uses

Page 5: How to build a High Performance PSGI/Plack Server

Perl (5.16 and 5.8)

Page 6: How to build a High Performance PSGI/Plack Server

Carton

Page 7: How to build a High Performance PSGI/Plack Server

Plack/PSGI and mod_perl

Page 8: How to build a High Performance PSGI/Plack Server

$ curl -I http://blog.livedoor.jp/staff/| grep Server

Server: Plack::Handler::Starlet

Page 9: How to build a High Performance PSGI/Plack Server

Starlet handles1 Billion(10億) reqs/day

Page 10: How to build a High Performance PSGI/Plack Server

To get over this burst traffic,

We need to improvePerformance

across all layersこの負荷を乗り切るために様々なレイヤーで最適化をしています

Page 11: How to build a High Performance PSGI/Plack Server

Layers

Hardware / Network

OS

App Server

Routing

Cache Logic

SQL

Template Engine

RDBMS

Cached Web Server

Page 12: How to build a High Performance PSGI/Plack Server

Hardware / Network

OS

Routing

Cache Logic

SQL

Template Engine

RDBMS

Cached Web Server

Today’s Topic

Page 13: How to build a High Performance PSGI/Plack Server

Hardware / Network

OS

Routing

Cache Logic

SQL

Template Engine

RDBMS

Cached Web Server

Today’s Topic

App Server

Page 14: How to build a High Performance PSGI/Plack Server

By the way..

Page 15: How to build a High Performance PSGI/Plack Server

“Open & Share”is our driver

for excellence.And LOVE CPAN/OSS

Open & Share は私たちの目指すところです。CPAN/OSSを多く使い、また貢献もしています

Page 16: How to build a High Performance PSGI/Plack Server

Improving Performance of livedoorBlog

directly linkedPerformance of Plack/Starlet

on CPAN

livedoorBlogのパフォーマンス改善で行った事はCPAN上のPlack/Starletにも当然影響してきます

Page 17: How to build a High Performance PSGI/Plack Server

0

3500

7000

10500

14000 13083

6241

“Hello World” Reqs/Sec

Plack 1.0016 1.0029Starlet 0.16 0.20

2013/02 2013/09

mod_perl era plack era

Page 18: How to build a High Performance PSGI/Plack Server

Monoceros

Page 19: How to build a High Performance PSGI/Plack Server

Monoceros isa yet another

Plack/PSGI Serverfor Performance

Page 20: How to build a High Performance PSGI/Plack Server

the Goal

Page 21: How to build a High Performance PSGI/Plack Server

Reduce TCP 3way hand shake

betweenProxy and PSGI Server

Page 22: How to build a High Performance PSGI/Plack Server

ReverseProxy

AppServer

GET / HTTP/1.1Host: example.com

SYNACK

SYN+ACK

HTTP/1.1 200 OKContent-Type: text/html

FINACK

GET /favicon.ico HTTP/1.1Host: example.com

SYNACK

SYN+ACK

HTTP/1.1 404 NOT FOUNDContent-Type: text/html

FINACK

Page 23: How to build a High Performance PSGI/Plack Server

HTTP/1.0-1.1 have KeepAlive

Page 24: How to build a High Performance PSGI/Plack Server

ReverseProxy

AppServer

GET / HTTP/1.0Host: example.comConnection: keep-alive

SYNACK

SYN+ACK

HTTP/1.0 200 OKContent-Type: text/htmlConnection: keep-alive

Content-Length: 941

GET /favicon.ico HTTP/1.1Host: example.com

HTTP/1.1 200 OKContent-Type: image/vnd.microsoft.icon

Transfer-Encoding: chunked

GET /site.css HTTP/1.1Host: example.com

HTTP/1.1 200 OKContent-Type: text/css

Content-Length: 1013

Page 25: How to build a High Performance PSGI/Plack Server

C10K problem

Page 26: How to build a High Performance PSGI/Plack Server

nginx

C10KReadyReverseProxy

nginx

nginx

StarletStarman

AppServer

KeepAlive Req

KeepAlive Req

KeepAlive Req

Page 27: How to build a High Performance PSGI/Plack Server

Starman, Starlet’sPreforking model requires1 connection per 1 process

By defaultStarman: 5 procs Starlet: 10 procs

Page 28: How to build a High Performance PSGI/Plack Server

Monoceros adoptsPreforking model,

But C10K ready

Page 29: How to build a High Performance PSGI/Plack Server

WorkerProcess

WorkerProcess

WorkerProcess

WorkerProcess

ManagerProcess

SOCK

Client

GET / HTTP/1.1Host: example.com

200 OKContent-Type: text/html

Page 30: How to build a High Performance PSGI/Plack Server

WorkerProcess

WorkerProcess

WorkerProcess

WorkerProcess

ManagerProcess

SOCK

Client

GET / HTTP/1.1Host: example.com

200 OKContent-Type: text/html

Page 31: How to build a High Performance PSGI/Plack Server

WorkerProcess

WorkerProcess

WorkerProcess

WorkerProcess

ManagerProcess

SOCK

Client

GET / HTTP/1.1Host: example.com

200 OKContent-Type: text/html

GET / HTTP/1.1Host: example.com

Event Driven

Page 32: How to build a High Performance PSGI/Plack Server

WorkerProcess

WorkerProcess

WorkerProcess

WorkerProcess

ManagerProcess

SOCK

Client

GET / HTTP/1.1Host: example.com

200 OKContent-Type: text/html

GET / HTTP/1.1Host: example.com

200 OKContent-Type: text/html

Event Driven

Page 33: How to build a High Performance PSGI/Plack Server

Monoceros Workersthat inherits “Starlet”

not C10K ready

Page 34: How to build a High Performance PSGI/Plack Server

Event DrivenManager Process

C10K readybuilt with AnyEvent

Page 35: How to build a High Performance PSGI/Plack Server

KeepAlive Benchmarklike a Browser

1) connect2) do requests certain number

3) leave alone a socket4) timeout and close

Page 36: How to build a High Performance PSGI/Plack Server

250 conn / 200 reqs

Starlet Monoceros

Total time (sec) 54.51 8.74

Failed reqs 971 0

Page 37: How to build a High Performance PSGI/Plack Server

Plack/PSGI Basics

Page 38: How to build a High Performance PSGI/Plack Server

PSGI = speci"cationPlack = implementation

Page 39: How to build a High Performance PSGI/Plack Server

PSGI Interface

my $app = sub { my $env = shift; ... return [200, [‘Content-Type’ => ‘text/html’], [‘Hello World’] ];};

Page 40: How to build a High Performance PSGI/Plack Server

PSGI environment hash

* CGI keys REQUEST_METHOD,SCRIPT_NAME, PATH_INFO,REQUEST_URI, QUERY_STRING,SERVER_PROTOCOL,HTTP_*

* PSGI-specific keys psgi.version, psgi.url_scheme, psgi.input, psgi.errors, psgi.multiprocess, psgi.streaming psgi.nonblocking

$env->{...}

Page 41: How to build a High Performance PSGI/Plack Server

PSGI Response (1) ArrayRef

[200, #status code [ ‘Content-Type’ => ‘text/html’, ‘Content-Length => 10 ], [ ‘Hello’, ‘World’ ]];

Page 42: How to build a High Performance PSGI/Plack Server

PSGI Response (1’) arrayref+IO::Handle

open my $fh, ‘<’, ‘/path/icon.jpg’;

[200, [ ‘Content-Type’ => ‘image/jpeg’, ‘Content-Length => 123456789 ], $fh];

Page 43: How to build a High Performance PSGI/Plack Server

PSGI Response (2)Delayed and Streamingsub { my $env = shift; return sub { my $responder = shift; ... $responder->([ 200, $headers, [$body] ]); }};

Page 44: How to build a High Performance PSGI/Plack Server

PSGI Response (2’)Delayed and Streamingreturn sub { my $responder = shift; my $writer = $responder->([200, $headers]); wait_for_events(sub { my $new_event = shift; if ($new_event) { $writer->write($new_event->as_json . "\n"); } else { $writer->close; } });};

Page 45: How to build a High Performance PSGI/Plack Server

Role of “PSGI Server”

Page 46: How to build a High Performance PSGI/Plack Server

PSGI Server“A PSGI Server is a Perl program

providing an environment for a PSGI application to run in”

Page 47: How to build a High Performance PSGI/Plack Server

PSGIServer

App$env

$res

Apache

Nginx

Apache

ProxyBrowser

CGI

mod_perl

FCGI

HTTP

Perl direct

Page 48: How to build a High Performance PSGI/Plack Server

PSGI Serveris called

“Plack Handler”

Page 49: How to build a High Performance PSGI/Plack Server

Plack HandlerAdaptor interface Plack and PSGI Server.

Make PSGI Server to runwith “plackup”

Page 50: How to build a High Performance PSGI/Plack Server

e.g. Starman

Starman::Server= PSGI Server

Plack::Handler::Starman= Plack Handler

Page 51: How to build a High Performance PSGI/Plack Server

Make

PSGI/PlackServer

a High Performance

Page 52: How to build a High Performance PSGI/Plack Server

Tiny StandalonePSGI Web Server

Page 53: How to build a High Performance PSGI/Plack Server

my $null_io = do { open my $io, "<", \""; $io };

my $app = sub { my $env = shift return [200,['Content-Type'=>'text/html'],['Hello','World',"\n"]];};

my $listen = IO::Socket::INET->new( Listen => 5, LocalAddr => 'localhost', LocalPort => 5000, ReuseAddr => 1,);

while ( my $conn = $listen->accept ) { my $env = { SERVER_PORT => '5000', SERVER_NAME => 'localhost', SCRIPT_NAME => '', REMOTE_ADDR => $conn->peerhost, 'psgi.version' => [ 1, 1 ], 'psgi.errors' => *STDERR, 'psgi.url_scheme' => 'http', 'psgi.run_once' => Plack::Util::FALSE, 'psgi.multithread' => Plack::Util::FALSE, 'psgi.multiprocess' => Plack::Util::FALSE, 'psgi.streaming' => Plack::Util::FALSE, 'psgi.nonblocking' => Plack::Util::FALSE, 'psgi.input' => $null_io, }; $conn->sysread( my $buf, 4096); my $reqlen = Plack::HTTPParser::parse_http_request($buf, $env);

my $res = Plack::Util::run_app $app, $env;

my @lines = ("HTTP/1.1 $res->[0] @{[ status_message($res->[0]) ]}\015\012"); for (my $i = 0; $i < @{$res->[1]}; $i += 2) { next if $res->[1][$i] eq 'Connection'; push @lines, "$res->[1][$i]: $res->[1][$i + 1]\015\012"; } push @lines, "Connection: close\015\12\015\12";

$conn->syswrite(join "",@lines); Plack::Util::foreach($res->[2], sub { $conn->syswrite(shift); }); $conn->close;}

60 lines

Page 54: How to build a High Performance PSGI/Plack Server

Listen and Accept

Page 55: How to build a High Performance PSGI/Plack Server

my $listen = IO::Socket::INET->new( Listen => 5, LocalAddr => 'localhost', LocalPort => 5000, ReuseAddr => 1,);

while ( my $conn = $listen->accept ) { ...}

Page 56: How to build a High Performance PSGI/Plack Server

Read a request

Page 57: How to build a High Performance PSGI/Plack Server

use Plack::HTTPParser qw/parse_http_request/;my $null_io = do { open my $io, "<", \""; $io };

while ( my $conn = $listen->accept ) {

my $env = { SERVER_PORT => '5000', SERVER_NAME => 'localhost', SCRIPT_NAME => '', REMOTE_ADDR => $conn->peerhost, 'psgi.version' => [ 1, 1 ], 'psgi.errors' => *STDERR, 'psgi.url_scheme' => 'http', 'psgi.multiprocess' => Plack::Util::FALSE, 'psgi.streaming' => Plack::Util::FALSE, 'psgi.nonblocking' => Plack::Util::FALSE, 'psgi.input' => $null_io, };

$conn->sysread(my $buf, 4096); my $reqlen = parse_http_request($buf, $env);

Page 58: How to build a High Performance PSGI/Plack Server

Run App

Page 59: How to build a High Performance PSGI/Plack Server

my $res = $app->($env);

or

my $res = Plack::Util::run_app $app, $env;

Page 60: How to build a High Performance PSGI/Plack Server

Write a response

Page 61: How to build a High Performance PSGI/Plack Server

use HTTP::Status qw/status_message/;

my $res = ..

my @lines = ("HTTP/1.1 $res->[0] \ @{[ status_message($res->[0]) ]}\015\012");

for (my $i = 0; $i < @{$res->[1]}; $i += 2) { next if $res->[1][$i] eq 'Connection'; push @lines, "$res->[1][$i]: $res->[1][$i + 1]\015\012";}push @lines, "Connection: close\015\12\015\12";

$conn->syswrite(join "",@lines);

foreach my $buf ( @{$res->[2]} ) { $conn->syswrite($buf);});

$conn->close;

Page 62: How to build a High Performance PSGI/Plack Server

This PSGI Serverhas some problem

* handle only one at once* no timeout

* may not fast

Page 63: How to build a High Performance PSGI/Plack Server

Increase concurrency

Page 64: How to build a High Performance PSGI/Plack Server

Multi ProcessIO Multiplexing

orBoth

Page 65: How to build a High Performance PSGI/Plack Server

Preforking modelSimple, Scaling

Page 66: How to build a High Performance PSGI/Plack Server

Manager

Page 67: How to build a High Performance PSGI/Plack Server

Manager

bind

listen

Page 68: How to build a High Performance PSGI/Plack Server

Worker

accept

Worker

accept

Worker

accept

Worker

accept

Manager

bind

listen

fork fork fork fork

Page 69: How to build a High Performance PSGI/Plack Server

Worker

accept

Worker

accept

Worker

accept

Worker

accept

Manager

bind

listen

fork fork fork fork

Client Client ClientClient

Page 70: How to build a High Performance PSGI/Plack Server

use Parallel::Prefork;

my $listen = IO::Socket::INET->new( Listen => 5, LocalAddr => 'localhost', LocalPort => 5000, ReuseAddr => 1,);

my $pm = Parallel::Prefork->new({ max_workers => 5, trap_signals => { TERM => 'TERM', HUP => 'TERM', }});

while ( $pm->signal_received ne 'TERM') { $pm->start(sub{ while ( my $conn = $listen->accept ) { my $env = {..}

Page 71: How to build a High Performance PSGI/Plack Server

NO Accept Serialization

Page 72: How to build a High Performance PSGI/Plack Server

os/kernel

Worker

accept

Worker

accept

Worker

accept

Worker

accept

Manager

bind

listen

Zzz.. Zzz.. Zzz.. Zzz..

Page 73: How to build a High Performance PSGI/Plack Server

os/kernel

Worker

accept

Worker

accept

Worker

accept

Worker

accept

Client

Manager

bind

listen

Zzz.. Zzz.. Zzz.. Zzz..

Page 74: How to build a High Performance PSGI/Plack Server

os/kernel

Worker

accept

Worker

accept

Worker

accept

Worker

accept

Client

Manager

bind

listen

Zzz.. Zzz.. Zzz.. Zzz..

Page 75: How to build a High Performance PSGI/Plack Server

os/kernel

Worker

accept

Worker

accept

Worker

accept

Worker

accept

Client

Manager

bind

listen

Thundering Herd突然の負荷

WakeUp WakeUp WakeUp WakeUP

Page 76: How to build a High Performance PSGI/Plack Server

os/kernel

Worker

accept

Worker

accept

Worker

accept

Worker

accept

Client

Manager

bind

listen

Thundering Herd突然の負荷

WakeUp WakeUp WakeUp WakeUP

Page 77: How to build a High Performance PSGI/Plack Server

Thundering Herdis an old story

Page 78: How to build a High Performance PSGI/Plack Server

Worker

accept

Worker

accept

Worker WorkerManager

bind

listen accept accept

Client

Zzz.. Zzz.. Zzz..Zzz..

Page 79: How to build a High Performance PSGI/Plack Server

Worker

accept

Worker

accept

Worker WorkerManager

bind

listen accept accept

Client

Zzz.. Zzz.. Zzz..Zzz..

Page 80: How to build a High Performance PSGI/Plack Server

Worker

accept

Worker

accept

Worker WorkerManager

bind

listen accept accept

Client

modern os/kernel

Zzz.. Zzz.. Zzz..Zzz..

Page 81: How to build a High Performance PSGI/Plack Server

Worker

accept

Worker

accept

Worker WorkerManager

bind

listen accept accept

Client

modern os/kernel

Zzz.. Zzz.. Zzz..Zzz..

Page 82: How to build a High Performance PSGI/Plack Server

Worker

accept

Worker

accept

Worker WorkerManager

bind

listen accept accept

Client

modern os/kernel

Zzz.. Zzz..Zzz..WakeUp

Page 83: How to build a High Performance PSGI/Plack Server

NO Accept Serialization(except for multiple interface)

Page 84: How to build a High Performance PSGI/Plack Server

TCP_DEFER_ACCEPT

Page 85: How to build a High Performance PSGI/Plack Server

Wake up a process when DATA arrived

not established

コネクションが完了したタイミングではなく、データが到着した段階でプロセスを起こします

Page 86: How to build a High Performance PSGI/Plack Server

clientA

clientB

GET / HTTP/1.0Host: example.comConnection: keep-alive

SYNACK

SYN+ACK

SYNACK

SYN+ACK

GET / HTTP/1.0Host: example.comConnection: keep-alive

default defer_accept

Accept

RunApp

blockto

read

Page 87: How to build a High Performance PSGI/Plack Server

RunApp

clientA

clientB

GET / HTTP/1.0Host: example.comConnection: keep-alive

SYNACK

SYN+ACK

SYNACK

SYN+ACK

GET / HTTP/1.0Host: example.comConnection: keep-alive

default defer_accept

Accept

RunApp

Accept

blockto

read

Page 88: How to build a High Performance PSGI/Plack Server

RunApp

clientA

clientB

GET / HTTP/1.0Host: example.comConnection: keep-alive

SYNACK

SYN+ACK

SYNACK

SYN+ACK

GET / HTTP/1.0Host: example.comConnection: keep-alive

default defer_accept

Accept

RunApp

Accept

blockto

read

idle

Page 89: How to build a High Performance PSGI/Plack Server

RunApp

clientA

clientB

GET / HTTP/1.0Host: example.comConnection: keep-alive

SYNACK

SYN+ACK

SYNACK

SYN+ACK

GET / HTTP/1.0Host: example.comConnection: keep-alive

default defer_accept

Accept

RunApp

Accept

RunApp

Accept

RunApp

Accept

blockto

read

idle

Page 90: How to build a High Performance PSGI/Plack Server

use Socket qw(IPPROTO_TCP);

my $listen = IO::Socket::INET->new( Listen => 5, LocalAddr => 'localhost', LocalPort => 5000, ReuseAddr => 1,);

if ($^O eq 'linux') { setsockopt($listen, IPPROTO_TCP, 9, 1);}

Page 91: How to build a High Performance PSGI/Plack Server

timeout to read header

Page 92: How to build a High Performance PSGI/Plack Server

alarm

Page 93: How to build a High Performance PSGI/Plack Server

my $READ_TIMEOUT = 5;

eval { local $SIG{ALRM} = sub { die "Timed out\n"; }; alarm( $READ_TIMEOUT ); $conn->sysread(my $buf, 4096);};alarm(0);

next if ( $@ && $@ =~ /Timed out/ );

my $reqlen = parse_http_request($buf, $env);

Page 94: How to build a High Performance PSGI/Plack Server

nonblocking + select

Page 95: How to build a High Performance PSGI/Plack Server

use IO::Select;my $READ_TIMEOUT = 5;

while( my $conn = $listen->accept ) {

$conn->blocking(0);

my $select = IO::Select->new($conn); my @ready = $select->can_read($READ_TIMEOUT); next unless @ready;

$conn->sysread($buf, 4096);

my $reqlen = parse_http_request($buf, $env);

Page 96: How to build a High Performance PSGI/Plack Server

alarmvs.

nonblocking + select

Page 97: How to build a High Performance PSGI/Plack Server

Fewer syscalls is good

Page 98: How to build a High Performance PSGI/Plack Server

Hardwares

User Application

OS/Kernel

system callslisten,fork, accept, read, write, select, alarm

Worker Worker Worker Worker Worker

Page 99: How to build a High Performance PSGI/Plack Server

alarm

Page 100: How to build a High Performance PSGI/Plack Server

rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0rt_sigaction(SIGALRM, {0x47e5b0, [], SA_RESTORER, 0x7ff7d6e0cba0}, {SIG_DFL, [], SA_RESTORER, 0x7ff7d6e0cba0}, 8) = 0rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0alarm(5) = 0read(7, "GET / HTTP/1.1\r\nUser-Agent: curl"..., 65536) = 155rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0rt_sigaction(SIGALRM, {SIG_DFL, [], SA_RESTORER, 0x7ff7d6e0cba0}, {0x47e5b0, [], SA_RESTORER, 0x7ff7d6e0cba0}, 8) = 0rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0alarm(0) = 5 9 syscalls

Page 101: How to build a High Performance PSGI/Plack Server

non-blocking + select

Page 102: How to build a High Performance PSGI/Plack Server

fcntl(5, F_GETFL) = 0x2 (flags O_RDWR)fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 0select(8, [5], NULL, [5], {300, 0}) = 1 (in [5], left {299, 999897})read(5, "GET / HTTP/1.1\r\nUser-Agent: curl"..., 131072) = 155

4 syscalls

Page 103: How to build a High Performance PSGI/Plack Server

Parse a request with “C”

Page 104: How to build a High Performance PSGI/Plack Server

$ cpanm HTTP::Parser::XS

Plack::HTTPParser uses H::P::XS if installed

Page 105: How to build a High Performance PSGI/Plack Server

TCP_NODELAY

Page 106: How to build a High Performance PSGI/Plack Server

When data was writtenTCP packets does not

immediately send

“TCP uses Nagle's algorithm to collect small packets

for send all at once by default”

Page 107: How to build a High Performance PSGI/Plack Server

write(“foo”)

write(“bar”)

os/kernel networkinterfaceApplication

buffering

“foobar”

Page 108: How to build a High Performance PSGI/Plack Server

write(“foo”)

write(“bar”)

os/kernel networkinterfaceApplication

“foo”

TCP_NODELAY

“bar”

Page 109: How to build a High Performance PSGI/Plack Server

Take care of excessive fragmentation of TCP

packets

Page 110: How to build a High Performance PSGI/Plack Server

Write in oncejoin content in Server

Page 111: How to build a High Performance PSGI/Plack Server

my @lines = ("HTTP/1.1 $res->[0] @{[ status_message($res->[0]) ]}\015\012");

for (my $i = 0; $i < @{$res->[1]}; $i += 2) { next if $res->[1][$i] eq 'Connection'; push @lines, "$res->[1][$i]: $res->[1][$i + 1]\015\012";}push @lines, "Connection: close\015\12\015\12";

$conn->syswrite(join "",@lines, @{$res->[2]});

Page 112: How to build a High Performance PSGI/Plack Server

accept4, writev

Page 113: How to build a High Performance PSGI/Plack Server

Choose PSGI/Plack

Server

Page 114: How to build a High Performance PSGI/Plack Server

CPAN has manyPSGI Server &

Plack::Hanlder:**

Page 115: How to build a High Performance PSGI/Plack Server

Standalone(HTTP::Server::PSGI)

Default server for plackupSingle process Web Server

For development

Page 116: How to build a High Performance PSGI/Plack Server

Starman

Preforking Web ServerHTTP/1.1, HTTPS,

Multiple interfaces, unix-domain socket,

hot deploy using Server::Starter

Page 117: How to build a High Performance PSGI/Plack Server

Starlet

Preforking Web ServerHTTP/1.1(0.20~)

hot deploy using Server::StarterSimple and Fast

Page 118: How to build a High Performance PSGI/Plack Server

Monoceros

C10K Ready Preforking Web ServerHTTP/1.1

hot deploy using Server::Starter

Page 119: How to build a High Performance PSGI/Plack Server

Twiggy

based on AnyEventnonblocking, streaming

Single Process

Page 120: How to build a High Performance PSGI/Plack Server

Twiggy::Prefork

based on Twiggy and Parallel::Prefork

nonblocking, streamingMulti Process

hot deploy using Server::Starter

Page 121: How to build a High Performance PSGI/Plack Server

Feersum

Web server based on EV/libevnonblocking, streaming

Single/Multi Process

Page 122: How to build a High Performance PSGI/Plack Server

How to choosePSGI Server

Page 123: How to build a High Performance PSGI/Plack Server

SingleProcess

MultiProcess

CPU Intensive -Starlet

StarmanMonoceros

RequiresEvent Driven

TwiggyFeersum

Twiggy::PreforkFeersumTy

pe o

f Web

App

licat

ion

Page 124: How to build a High Performance PSGI/Plack Server

Finding Bottlenecks of Performance

Page 125: How to build a High Performance PSGI/Plack Server

use Devel::NYTProf

Page 126: How to build a High Performance PSGI/Plack Server
Page 127: How to build a High Performance PSGI/Plack Server

Flame Graph is awesome

Pro"le nytprof.out.{PID}for preforking server

$ nytprofhtml -f nytprof.out.1210$ open nytprof/index.html

Page 128: How to build a High Performance PSGI/Plack Server

use strace or dtrusstrace syscalls

Page 129: How to build a High Performance PSGI/Plack Server

$ strace -tt -s 200 -p {pid} \ 2>&1 | tee /tmp/trace.txt

Page 130: How to build a High Performance PSGI/Plack Server

Process 30929 attached - interrupt to quit16:13:46.826828 accept(4, {sa_family=AF_INET, sin_port=htons(43783), sin_addr=inet_addr("127.0.0.1")}, [16]) = 516:13:48.916233 ioctl(5, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff2fb61730) = -1 EINVAL (Invalid argument)16:13:48.916392 lseek(5, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)16:13:48.916493 ioctl(5, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff2fb61730) = -1 EINVAL (Invalid argument)16:13:48.916573 lseek(5, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)16:13:48.916661 fcntl(5, F_SETFD, FD_CLOEXEC) = 016:13:48.916873 fcntl(5, F_GETFL) = 0x2 (flags O_RDWR)16:13:48.916959 fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 016:13:48.917095 setsockopt(5, SOL_TCP, TCP_NODELAY, [1], 4) = 016:13:48.917362 read(5, "GET / HTTP/1.0\r\nHost: 127.0.0.1:5005\r\nUser-Agent: ApacheBench/2.3\r\nAccept: */*\r\n\r\n", 131072) = 8216:13:48.917613 brk(0x1e8e000) = 0x1e8e00016:13:48.917746 gettimeofday({1379402028, 917802}, NULL) = 016:13:48.917953 write(5, "HTTP/1.1 200 OK\r\nDate: Tue, 17 Sep 2013 07:13:48 GMT\r\nServer: Plack::Handler::Starlet\r\nContent-Type: html\r\nConnection: close\r\n\r\nhello", 133) = 13316:13:48.918187 close(5) = 016:13:48.918428 accept(4, {sa_family=AF_INET, sin_port=htons(43793), sin_addr=inet_addr("127.0.0.1")}, [16]) = 516:13:48.923736 ioctl(5, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff2fb61730) = -1 EINVAL (Invalid argument)16:13:48.923843 lseek(5, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)16:13:48.923924 ioctl(5, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff2fb61730) = -1 EINVAL (Invalid argument)16:13:48.924461 lseek(5, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)16:13:48.924600 fcntl(5, F_SETFD, FD_CLOEXEC) = 016:13:48.924762 fcntl(5, F_GETFL) = 0x2 (flags O_RDWR)16:13:48.924853 fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 016:13:48.924939 setsockopt(5, SOL_TCP, TCP_NODELAY, [1], 4) = 016:13:48.925162 read(5, "GET / HTTP/1.0\r\nHost: 127.0.0.1:5005\r\nUser-Agent: ApacheBench/2.3\r\nAccept: */*\r\n\r\n", 131072) = 8216:13:48.925445 gettimeofday({1379402028, 925494}, NULL) = 016:13:48.925629 write(5, "HTTP/1.1 200 OK\r\nDate: Tue, 17 Sep 2013 07:13:48 GMT\r\nServer: Plack::Handler::Starlet\r\nContent-Type: html\r\nConnection: close\r\n\r\nhello", 133) = 13316:13:48.925854 close(5) = 016:13:48.926084 accept(4, {sa_family=AF_INET, sin_port=htons(43803), sin_addr=inet_addr("127.0.0.1")}, [16]) = 516:13:48.930480 ioctl(5, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff2fb61730) = -1 EINVAL (Invalid argument)16:13:48.930626 lseek(5, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)16:13:48.930744 ioctl(5, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff2fb61730) = -1 EINVAL (Invalid argument)16:13:48.930838 lseek(5, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)16:13:48.930915 fcntl(5, F_SETFD, FD_CLOEXEC) = 016:13:48.931070 fcntl(5, F_GETFL) = 0x2 (flags O_RDWR)16:13:48.931170 fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 016:13:48.931383 setsockopt(5, SOL_TCP, TCP_NODELAY, [1], 4) = 016:13:48.931536 read(5, "GET / HTTP/1.0\r\nHost: 127.0.0.1:5005\r\nUser-Agent: ApacheBench/2.3\r\nAccept: */*\r\n\r\n", 131072) = 8216:13:48.931748 gettimeofday({1379402028, 931791}, NULL) = 016:13:48.931869 write(5, "HTTP/1.1 200 OK\r\nDate: Tue, 17 Sep 2013 07:13:48 GMT\r\nServer: Plack::Handler::Starlet\r\nContent-Type: html\r\nConnection: close\r\n\r\nhello", 133) = 13316:13:48.932078 close(5) = 016:13:48.932256 accept(4, {sa_family=AF_INET, sin_port=htons(43813), sin_addr=inet_addr("127.0.0.1")}, [16]) = 5

Page 131: How to build a High Performance PSGI/Plack Server

in conclusion

Page 132: How to build a High Performance PSGI/Plack Server

PSGI Server get Faster.

Page 133: How to build a High Performance PSGI/Plack Server

PSGI/Plack RocksStable, Fast

Found problems?RT, GitHub Issue, PullReqs

IRC #perl @kazeburo

Page 134: How to build a High Performance PSGI/Plack Server

#"n. Thank you!