Rails multitenant architecture, scoping access to multiple tenants

天涯浪子 提交于 2019-12-06 10:36:38

问题


We have a single-tenant database architecture at the moment with MySQL running upward of 100 databases. We switch database connection on subdomain using the Apartment gem and all is dandy!

However, we have a requirement now to create so-called "Umbrella" clients which can access all the data from a group of our existing clients. I don't see this as immediately feasible with our single-tenant database architecture (I looked into it and querying multiple MySQL databases just seemed hellish), so I'm beginning to look at different implementations with Postgres schemas.

I'm looking for some advice:

  • is it possible to query multiple schemas in Postgres and collate the results somehow (looking for Rails implementation)? I can foresee problems with conflicting primary keys?

  • Would it be better to have a new schema that is somehow represents/duplicates all the data in the group of schemas that need to be accessed? It would need to be realtime.

  • If so, can something similar be achieved in my current multiple DB set-up with MySQL? (to minimise the pain)

I'm wary of using a database field to achieve multitenancy in MySQL as data security/privacy is a huge thing for this product, and there's so much potential for developer error that way.


回答1:


just thinking through this on a high level approach to this problem.

You could create a pg view table to access this data (although it will be slower than accessing the databases themselves).

Then you hopefully have enough unique fields in your table to create a compound or composite key. (Then you wouldn't have to create a new key column, just an index). Because Rails 3 is ORM agnostic, you could then use DataMapper (or maybe the new ROM gem) to establish the connection for this one model.

If you do compound keys, realize that you might have to explicitly define the *to_param* method in your model to build the key as a string. This is for unwrapping the :id when you send it in a url.

You can setup access to this view through a different Postgres user and then use Rails' ability for multiple connections to create a model for it. We did this previously to aggregate data from multiple tables with some restrictions on what was being shown, but I don't see why that wouldn't apply in your use case.

Another option is that perhaps you could use Mongo as the "transient query database". BSON would give you unique keys automatically. And you could create Objects that are essentially SQL Scalar Objects. Not sure you'd want to do a write back to the original database in this case though... but you feasibly could do it.

Bottom line IMO is I think the best solution lies on the database side of the house because you're using multiple databases. Dealing with these items at the database layer seems the best solution.

Having said all of this... this also seems like a process smell. If I read the problem as stated correctly, I think what you're really trying to do in this case is what Hadoop is designed for... essentially map/reduce of relevant data (aka Big Data Analysis)

Good luck!




回答2:


Despite finding many examples of multitenancy in Rails applications when I first set out to do it, I couldn't find one that made me felt completely comfortable either. But I finally have a solution I'm happy with.

I started with the 'multitenancy with scopes' railscast

http://railscasts.com/episodes/388-multitenancy-with-scopes

then looked at making multi-tenancy work with devise subdomains using this guide:

https://github.com/plataformatec/devise/wiki/How-To:--Isolate-users-to-log-into-a-single-subdomain

But I didn't take that at face value; I dove in to really understand how devise worked that way.

Once I had all that in place, I was ready for the multitenant gem:

https://github.com/wireframe/multitenant

But I didn't stop there. the multitenant gem requires that you say Multitenant.with_tenant whenever you want things scoped appropriatey, so I created a TenantController that looks like this:

  around_filter :scope_current_tenant

  def scope_current_tenant
    begin
      Firm.current = Firm.find_by_subdomain!(request.subdomain)
    rescue
      raise ActionController::RoutingError.new('Not Found')
    end

    Multitenant.with_tenant Firm.current do
      yield
    end

    ensure
      Firm.current = nil
    end
  end

and then any controller I want to be scoped by tenant inherits from TenantController rather than ApplicationController. That way I didn't have to remember anything in the details of the controller, it 'just worked'. the only thing developers had to think about was 'is this a controller that is handling tenant data?'

While this still depends on developers doing a few things correctly (inheriting from the right controller, saying 'acts_as_multitenant' in the model, it works really well in practice.




回答3:


OBS: I'm not a Ruby guy, so I can only give you the PG side of the idea.

With PostgreSQL schemas you can easily manage it. Just create a schema for each tenant you have, so in you application, when you need to change the tenant you just do:

SET search_path TO client1;

With that, when you query for a table, let's say customer, you only need to do on the same connection:

SELECT ... FROM customer ...;

And, when you need to query for another tenant (not in search_path) you can query the table with the schema:

SELECT ... FROM client2.customer ...;

And you can use another schema to store public information, like the public schema, just adding it to the end of search_path:

SET search_path TO client1, public;



回答4:


Hate to say it since it sounds like you're already quite invested in your current system but it sounds like a job that would be better suited for a NoSQL solution.

Specifically, I'm thinking of MongoDB which uses a "schemaless", key-value database design. This would enable you pull data from your database based on a key and sort it in software. MongoDB also supports sharding which lets you use one database across as many database servers as you want, which sounds like it could work well in you application. The docs at http://www.mongodb.org/ might be worth checking. I'm not sure if it would be a perfect fit but it sounds like it could work for your application.



来源:https://stackoverflow.com/questions/17279141/rails-multitenant-architecture-scoping-access-to-multiple-tenants

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!