Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rewriting the Parse API in Go.

Rewriting the Parse API in Go.

GopherCon 2015 Talk on how we rewrote the Parse API

Abhishek Kona

July 09, 2015
Tweet

More Decks by Abhishek Kona

Other Decks in Programming

Transcript

  1. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 1/39 Rewriting

    the Parse API in Go GopherCon 2015, Denver 8 July 2015 Abhishek Kona Software Engineer at Parse and Facebook
  2. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 2/39 What

    is this talk about? Why we rewrote the Parse API in Go Tools and libraries we built
  3. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 3/39 What

    is Parse? Backend as a service SDKs for iOS, Android, JS, React, Windows, PHP Acquired by Facebook in 2013
  4. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 6/39 Scalability

    Issues in 2013 Single popular app could take down Parse Fixed-size unicorn pool Lengthy deploy times Spooky action at a distance
  5. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 8/39 Why

    Rewrite? Huge estimated reliability win Wanted easier deploys Needed faster tests Hard to evolve to existing Ruby codebase
  6. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 9/39 Why

    Go? Statically typed Good concurrency support Dynamic number of worker goroutines per HTTP server Easy to attract engineers
  7. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 10/39 Rules

    of the Rewrite Don't break backwards compatibility No downtime
  8. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 11/39 Initial

    Ports Hosting server Parse Push Notification Service (PPNS) Maintains long-lived push sockets with Android clients Concurrent conns per node increased from 250K to 1.5M
  9. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 12/39 Mongo

    Proxy github.com/facebookgo/dvara (https://github.com/facebookgo/dvara) Mongo used to limit max number of connections to 20000 We wrote our own proxy for Mongo in Go Made easy by Go runtime's use of non-blocking I/O
  10. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 13/39 Rollout

    Migrate endpoints one by one Diffed responses between old and new code using a shadow cluster Started with low-traffic read only endpoints Graduated to write endpoints
  11. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 14/39 Comment

    Goldmine / / N o t e : a n u n s e t c a c h e v e r s i o n i s t r e a t e d b y r u b y a s “ ” . / / B e c a u s e o f t h i s , d i r t y i n g t h i s i s n ’ t a s s i m p l e a s d e l e t i n g i t – w e n e e d t o / / a c t u a l l y s e t a n e w v a l u e . / / T h i s b y t e s e q u e n c e i s w h a t r u b y e x p e c t s . / / y e s t h a t ’ s a p a r e n a f t e r t h e s e c o n d 1 8 0 , p e r r u b y . / / I n s e r t i n g a n d h a v i n g a n o p i s k i n d a w e i r d : W e a l r e a d y k n o w / / s t a t e z e r o . B u t r u b y s u p p o r t s i t , s o g o d o e s t o o . / / s i n g l e g e o q u e r y , d o n ’ t d o a n y t h i n g . s t u p i d a n d d o e s n o t m a k e s e n s e / / b u t r u b y d o e s i t . C h a n g i n g t h i s w i l l b r e a k a l o t o f c l i e n t t e s t s . / / j u s t b e n i c e a n d f i x i t h e r e . / / R u b y s e t s v a r i o u s d e f a u l t s d i r e c t l y i n t h e s t r u c t u r e a n d e x p e c t s t h e m t o a p p e a r i n c a c h e . / / F o r c o n s i s t e n c y , w e ’ l l d o t h e s a m e t h i n g .
  12. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 15/39 A

    Young Language Some good libraries: mgo, memcache, etc. Some missing libraries
  13. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 17/39 Dependency

    Injection Helps instantiate implementations for test and production Easy to miss passing a dependency to a struct
  14. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 18/39 Introducing

    Inject github.com/facebookgo/inject (http://github.com/facebookgo/inject) Only occurs at process startup for singletons Dependencies declared using struct tags Fail instead of guessing
  15. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 19/39 Dependency

    Injection Example t y p e H a n d l e r s t r u c t { S c r i b e * s c r i b e . C l i e n t ` i n j e c t : " " ` L o g l o g g e r . L o g g e r ` i n j e c t : " " ` } / / S e r v e H T T P a s a m p l e i m p l e m e n t a t i o n f u n c ( h * H a n d l e r ) S e r v e H T T P ( w R e s p o n s e W r i t e r , r * R e q u e s t ) { p a r a m s : = e x t r a c t P a r a m s ( r ) h . S c r i b e . L o g ( p a r a m s ) h . L o g ( " e v e r y t h i n g o k " ) w . W r i t e ( r e s ) }
  16. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 20/39 Main

    for Inject f u n c m a i n ( ) { v a r g i n j e c t . G r a p h e r r : = g . P r o v i d e ( & i n j e c t . O b j e c t { V a l u e : s c r i b e . N e w H T T P S c r i b e C l i e n t ( ) } , & i n j e c t . O b j e c t { V a l u e : p a r s e . N e w L o g g e r ( ) } , ) i f e r r ! = n i l { f m t . F p r i n t l n ( o s . S t d e r r , e r r ) o s . E x i t ( 1 ) } i f e r r : = g . P o p u l a t e ( ) ; e r r ! = n i l { f m t . F p r i n t l n ( o s . S t d e r r , e r r ) o s . E x i t ( 1 ) } / / r e s t o f m a i n }
  17. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 21/39 Initializing

    and Destroying Injected Objects github.com/facebookgo/startstop (http://github.com/facebookgo/startstop) Traverses object graph At startup: calls S t a r t on each injected object in dependency order At shutdown: calls S t o p on each injected object in reverse dependency order Fails on cycles
  18. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 22/39 Start-Stop

    Example t y p e S c r i b e C l i e n t { T h r i f t * T h r i f t P o o l ` i n j e c t : " " ` } / / S c r i b e C l i e n t s t a r t w i l l b e c a l l e d a f t e r T h r i f t P o o l . S t a r t f u n c ( s * S c r i b e C l i e n t ) S t a r t ( ) e r r o r { f m t . P r i n t l n ( " s t a r t i n g s c r i b e c l i e n t " ) r e t u r n n i l } t y p e T h r i f t P o o l s t r u c t { / / } / / T h r i f t P o o l s t a r t w i l l b e c a l l e d f i r s t . f u n c ( t * T h r i f t P o o l ) S t a r t ( ) e r r o r { f m t . P r i n t l n ( " s t a r t i n g t h r i f t p o o l " ) r e t u r n t . t c p D i a l ( ) } f u n c ( t * T h r i f t P o o l ) S t o p ( ) e r r o r { f m t . P r i n t l n ( " s t o p p i n g t h r i f t p o o l " ) r e t u r n t . t c p C l o s e A l l ( ) }
  19. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 23/39 Graceful

    Restarts github.com/facebookgo/grace (https://github.com/facebookgo/grace) Restart servers gracefully on deploys On USR2, spawns new process and hands off listening socket
  20. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 24/39 Error

    Reporting github.com/facebookgo/stackerr (https://github.com/facebookgo/stackerr) Wrap error calls with stackerr Aggregate errors based on stack trace in an in-house system called Logview
  21. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 25/39 Stackerr

    Example f u n c m a i n ( ) { e r r : = e r r 2 ( ) f m t . P r i n t l n ( e r r ) } f u n c e r r 2 ( ) e r r o r { e r r : = e r r 1 ( ) i f e r r ! = n i l { r e t u r n s t a c k e r r . W r a p ( e r r ) } r e t u r n n i l } f u n c e r r 1 ( ) e r r o r { r e t u r n s t a c k e r r . W r a p ( e r r o r s . N e w ( " f a i l u r e " ) ) }
  22. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 26/39 Stackerr

    Output f a i l u r e / p r i v a t e / t m p / s t a c k e r r . g o : 2 5 e r r 1 / p r i v a t e / t m p / s t a c k e r r . g o : 1 7 e r r 2 / p r i v a t e / t m p / s t a c k e r r . g o : 1 2 m a i n / u s r / l o c a l / C e l l a r / g o / 1 . 4 . 2 / l i b e x e c / s r c / r u n t i m e / p r o c . g o : 7 2 m a i n / u s r / l o c a l / C e l l a r / g o / 1 . 4 . 2 / l i b e x e c / s r c / r u n t i m e / a s m _ a m d 6 4 . s : 2 2 3 3 g o e x i t ( S t a c k 2 ) / p r i v a t e / t m p / s t a c k e r r . g o : 1 9 e r r 2 / p r i v a t e / t m p / s t a c k e r r . g o : 1 2 m a i n / u s r / l o c a l / C e l l a r / g o / 1 . 4 . 2 / l i b e x e c / s r c / r u n t i m e / p r o c . g o : 7 2 m a i n / u s r / l o c a l / C e l l a r / g o / 1 . 4 . 2 / l i b e x e c / s r c / r u n t i m e / a s m _ a m d 6 4 . s : 2 2 3 3 g o e x i t
  23. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 27/39 Muster

    github.com/facebookgo/muster (https://github.com/facebookgo/muster) A library to perform operations in a batch Two tunables: M a x B a t c h S i z e and B a t c h T i m e o u t
  24. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 28/39 Generics

    github.com/facebookgo/generics (https://github.com/facebookgo/generics)
  25. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 29/39 More

    Libraries github.com/facebookgo (https://github.com/facebookgo) Many more small libraries httpcontrol, ensure, stack
  26. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 32/39 Results

    ~175k LOC in Go vs ~130k LOC in Ruby ~3 minutes to run all the unit tests (down from 25min) Apps start in seconds instead of minutes Downsized API server pool by 90% Rolling restarts dropped from 30 minutes to 3 minutes
  27. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 33/39 Parse

    circa 2015 >500K apps built on Parse 2-3x YoY traffic growth Primarily a Go stack
  28. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 35/39 Go

    Side Effects Deploying with static binaries is easy Developers are responsible for deploys, not ops
  29. 7/8/2015 Rewriting the Parse API in Go http://localhost:3999/gophercon_2015.slide#1 38/39 Thank

    you Abhishek Kona Software Engineer at Parse and Facebook [email protected] (mailto:[email protected]) http://sheki.in (http://sheki.in) @sheki (http://twitter.com/sheki)