According to the GAE docs on the Multitenancy API:
Multitenancy is the name given to a software architecture in which one instance of an application, running on a remote server, serves many client organizations (also known as tenants).
But isn't this what every web application is? Dozens, hundreds, maybe even thousands of users all logging in to the system, accessing the same software, but from inside the context of their own "user accounts"? Or is Google's Multitenancy API some kind of API for developing generic data abstraction layers that can be used as backends for multiple apps?
I guess I don't get the meaning of a "Google multi-tenant" app, and as such, don't understand the purpose or usefulness of the Multitenancy API. Thanks in advance for any clarity here!
Consider the standard way that multitenancy is implemented: You add a "tenant ID" field to one or more tables, then include that ID in a WHERE clause. And you index that field.
You could take the same approach in App Engine, adding an indexed property to some of your entities to hold a tenant ID, carefully including that ID in GQL WHERE clauses (or a filters). This'll cost you a bit more on writes (for the two indexes on that property), and more if the ID participates in queries that include other filters, as those would require additional composite indexes that include the ID.
Or you user our multitenancy API, which gives you the same effect without the additional costs for index writes. You get slightly simpler code, and less expense.
Multitenancy here doesn't refer to users of your app as such, but 'instances' of your app with 'separate' datastores.
They aren't really separate instances or separate datastores, as those requests might be served by a shared instance and they are definitely talking to the same datastore. However, by using the API you can set up your app so that the data is partitioned into separate namespaces which don't pollute each other.
If you have only one user on your app, then multi-users and multi-tenanting is pretty much the same thing. If you have multiple users, then generally you'll be sharing data between the users. If so, you can use multitenancy to share data within only a certain group of users and partition the rest off in their own tenancy.
As jtahlborn rightly states, each of our GAE apps is already a tenant on the GAE infrastructure. We aren't able to share data between different apps because they are completely partitioned from each other.
As Dave says, we could implement multitenancy ourselves by adding some kind of domain name or partition id to all our data. The API just gives an easier way to do that.
The difference is whose tenants you are talking about. GAE was multi-tenant from day one in that each program(tenant) ran in a common GAE infrastructure. however, initially, your program itself just managed one body of data (when GAE was first released). the GAE "multi-tenancy API" enables your single program to manage its(your) own tenants (so your tenants as opposed to GAE's tenants).
to state it concisely and confusingly: the "multi-tenancy API" allows you to manage your own tenants(users) within a single GAE program, which is in turn hosted as a tenant(program) within the GAE infrastructure.
in theory, of course, you could always have done this from day 1 in GAE, but all the work for managing the data between your tenants would have been handled in your code. the "multi-tenancy API" attempts to remove that pain from the programmer and make it much simpler to segment the data within your program.
Related
I am developing a Spring MVC JPA web application. When this application is deployed in live the same DB that my application interacts with will be used by other 2 Dotnet and VB applications at the same time. I am managing the concurrency of my JPA app through version column.
Will there be any issue when running these 3 apps at the same time for the same database? All systems are using the same tables.
I will have to build another application (most probably Spring MVC + JPA) for the same DB in the future. Will there be any issues when running both apps at the same time (in terms of persisting the same tables in both apps etc.)?
Multiple applications accessing the same database tables can be (and usually is) a concurrency nightmare. Just adding a version column to tables does not help because each application may use different concurrency management mechanisms. Common problems encountered when sharing a database across applications (assuming read-write access for all and in no particular order):
Concurrency mismatch: Imagine one application using optimistic locking throughout, another using pessimistic locking and a third using no locking at all (since all are maintained by different teams). Even if there is a central architecture group handing out good application architecture advice to everyone, developers can do whatever they like and end up causing concurrency hell.
Deadlocks: Imagine one application using SERIALIZABLE isolation level for all transactions and performing long-running operations on the database, causing queues, deadlocks and timeouts. Even if other applications do not corrupt data, they may end up seeing too many errors due to deadlocks and timeouts, reducing their usefulness.
Data validity: It is common for developers to use in-memory caches for storing fixed or slow-changing data to save repeated database roundtrips. In a JPA application backed by Hibernate, developers could use a second-level cache. However, if another application updates the database, the cache would be holding stale (and therefore inaccurate) data.
Data integrity: Different applications may use different parts of the data. If all are allowed to update the common data independently, how is referential integrity maintained? What about business rules? Will they have to be duplicated across the applications?
Team communication overhead: Each team has to keep the other teams informed about changes they need to make to the schema so that they do not step on to each others' toes. This may even reduce agility if other teams do not agree with changes required by a team or if priorities cannot be aligned.
Schema errors: What happens if someone deletes, renames, moves or archives tables or columns required by an application?
Access control: If the underlying data is sensitive and requires authentication and authorization, access control checks will have to be duplicated across the applications.
Ownership: Who owns the common tables becomes a challenge as each team may have its own stakeholders, roadmap, constraints and priorities.
Portability: If the underlying database (vendor and type) has to be changed some day, all applications will need to be changed.
Auditing and versioning: If common data needs to be audited and/or versioned (multiple versions of data rows), the code will either have to be duplicated across applications or built into the database (which may not be easy within the database, for example, knowing which application user changed a record). If done within the database, portability is affected again because the syntax may vary from one database vendor to another.
Database-specific optimizations: Some scenarios (for example, reporting) may require native queries or other optimizations that may not be possible or too hard to perform using an ORM technology like JPA. If multiple applications require access to optimized queries, such functionality will either have to be built into the database (stored procedures) or duplicated across the applications (in possibly different ways).
Archival and partitioning: Different applications may have different archival and partitioning requirements. Who makes sure that everyone's needs are met equally?
Standardization: If different teams are allowed to manage the common database objects on their own, how are things such as data dictionary, naming conventions, etc. managed? A table that is used by different teams may have differently (and mostly annoyingly) named columns, constraints, etc.
A better approach is to expose the common database tables using a service. The service can keep things consistent and controlled at all times. A common team handling changes to the service can ensure that unexpected changes are minimized and also communicated to all affected parties in a timely manner.
Our framework is Grails. Say domain.com contains an application and currently used by some client. If we want to allow another client with the same functionality but providing a separation for the data of two clients, so that they can't mix both, how to do this? And whenever we want to add n clients to this application, what is the best method to be followed, so that with less / no configuration we can share the common war file for these clients by separating the db.
How the real time web development handle these type of situations?
And, one more point is how to provide client1.domain.com works for client1 and client2.domain.com works for client2. How to make the war file (in Java / Grails) to work like this? Otherwise we have to programmatically control the clients with in the project for every feature to be allowed or unnecessarily maintain separate war file for each client, which will be a waste of resources.
You're describing multitenancy - create one table for N 'tenants' instead of N identical (or nearly) tables, but partition it with a tenant_id column, and use that to filter results in SQL WHERE clauses.
For example the generated code for findByUsername would be something like select * from person where username='foo' and tenant_id=3' - the same code as a regular call but with the tenant_id column to restrict within that tenant's data.
Note that previously simple things like unique constraints are now harder because you would want to restrict uniqueness within a tenant, but allow a value to be reused across tenants. In this case changing the unique constraint to be on the combo of username and tenant_id works and does the heavy lifting in the database.
For a while there were several related plugins, but they relied on tweaking internal APIs and some features broke in newer Hibernate versions. But I believe that http://grails.org/plugin/multi-tenant-single-db is active; it was updated over a year ago, but it is being used. Contact the authors if it looks like it'll be what you need to be sure it's active. Note that this can only work with Hibernate 3.x.
Hibernate 4 added support for multitenancy, but I haven't heard much about its use in Grails (which is expected, since it's not that common a requirement). It's not well documented, but this bug report highlights some of the potential pitfalls and should still be a working example (the test app is still on GitHub): https://jira.grails.org/browse/GPHIB-6.
I'd like to ensure that this is working and continues to work, so please let me know via email if you have issues later. It's a great feature and having it in Hibernate core makes things a lot easier for us. But we need to make it easy to use and well-documented, and that will happen a lot faster when it's being used in a real project.
The standard example is probably where you offer a service to multiple companies on the same hosted instance and want employees to be able to see data only from other employees of the same company, not of potentially competitive companies.
I'm using JBossAS7 with Hibernate 4.x.
I could push the company information down from the UI layer and have the (stateless) persistence layer filter on that, but it seems like a bad idea to me, I'd rather have it done in one place closer to the database.
I'm guessing there must be a standard, secure solution for this, maybe around security domains or hibernate sessions? Thoughts? Thanks in advance.
You seem to be building a "multi-tenant application". Hibernate's support for multi-tenancy is quite restricted at the moment, with feature request 5697 having been recently completed, in 4.0.0.Alpha2. Note that this feature request does not address addition of tenant discriminator columns in the entities, which going by the discussion in JIRA, would arrive in 4.0.0.Alpha3 or 4.1.0 (going by JIRA). At the moment, you can store the data related to various tenants in different databases or schemas.
You can also read this related blog post, on various options regarding achieving multi-tenancy in Hibernate; this is quite old compared to the work done in HHH-5697, and does not discuss how one would create a multi-tenant application with tenant discriminator columns in the entity model.
I'm not sure of any standard, but have worked on two systems where it was important. These pre-dated tools like Hibernate and our use of J2EE.
In all systems I've worked on we've had to code this ourselves - using company as part of our keys in requests.
One possibility is a whole different "whatever your database calls its partition" for each customer. (Schema if you're in Oracle). Sounds more complex but it does guarantee isolation between companies and it does also allow some management of scaling or new/delete company. In my previous place of work I remember legal types felt nervous if anyone mentioned keeping more than one company's data in the same table - so that kept them happy.
You could either have your app server connect to the database as a trusted user who can access all, or make sure you pass the end user's credentials down when you connect. I've heard of this. It sounds good from a security point of view and means in a database like Oracle the right thing will just happen. I've not seen it done and wonder how well connection pooling would work if at all.
Edit: Vineet's answer above seems to cover it well. It's an area I'll have to look at more. We've probably got too much legacy code here to change.
I have an existing Java EE 6 application (deployed in Glassfish v 3.1) and want to support multiple tenants. Technologies/APIs I'm currently using in my app are
EJB (including the EJB timer service)
JPA 2.0 (EclipseLink)
JSF 2.0
JMS
JAX-RS
I plan to use CDI as well
As far as I know, adding multi-tenancy support affects only the persistence layer. My question: Has anybody done this before? What are the steps to convert the application? Will this affect other layers other than persistence?
There will be a high number of tenants, therefore, all data will reside in the same DB schema.
Persistence Layer
Start with the persistence layer. Roll upwards through your architecture once you have that done.
The Schema that you are proposing would have an ID that identifies the tenant (eg. TenantId). Each table would have this ID. In all of your queries you would have to ensure that the TenantId matches the logged in User's TenantId.
The difficulty with this is that it is a very manual process.
If you go with Hibernate as your JPA provider then there are some tools that will help with this; namely Hibernate Filters.
These are commonly used to restrict access on multi-tenant Schemas (see here and here for some more)
I haven't used EclipseLink but it does look like it has good support for Multi-Tenancy as well. The DiscriminatorColumn looks like a very similar concept to Hibernate Filters.
Service Layer
I assume that you're using JAX-RS and JMS for a Service Layer. If so then you will also need to think about how you are going to pass the tenantId around and authenticate your Tenants. How are you going to prevent one tenant from accessing the REST service of another? Same thing for JMS.
UI Layer
You are going to have to hook up your login in your UI to a Bean (Hibernate or Eclipselink) that sets the TenantId for the Filter/Discriminator.
Tell us about the number and the degree of separation and customization necessary for different tenants.
If you have a small number of tenants, I would propose to create a customizable "white-label" product. This gives you the opportunity to create some specific things for one tenant without overcomplexing matters. Plus, separating the applications per tenant helps you in maintenance. We did this for a product with a handful of different tenants.
If you have many tenants, this is of course no longer practical. We did a generic version of the same product. All we did then was distinguish tenants by id after login, thus separating the data from others. But still, there was nothing to do in terms of changing the application or a layer within, the id was all what was needed to separate the data and the workflow is automatically separated by having different instances of beans or other managed objects.
There's several ways you can go with this, depending on the level of separation you want to achieve and how many concurrent tenants you want to support. At one extreme, you can create a new schema for each tenant and therefore ensure database-level isolation of data. For most practical purposes it's usually sufficient to have a logical partitioning of your data by assigning a tenant_id to every entity in your domain model and maintaining foreign-key constraints. Of course this means you'll probably want to always pass in your current session's tenant_id to every query / finder method so that it can restrict the data set based on that. You'll want to make sure that users cannot access another tenant's data by entering a tenant id (or a entity id) that does not belong to them in url.
Go message oriented.
If you choose messaging as the strategic approach and refactor (if necessary) business logic around JMS, then other options remain viable and locally applicable.
With this approach, you pay a specific fixed cost (refactor) in your existing (single tenant) system. You then can apply approaches of various degrees of complexity, ranging from simple sharding (#Geziefer's id based association) to a full blown shared-core-schema + extended-tenant-specific-schemas approach, without impacting system architecture and additional refactoring.
You will further have orthogonal control over your system data flows via the messaging layer (applying routers, filters, special processing paths, etc.)
[edit per request]
There is nothing per se in M.T. that explicitly suggests message orientation. But as a general problem, we are looking at widening interfaces, and enriched data flows. Per an API based approach, you would need to carefully inject the appropriate the tenant discriminant in all required interfaces (e.g. methods). A message based (or alternatively a context based API approach) allows for a normative (stable) interface (e.g. message.send()) and at the same allows for explicit specialized data flows. If switching to a message based backbone is not on the table, you are strongly suggested to consider injecting a uniform context (e.g. "RequestContext") param in your APIs. This single extension should cover all your future specialization needs.
I am currently looking into converting a single-tenant Java based web-app that uses Spring, GWT, Hibernate, Jackrabbit, Hibernate Search / Lucene (among others) into a fully fledged SaaS style app.
I stumbled across an article that highlights the following 7 "things" as important changes to make to a single tenant app to make it an SaaS app:
The application must support multi-tenancy.
The application must have some level of self-service sign-up.
There must be a subscription/billing mechanism in place.
The application must be able to scale efficiently.
There must be functions in place to monitor, configure, and manage the application and tenants.
There must be a mechanism in place to support unique user identification and authentication.
There must be a mechanism in place to support some level of customization for each tenant.
My question is has anyone implemented any of the above 7 things in a SaaS /multi-tenant app using similar technologies to those that I have listed? I am keen to get as much input regarding the best ways to do so before I go down the path that I am currently considering.
As a start I am quite sure that I have a good handle on how to handle multiple tenants at a model level. I am thinking of adding a tenant ID to all of our tables and then using a Hibernate filter (and a Full Text Filter for Hibernate Search) to filter based on the logged on user's tenant ID for all queries.
I do however have some concerns around performance as well especially when our number of tenants grows quite high.
Any suggestions on how to implement such a solution will be greatly appreciated (and I apologise if this question is a bit too open-ended).
I would recommend that you architect your application to support all the 4 types of tenant isolation namely separate database for each tenant, separate schema for each tenant, separate table for each tenant and shared table for all tenants with a tenant ID. This will give you the flexibility to horizontally partition your database as you grow, having multiple databases each having a group of smaller tenants and also the ability to have a separate database for some large tenants. Some of your large tenants could also insist that their data (database) should reside in their premise, while the application can run off the cloud.
Here is an exaustive check list of non-functional and infrastructure level features that you may want to consider while architecting your application (some of them you may not need immediately, but think of a business situation of how you will handle such a need if your competition starts offering it)
tenant level customization of a) UI themes and logos b) forms and grids, c) data model extensions and custom fields, d) notification templates, e) pick up lists and master data
tenant level creation and administration of roles and privileges, field level access permissions, data scope policies
tenant level access control settings for modules and features, so that specific modules and features could be enabled / disabled depending on the subscription package.
Metering and monitoring of tasks / events / transactions and restriction of access control once the purchased quota is exceeded. The ability to meter any new entity in the future if and when your business model changes.
Externalising the business rules and workflows out of your code base and representing them as meta data, so that you can customize them for each tenant group / tenant.
Query builder for creating custom reports that is aware of the tenant as well as custom fields added by specific tenants.
Tenant encapsulation and framework level connection string management such that your developers do not have to worry about tenant IDs while writing queries.
All these are based on our experience in building a general purpose multi-tenant framework that can be used for any domain or application. Unfortunately, you cannot use our framework as it is based on .NET
But the engineering needs of any multi-tenant SaaS product (new or migrated) are the same irrespective of the technology stack that you use.
All of the technologies that you listed are quite common and reasonable for both single- and multi-tenant applications. I'd say supporting the 7 "things" for SaaS is much more of a function of how you use the technologies than which. It sounds like you already have a single-tenant application that works. So there's probably not much reason to deviate from the technology selections there unless something is just not working very well already. Your question is otherwise fairly open-ended though, so it's hard to be too much more specific there.
I do have some feedback on splitting the database (and perhaps other things) by tenant ID though. If you know you might eventually have a lot of tenants (say many thousands or more, particularly if they're small) then what you suggest is perhaps best. If however you'll have a smaller number of tenants (particularly if they're large) you might want to consider a database per tenant, so they each have their own table space. By that I mean a single database installation with multiple instances of the same schema inside of it, one per tenant.
There are a few reasons this can be an advantage. One is performance as you mentioned. Adding a tenant ID to every single table is overhead on disk access, query time and increases code complexity. Every index in the database will need to include the tenant ID as well. You run an additional risk of mixing data between tenants if you're not careful (although a Hibernate filter would help mitigate that). With a database per tenant you could restrict access to only the correct one. Porting your current application will probably be a lot easier too, you basically just need to intercept your request somewhere early to decide the tenant based on the URL and point to the right database. Backups are also easy to do per tenant, particularly useful if you ever intend on allowing them to download a backup.
On the other hand there are reasons not to do this. You'll have a lot of database schemas to deal with and they'll have to be updated independently (which can actually be an advantage if you want to avoid taking all tenants down for a schema change, you can roll them out incrementally). It lets you have special cases that could deviate from treating the platform as a true multi-tenant SaaS deployment that's upgraded all at once, resulting in management of multiple versions in production. Lastly I've heard there is a breaking point with just about every database vendor out there in the number of schema instances they'll support in one installation (supposedly some can go to hundreds of thousands though).
It really depends on your use case of course. You mentioned single-tenant which leads me to believe you don't have too many tenants right now, however you do mention growing to lots of tenants. I'm not sure if you mean hundreds or millions, yet either way I hope this helps some with your considerations. Best of luck!
There is no simple answer. I can describe my own solution. It may serve as an inspiration for the others.
tenant per database (postgres)
one additional database shared between tenants
Spring + MyBatis
Spring Security authentication
Details here: http://blog.trixi.cz/2012/01/multitenancy-using-spring-and-postgresql/
For (1): Hibernate supporting multi-tenant configurations out of the box from version 4.
At the moment of writing supported are DB-per-tenant and schema-per-tenant and keeping all tenants in a same DB using discriminator is not yet supported. We have used this functionality successfully in our application (DB-per-client approach).
For (3): After some investigation done we decided to go with Braintree to implement billing. Another solutions many people recommend: Authorize.net, Stripe, PayPal.
For (4): We have used clustered configuration with Hibernate/Spring and JBoss Cache for 2nd level caching. At these days this became "common" and using PaaS services like Jelastic you can even get it pre-configured out of the box.
What you describe is a full service Saas style application serving multiple tenants. There are a few things you have to decide like how critical is data isolation? If you are building for a medical or financial domain, data isolation is a critical factor.
Well, I cannot help answer all your points, but I would suggest looking at database-per-tenant approach for your application as it provides the highest level of data isolation.
Since you are using the Java, Spring, Hibernate stack, I can help you with a small example application I wrote. It is a working example which you can quickly run in your local laptop. I have shared it here. Do take a look and let me know if it answers some of your questions.