Slide 1

Slide 1 text

Scaling Extending & Expanding Your Application Through Messaging ! Avi Tzurel

Slide 2

Slide 2 text

ME • Avi Tzurel • [email protected] • @KensoDev (Twitter, Github, Facebook)

Slide 3

Slide 3 text

What are we talking about? • Current way of building 95% of rails apps • Why is that broken? • Why should you care? • New and improved way of building connected apps

Slide 4

Slide 4 text

Our Use Case

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

Writing a review • Set the review language • Set the review rank (based on some rules) • Update the user score • Was he first to write a full review? (better score) • Update the place score • Update the place score in a travel style • Update the personal place score for user graph

Slide 7

Slide 7 text

The Rails Way • How would you say rails is designed to do this?

Slide 8

Slide 8 text

Yes, I am asking a question ! What would you say is the rails way?

Slide 9

Slide 9 text

The Rails Way

Slide 10

Slide 10 text

Problems

Slide 11

Slide 11 text

Problems • Overloading the Lib Directory • Lib directory gets to be the junk of rails apps

Slide 12

Slide 12 text

It goes on and on....

Slide 13

Slide 13 text

Problems • Application is bloating beyond your control • Gemfile • Initializers • Models • Super slow startup times • Super slow testing times

Slide 14

Slide 14 text

The slightly better way

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

Again... • Working with workers will make life a bit better • Still lots of bloat in the lib dir • Lots of workers in the application code to load • Where the hell is my logic? • Some engineers put it in the worker, some do classes

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

It Still Sucks!

Slide 19

Slide 19 text

• Going into the better way I will try… • Being framework Agnostic • Giving the concept, you make it great for you. • Making sure you know it’s not a one size fits all There’s a better way

Slide 20

Slide 20 text

NOT • Not a single application • Not a single logic location • Not a single test suite • Not a single Gemfile • Not a magic solution for all apps • Not something to start with right away (for a MVP)

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

Publishing Events • Working with Events, not workers or classes • Every model/class can publish any event • There’s no ACK on the other side, it’s just publishing the message to your broker (I said I will be agnostic) • The model/observer responsibility ends here

Slide 24

Slide 24 text

Subscribing • On the other side, your “mini-apps” can subscribe to those events • Events can be unique strings or topics • For example “recommendation_change” is a topic • Any app that cares about this, will register on the event

Slide 25

Slide 25 text

Our Mini apps • LanguageDetectionApp • RecommendationRankingApp • PlaceScoringApp • TravelStyleScoringApp • UserScoringSystem • GraphScoringSystem

Slide 26

Slide 26 text

• Apps can be written in • Full rails apps • Ruby • Sinatra apps • Go • Java more on apps

Slide 27

Slide 27 text

more on apps • Different Gems for different apps • Tests only run on those apps on change • Now, when you change your main app, it runs only those relevant specs • Different API’s, can even be different languages

Slide 28

Slide 28 text

Message Types

Slide 29

Slide 29 text

Publisher => Consumer

Slide 30

Slide 30 text

send.rb #!/usr/bin/env ruby
 # encoding: utf-8
 
 require "bunny"
 
 conn = Bunny.new(:automatically_recover => false)
 conn.start
 
 ch = conn.create_channel
 q = ch.queue("hello")
 
 ch.default_exchange.publish("Hello World!", :routing_key => q.name)
 puts " [x] Sent 'Hello World!'"
 
 conn.close

Slide 31

Slide 31 text

receive.rb #!/usr/bin/env ruby
 # encoding: utf-8
 
 require "bunny"
 
 conn = Bunny.new(:automatically_recover => false)
 conn.start
 
 ch = conn.create_channel
 q = ch.queue("hello")
 
 begin
 puts " [*] Waiting for messages. To exit press CTRL+C"
 q.subscribe(:block => true) do |delivery_info, properties, body|
 puts " [x] Received #{body}"
 end
 rescue Interrupt => _
 conn.close
 
 exit(0)
 end

Slide 32

Slide 32 text

Work Queues

Slide 33

Slide 33 text

new_task.rb #!/usr/bin/env ruby
 # encoding: utf-8
 
 require "bunny"
 
 conn = Bunny.new(:automatically_recover => false)
 conn.start
 
 ch = conn.create_channel
 q = ch.queue("task_queue", :durable => true)
 
 msg = ARGV.empty? ? "Hello World!" : ARGV.join(" ")
 
 q.publish(msg, :persistent => true)
 puts " [x] Sent #{msg}"
 
 conn.close

Slide 34

Slide 34 text

worker.rb #!/usr/bin/env ruby
 # encoding: utf-8
 
 require "bunny"
 
 conn = Bunny.new(:automatically_recover => false)
 conn.start
 
 ch = conn.create_channel
 q = ch.queue("task_queue", :durable => true)
 
 ch.prefetch(1)
 puts " [*] Waiting for messages. To exit press CTRL+C"
 
 begin
 q.subscribe(:manual_ack => true, :block => true) do |delivery_info, properties, body|
 puts " [x] Received '#{body}'"
 # imitate some work
 sleep body.count(".").to_i
 puts " [x] Done"
 ch.ack(delivery_info.delivery_tag)
 end
 rescue Interrupt => _
 conn.close
 end

Slide 35

Slide 35 text

Exchance *Not the MS exchange

Slide 36

Slide 36 text

Topics

Slide 37

Slide 37 text

Topics • Possibly the most powerful feature of RabbitMQ • You can register to a topic via string/partial/regex • Exchange publishes to queues and consumers consume

Slide 38

Slide 38 text

emit_log_topic.rb #!/usr/bin/env ruby
 # encoding: utf-8
 
 require "bunny"
 
 conn = Bunny.new
 conn.start
 
 ch = conn.create_channel
 x = ch.topic("topic_logs")
 severity = ARGV.shift || "anonymous.info"
 msg = ARGV.empty? ? "Hello World!" : ARGV.join(" ")
 
 x.publish(msg, :routing_key => severity)
 puts " [x] Sent #{severity}:#{msg}"
 
 conn.close

Slide 39

Slide 39 text

receive_logs_topic.rb #!/usr/bin/env ruby
 # encoding: utf-8
 
 require "bunny"
 
 if ARGV.empty?
 abort "Usage: #{$0} [binding key]"
 end
 
 conn = Bunny.new
 conn.start
 
 ch = conn.create_channel
 x = ch.topic("topic_logs")
 q = ch.queue("", :exclusive => true)
 
 ARGV.each do |severity|
 q.bind(x, :routing_key => severity)
 end
 
 puts " [*] Waiting for logs. To exit press CTRL+C"
 
 begin
 q.subscribe(:block => true) do |delivery_info, properties, body|
 puts " [x] #{delivery_info.routing_key}:#{body}"
 end
 rescue Interrupt => _
 ch.close
 conn.close
 end

Slide 40

Slide 40 text

Receiving Logs # All Logs
 ruby -rubygems receive_logs_topic.rb "#"
 
 # Logs that start with kern
 ruby -rubygems receive_logs_topic.rb "kern.*"
 
 # Only Critical
 ruby -rubygems receive_logs_topic.rb "*.critical"
 
 # Multiple
 ruby -rubygems receive_logs_topic.rb "kern.*" "*.critical"
 
 # Emiting kern facility log
 ruby -rubygems emit_log_topic.rb "kern.critical" "A critical kernel error"

Slide 41

Slide 41 text

Full Architecture

Slide 42

Slide 42 text

Full Flow

Slide 43

Slide 43 text

Full Flow

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

Gotchas • Configuration of apps • Redis connection • DB connection • Mongo Connection • Memcached connection • Deployments

Slide 46

Slide 46 text

• Application config can be stored in... • Chef Data Bags (recommended) • ENV Variables (requires a bit more hassle) we work this way right now and making a move to the previous • Thanks to Avner @ Fiverr for the Chef idea Gotchas

Slide 47

Slide 47 text

Advantages • Full decoupling • Throw complete chunks of code to the trash • No more feature XXX, no problem • Adding another feature dependent on an event, No problem, Main app does not change (doesn’t even have to be redeployed) AMAZING RIGHT?

Slide 48

Slide 48 text

Advantages #2 • Improved response time (any async will give you that though) • Reduced complexity by decoupling • Build apps that use the language best suited instead of one gigantic monster app in Ruby/Rails • Deploy separately, scale separately

Slide 49

Slide 49 text

Read more • Bunny for RabbitMQ • Sneakers (Awesome!!! Thanks to @jundot) • RabbitMQ docs • http://www.rubyinside.com/why-rubyists-should-care- about-messaging-a-high-level-intro-5017.html • http://en.wikipedia.org/wiki/ Fallacies_of_Distributed_Computing • Messaging middleware used at Wikipedia

Slide 50

Slide 50 text

Thank you! ! Questions?