Slide 1

Slide 1 text

Jeremy Mikola jmikola

Slide 2

Slide 2 text

Let’s make a web server

Slide 3

Slide 3 text

Node.js v a r h t t p = r e q u i r e ( ' h t t p ' ) ; v a r s e r v e r = n e w h t t p . S e r v e r ( ) ; s e r v e r . o n ( ' r e q u e s t ' , f u n c t i o n ( r e q , r e s ) { r e s . w r i t e H e a d ( 2 0 0 , { ' C o n t e n t - T y p e ' : ' t e x t / p l a i n ' } ) ; r e s . e n d ( ' H e l l o W o r l d ' ) ; } ) ; s e r v e r . l i s t e n ( 8 0 0 0 , ' 1 2 7 . 0 . 0 . 1 ' ) ;

Slide 4

Slide 4 text

Python f r o m t w i s t e d . i n t e r n e t i m p o r t r e a c t o r f r o m t w i s t e d . w e b . s e r v e r i m p o r t S i t e f r o m t w i s t e d . w e b . r e s o u r c e i m p o r t R e s o u r c e c l a s s H e l l o W o r l d P a g e ( R e s o u r c e ) : i s L e a f = T r u e d e f r e n d e r _ G E T ( s e l f , r e q u e s t ) : r e t u r n " H e l l o W o r l d " r e s o u r c e = H e l l o W o r l d P a g e ( ) f a c t o r y = S i t e ( r e s o u r c e ) r e a c t o r . l i s t e n T C P ( 8 0 0 0 , f a c t o r y ) r e a c t o r . r u n ( )

Slide 5

Slide 5 text

PHP $ s e r v e r = s t r e a m _ s o c k e t _ s e r v e r ( ' t c p : / / 1 2 7 . 0 . 0 . 1 : 8 0 0 0 ' ) ; w h i l e ( $ c o n n = s t r e a m _ s o c k e t _ a c c e p t ( $ s e r v e r , - 1 ) ) { f w r i t e ( $ c o n n , " H T T P / 1 . 1 2 0 0 O K \ r \ n " ) ; f w r i t e ( $ c o n n , " C o n t e n t - L e n g t h : 1 1 \ r \ n \ r \ n " ) ; f w r i t e ( $ c o n n , " H e l l o W o r l d " ) ; f c l o s e ( $ c o n n ) ; } What’s the difference?

Slide 6

Slide 6 text

Blocking IO - 1 Why is this a problem?

Slide 7

Slide 7 text

Blocking IO I O C P U I O C P U I O C P U

Slide 8

Slide 8 text

Common Latencies L 1 c a c h e r e f e r e n c e 0 . 5 n s B r a n c h m i s p r e d i c t 5 n s L 2 c a c h e r e f e r e n c e 7 n s M u t e x l o c k / u n l o c k 2 5 n s M a i n m e m o r y r e f e r e n c e 1 0 0 n s S e n d 1 K b y t e s o v e r 1 G b p s n e t w o r k 1 0 , 0 0 0 n s R e a d 4 K r a n d o m l y f r o m S S D 1 5 0 , 0 0 0 n s R e a d 1 M B s e q u e n t i a l l y f r o m m e m o r y 2 5 0 , 0 0 0 n s R o u n d t r i p w i t h i n s a m e d a t a c e n t e r 5 0 0 , 0 0 0 n s R e a d 1 M B s e q u e n t i a l l y f r o m S S D 1 , 0 0 0 , 0 0 0 n s D i s k s e e k 1 0 , 0 0 0 , 0 0 0 n s R e a d 1 M B s e q u e n t i a l l y f r o m d i s k 2 0 , 0 0 0 , 0 0 0 n s R o u n d t r i p f r o m U S t o E u r o p e 1 5 0 , 0 0 0 , 0 0 0 n s https://gist.github.com/jboner/2841832

Slide 9

Slide 9 text

Common Latencies S e n d 1 K b y t e s o v e r 1 G b p s n e t w o r k 1 0 , 0 0 0 n s R e a d 4 K r a n d o m l y f r o m S S D 1 5 0 , 0 0 0 n s R e a d 1 M B s e q u e n t i a l l y f r o m m e m o r y 2 5 0 , 0 0 0 n s R o u n d t r i p w i t h i n s a m e d a t a c e n t e r 5 0 0 , 0 0 0 n s R e a d 1 M B s e q u e n t i a l l y f r o m S S D 1 , 0 0 0 , 0 0 0 n s D i s k s e e k 1 0 , 0 0 0 , 0 0 0 n s R e a d 1 M B s e q u e n t i a l l y f r o m d i s k 2 0 , 0 0 0 , 0 0 0 n s R o u n d t r i p f r o m U S t o E u r o p e 1 5 0 , 0 0 0 , 0 0 0 n s https://gist.github.com/jboner/2841832

Slide 10

Slide 10 text

C10k Problem You can buy a 1000MHz machine with 2 gigabytes of RAM and an 1000Mbit/sec Ethernet card for $1200 or so. At 20000 clients, that’s 50KHz, 100Kbytes, and 50Kbits/sec per client. It shouldn’t take any more horsepower than that to take four kilobytes from the disk and send them to the network once a second for each of twenty thousand clients. So hardware is no longer the bottleneck. “ http://www.kegel.com/c10k.html

Slide 11

Slide 11 text

How can we solve this?

Slide 12

Slide 12 text

Threading I O C P U I O C P U I O C P U

Slide 13

Slide 13 text

Non-blocking IO I O C P U I O C P U I O C P U

Slide 14

Slide 14 text

Tools within PHP p t h r e a d s p o p e n ( ) p r o c _ o p e n ( ) p c n t l _ f o r k ( ) s o c k e t _ s e l e c t ( ) s t r e a m _ s e l e c t ( ) s t r e a m _ s e t _ b l o c k i n g ( ) c u r l _ m u l t i _ s e l e c t ( )

Slide 15

Slide 15 text

$ man 2 select S E L E C T ( 2 ) L i n u x P r o g r a m m e r ' s M a n u a l N A M E s e l e c t , p s e l e c t - s y n c h r o n o u s I / O m u l t i p l e x i n g S Y N O P S I S # i n c l u d e < s y s / s e l e c t . h > i n t s e l e c t ( i n t n f d s , f d _ s e t * r e a d f d s , f d _ s e t * w r i t e f d s , f d _ s e t * e x c e p t f d s , s t r u c t t i m e v a l * t i m e o u t ) ; i n t p s e l e c t ( i n t n f d s , f d _ s e t * r e a d f d s , f d _ s e t * w r i t e f d s , f d _ s e t * e x c e p t f d s , c o n s t s t r u c t t i m e s p e c * t i m e o u t , c o n s t s i g s e t _ t * s i g m a s k ) ; D E S C R I P T I O N s e l e c t ( ) a n d p s e l e c t ( ) a l l o w a p r o g r a m t o m o n i t o r m u l t i p l e f i l e d e s c r i p t o r s , w a i t i n g u n t i l o n e o r m o r e o f t h e f i l e d e s c r i p t o r s b e c o m e " r e a d y " f o r s o m e c l a s s o f I / O o p e r a t i o n ( e . g . , i n p u t p o s s i b l e ) . A f i l e d e s c r i p t o r i s c o n s i d e r e d r e a d y i f i t i s p o s s i b l e t o p e r f o r m t h e c o r r e s p o n d i n g I / O o p e r a t i o n ( e . g . , r e a d ( 2 ) ) w i t h o u t b l o c k i n g .

Slide 16

Slide 16 text

Polling IO $ r e a d a b l e = $ r e a d S t r e a m s ; $ w r i t a b l e = $ w r i t e S t r e a m s ; $ e x c e p t = n u l l ; i f ( s t r e a m _ s e l e c t ( $ r e a d a b l e , $ w r i t a b l e , $ e x c e p t , 1 ) ) { f o r e a c h ( $ r e a d a b l e a s $ s t r e a m ) { / / . . . } f o r e a c h ( $ w r i t a b l e a s $ s t r e a m ) { / / . . . } }

Slide 17

Slide 17 text

Event Loop Tracks timers and streams Each loop iteration is a "tick" Ticks execute timers and poll IO Polling timeout can be calculated No timers/streams ends loop

Slide 18

Slide 18 text

Event-driven, non-blocking I/O with PHP.

Slide 19

Slide 19 text

Hello World $ l o o p = R e a c t \ E v e n t L o o p \ F a c t o r y : : c r e a t e ( ) ; $ s o c k e t = n e w R e a c t \ S o c k e t \ S e r v e r ( $ l o o p ) ; $ h t t p = n e w R e a c t \ H t t p \ S e r v e r ( $ s o c k e t ) ; $ h t t p - > o n ( ' r e q u e s t ' , f u n c t i o n ( $ r e q , $ r e s ) { $ r e s - > w r i t e H e a d ( 2 0 0 , [ ' C o n t e n t - T y p e ' = > ' t e x t / p l a i n ' ] ) ; $ r e s - > e n d ( ' H e l l o W o r l d ' ) ; } ) ; $ s o c k e t - > l i s t e n ( 8 0 0 0 ) ; $ l o o p - > r u n ( ) ;

Slide 20

Slide 20 text

Reactor Pattern Resources Demultiplexer Dispatcher Request Handlers

Slide 21

Slide 21 text

React’s Stack D N o d e A R . D r o n e W h o i s S O C K S R e d i s W e b S o c k e t s S t o m p Ø M Q I R C D N S H t t p H t t p C l i e n t S o c k e t C h i l d P r o c e s s S t r e a m E v e n t L o o p E v e n t E m i t t e r

Slide 22

Slide 22 text

Event Loop Add/remove readable/writable streams Schedule run-once or periodic timers Multiple implementations StreamSelectLoop uses LibEventLoop uses extension LibEvLoop uses extension stream_select() libevent libev

Slide 23

Slide 23 text

Event Loop $ l o o p = R e a c t \ E v e n t L o o p \ F a c t o r y : : c r e a t e ( ) ; $ s e r v e r = s t r e a m _ s o c k e t _ s e r v e r ( ' t c p : / / 1 2 7 . 0 . 0 . 1 : 8 0 8 0 ' ) ; s t r e a m _ s e t _ b l o c k i n g ( $ s e r v e r , 0 ) ; $ l o o p - > a d d R e a d S t r e a m ( $ s e r v e r , f u n c t i o n ( $ s e r v e r ) u s e ( $ l o o p ) { $ c o n n = s t r e a m _ s o c k e t _ a c c e p t ( $ s e r v e r ) ; $ d a t a = " H T T P / 1 . 1 2 0 0 O K \ r \ n " ; $ d a t a . = " C o n t e n t - L e n g t h : 1 1 \ r \ n \ r \ n " $ d a t a . = " H e l l o W o r l d " ; $ l o o p - > a d d W r i t e S t r e a m ( $ c o n n , f u n c t i o n ( $ c o n n ) u s e ( & $ d a t a , $ l o o p ) { $ b y t e s W r i t t e n = f w r i t e ( $ c o n n , $ d a t a ) ; i f ( $ b y t e s W r i t t e n = = = s t r l e n ( $ d a t a ) ) { f c l o s e ( $ c o n n ) ; $ l o o p - > r e m o v e S t r e a m ( $ c o n n ) ; } e l s e { $ d a t a = s u b s t r ( $ d a t a , 0 , $ b y t e s W r i t t e n ) ; } } ) ; } ) ; $ l o o p - > r u n ( ) ;

Slide 24

Slide 24 text

Stream Wraps a PHP stream resource Registered with the event loop Readable and writable Buffered reads and writes

Slide 25

Slide 25 text

ReadableStream i s R e a d a b l e ( ) p a u s e ( ) r e s u m e ( ) p i p e ( W r i t a b l e S t r e a m $ d e s t ) c l o s e ( ) Events d a t a , e n d , e r r o r , c l o s e

Slide 26

Slide 26 text

WritableStream i s W r i t a b l e ( ) w r i t e ( $ d a t a ) e n d ( $ d a t a = n u l l ) c l o s e ( ) Events d r a i n , e r r o r , c l o s e , p i p e

Slide 27

Slide 27 text

Streams Readable → Writable

Slide 28

Slide 28 text

CompositeStream Joins writable and readable streams

Slide 29

Slide 29 text

ThroughStream Allows data to be filtered

Slide 30

Slide 30 text

BufferedSink Converts writable stream to a promise

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

Promises Wouldn’t it be nice if asynchronous functions could return immediately?

Slide 33

Slide 33 text

Deferred p r o m i s e ( ) r e s o l v e ( $ v a l u e = n u l l ) r e j e c t ( $ r e a s o n = n u l l ) p r o g r e s s ( $ u p d a t e = n u l l ) Computation or unit of work that may not have completed yet

Slide 34

Slide 34 text

Promise Placeholder for the result of a deferred computation t h e n ( $ o n F u l f i l l e d , $ o n R e j e c t e d , $ o n P r o g r e s s ) t h e n ( ) returns a new Promise composing the first

Slide 35

Slide 35 text

Promises in Action $ l o o p = R e a c t \ E v e n t L o o p \ F a c t o r y : : c r e a t e ( ) ; $ f a c t o r y = n e w R e a c t \ D n s \ R e s o l v e r \ F a c t o r y ( ) ; $ d n s = $ f a c t o r y - > c r e a t e ( ' 8 . 8 . 8 . 8 ' , $ l o o p ) ; $ d n s - > r e s o l v e ( $ a r g v [ 1 ] ) - > t h e n ( f u n c t i o n ( $ i p ) { e c h o " H o s t : $ i p \ n " ; } , f u n c t i o n ( $ e ) { e c h o " E r r o r : { $ e - > g e t M e s s a g e ( ) } \ n " ; } ) ; $ l o o p - > r u n ( ) ; $ p h p d n s . p h p j m i k o l a . n e t H o s t : 9 7 . 1 0 7 . 1 3 1 . 5 4

Slide 36

Slide 36 text

Suggested Reading — Domenic Denicola “You’re missing the point of promises” Now back to the stack…

Slide 37

Slide 37 text

Socket Abstracts s t r e a m _ s o c k e t _ s e r v e r ( ) Connections are readable/writable Server and client contexts TCP connections

Slide 38

Slide 38 text

Server l i s t e n ( $ p o r t , $ h o s t ) g e t P o r t ( ) s h u t d o w n ( ) Events c o n n e c t i o n , e r r o r

Slide 39

Slide 39 text

Connection g e t R e m o t e A d d r e s s ( ) i s R e a d a b l e ( ) p a u s e ( ) r e s u m e ( ) p i p e ( W r i t a b l e S t r e a m $ d e s t ) i s W r i t a b l e ( ) w r i t e ( $ d a t a ) e n d ( $ d a t a = n u l l ) c l o s e ( ) Events d a t a , d r a i n , e n d , e r r o r , c l o s e , p i p e

Slide 40

Slide 40 text

TCP Chat $ l o o p = R e a c t \ E v e n t L o o p \ F a c t o r y : : c r e a t e ( ) ; $ s o c k e t = n e w R e a c t \ S o c k e t \ S e r v e r ( $ l o o p ) ; $ c l i e n t s = n e w S p l O b j e c t S t o r a g e ( ) ; $ s o c k e t - > o n ( ' c o n n e c t i o n ' , f u n c t i o n ( $ c o n n ) u s e ( $ c l i e n t s ) { $ c l i e n t s - > a t t a c h ( $ c o n n ) ; $ c o n n - > o n ( ' d a t a ' , f u n c t i o n ( $ d a t a ) u s e ( $ c l i e n t s , $ c o n n ) { f o r e a c h ( $ c l i e n t s a s $ c l i e n t ) { i f ( $ c o n n = = = $ c l i e n t ) { c o n t i n u e ; } $ c l i e n t - > w r i t e ( $ c o n n - > g e t R e m o t e A d d r e s s ( ) . ' : ' . $ d a t a ) ; } } ) ; $ c o n n - > o n ( ' e n d ' , f u n c t i o n ( ) u s e ( $ c l i e n t s , $ c o n n ) { $ c l i e n t s - > d e t a c h ( $ c o n n ) ; } ) ; } ) ; $ s o c k e t - > l i s t e n ( 8 8 8 8 , ' 0 . 0 . 0 . 0 ' ) ; $ l o o p - > r u n ( ) ;

Slide 41

Slide 41 text

TCP Chat $ t e l n e t j m i k o l a . n e t 8 8 8 8 T r y i n g 9 7 . 1 0 7 . 1 3 1 . 5 4 . . . C o n n e c t e d t o j m i k o l a . n e t . E s c a p e c h a r a c t e r i s ' ^ ] ' . I s t h i s t h i n g o n ? 1 0 . 1 0 . 2 1 7 . 2 0 2 : H e l l o !

Slide 42

Slide 42 text

MongoDB Shell $ l o o p = R e a c t \ E v e n t L o o p \ F a c t o r y : : c r e a t e ( ) ; $ p r o c e s s = n e w R e a c t \ C h i l d P r o c e s s \ P r o c e s s ( ' m o n g o ' ) ; $ s t d o u t = n e w R e a c t \ S t r e a m \ S t r e a m ( f o p e n ( ' p h p : / / s t d o u t ' , ' w ' ) , $ l o o p ) ; $ p r o c e s s - > o n ( ' e x i t ' , f u n c t i o n ( $ e x i t C o d e , $ t e r m S i g n a l ) u s e ( $ s t d o u t ) { $ s t d o u t - > c l o s e ( ) ; } ) ; $ l o o p - > a d d T i m e r ( 0 . 0 0 1 , f u n c t i o n ( $ t i m e r ) u s e ( $ p r o c e s s , $ s t d o u t ) { $ p r o c e s s - > s t a r t ( $ t i m e r - > g e t L o o p ( ) ) ; $ p r o c e s s - > s t d o u t - > p i p e ( $ s t d o u t ) ; } ) ; $ l o o p - > a d d T i m e r ( 1 , f u n c t i o n ( $ t i m e r ) u s e ( $ p r o c e s s ) { $ p r o c e s s - > s t d i n - > w r i t e ( " d b . f o o . d r o p ( ) ; \ n " ) ; $ p r o c e s s - > s t d i n - > w r i t e ( " d b . f o o . i n s e r t ( { x : 1 } ) ; \ n " ) ; $ p r o c e s s - > s t d i n - > w r i t e ( " d b . f o o . i n s e r t ( { x : 2 } ) ; \ n " ) ; $ p r o c e s s - > s t d i n - > w r i t e ( " d b . f o o . i n s e r t ( { x : 3 } ) ; \ n " ) ; $ p r o c e s s - > s t d i n - > w r i t e ( " d b . f o o . f i n d ( ) . s o r t ( { x : - 1 } ) ; \ n " ) ; $ p r o c e s s - > s t d i n - > w r i t e ( " e x i t \ n " ) ; } ) ; $ l o o p - > r u n ( ) ;

Slide 43

Slide 43 text

Avoid Blocking Database queries Disk and file IO CPU-intensive tasks

Slide 44

Slide 44 text

Helpful Tools Inter-process communication Message queues Break up computations with $ l o o p - > n e x t T i c k ( c a l l a b l e )

Slide 45

Slide 45 text

Async MySQL m y s q l i _ q u e r y ( $ l i n k , $ q u e r y , M Y S Q L I _ A S Y N C ) m y s q l i _ p o l l ( & $ r e a d , & $ e r r o r , & $ r e j e c t , $ s e c ) m y s q l i _ r e a p _ a s y n c _ q u e r y ( $ l i n k )

Slide 46

Slide 46 text

Async MySQL m y s q l i _ p o l l ( & $ r e a d , & $ e r r o r , & $ r e j e c t , $ s e c ) This looks a lot like s t r e a m _ s e l e c t ( )

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

$ c o m p o s e r r e q u i r e " r e a c t / r e a c t = ~ 0 . 4 "

Slide 49

Slide 49 text

WebSockets https://github.com/cboden/Ratchet

Slide 50

Slide 50 text

GifSockets https://github.com/videlalvaro/gifsockets https://github.com/reactphp/gifsocket

Slide 51

Slide 51 text

Thanks! r e a c t p h p . o r g Questions?

Slide 52

Slide 52 text

Image Credits http://www.mariouniverse.com/sprites/snes/smw http://larsurus.deviantart.com/art/Lyra-on-Segway-PNG-269707453