Why Events Are A Bad Idea (for high-concurrency servers)

25
Why Events Are A Bad Idea (for high-concurrency servers) Rob von Behren, Jeremy Condit and Eric Brewer University of California at Berkeley {jrvb,jcondit,brewer}@cs.berkeley.ed u http://capriccio.cs.berkeley.edu

description

Why Events Are A Bad Idea (for high-concurrency servers). Rob von Behren, Jeremy Condit and Eric Brewer University of California at Berkeley {jrvb,jcondit,brewer}@cs.berkeley.edu http://capriccio.cs.berkeley.edu. The Stage. Highly concurrent applications - PowerPoint PPT Presentation

Transcript of Why Events Are A Bad Idea (for high-concurrency servers)

Page 1: Why Events Are A Bad Idea (for high-concurrency servers)

Why Events Are A Bad Idea

(for high-concurrency servers)

Rob von Behren, Jeremy Condit and Eric Brewer

University of California at Berkeley{jrvb,jcondit,brewer}@cs.berkeley.edu

http://capriccio.cs.berkeley.edu

Page 2: Why Events Are A Bad Idea (for high-concurrency servers)

The Stage Highly concurrent applications

Internet servers (Flash, Ninja, SEDA)

Transaction processing databases Workload

Operate “near the knee” Avoid thrashing!

What makes concurrency hard? Race conditions Scalability (no O(n) operations) Scheduling & resource sensitivity Inevitable overload Code complexity

Ideal

Peak: some resource at max

Overload: someresource thrashing

Load (concurrent tasks)Perf

orm

anc

e

Page 3: Why Events Are A Bad Idea (for high-concurrency servers)

The Debate Performance vs.

Programmability Current threads pick one Events somewhat better

Questions Threads vs. Events? How do we performance and

programmability?

PerformanceEase

of

Pro

gra

mm

ing Current

Threads

Current Threads

Current Events

Ideal

Page 4: Why Events Are A Bad Idea (for high-concurrency servers)

Our Position Thread-event duality still holds But threads are better anyway

More natural to program Better fit with tools and hardware

Compiler-runtime integration is key

Page 5: Why Events Are A Bad Idea (for high-concurrency servers)

The Duality Argument General assumption: follow “good practices” Observations

Major concepts are analogous Program structure is similar Performance should be similar

Given good implementations!

Threads Events Monitors Exported functions Call/return and fork/join Wait on condition variable

Event handler & queue Events accepted Send message / await reply Wait for new messages

AcceptConn.

WriteResponse

ReadFile

ReadRequest

PinCache

Web Server

Exit

Page 6: Why Events Are A Bad Idea (for high-concurrency servers)

The Duality Argument General assumption: follow “good practices” Observations

Major concepts are analogous Program structure is similar Performance should be similar

Given good implementations!

Threads Events Monitors Exported functions Call/return and fork/join Wait on condition variable

Event handler & queue Events accepted Send message / await reply Wait for new messages

AcceptConn.

WriteResponse

ReadFile

ReadRequest

PinCache

Web Server

Exit

Page 7: Why Events Are A Bad Idea (for high-concurrency servers)

The Duality Argument General assumption: follow “good practices” Observations

Major concepts are analogous Program structure is similar Performance should be similar

Given good implementations!

Threads Events Monitors Exported functions Call/return and fork/join Wait on condition variable

Event handler & queue Events accepted Send message / await reply Wait for new messages

AcceptConn.

WriteResponse

ReadFile

ReadRequest

PinCache

Web Server

Exit

Page 8: Why Events Are A Bad Idea (for high-concurrency servers)

“But Events Are Better!” Recent arguments for events

Lower runtime overhead Better live state management Inexpensive synchronization More flexible control flow Better scheduling and locality

All true but… No inherent problem with threads! Thread implementations can be improved

Page 9: Why Events Are A Bad Idea (for high-concurrency servers)

Runtime Overhead Criticism: Threads don’t

perform well for high concurrency

Response Avoid O(n) operations Minimize context switch overhead

Simple scalability test Slightly modified GNU Pth Thread-per-task vs.

single thread Same performance!

Requ

ests

/ Sec

ond

Concurrent Tasks

Event-Based Server

Threaded Server

20000

30000

40000

50000

60000

70000

80000

90000

100000

110000

1 10 100 1000 10000 100000 1e+06

Page 10: Why Events Are A Bad Idea (for high-concurrency servers)

Live State Management Criticism: Stacks are bad for live

state Response

Fix with compiler help Stack overflow vs. wasted space

Dynamically link stack frames Retain dead state

Static lifetime analysis Plan arrangement of stack Put some data on heap Pop stack before tail calls

Encourage inefficiency Warn about inefficiency

Live

Live

Dead

Unused

Thread State (stack)

Event State (heap)

Page 11: Why Events Are A Bad Idea (for high-concurrency servers)

Synchronization Criticism: Thread synchronization is

heavyweight Response

Cooperative multitasking works for threads, too! Also presents same problems

Starvation & fairness Multiprocessors Unexpected blocking (page faults, etc.)

Compiler support helps

Page 12: Why Events Are A Bad Idea (for high-concurrency servers)

Control Flow Criticism: Threads have

restricted control flow Response

Programmers use simple patterns Call / return Parallel calls Pipelines

Complicated patterns are unnatural

Hard to understand Likely to cause bugs

Page 13: Why Events Are A Bad Idea (for high-concurrency servers)

Scheduling

Task

Pro

gra

m

Loca

tion

Criticism: Thread schedulers are too generic

Can’t use application-specific information Response

2D scheduling: task & program location Threads schedule based on task only Events schedule by location (e.g. SEDA)

Allows batching Allows prediction for SRCT

Threads can use 2D, too! Runtime system tracks current location Call graph allows prediction

Page 14: Why Events Are A Bad Idea (for high-concurrency servers)

Scheduling

Task

Pro

gra

m

Loca

tion

Threads

Criticism: Thread schedulers are too generic

Can’t use application-specific information Response

2D scheduling: task & program location Threads schedule based on task only Events schedule by location (e.g. SEDA)

Allows batching Allows prediction for SRCT

Threads can use 2D, too! Runtime system tracks current location Call graph allows prediction

Page 15: Why Events Are A Bad Idea (for high-concurrency servers)

Scheduling Criticism: Thread schedulers are too

generic Can’t use application-specific information

Response 2D scheduling: task & program location

Threads schedule based on task only Events schedule by location (e.g. SEDA)

Allows batching Allows prediction for SRCT

Threads can use 2D, too! Runtime system tracks current location Call graph allows prediction

Task

Pro

gra

m

Loca

tion

Threads

Events

Page 16: Why Events Are A Bad Idea (for high-concurrency servers)

The Proof’s in the Pudding User-level threads package

Subset of pthreads Intercept blocking system calls No O(n) operations Support > 100K threads 5000 lines of C code

Simple web server: Knot 700 lines of C code

Similar performance Linear increase, then steady Drop-off due to poll()

overhead

0

100

200

300

400

500

600

700

800

900

1 4 16 64 256 1024 4096 16384

KnotC (Favor Connections)KnotA (Favor Accept)

Haboob

Concurrent Clients

Mbit

s /

seco

nd

Page 17: Why Events Are A Bad Idea (for high-concurrency servers)

Our Big But… More natural programming model

Control flow is more apparent Exception handling is easier State management is automatic

Better fit with current tools & hardware Better existing infrastructure Allows better performance?

Page 18: Why Events Are A Bad Idea (for high-concurrency servers)

Control Flow Events obscure control flow

For programmers and tools

Threads Eventsthread_main(int sock) { struct session s; accept_conn(sock, &s); read_request(&s); pin_cache(&s); write_response(&s); unpin(&s);}

pin_cache(struct session *s) { pin(&s); if( !in_cache(&s) ) read_file(&s);}

AcceptHandler(event e) { struct session *s = new_session(e); RequestHandler.enqueue(s);}RequestHandler(struct session *s) { …; CacheHandler.enqueue(s);}CacheHandler(struct session *s) { pin(s); if( !in_cache(s) ) ReadFileHandler.enqueue(s); else ResponseHandler.enqueue(s);}. . . ExitHandlerr(struct session *s) { …; unpin(&s); free_session(s); }

AcceptConn.

WriteResponse

ReadFile

ReadRequest

PinCache

Web Server

Exit

Page 19: Why Events Are A Bad Idea (for high-concurrency servers)

Control Flow

AcceptConn.

WriteResponse

ReadFile

ReadRequest

PinCache

Web Server

Exit

Threads Eventsthread_main(int sock) { struct session s; accept_conn(sock, &s); read_request(&s); pin_cache(&s); write_response(&s); unpin(&s);}

pin_cache(struct session *s) { pin(&s); if( !in_cache(&s) ) read_file(&s);}

CacheHandler(struct session *s) { pin(s); if( !in_cache(s) ) ReadFileHandler.enqueue(s); else ResponseHandler.enqueue(s);}RequestHandler(struct session *s) { …; CacheHandler.enqueue(s);}. . . ExitHandlerr(struct session *s) { …; unpin(&s); free_session(s); }AcceptHandler(event e) { struct session *s = new_session(e); RequestHandler.enqueue(s); }

Events obscure control flow For programmers and tools

Page 20: Why Events Are A Bad Idea (for high-concurrency servers)

Exceptions Exceptions complicate control flow

Harder to understand program flow Cause bugs in cleanup code Accept

Conn.

WriteResponse

ReadFile

ReadRequest

PinCache

Web Server

Exit

Threads Eventsthread_main(int sock) { struct session s; accept_conn(sock, &s); if( !read_request(&s) ) return; pin_cache(&s); write_response(&s); unpin(&s);}

pin_cache(struct session *s) { pin(&s); if( !in_cache(&s) ) read_file(&s);}

CacheHandler(struct session *s) { pin(s); if( !in_cache(s) ) ReadFileHandler.enqueue(s); else ResponseHandler.enqueue(s);}RequestHandler(struct session *s) { …; if( error ) return; CacheHandler.enqueue(s);}. . . ExitHandlerr(struct session *s) { …; unpin(&s); free_session(s); }AcceptHandler(event e) { struct session *s = new_session(e); RequestHandler.enqueue(s); }

Page 21: Why Events Are A Bad Idea (for high-concurrency servers)

State Management

Threads Eventsthread_main(int sock) { struct session s; accept_conn(sock, &s); if( !read_request(&s) ) return; pin_cache(&s); write_response(&s); unpin(&s);}

pin_cache(struct session *s) { pin(&s); if( !in_cache(&s) ) read_file(&s);}

CacheHandler(struct session *s) { pin(s); if( !in_cache(s) ) ReadFileHandler.enqueue(s); else ResponseHandler.enqueue(s);}RequestHandler(struct session *s) { …; if( error ) return; CacheHandler.enqueue(s);}. . . ExitHandlerr(struct session *s) { …; unpin(&s); free_session(s); }AcceptHandler(event e) { struct session *s = new_session(e); RequestHandler.enqueue(s); }

AcceptConn.

WriteResponse

ReadFile

ReadRequest

PinCache

Web Server

Exit

Events require manual state management Hard to know when to free

Use GC or risk bugs

Page 22: Why Events Are A Bad Idea (for high-concurrency servers)

Existing Infrastructure Lots of infrastructure for threads

Debuggers Languages & compilers

Consequences More amenable to analysis Less effort to get working systems

Page 23: Why Events Are A Bad Idea (for high-concurrency servers)

Better Performance? Function pointers & dynamic dispatch

Limit compiler optimizations Hurt branch prediction & I-cache locality

More context switches with events? Example: Haboob does 6x more than Knot Natural result of queues

More investigation needed!

Page 24: Why Events Are A Bad Idea (for high-concurrency servers)

The Future:Compiler-Runtime Integration

Insight Automate things event programmers do by hand Additional analysis for other things

Specific targets Dynamic stack growth* Live state management Synchronization Scheduling*

Improve performance and decrease complexity

* Working prototype in threads package

Page 25: Why Events Are A Bad Idea (for high-concurrency servers)

Conclusion Threads Events

Performance Expressiveness

Threads > Events Complexity / Manageability

Performance and Ease of use? Compiler-runtime integration is key

PerformanceEase

of

Pro

gra

mm

ing Current

Threads

Current Threads

Current Events

New Threads?