Our experience launching a
    Ruby on Rails app


     Andrew Flockhart
     @andruflockhart
    aflock@branch.com
What is Branch?
Our stack

• Rails
• Postgres
• Heroku
• Amazon EC2
Monitoring


• StatsD +
  Datadog
• New Relic
• Resque
Lessons from Launch

• What to optimize?
• Async ALL the things! (?)
• Don’t let rails make you dumb!
Predicting your app’s future is tough




                      Photo by FUNKYAH
Finding the bottlenecks
App load
• We didn’t predict where the hotspots
  would be correctly
• Validations were a large bottleneck
Conclusion:
Indexes are your friend
• One sql statement cut our DB load in half
• Functional indexes++
Lessons from Branch's launch
DelayedJob vs. Resque
DelayedJob vs. Resque
• DelayedJob is simple, plug and play, great
  for small volume of jobs
DelayedJob vs. Resque
• DelayedJob is simple, plug and play, great
  for small volume of jobs
• Resque is more granular, allows more
  control
DelayedJob vs. Resque
• DelayedJob is simple, plug and play, great
  for small volume of jobs
• Resque is more granular, allows more
  control
  •   Different queues
DelayedJob vs. Resque
• DelayedJob is simple, plug and play, great
  for small volume of jobs
• Resque is more granular, allows more
  control
  •   Different queues

  •   Priorities
DelayedJob vs. Resque
• DelayedJob is simple, plug and play, great
  for small volume of jobs
• Resque is more granular, allows more
  control
  •   Different queues

  •   Priorities

  •   Visibility
Resque
Background jobs are
                                 magic, right?




photo by Jenn and Tony Bot
Background jobs are
                                 magic, right?




photo by Jenn and Tony Bot
Background jobs are
                                 magic, right?




photo by Jenn and Tony Bot
Over half of our database load was
   background tasks at times
Over half of our database load was
   background tasks at times


              :0
Autoscaling workers

• Easy to do with Heroku’s API
• Saves money
• Your app is now responsive to load
Be mindful of your
background tasks!
Be mindful of your
    background tasks!
1. Treat your jobs as users
Be mindful of your
    background tasks!
1. Treat your jobs as users
2. Have a sensible upper bound to the # of
   workers
Be mindful of your
    background tasks!
1. Treat your jobs as users
2. Have a sensible upper bound to the # of
   workers
3. Monitor, monitor, monitor
Don’t let rails make you lazy!
Learn to speak SQL
• It’s easy to write naive migrations with no
  repercussions while you’re developing




• But who wants to do 500,000 insert
  statements?
4 is better than 500,000




So be conscious of what SQL rails generates
You can serialize
objects into your tables
You can serialize
objects into your tables
You can serialize
objects into your tables




     Sounds great!
Serializing/Deserializing to/from text is expensive!
Solution?
Solution?

• This is why we have relations between
  tables
Solution?

• This is why we have relations between
  tables
• Don’t store anything extraneous
Solution?

• This is why we have relations between
  tables
• Don’t store anything extraneous
• Generate on the fly, or use something like
  hstore.
Hstore is faster.
In conclusion
In conclusion

• Expect your app to misbehave
In conclusion

• Expect your app to misbehave
• Async isn’t an optimization cure-all
In conclusion

• Expect your app to misbehave
• Async isn’t an optimization cure-all
• Don’t let Rails make you lazy!
Thanks!




     Psst! We’re hiring.
    aflock@branch.com

          Slides:
bit.ly/branch_launch_lessons
Sources
• Autoscale workers: http://blog.leshill.org/
  blog/2011/04/03/using-resque-and-resque-
  scheduler-on-heroku.html
• Using hstore with rails: http://
  travisjeffery.com/b/2012/02/using-postgress-
  hstore-with-rails/
• These slides: bit.ly/branch_launch_lessons

More Related Content

PDF
An Introduction to jOOQ
PDF
Introduction to jOOQ
PDF
Reactive All the Way Down the Stack
PDF
6 reasons Jubilee could be a Rubyist's new best friend
PPTX
DevOps at Lowe's - Our Journey
PDF
Reactive Streams and the Wide World of Groovy
PDF
The Power of RxJS in Nativescript + Angular
KEY
MonoRails - GoGaRuCo 2012
An Introduction to jOOQ
Introduction to jOOQ
Reactive All the Way Down the Stack
6 reasons Jubilee could be a Rubyist's new best friend
DevOps at Lowe's - Our Journey
Reactive Streams and the Wide World of Groovy
The Power of RxJS in Nativescript + Angular
MonoRails - GoGaRuCo 2012

What's hot (19)

PPTX
Akka.Net Ottawa .NET User Group Meetup
PPTX
PDF
Scala in-practice-3-years by Patric Fornasier, Springr, presented at Pune Sca...
PDF
Coolblue Behind the Scenes | Niels Abels - Continuous Delivery.
PDF
Choosing Javascript Libraries to Adopt for Development
PDF
RxJS: A Beginner & Expert's Perspective - ng-conf 2017
PDF
We've being shifting
KEY
Core conv
PDF
Coolblue Behind the Scenes | Jeffrey Simons - The UX nerd and you.
ZIP
Deployment in Drupal 8
PDF
A Practical Approach to React Native at All Things Open Conference
PDF
PPTX
ELAG 2016: Going Live - The highs and lows of getting a project into service
PDF
Donald Ferguson - Old Programmers Can Learn New Tricks
PDF
Challenges of moving a java team to scala
PDF
Charity Hound - Serverless, NoOps, The Tooth Fairy
PDF
Optimera STHLM 2011 - Mikael Berggren, Spotify
PDF
Build a Startup with Clojure(Script)
PDF
Funtional Ruby - Mikhail Bortnyk
Akka.Net Ottawa .NET User Group Meetup
Scala in-practice-3-years by Patric Fornasier, Springr, presented at Pune Sca...
Coolblue Behind the Scenes | Niels Abels - Continuous Delivery.
Choosing Javascript Libraries to Adopt for Development
RxJS: A Beginner & Expert's Perspective - ng-conf 2017
We've being shifting
Core conv
Coolblue Behind the Scenes | Jeffrey Simons - The UX nerd and you.
Deployment in Drupal 8
A Practical Approach to React Native at All Things Open Conference
ELAG 2016: Going Live - The highs and lows of getting a project into service
Donald Ferguson - Old Programmers Can Learn New Tricks
Challenges of moving a java team to scala
Charity Hound - Serverless, NoOps, The Tooth Fairy
Optimera STHLM 2011 - Mikael Berggren, Spotify
Build a Startup with Clojure(Script)
Funtional Ruby - Mikhail Bortnyk

Viewers also liked (9)

PDF
Branching Strategies: Feature Branches vs Branch by Abstraction
PDF
Branch to branch by Photis Patriotis
PDF
Tranforming Branches and the Branch Network
PPT
Configuration Management
PDF
Learn BEM: CSS Naming Convention
PDF
SEO: Getting Personal
PDF
Succession “Losers”: What Happens to Executives Passed Over for the CEO Job?
PPTX
How to Build a Dynamic Social Media Plan
PDF
Study: The Future of VR, AR and Self-Driving Cars
Branching Strategies: Feature Branches vs Branch by Abstraction
Branch to branch by Photis Patriotis
Tranforming Branches and the Branch Network
Configuration Management
Learn BEM: CSS Naming Convention
SEO: Getting Personal
Succession “Losers”: What Happens to Executives Passed Over for the CEO Job?
How to Build a Dynamic Social Media Plan
Study: The Future of VR, AR and Self-Driving Cars

Similar to Lessons from Branch's launch (20)

KEY
Social dev camp_2011
PPTX
Inside Wordnik's Architecture
PDF
JSON all the way
PDF
Core Data in RubyMotion #inspect
PDF
Cloud conference - mongodb
PDF
Dev ops lessons learned - Michael Collins
PDF
ChefConf 2015 - Chef Retrospective
PDF
Web APIs: The future of software
PPTX
Running MongoDB in the Cloud
PDF
Erlang factory SF 2011 "Erlang and the big switch in social games"
PDF
Erlang, the big switch in social games
PDF
What Drove Wordnik Non-Relational?
PDF
Systems Monitoring with Prometheus (Devops Ireland April 2015)
PDF
Dev Ops without the Ops
PPTX
Scaling with swagger
PPTX
System insight without Interference
PPTX
My Little Webap - DevOpsSec is Magic
PDF
ITB 2023 10 Techniques for writing easy yet stupidly thorough unit tests_Dan ...
PPTX
Relay: Seamless Syncing for React (VanJS)
PPTX
Dapper: the microORM that will change your life
Social dev camp_2011
Inside Wordnik's Architecture
JSON all the way
Core Data in RubyMotion #inspect
Cloud conference - mongodb
Dev ops lessons learned - Michael Collins
ChefConf 2015 - Chef Retrospective
Web APIs: The future of software
Running MongoDB in the Cloud
Erlang factory SF 2011 "Erlang and the big switch in social games"
Erlang, the big switch in social games
What Drove Wordnik Non-Relational?
Systems Monitoring with Prometheus (Devops Ireland April 2015)
Dev Ops without the Ops
Scaling with swagger
System insight without Interference
My Little Webap - DevOpsSec is Magic
ITB 2023 10 Techniques for writing easy yet stupidly thorough unit tests_Dan ...
Relay: Seamless Syncing for React (VanJS)
Dapper: the microORM that will change your life

Recently uploaded (20)

PPTX
From Curiosity to ROI — Cost-Benefit Analysis of Agentic Automation [3/6]
PPTX
CRM(Customer Relationship Managmnet) Presentation
PDF
CCUS-as-the-Missing-Link-to-Net-Zero_AksCurious.pdf
PDF
Domain-specific knowledge and context in large language models: challenges, c...
PDF
Introduction to c language from lecture slides
PDF
Slides World Game (s) Great Redesign Eco Economic Epochs.pdf
PDF
GDG Cloud Southlake #45: Patrick Debois: The Impact of GenAI on Development a...
PDF
Secure Java Applications against Quantum Threats
PDF
Peak of Data & AI Encore: Scalable Design & Infrastructure
PPTX
maintenance powerrpoint for adaprive and preventive
PDF
TicketRoot: Event Tech Solutions Deck 2025
PDF
Child-friendly e-learning for artificial intelligence education in Indonesia:...
PDF
Revolutionizing recommendations a survey: a comprehensive exploration of mode...
PDF
Uncertainty-aware contextual multi-armed bandits for recommendations in e-com...
PDF
1_Keynote_Breaking Barriers_한계를 넘어서_Charith Mendis.pdf
PDF
Advancements in abstractive text summarization: a deep learning approach
PDF
Addressing the challenges of harmonizing law and artificial intelligence tech...
PDF
Human Computer Interaction Miterm Lesson
PDF
TrustArc Webinar - Data Minimization in Practice_ Reducing Risk, Enhancing Co...
PPTX
Strategic Picks — Prioritising the Right Agentic Use Cases [2/6]
From Curiosity to ROI — Cost-Benefit Analysis of Agentic Automation [3/6]
CRM(Customer Relationship Managmnet) Presentation
CCUS-as-the-Missing-Link-to-Net-Zero_AksCurious.pdf
Domain-specific knowledge and context in large language models: challenges, c...
Introduction to c language from lecture slides
Slides World Game (s) Great Redesign Eco Economic Epochs.pdf
GDG Cloud Southlake #45: Patrick Debois: The Impact of GenAI on Development a...
Secure Java Applications against Quantum Threats
Peak of Data & AI Encore: Scalable Design & Infrastructure
maintenance powerrpoint for adaprive and preventive
TicketRoot: Event Tech Solutions Deck 2025
Child-friendly e-learning for artificial intelligence education in Indonesia:...
Revolutionizing recommendations a survey: a comprehensive exploration of mode...
Uncertainty-aware contextual multi-armed bandits for recommendations in e-com...
1_Keynote_Breaking Barriers_한계를 넘어서_Charith Mendis.pdf
Advancements in abstractive text summarization: a deep learning approach
Addressing the challenges of harmonizing law and artificial intelligence tech...
Human Computer Interaction Miterm Lesson
TrustArc Webinar - Data Minimization in Practice_ Reducing Risk, Enhancing Co...
Strategic Picks — Prioritising the Right Agentic Use Cases [2/6]

Lessons from Branch's launch

Editor's Notes

  • #2: Hi Im andrew blah blah blah\n
  • #3: What is branch anyway?\nThink of a dinner table conversation on the web\n\nIn between a blog post, 1 person, and a forum open to anyone\n\nWe’re trying to create a place for thoughtful communication\nSo, \nhow did we build it??\n\n
  • #4: We’re running a pretty standard Rails app off of heroku,\nPostgres for our DB, Redis on EC2 for caching and misc. key value\nCoffee/Haml for the frontend\nHow do we monitor it?\nadd ec2\n
  • #5: a few tools Using statsD on ec2 paired with datadog for most of our app stats - \n\netsy developed statsD as a metrics aggregator-\n we send over all our metrics from logs and internal events to statsd, and it gets aggregated and sent to datadog\n\nddog makes it very easy to define and track custom metrics , \nand alerts\n\nTo keep tabs on DB< New Relic through heroku\n\nTo keep an eye on async tasks, Resque web app (more on that later)\n
  • #6: We learned alot during our launch, tonight I’m going to talk about the three biggest take aways we got from it.\n\nThese aren’t branch-specific lessons, should be applicable to any consumer-facing rails app \n
  • #7: Probably stating the obvious, but we can’t predict the future as much as we might like to believe.\n\nThe week before launch we thought about what to optimize.\n\nWe set up a waitlist system so we could throttle the number of people using our site\n\nwhat about people who are using our site?\n\n“Creating branches!” Since we’re granting 100s of ppl access, that will cause a bunch of load- lets optimize that\n\nopened the floodgates\n
  • #8: New Relic ++\nThe ability to drill down into your database load made optimizing so much easier\n\nNR catalogues every request and database transaction, \nWe can examine the stack traces for slow queries,\nView response time geographically\n\nBeyond just which transactions are slow- which components of those transactions are slow?\nare you stuck in ruby, or doing too many sql calls.\n\nSo as we looked at our db load during the first few days,\n
  • #9: This is what we set up to throttle load!, but it was regularly making up >20% of our database operations\n\nWHY??\n\nWhat does the validates_uniqueness do?\nPostgres scans for matches, so if there are not indexes, you are doing close to a full table scan!\n\nIn the end, the public facing actions that we weren’t throttling were the biggest load\n\nFirst day we didn’t even invite anyone since we were just struggling to keep up with waitlist signups\n\nsolution?\n
  • #10: We needed to optimize those validations, one specific culprit was the email uniqueness\nwe added a functional index on the email column\nwe LOWERCASE FUNCTION t\n\nsidenote: active record doesn’t support creating functional indexes, hence the explicit sql\n\nthis also means we needed to store our scheme as a structure.sql dump instead of schema.rb\nin order to reconstruct it\n\nSo that was the first thing we learned\n-- Optimizing based on assumptions is going to be wrong sometimes, so be ready for that and have the tools to deal with it.\n
  • #11: Everyone loves async right?\n\nAlot of our app happens asynchronously at branch, \neverything from sending emails to pushing realtime updates,\n to firing off tweets\n\nsidenote -- give you a rundown of how we handle that\n
  • #12: We used DJob until a few weeks before launch\n\nDelayedJob is great and super easy to work with,\nin the end we wanted more granular control over our background tasks since a lot of stuff happens there\n\n_different queues, priorities, complete visibility into them , failed jobs etc.\n\n\n
  • #13: We used DJob until a few weeks before launch\n\nDelayedJob is great and super easy to work with,\nin the end we wanted more granular control over our background tasks since a lot of stuff happens there\n\n_different queues, priorities, complete visibility into them , failed jobs etc.\n\n\n
  • #14: We used DJob until a few weeks before launch\n\nDelayedJob is great and super easy to work with,\nin the end we wanted more granular control over our background tasks since a lot of stuff happens there\n\n_different queues, priorities, complete visibility into them , failed jobs etc.\n\n\n
  • #15: We used DJob until a few weeks before launch\n\nDelayedJob is great and super easy to work with,\nin the end we wanted more granular control over our background tasks since a lot of stuff happens there\n\n_different queues, priorities, complete visibility into them , failed jobs etc.\n\n\n
  • #16: We used DJob until a few weeks before launch\n\nDelayedJob is great and super easy to work with,\nin the end we wanted more granular control over our background tasks since a lot of stuff happens there\n\n_different queues, priorities, complete visibility into them , failed jobs etc.\n\n\n
  • #17: Being able to see into the queues individually (and individually kill them) saved our asses more than once.\n\nESPECIALLY EXAMINING failed queue in detail, \nwhich jobs are failing, \nhow frequently, \nare there stuck workers\n\n\nRuns on Redis, created by @defunkt, has a great community and a host of plugins \n
  • #18: When thinking about how to optimize Branch before launch, we mostly concentrated on how to optimize user response time. \n\nSo we ended up making a bunch of actions asynchronous-\n\nwe even have quite a few background jobs which QUEUE background jobs.\n\nIf they’re processed in the background, who cares if they’re fast?\n\n\n
  • #19: When thinking about how to optimize Branch before launch, we mostly concentrated on how to optimize user response time. \n\nSo we ended up making a bunch of actions asynchronous-\n\nwe even have quite a few background jobs which QUEUE background jobs.\n\nIf they’re processed in the background, who cares if they’re fast?\n\n\n
  • #20: A big lesson for us is that you can’t think like that- especially when so much of your app is async\n\nespecially at peak activity times like when we would send batches of invites\n\nHOW\n\n\n\n
  • #21: There are a bunch of great blog posts and gems to do this\n\nbut be careful!\n\n\n
  • #22: They are not fire and forget\n\nWhen you have a lot of workers doing silly things in your DB, the result can be catastrophic\n
  • #23: They are not fire and forget\n\nWhen you have a lot of workers doing silly things in your DB, the result can be catastrophic\n
  • #24: They are not fire and forget\n\nWhen you have a lot of workers doing silly things in your DB, the result can be catastrophic\n
  • #25: Rails is great- gives us alot of convenience, makes it easy to develop quickly\n\nactive record abstracts your database for you, but \n\nthat’s a double edged sword\n
  • #26: I can run this migration, even on production data, and it won’t be THAT painful.\nI even think I’m being efficient with find_each\n\nIt should be. Running a migration like this on prod can brick for ??? how long\n
  • #27: there’s probably a SQL ninja here who could accomplish this in 1 call,\n\nbut we can all agree this is much better than the first\n\nThe ORM makes it easy to ignore sql completely, but that will bite you. FOR INSTANCE\n
  • #28: At first: this sounds super convenient\n\n
  • #29: At first: this sounds super convenient\n\n
  • #30: Especially with big objects! \n\ngod forbid you do any type of validations on those serialized hashes, since they dont support indices\n\nWe were storing twitter token objects, \nUpdating/ changing the tables, or moving the data became EXTREMELY expensive. \n\n\nyou have to de-serialize in memory! \n
  • #31: \nIf your object is so important, maybe it needs its own table?\n\nIf you don’t have to store it, dont!\n\nHstore fsho!\n
  • #32: \nIf your object is so important, maybe it needs its own table?\n\nIf you don’t have to store it, dont!\n\nHstore fsho!\n
  • #33: \nIf your object is so important, maybe it needs its own table?\n\nIf you don’t have to store it, dont!\n\nHstore fsho!\n
  • #34: Hstore is the way postgres stores hashes\n\nit’s not supported in rails natively yet, but there are gems that will allow you to use\n\nmuch faster!\n\nthose are just two examples of ways to shoot yourself in the foot with rails\n\nstay alert!\n
  • #35: \n
  • #36: \n
  • #37: \n
  • #38: \n
  • #39: \n