Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Enterprise Architectures with Ruby (and Rails)

42,989 views

Published on

Published in: Technology

Enterprise Architectures with Ruby (and Rails)

  1. 1. Enterprise Architecture withRuby (and Rails)Building amazing products, companies andtechnology using Ruby on Rails and friends.An opinionated overview for MagmaRails.MX byKonstantin Gredeskoul, CTO, Wanelo, Inctwitter: @kig, github.com/kigster
  2. 2. My Background CTO @ Wanelo.com — “Pinterest for shopping” Principal @ ModCloth.com — is one of the largest independent e-commerce Rails sites Principal @ Blurb.com — print-on-demand bookstore, and a large e-commerce web site Professionally building enterprise software since 1995 Converted from Java/Perl/C to ruby in 2006
  3. 3. What is Enterprise?
  4. 4. What is Enterprise?It’s an organization with many people,services, technologies
  5. 5. What is Enterprise?It’s an organization with many people,services, technologiesEnterprise architecture is an ongoingbusiness function that helps an enterprisefigure out how to best execute the strategiesthat drive its development [ref: wikipedia]
  6. 6. From Start-Up To Enterprise
  7. 7. From Start-Up To EnterpriseMany modern enterprises started small, astiny start-ups
  8. 8. From Start-Up To EnterpriseMany modern enterprises started small, astiny start-upsMany start-ups choose RoR for productivity
  9. 9. From Start-Up To EnterpriseMany modern enterprises started small, astiny start-upsMany start-ups choose RoR for productivityAs the start-up grows, so does the technology,applications, and the stack.
  10. 10. Teams using RoR can bevery productive
  11. 11. Teams using RoR can bevery productiveProductivity is super important for unprovenyoung companies trying things out
  12. 12. Teams using RoR can bevery productiveProductivity is super important for unprovenyoung companies trying things out“Build quickly, iterate, avoid building featuresusers don’t need” — Lean Start-Up Movement
  13. 13. Teams using RoR can bevery productiveProductivity is super important for unprovenyoung companies trying things out“Build quickly, iterate, avoid building featuresusers don’t need” — Lean Start-Up MovementDo not optimize “prematurely”, but think abouttomorrow’s scalability when building today.
  14. 14. Productivity vs Scale:The Dilemma!
  15. 15. Productivity vs Scale:The Dilemma!To move fast - we use Ruby (dynamiclanguages), a framework (Rails), cloud, afamiliar database, and keep the team small
  16. 16. Productivity vs Scale:The Dilemma!To move fast - we use Ruby (dynamiclanguages), a framework (Rails), cloud, afamiliar database, and keep the team smallTo truly scale an application - need multiplelanguages (Java, C/C++, Scala), custom or noframeworks, datacenter, large team
  17. 17. But does everyone needmega scale?
  18. 18. But does everyone needmega scale?Majority of Rails projects are OK without mega-scale (only a tiny fraction is like Twitter or Facebook)
  19. 19. But does everyone needmega scale?Majority of Rails projects are OK without mega-scale (only a tiny fraction is like Twitter or Facebook)Ruby/Rails can happily grow into a largeapplications without major rewrites
  20. 20. But does everyone needmega scale?Majority of Rails projects are OK without mega-scale (only a tiny fraction is like Twitter or Facebook)Ruby/Rails can happily grow into a largeapplications without major rewritesBest assurance that an application will growwell with it’s use, is to follow best practices.
  21. 21. So what is this talk about?
  22. 22. So what is this talk about? How to start small But move fast
  23. 23. So what is this talk about? How to start small But move fast How to evolve a Rails app But keep it scalable
  24. 24. So what is this talk about? How to start small But move fast How to evolve a Rails app But keep it scalable How to split things up When the app gets large, and keep everyone sane
  25. 25. Part 1:How to start small, but move fast
  26. 26. Get a great team together
  27. 27. Get a great team together Keep team size small, 4-6 developers is ideal
  28. 28. Get a great team together Keep team size small, 4-6 developers is ideal Have at least 2-3 ruby/rails/front-end experts on the team
  29. 29. Get a great team together Keep team size small, 4-6 developers is ideal Have at least 2-3 ruby/rails/front-end experts on the team Do automated testing (and TDD) from the beginning. Hard to add later.
  30. 30. Process matters
  31. 31. Process matters Paired Programming is amazing. Level the field, transfer knowledge, build trust within the team, move faster
  32. 32. Process matters Paired Programming is amazing. Level the field, transfer knowledge, build trust within the team, move faster Morning stand-ups, weekly sprint planners, technical discussions as needed, retrospectives
  33. 33. Process matters Paired Programming is amazing. Level the field, transfer knowledge, build trust within the team, move faster Morning stand-ups, weekly sprint planners, technical discussions as needed, retrospectives Dedicated graphic designer/UXR, and a Product Manager
  34. 34. Everyday tools matter
  35. 35. Everyday tools matter RubyMine IDE is very powerful, but $69 Other tools also work, VIM, TextMate
  36. 36. Everyday tools matter RubyMine IDE is very powerful, but $69 Other tools also work, VIM, TextMate When pairing, using consistent toolset is very important. Pick it and stick to it.
  37. 37. Everyday tools matter RubyMine IDE is very powerful, but $69 Other tools also work, VIM, TextMate When pairing, using consistent toolset is very important. Pick it and stick to it. If everyone has their own laptop, create a common OS account and use it to pair
  38. 38. Communication is key
  39. 39. Communication is key Continuous Integration server runs all automated tests (Jenkins is great!) Everyone knows when tests break!
  40. 40. Communication is key Continuous Integration server runs all automated tests (Jenkins is great!) Everyone knows when tests break!
  41. 41. Communication is key Continuous Integration server runs all automated tests (Jenkins is great!) Everyone knows when tests break! Pivotal CI Monitor open source app pulls from Jenkins
  42. 42. Communication is key
  43. 43. Communication is key Use Chat (eg, Campfire) to notify team about check-ins, deploys or failed builds
  44. 44. Communication is key Use Chat (eg, Campfire) to notify team about check-ins, deploys or failed builds Review other’s commits (ie, on GitHub) to learn as much code as possible
  45. 45. Communication is key Use Chat (eg, Campfire) to notify team about check-ins, deploys or failed builds Review other’s commits (ie, on GitHub) to learn as much code as possible Take care of your team mates, and do worry about the project. Success depends on it.
  46. 46. A few more awesome tools*
  47. 47. A few more awesome tools* iTerm2 - free mega awesome Terminal replacement (Cmd-D/Cmd-Shift-D)
  48. 48. A few more awesome tools* iTerm2 - free mega awesome Terminal replacement (Cmd-D/Cmd-Shift-D) SizeUp - align windows on the screen right/left/ up/down/middle.
  49. 49. A few more awesome tools* iTerm2 - free mega awesome Terminal replacement (Cmd-D/Cmd-Shift-D) SizeUp - align windows on the screen right/left/ up/down/middle. iStat Menus - view CPU, Network IO, Disk in Mac OS-X Toolbar
  50. 50. A few more awesome tools* iTerm2 - free mega awesome Terminal replacement (Cmd-D/Cmd-Shift-D) SizeUp - align windows on the screen right/left/ up/down/middle. iStat Menus - view CPU, Network IO, Disk in Mac OS-X Toolbar CCMenu - view results of CI in your toolbar
  51. 51. Choice of libraries matters
  52. 52. Choice of libraries matters MiniTest, Jasmine, Capybara (RackTest + Selenium) for testing
  53. 53. Choice of libraries matters MiniTest, Jasmine, Capybara (RackTest + Selenium) for testing Devise for authentication, user mgmt
  54. 54. Choice of libraries matters MiniTest, Jasmine, Capybara (RackTest + Selenium) for testing Devise for authentication, user mgmt Twitter Bootstrap for early UI is amazing although we prefer SCSS instead of LESS
  55. 55. Choice of libraries matters MiniTest, Jasmine, Capybara (RackTest + Selenium) for testing Devise for authentication, user mgmt Twitter Bootstrap for early UI is amazing although we prefer SCSS instead of LESS HAML for views, RABL for APIs
  56. 56. Data matters the most
  57. 57. Data matters the most Relational Databases: PostgreSQL, MySQL High consistency, reliability, decades of research, great performance, gets tricky at mega-scale
  58. 58. Data matters the most Relational Databases: PostgreSQL, MySQL High consistency, reliability, decades of research, great performance, gets tricky at mega-scale BigTable based: MongoDB, HBase Eventual consistency, recent, have indexes, almost table-like. Also tricky at mega scale.
  59. 59. Data matters the most Relational Databases: PostgreSQL, MySQL High consistency, reliability, decades of research, great performance, gets tricky at mega-scale BigTable based: MongoDB, HBase Eventual consistency, recent, have indexes, almost table-like. Also tricky at mega scale. Amazon Dynamo like: RIAK, Voldemort Distributed hash-table, tricky from the very beginning.
  60. 60. What to choose?
  61. 61. What to choose? Without a strong reason otherwise, choose a relational database. I prefer PostgreSQL.
  62. 62. What to choose? Without a strong reason otherwise, choose a relational database. I prefer PostgreSQL. Instagram scaled on PostgreSQL very well
  63. 63. What to choose? Without a strong reason otherwise, choose a relational database. I prefer PostgreSQL. Instagram scaled on PostgreSQL very well If under pressure and in doubt, it’s OK to choose whatever you are familiar with.
  64. 64. Part 2:How to evolve a Rails App
  65. 65. New Rails Project: Day 1
  66. 66. New Rails Project: Day 1rails new my-awesome-appcd my-awesome-apprake db:migrate
  67. 67. New Rails Project: Day 1rails new my-awesome-appcd my-awesome-apprake db:migrate
  68. 68. New Rails Project: Day 1rails new my-awesome-appcd my-awesome-apprake db:migrate ruby 1.9.3-p125 rails 3.2.3 macbook air 1.8Ghz
  69. 69. incoming http1. Starting Up One app server, one db, nginx 10 unicorns per app server Unicorn // Passenger Unicorn Passenger Ruby Ruby VM N) VM (times nginx for static assets PostgreSQL for data Always put your DB on a separate server DB Cloud
  70. 70. incoming http1. Starting Up nginx Unicorn // Passenger Unicorn Passenger Ruby Ruby VM N) VM (times DB
  71. 71. incoming http1. Starting Up nginxSimple, but no app server Unicorn // Passenger Unicorn Passengerredundancy, limited Ruby Ruby VM N) VM (timesthroughput DB
  72. 72. incoming http1. Starting Up nginxSimple, but no app server Unicorn // Passenger Unicorn Passengerredundancy, limited Ruby Ruby VM N) VM (timesthroughput10 unicorns = 10concurrent requests at any DBone time
  73. 73. incoming http2. Growing Up nginxSplit into multiple App Unicorn // Passenger Unicorn PassengerServers Ruby Ruby VM N) VM (timesHAProxy to distribute loadnginx for static files foundon local file system, proxyrequests otherwise DB
  74. 74. incoming http2. Growing Up nginx haproxySplit into multiple AppServers Unicorn Unicorn / PassengerHAProxy to distribute load Ruby VM Ruby VMnginx for static files foundon local file system, proxyrequests otherwise DB
  75. 75. incoming http2. Growing Up nginx haproxySite usage grows.Responses get slow. Unicorn Unicorn / Passenger Ruby VM Ruby VM DB
  76. 76. incoming http2. Growing Up nginx haproxySite usage grows.Responses get slow. Unicorn Unicorn / Passenger Ruby VM Ruby VMStarted at 150ms, then400ms, then 700ms.... DB
  77. 77. incoming http3. Scaling Up nginx haproxy Unicorn Unicorn / Passenger Ruby VM Ruby VM DB
  78. 78. incoming http3. Scaling Up nginx Add MemCached (1Gb+) haproxy Unicorn Unicorn / Passenger Ruby VM Ruby VM DB
  79. 79. incoming http3. Scaling Up nginx Add MemCached (1Gb+) haproxy Use Redis (or cookies) for sessions (reduce db load) Unicorn Unicorn / Passenger Ruby VM Ruby VM DB
  80. 80. incoming http3. Scaling Up nginx Add MemCached (1Gb+) haproxy Use Redis (or cookies) for sessions (reduce db load) Unicorn Unicorn / Passenger Ruby VM Ruby VM memcache redis DB
  81. 81. incoming http3. Scaling Up nginx Add MemCached (1Gb+) haproxy Use Redis (or cookies) for sessions (reduce db load) Unicorn Unicorn / Passenger Ruby VM Ruby VM memcache Add action caching (even short TTL helps, i.e. 1min) redis DB
  82. 82. incoming http3. Scaling Up nginx Add MemCached (1Gb+) haproxy Use Redis (or cookies) for sessions (reduce db load) Unicorn Unicorn / Passenger Ruby VM Ruby VM memcache Add action caching (even short TTL helps, i.e. 1min) redis Use AJAX to personalize pages to make them cacheable* DB
  83. 83. Personalization with AJAX -A brief de-tour
  84. 84. Personalization with AJAX -A brief de-tour1. Logged in (or not) user requests a page...
  85. 85. Personalization with AJAX -A brief de-tour1. Logged in (or not) user requests a page...2. Page is served from the cache without any personalization (no “Hi John!”, “Logout”, etc)
  86. 86. Personalization with AJAX -A brief de-tour1. Logged in (or not) user requests a page...2. Page is served from the cache without any personalization (no “Hi John!”, “Logout”, etc)3. on document.ready: AJAX hits the server, gets tiny JSON data of the current user (or “not logged in”)
  87. 87. Personalization with AJAX -A brief de-tour1. Logged in (or not) user requests a page...2. Page is served from the cache without any personalization (no “Hi John!”, “Logout”, etc)3. on document.ready: AJAX hits the server, gets tiny JSON data of the current user (or “not logged in”)4. JS modifies the DOM to show user’s logged in state, any other personalization, or “Log In”.
  88. 88. Personalization with AJAX -How?
  89. 89. Personalization with AJAX -Where?
  90. 90. Personalization with AJAX -Why?
  91. 91. Personalization with AJAX -Why? Because entire page can be served from the cache (often 50Kb+ per request)
  92. 92. Personalization with AJAX -Why? Because entire page can be served from the cache (often 50Kb+ per request) No ActiveRecord and no rendering makes it really fast!
  93. 93. Personalization with AJAX -Why? Because entire page can be served from the cache (often 50Kb+ per request) No ActiveRecord and no rendering makes it really fast! Recent rough test using Rails 3.2.3, ruby 1.9.3-p194, memcached: 4ms latency!!!
  94. 94. Why not page caching?
  95. 95. Why not page caching? Because unlike action caching, page caching is file-system based.
  96. 96. Why not page caching? Because unlike action caching, page caching is file-system based. Because it’s more difficult to expire
  97. 97. Why not page caching? Because unlike action caching, page caching is file-system based. Because it’s more difficult to expire Because it’s more difficult to share across many servers
  98. 98. incoming http4. Scaling Images nginx haproxy We are serving lots of images. Nginx is getting slammed. Unicorn Unicorn / Passenger Ruby VM memcache Ruby VM redis DB
  99. 99. incoming http4. Scaling Images nginx haproxy We are serving lots of images. Nginx is getting slammed. Unicorn Unicorn / Passenger Ruby VM memcache Ruby VM Should we add more redis balancers? Write our own? DB
  100. 100. incoming http4. Scaling Images nginx haproxy We are serving lots of images. Nginx is getting slammed. Unicorn Unicorn / Passenger Ruby VM memcache Ruby VM Should we add more redis balancers? Write our own? DB HELLZ NO!
  101. 101. incoming incoming http http4. Scaling Images CDN cache images, JS nginx haproxy Unicorn // Passenger Unicorn Passenger RubyRuby VM N) VM (times memcache redis DB
  102. 102. incoming incoming http http4. Scaling Images CDN cache images, JS Don’t wait to use a CDN to SERVE images, especially nginx user-uploaded images. haproxy Unicorn // Passenger Unicorn Passenger RubyRuby VM N) VM (times memcache redis DB
  103. 103. incoming incoming http http4. Scaling Images CDN cache images, JS Don’t wait to use a CDN to SERVE images, especially nginx user-uploaded images. haproxy S3 is a popular choice to STORE images. Unicorn // Passenger Unicorn Passenger RubyRuby VM N) VM (times memcache redis DB
  104. 104. incoming incoming http http4. Scaling Images CDN cache images, JS Don’t wait to use a CDN to SERVE images, especially nginx user-uploaded images. haproxy S3 is a popular choice to STORE images. Unicorn // Passenger Unicorn Passenger RubyRuby VM N) VM (times memcache But it’s smart to keep a redis local backup copy... DB
  105. 105. incoming incoming http http5. Deployments and CDN Downtime cache images, JS Our site is popular! nginx And our users hate haproxy downtime. Unicorn // Passenger Unicorn Passenger RubyRuby VM N) VM (times memcache redis DB
  106. 106. incoming incoming http http5. Deployments and CDN Downtime cache images, JS Our site is popular! nginx And our users hate haproxy downtime. Unicorn // Passenger Unicorn Passenger RubyRuby VM N) VM (times memcache They really really do. redis DB
  107. 107. 5. Deployments and Downtime
  108. 108. 5. Deployments and Downtime We want to be able to deploy the code while the site is running. So users are happy.
  109. 109. 5. Deployments and Downtime We want to be able to deploy the code while the site is running. So users are happy. There are several ways to do that.
  110. 110. 5. Deployments and Downtime We want to be able to deploy the code while the site is running. So users are happy. There are several ways to do that. This solution uses DNS round robin with two balancers, and two public IP addresses.
  111. 111. Two Cluster Solution = Almost Zero Downtime incoming http incoming http balancer1 balancer2 nginx nginx haproxy haproxyUnicorn // PassengerUnicorn Passenger Unicorn // Passenger Unicorn PassengerRubyRuby VM N) VM (times memcache memcache RubyRuby VM N) VM (times redis DB
  112. 112. Two Cluster Solution = Almost Zero Downtime incoming http incoming http balancer1 balancer2 nginx nginx haproxy haproxyUnicorn // PassengerUnicorn Passenger Unicorn // Passenger Unicorn PassengerRubyRuby VM N) VM (times memcache memcache RubyRuby VM N) VM (times redis DB
  113. 113. Temporary Redirect Rule
  114. 114. Two Clusters are cool!
  115. 115. Two Clusters are cool! Cluster 1 runs old code and is live
  116. 116. Two Clusters are cool! Cluster 1 runs old code and is live Cluster 2 gets new code
  117. 117. Two Clusters are cool! Cluster 1 runs old code and is live Cluster 2 gets new code Old and new run in parallel, but only one is serving live traffic
  118. 118. Migrations with ZeroDowntime?
  119. 119. Migrations with ZeroDowntime? Almost possible on a live system, if:
  120. 120. Migrations with ZeroDowntime? Almost possible on a live system, if: We are not removing or renaming columns or tables in active use
  121. 121. Migrations with ZeroDowntime? Almost possible on a live system, if: We are not removing or renaming columns or tables in active use Migrations do not lock tables (for too long)
  122. 122. Migrations with ZeroDowntime? Almost possible on a live system, if: We are not removing or renaming columns or tables in active use Migrations do not lock tables (for too long) Column/Table renames/deletes can be done in two deployments instead of one
  123. 123. So the app is now faster, and wecan deploy without a downtime
  124. 124. So the app is now faster, and wecan deploy without a downtime What about email and other long-running tasks?
  125. 125. So the app is now faster, and wecan deploy without a downtime What about email and other long-running tasks? Don’t forget SPF records.
  126. 126. incoming httpBackground Jobs withResque balancer1 nginxBut monitor it’s queues haproxyMust restart on reboot Resque Workers Unicorn memcache redis DB
  127. 127. incoming httpBackground Jobs withResque balancer1 nginxBut monitor it’s queues haproxyMust restart on reboot Resque Workers Unicorn memcache redisresque-cleaner isawesome! DB
  128. 128. Different queues for different types of jobs
  129. 129. Different queues for different types of jobsRelatively easy to implement priorities for Jobs(order queues by priority)
  130. 130. Different queues for different types of jobsRelatively easy to implement priorities for Jobs(order queues by priority)Group Jobs by execution times to avoid delays
  131. 131. Different queues for different types of jobsRelatively easy to implement priorities for Jobs(order queues by priority)Group Jobs by execution times to avoid delays Resque::Worker x N QUEUE=SlowQueue1,SlowQueue2 redis Resque::Worker x M QUEUE=FastQueue1,FastQueue2
  132. 132. DB Usage and complexity grows.We are doing big joins with manytables, and they are taking their sweettime.
  133. 133. Solr to the Resque
  134. 134. Solr to the Resque Use Solr instead of doing complex joins
  135. 135. Solr to the Resque Use Solr instead of doing complex joins Solr reads are < 10ms
  136. 136. Solr to the Resque Use Solr instead of doing complex joins Solr reads are < 10ms Sunspot Gem by default writes to Solr from each ruby VM (i.e. unicorn)!
  137. 137. Solr to the Resque Use Solr instead of doing complex joins Solr reads are < 10ms Sunspot Gem by default writes to Solr from each ruby VM (i.e. unicorn)! Serialize writes with Resque!
  138. 138. Solr to the Resque Use Solr instead of doing complex joins Solr reads are < 10ms Sunspot Gem by default writes to Solr from each ruby VM (i.e. unicorn)! Serialize writes with Resque! One master for writes
  139. 139. Solr to the Resque Use Solr instead of doing complex joins Solr reads are < 10ms Sunspot Gem by default writes to Solr from each ruby VM (i.e. unicorn)! Serialize writes with Resque! One master for writes Read replicas on each app server
  140. 140. Putting it together Unicorn Unicorn / Workers Resque Passenger Unicorn / Passenger Ruby VM Ruby VM 3. Update Solr solr_replica 4. Replicate solr_master 2. Read Model Info 1. Model Changed redis DB
  141. 141. At this size...
  142. 142. At this size...Automate everythingChef or Puppet is awesome
  143. 143. At this size...Automate everythingChef or Puppet is awesomeMonitor everythingTolerate reboots, restarts, partial failures
  144. 144. At this size...Automate everythingChef or Puppet is awesomeMonitor everythingTolerate reboots, restarts, partial failuresUse OS services layer to start/stop everythingEnsures recovery after reboot
  145. 145. At this size...Automate everythingChef or Puppet is awesomeMonitor everythingTolerate reboots, restarts, partial failuresUse OS services layer to start/stop everythingEnsures recovery after rebootCapistrano tends to gets “complex”Can also deploy with Chef
  146. 146. Choose Vendors WiselyYou can pick your own, but here is my list:
  147. 147. Choose Vendors WiselyYou can pick your own, but here is my list: Clouds - JOYENT, EngineYard fastest I/O cloud, but on Solaris derivative
  148. 148. Choose Vendors WiselyYou can pick your own, but here is my list: Clouds - JOYENT, EngineYard fastest I/O cloud, but on Solaris derivative Automation - Chef + OPSCODE
  149. 149. Choose Vendors WiselyYou can pick your own, but here is my list: Clouds - JOYENT, EngineYard fastest I/O cloud, but on Solaris derivative Automation - Chef + OPSCODE Caching/CDN - FASTLY.COM varnish based CDN, very fast, full power of VCL configuration
  150. 150. Choose Vendors WiselyYou can pick your own, but here is my list: Clouds - JOYENT, EngineYard fastest I/O cloud, but on Solaris derivative Automation - Chef + OPSCODE Caching/CDN - FASTLY.COM varnish based CDN, very fast, full power of VCL configuration Metrics and Performance - NewRelic Turnkey solution, getting better every day
  151. 151. In Development
  152. 152. In DevelopmentUse foreman to start dependent services (Solr,Redis, Resque) from a Procfile
  153. 153. In DevelopmentUse foreman to start dependent services (Solr,Redis, Resque) from a ProcfileDo “Just enough” testing with Solr - it’s slow!
  154. 154. In DevelopmentUse foreman to start dependent services (Solr,Redis, Resque) from a ProcfileDo “Just enough” testing with Solr - it’s slow!Deploy to single-box demo servers often usingthe same Capistrano scripts used forproduction
  155. 155. Mature App: Day 700
  156. 156. Mature App: Day 700cd my-awesome-apprake rspec:models rspec:controllers rspec:libsrake cucumber:webrat cucumber:selenium jasmine
  157. 157. Mature App: Day 700cd my-awesome-apprake rspec:models rspec:controllers rspec:libsrake cucumber:webrat cucumber:selenium jasmine
  158. 158. How Big Exactly?
  159. 159. How Big Exactly?200+ models200K+ lines of RUBY source code without gems100K+ lines of ERB, HTML and HAML templates100+ gem dependencies
  160. 160. How Big Exactly?200+ models200K+ lines of RUBY source code without gems100K+ lines of ERB, HTML and HAML templates100+ gem dependenciesthis is a real world application that’s in production today.
  161. 161. Is that too big?
  162. 162. Is that too big? This cat’s name is Lenin
  163. 163. Here is why I think it is.
  164. 164. Here is why I think it is.1.5+ hours for the full the test suite to complete10 mins of db seeds, 30 minutes for unit tests only, etc
  165. 165. Here is why I think it is.1.5+ hours for the full the test suite to complete10 mins of db seeds, 30 minutes for unit tests only, etcmerges often result in integration tests going RED
  166. 166. Here is why I think it is.1.5+ hours for the full the test suite to complete10 mins of db seeds, 30 minutes for unit tests only, etcmerges often result in integration tests going RED20 seconds boot-up time for Rails env (r console, etc)!
  167. 167. Here is why I think it is.1.5+ hours for the full the test suite to complete10 mins of db seeds, 30 minutes for unit tests only, etcmerges often result in integration tests going RED20 seconds boot-up time for Rails env (r console, etc)!500Mb of RSS RAM for one single-threaded web process
  168. 168. Here is why I think it is.1.5+ hours for the full the test suite to complete10 mins of db seeds, 30 minutes for unit tests only, etcmerges often result in integration tests going RED20 seconds boot-up time for Rails env (r console, etc)!500Mb of RSS RAM for one single-threaded web processit’s a difficult undertaking to upgrade dependencies and rails
  169. 169. Yeah.
  170. 170. It was much nicer when it was a bit smaller..
  171. 171. It was much nicer when it was a bit smaller..
  172. 172. Let’s zoom in...
  173. 173. Let’s zoom in...Is PERFORMANCE of the app an issue?
  174. 174. Let’s zoom in...Is PERFORMANCE of the app an issue? NO! 150ms per request avg
  175. 175. Let’s zoom in...Is PERFORMANCE of the app an issue? NO! 150ms per request avgIs SCALABILITY of the app an issue?
  176. 176. Let’s zoom in...Is PERFORMANCE of the app an issue? NO! 150ms per request avgIs SCALABILITY of the app an issue? NO! 8000+ concurrent users
  177. 177. Let’s zoom in...Is PERFORMANCE of the app an issue? NO! 150ms per request avgIs SCALABILITY of the app an issue? NO! 8000+ concurrent usersIs RELIABILITY of the app an issue?
  178. 178. Let’s zoom in...Is PERFORMANCE of the app an issue? NO! 150ms per request avgIs SCALABILITY of the app an issue? NO! 8000+ concurrent usersIs RELIABILITY of the app an issue? NO! barely any downtime in over one year
  179. 179. Then WTF is the Problem?
  180. 180. Then WTF is the Problem?Is PRODUCTIVITY of developing the app an issue?
  181. 181. Then WTF is the Problem?Is PRODUCTIVITY of developing the app an issue? YES! Lots of waiting all the time
  182. 182. Then WTF is the Problem?Is PRODUCTIVITY of developing the app an issue? YES! Lots of waiting all the timeIs MERGING source code between parallel projects difficult?
  183. 183. Then WTF is the Problem?Is PRODUCTIVITY of developing the app an issue? YES! Lots of waiting all the timeIs MERGING source code between parallel projects difficult? YES! 30+ people sharing large codebase
  184. 184. Then WTF is the Problem?Is PRODUCTIVITY of developing the app an issue? YES! Lots of waiting all the timeIs MERGING source code between parallel projects difficult? YES! 30+ people sharing large codebaseIs KEEPING TEST SUIT GREEN challenging?
  185. 185. Then WTF is the Problem?Is PRODUCTIVITY of developing the app an issue? YES! Lots of waiting all the timeIs MERGING source code between parallel projects difficult? YES! 30+ people sharing large codebaseIs KEEPING TEST SUIT GREEN challenging? YES! tests are brittle and long running
  186. 186. But wait, there’s more!
  187. 187. But wait, there’s more! What about DEPLOYMENT of a large app? Takes a long time, and small tweaks require full deploys
  188. 188. But wait, there’s more! What about DEPLOYMENT of a large app? Takes a long time, and small tweaks require full deploys What about HOSTING COSTS? Necessary to provide enough RAM for the app to be scalable.
  189. 189. RAM? Latency matters...
  190. 190. RAM? Latency matters... 1 Request = 200ms on average latency 5 reqs/second on a single-threaded ruby VM process
  191. 191. RAM? Latency matters... 1 Request = 200ms on average latency 5 reqs/second on a single-threaded ruby VM process 30,000 RPM = 500 r/sec = 100 processes 50Gb of RAM @ 200ms latency If average latency is 600ms, need 150Gb of RAM !!!
  192. 192. Smaller is actually better.
  193. 193. So how do we solve this?
  194. 194. Part 3:How to split things up
  195. 195. Couple of main themes
  196. 196. Couple of main themes Break up into smaller applications
  197. 197. Couple of main themes Break up into smaller applications Extract services and create APIs
  198. 198. Couple of main themes Break up into smaller applications Extract services and create APIs Extract libraries (gems)
  199. 199. Smaller Applications
  200. 200. Smaller Applications Contain web GUI, logic, and data
  201. 201. Smaller Applications Contain web GUI, logic, and data May combine with other apps
  202. 202. Smaller Applications Contain web GUI, logic, and data May combine with other apps May rely on common libraries
  203. 203. Smaller Applications Contain web GUI, logic, and data May combine with other apps May rely on common libraries May rely on services
  204. 204. Smaller Applications Contain web GUI, logic, and data May combine with other apps May rely on common libraries May rely on services Typically run in their own Ruby VM
  205. 205. Consider a Typical E-Commerce Store
  206. 206. Consider a Typical E-Commerce Store Users must be able to register, login, logout (profiles)
  207. 207. Consider a Typical E-Commerce Store Users must be able to register, login, logout (profiles) Users must be able to browse and search products, view, and add to cart
  208. 208. Consider a Typical E-Commerce Store Users must be able to register, login, logout (profiles) Users must be able to browse and search products, view, and add to cart Users must be able to checkout
  209. 209. Consider a Typical E-Commerce Store Users must be able to register, login, logout (profiles) Users must be able to browse and search products, view, and add to cart Users must be able to checkout Probably many other stories, such as admin, but we’ll ignore for now.
  210. 210. One idea...
  211. 211. One idea... Application 1: Marketing, Product Catalog Browser, Search + Product Detail Page
  212. 212. One idea... Application 1: Marketing, Product Catalog Browser, Search + Product Detail Page Application 2: Checkout, Payment, Order History, Returns Fulfillment
  213. 213. One idea... Application 1: Marketing, Product Catalog Browser, Search + Product Detail Page Application 2: Checkout, Payment, Order History, Returns Fulfillment Very clear user flow transfer and data separation.
  214. 214. Some things can be shared
  215. 215. Some things can be shared Service: Single Sign-on, User profiles, Login/Registration [devise?, rest-full authentication?]
  216. 216. Some things can be shared Service: Single Sign-on, User profiles, Login/Registration [devise?, rest-full authentication?] Service: Product Catalog data, Inventory Data
  217. 217. Some things can be shared Service: Single Sign-on, User profiles, Login/Registration [devise?, rest-full authentication?] Service: Product Catalog data, Inventory Data Service: Comments, Votes, Ratings, Reviews
  218. 218. Services Technologies
  219. 219. Services Technologies Rack/Sinatra/Rails are popular, and are often an entirely sufficient choice
  220. 220. Services Technologies Rack/Sinatra/Rails are popular, and are often an entirely sufficient choice Goliath is awesome if performance is important, and if the service is mostly I/O bound
  221. 221. Services Technologies Rack/Sinatra/Rails are popular, and are often an entirely sufficient choice Goliath is awesome if performance is important, and if the service is mostly I/O bound node.js is also a popular choice
  222. 222. Services Technologies Rack/Sinatra/Rails are popular, and are often an entirely sufficient choice Goliath is awesome if performance is important, and if the service is mostly I/O bound node.js is also a popular choice Implementation may change in the future, as long as the API stays consistent
  223. 223. http balancer / router /checkout → checkout app /* → catalog app catalog app checkout app cart DB CSS/UI Library DBProduct Service Reviews, User Auth / Login Inventory Comments, Profiles Votes, Ratings DB DB DB
  224. 224. http balancer / router /checkout → checkout app /* → catalog app catalog app checkout app CSS/UI Library DB DBProduct Service Reviews, User Auth / Login Inventory Comments, Profiles Votes, Ratings DB DB DB
  225. 225. http balancer / routerExtract look and feel /checkout → checkout app /* → catalog app(CSS/UI) into a gem to catalog app checkout appshare across apps CSS/UI Library DB DB Product Service Reviews, User Auth / Login Inventory Comments, Profiles Votes, Ratings DB DB DB
  226. 226. http balancer / routerExtract look and feel /checkout → checkout app /* → catalog app(CSS/UI) into a gem to catalog app checkout appshare across apps CSS/UI Library DB DBCreate client API wrapper Product Service Reviews, User Auth / Logingems for consumers Inventory Comments, Profiles Votes, Ratings DB DB DB
  227. 227. http balancer / routerExtract look and feel /checkout → checkout app /* → catalog app(CSS/UI) into a gem to catalog app checkout appshare across apps CSS/UI Library DB DBCreate client API wrapper Product Service Reviews, User Auth / Logingems for consumers Inventory Comments, Profiles Votes, Ratings DB DB DBCreate a single shared“base” client gem library
  228. 228. Rails App with < 30 Models
  229. 229. Rails App with < 30 Models Can run tests pretty quickly, hopefully under 5 minutes
  230. 230. Rails App with < 30 Models Can run tests pretty quickly, hopefully under 5 minutes Is often large enough to describe typical “clusters of functionality”, i.e. - mini apps
  231. 231. Rails App with < 30 Models Can run tests pretty quickly, hopefully under 5 minutes Is often large enough to describe typical “clusters of functionality”, i.e. - mini apps Ruby VM might actually stay under 100Mb of RSS RAM
  232. 232. Rails App with < 30 Models Can run tests pretty quickly, hopefully under 5 minutes Is often large enough to describe typical “clusters of functionality”, i.e. - mini apps Ruby VM might actually stay under 100Mb of RSS RAM Is more comprehensible and can be effectively maintained by a small dev team.
  233. 233. 3rd Party Integrations catalog app checkout app analytics financial warehouse and ERP system management reporting system CSS/UI LibraryDB DB Product Service Reviews, User Auth / Login Inventory Comments, Profiles Votes, Ratings DB DB DB
  234. 234. Ecosystem of Applications
  235. 235. Ecosystem of Applications Is inevitable in large companies
  236. 236. Ecosystem of Applications Is inevitable in large companies Scale better from team perspective
  237. 237. Ecosystem of Applications Is inevitable in large companies Scale better from team perspective Offer decoupling and implementation hiding
  238. 238. Ecosystem of Applications Is inevitable in large companies Scale better from team perspective Offer decoupling and implementation hiding Can be individually optimized and scaled
  239. 239. But then...Must every app know aboutevery other app?
  240. 240. API Proxy / Router catalog app checkout app analytics financial and ERP CSS/UI LibraryDB DB reporting system http://api.mycompany.com/ Product Service Reviews, User Auth / Login Inventory Comments, Profiles Votes, Ratings DB DB DB
  241. 241. Example: Order Placed
  242. 242. Example: Order Placed Warehouse Management System needs to be updated
  243. 243. Example: Order Placed Warehouse Management System needs to be updated Analytics Engine needs to be notified
  244. 244. Example: Order Placed Warehouse Management System needs to be updated Analytics Engine needs to be notified Financials needs to be updated
  245. 245. Example: Order Placed Warehouse Management System needs to be updated Analytics Engine needs to be notified Financials needs to be updated Question: which component is responsible for updating each application?
  246. 246. 1995 Was Great
  247. 247. 1995 Was Great GoF Design Patterns: Observer “...One-to-Many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically...”
  248. 248. Distributed Version
  249. 249. Distributed VersionPublish/Subscribe and Point-to-Point Asynchronous Middleware
  250. 250. Distributed VersionPublish/Subscribe and Point-to-Point Asynchronous Middleware
  251. 251. RabbitMQ is Great
  252. 252. Some Options for Pub/Sub
  253. 253. Some Options for Pub/SubRabbitMQ ruby-amqp gem to interface
  254. 254. Some Options for Pub/SubRabbitMQ ruby-amqp gem to interfaceEventMachine::Channel
  255. 255. Other Distributed Options
  256. 256. Other Distributed OptionsDRb - distributed Ruby (also Rinda, Starfish,beanstalkd, etc)
  257. 257. Other Distributed OptionsDRb - distributed Ruby (also Rinda, Starfish,beanstalkd, etc)DCell - actor based based on 0MQhttp://www.unlimitednovelty.com/2012/04/introducing-dcell-actor-based.html
  258. 258. Other Distributed OptionsDRb - distributed Ruby (also Rinda, Starfish,beanstalkd, etc)DCell - actor based based on 0MQhttp://www.unlimitednovelty.com/2012/04/introducing-dcell-actor-based.htmlAll of them are a bit too low level for sharingand consuming business events
  259. 259. I would love a library forpublishing business eventsbuilt on top
  260. 260. Dependency Stack Business Events Collection Commerce::OrderPlaced SharedEvent::Base AMQP-ruby Library AMQP::connect RabbitMQ Middleware
  261. 261. Future Library
  262. 262. Future Library Hides complexities of queues and exchanges
  263. 263. Future Library Hides complexities of queues and exchanges Consumers declare interest in events they care about, define persistence and retry policy
  264. 264. Future Library Hides complexities of queues and exchanges Consumers declare interest in events they care about, define persistence and retry policy Publishers fire! events and forget about it
  265. 265. Future Library, ctd.
  266. 266. Future Library, ctd. Once registered, consumers get messages even after being offline
  267. 267. Future Library, ctd. Once registered, consumers get messages even after being offline When publisher can submit an event to the queue, it’s job is done.
  268. 268. Future Library, ctd. Once registered, consumers get messages even after being offline When publisher can submit an event to the queue, it’s job is done. Library of business events becomes a compliment to the set of business APIs
  269. 269. Untangle Communications catalog app checkout app 4. consume InventoryChanged 1. publish OrderPlaced Messaging Bus 3. publish InventoryChanged 4. consume InventoryChanged 2. consume OrderPlacedanalytics and financial ERP inventory management reporting system
  270. 270. I don’t think this libraryexists yet, but I wouldlike to write one soon =)
  271. 271. Distributed Ruby Reading
  272. 272. Thank you.
  273. 273. Thank you.twitter: @kiggithub/kigster

×