$30 off During Our Annual Pro Sale. View Details »

The road to a Multi-Tenant Rails App

The road to a Multi-Tenant Rails App

At the beginning of the world there was a Rails app, built to solve a specific problem and it happens to be a single tenant app. In another SAAS world, with a freemium model, most of the tenants that signs up (after finding you on Google) are 'kinda lazy’, and don’t really use the app, and don't do anything other than signup. There will be, however, a few special users out there waiting for your app. They also found you on Google, signs up, logins on a daily basis, use it, and use it. Importantly, these special users had allocated the same amount of resources as the ‘kinda lazy’ ones.
To scale in the scenario describe requires a change in approach: Special tenants get Special treatment, while ‘kinda lazy’ tenants get default treatment (and shared resources).
In this talk I will describe a few options that are available for this problem.

Helio Cola

June 11, 2015
Tweet

More Decks by Helio Cola

Other Decks in Programming

Transcript

  1. The road to Multi-Tenant
    Helio Rodrigues
    Senior SW Engineer
    Mobile Posse
    www.mobileposse.com

    View Slide

  2. Thank you, first!
    ❖ To all DCRUG organizers
    ❖ To all ARUG organizers
    ❖ To all NOVARUG organizers
    You all provide an awesome service to science,
    technology, and all of us!

    View Slide

  3. Also: thanks to you
    ❖ Quote from Ken Collins (https://github.com/metaskills)

    View Slide

  4. about.me
    ❖ 15+ years developing Software
    ❖ ~10 years developing C/C++ in Solaris environment
    ❖ ~5/6 years since I found happiness
    ❖ ~4 years of full time happiness
    [email protected] - @hacrods
    ❖ I am extremely shy!

    View Slide

  5. Where I work!
    ❖ Full-time job: www.mobileposse.com
    ❖ Latest product: www.appenvoy.com
    ❖ Part-time job: You will hear about it one day!

    View Slide

  6. Agenda
    ❖ How we usually get to a multi tenant problem
    ❖ The problem
    ❖ Possible solutions & tradeoffs
    ❖ Core changes
    ❖ Delayed Jobs
    ❖ Database migrations
    ❖ Tenant migration
    ❖ Questions & Close up

    View Slide

  7. How we get there
    You go and build it:
    ❖ A rails app with a handful of delayed job tasks with MongoDB
    ❖ User management & CanCan(can) with System, Admin, and Editor roles
    ❖ Gems: Oauth2, doorkeeper, delayed_job, mustache, devise, foreman, fog, carrierwave, aws-core-sdk,
    parallel, newrelic_rpm, and gravtastic
    ❖ Create a JSON/REST API with swagger docs
    ❖ The signup process (via CMS)
    ✤ User signup trigger a chef/knife/recipe/stuff that does a lot of things including
    ✴ Open a AWS Route53 for my_user.user.myapp.com
    ✴ Install your rails app on /home/deployer/my_user on the WebServers + AppServers
    ✴ Configure nginx/passenger
    ✴ Start all rails apps
    ✦ db:seed will setup the MongoDB with initial user, password and a few other things
    ✴ Start delayed job workers

    View Slide

  8. tenant1
    Web Servers App Servers
    tenant1
    tenant1
    Mongo ReplicaSet
    tenant2
    tenant2
    tenant2

    View Slide

  9. The Single Tenant Problem
    ❖ Way too many resources allocated for non-active users
    ❖ Can’t fit too many users in a single landlord
    ❖ Users need to be deleted to open space for new users

    View Slide

  10. tenant1
    Web Servers App Servers
    tenant2
    tenant3
    tenant4
    tenant5
    tenant1
    tenant2
    tenant3
    tenant4
    tenant5
    tenant1
    tenant2
    tenant3
    tenant4
    tenant5
    Mongo ReplicaSet

    View Slide

  11. Agenda
    ❖ How we usually get to a multi tenant problem
    ❖ The problem
    ❖ Possible solutions & tradeoffs
    ❖ Core changes
    ❖ Delayed Jobs
    ❖ Database migrations
    ❖ Tenant migration
    ❖ Questions & Close up

    View Slide

  12. The Solution:
    ❖ Let’s GO Multi-Tenant
    Web Servers App Servers Mongo ReplicaSet
    tenant1
    tenant2
    tenant3
    tenant4
    tenant5
    Landlord1
    Landlord2
    tenant1
    tenant2
    tenant3
    tenant4
    tenant5
    Landlord1
    Landlord2

    View Slide

  13. Types of Multi-tenant apps:
    ✴ One database for all customers
    ✴ One database per customer
    ✴ One collection per partner
    ✴ Reference: https://docs.compose.io/use-cases/multi-
    tenant.html

    View Slide

  14. Agenda
    ❖ How we usually get to a multi tenant problem
    ❖ The problem
    ❖ Possible solutions & tradeoffs
    ❖ Core changes
    ❖ Delayed Jobs
    ❖ Database migrations
    ❖ Tenant migration
    ❖ Questions & Close up

    View Slide

  15. Core changes
    ✤ Database switch before reaches your app controllers
    ✤ Delayed jobs outside the tenant database
    ✤ Database migration per LandLord and rake tasks per
    tenant
    ✤ Signup/Delete a new tenant is now a feature the app
    needs to support
    ✤ Migrate tenant between landlords

    View Slide

  16. Database switch
    References
    ✦ https://groups.google.com/forum/#!msg/
    mongoid/eNenGVmfG48/cWuHFLAjVK0J

    View Slide

  17. Database switch
    References
    ✦ https://groups.google.com/forum/#!msg/
    mongoid/eNenGVmfG48/cWuHFLAjVK0J
    class MongoidDbSwitcher
    def initialize(app)
    @app = app
    end
    def call(env)
    response = @app.call(env)
    response[2] = ::Rack::BodyProxy.new(response[2]) do
    ::Mongoid.override_database("school_one_#{env['SERVER_NAME']}")
    end
    response
    end
    end
    config.middleware.insert_before Warden::Manager, MongoidDbSwitcher

    View Slide

  18. Database switch: appartment gem
    require 'rack/request'
    require 'apartment/tenant'
    require 'apartment/deprecation'
    module Apartment
    module Elevators
    # Provides a rack based tenant switching solution based on request
    #
    class Generic
    def initialize(app, processor = nil)
    @app = app
    @processor = processor || parse_method
    end
    def call(env)
    request = Rack::Request.new(env)
    database = @processor.call(request)
    Apartment::Tenant.switch! database if database
    @app.call(env)
    end
    def parse_database_name(request)
    deprecation_warning
    parse_tenant_name(request)
    end
    def parse_tenant_name(request)
    raise "Override"
    end
    def parse_method
    if self.class.instance_methods(false).include? :parse_database_name
    deprecation_warning
    method(:parse_database_name)
    else
    method(:parse_tenant_name)
    end
    end
    def deprecation_warning
    Apartment::Deprecation.warn "[DEPRECATED::Apartment] Use
    #parse_tenant_name instead of #parse_database_name -> #{self.class.name}"
    end
    end
    end
    end

    View Slide

  19. Database switch: appartment gem

    View Slide

  20. Database switch: appartment gem

    View Slide

  21. Agenda
    ❖ How we usually get to a multi tenant problem
    ❖ The problem
    ❖ Possible solutions & tradeoffs
    ❖ Core changes
    ❖ Delayed Jobs
    ❖ Database migrations
    ❖ Tenant migration
    ❖ Questions & Close up

    View Slide

  22. Delayed jobs
    Delayed jobs outside the tenant database
    ❖ The delayed jobs are
    created in the landlord’s
    DB but do things on the
    tenant’s DB

    View Slide

  23. Agenda
    ❖ How we usually get to a multi tenant problem
    ❖ The problem
    ❖ Possible solutions & tradeoffs
    ❖ Core changes
    ❖ Delayed Jobs
    ❖ Database migrations
    ❖ Tenant migration
    ❖ Questions & Close up

    View Slide

  24. Database migrations
    Database migration and rake tasks on a per tenant/
    landlord basis
    ❖ Keep the rails way
    ❖ Migration run for all tenants for a given LandLord
    ❖ Rake tasks run for a subset (one, two, or all)

    View Slide

  25. Signup/Delete
    ❖ Signup/Delete a new tenant is now a feature the app
    needs to support
    ❖ Tenant is white listed in each landlord and only those
    are answered by the landlord

    View Slide

  26. Moving tenants
    Multi instances with different purpose
    ✤ Default: all signups from the public website
    ✤ Bleeding Edge: latest and greatest features
    ✤ Stable: mature version, bug free
    ✤ Custom clients

    View Slide

  27. References
    ✦ http://mongoid.org/en/mongoid/docs/persistence.html#custom
    ✦ https://groups.google.com/forum/#!msg/mongoid/Rp64Tvjwtbk/dNVa92opzeIJ
    ✦ https://groups.google.com/forum/#!msg/mongoid/eNenGVmfG48/cWuHFLAjVK0J
    ✦ https://docs.compose.io/use-cases/multi-tenant.html
    ✦ https://github.com/influitive/apartment

    View Slide

  28. Before we go
    ✴ http://db-engines.com/en/ranking
    ✴ Google: db engines ranking
    Questions?

    View Slide