Many cloud-based, on-demand software services are actually multi-tenant applications, able to serve multiple users simultaneously on a single application instance. In the enterprise, for example, you might use Salesforce.com’s customer relationship management (CRM) service at the same time other companies are also using the same Salesforce.com application instance for their business purposes (without having to maintain the applications and data themselves).
The complexity of multi-tenancy can vary depending on the nature of the service, but building any multi-tenant infrastructure is not trivial and requires a lot of upfront thought and architectural work. In this first article of a three-part series on implementing a multi-tenant cloud architecture, I explore the multi-tenancy approaches that enterprise development organizations can use.
Security Risks of Multi-tenant Architecture
Before delving into the details of multi-tenancy approaches, let’s first address a major concern with multi-tenant architecture in general: data security.
Because of two main risk factors, most multi-tenant systems adhere to much higher security standards than standalone systems, depending on what type of multi-tenant infrastructure the system uses. The first risk applies to virtualized infrastructures, where a single physical machine hosts many separate virtual machines. In this kind of setup, one of the machines theoretically could monitor what its neighbors are doing, burrowing into the underlying infrastructure to bypass security implemented at the software layer.
The second risk is that a poorly implemented access management process or some kind of software bug could inadvertently expose one user’s data to other users. People are most conscious of this risk in a multi-tenant database, where every customer’s data is stored in the same tables. However, this risk also exists in multi-tenant infrastructures where only the application code is shared.
Approaches for Multi-tenant Architecture
So, how is multi-tenancy achieved? A typical software application consists of an application tier and a database tier (see Figure 1). Different strategies can be applied at the application and database tier to support multi-tenancy.
|Figure 1. Typical Software Application|
A Separate Instance Per Tenant
The simplest approach to implementing multi-tenancy is to create completely separate instances of servers (application and database) for each tenant. With this approach, application code and database schema for each tenant are deployed on completely separate servers and there is no sharing across tenants except the common codebase and schema definition. Each tenant can potentially have its own extension of the code and database schema to support any difference in processes and functionality from other tenants.
However, maintaining tenant-specific extensions can get very expensive. Even though a single codebase is shared across multiple tenants, the cost of deployment for each tenant can be pretty high. In turn, the cost of the service will increase. One way to optimize the cost with this approach is to host multiple instances of the application and database servers on the same hardware. This can be further optimized by using server virtualization. This approach is best used when the number of tenants is expected to be very small.
Shared Instances Across Tenants
A more optimal way of implementing a multi-tenant cloud (SaaS or PaaS) solution is to deploy shared instances of servers across multiple tenants. This is where the cloud starts to pay off. With this approach, compute and storage resources are shared across multiple tenants, resulting in a lower cost of service for each tenant.
With this approach, the following levels of sharing can be implemented to further reduce the cost of the service:
- Instance sharing: Instance sharing can be done either at the database server level only or at both the application and database server levels. Of course, more sharing means more savings, which you can pass on to customers with lower service prices. But more sharing also requires more upfront thought about the architecture and design of the service, because any problem with the shared instance will affect multiple tenants. This higher upfront investment can have a huge long-term payoff though by reducing the operational cost (and hence total cost of ownership) of the service.
- Database schema sharing: If instance sharing is implemented at the database level, within the same database server instance either a separate database user schema can be deployed for each tenant or all tenants can share a common database user schema. A common database schema is more cost effective than instance sharing, but it can be challenging to implement and optimize. Handling custom extensions for each tenant can make this even harder to implement.
One way to deal with this is to drive functionality based on metadata. To support tenant-specific extensions to processes and policies, each tenant can inherit the common metadata and define its own metadata on top of that. This is how Salesforce.com is designed. Database partitioning strategies can be implemented for better performance. Data is usually partitioned based on customer ID (Tenant ID) to keep all the data for a given customer in the same partition for performance reasons. A certain number of predetermined tenants live in each partition. The extent to which tenant-specific extensions need to be supported depends on the nature of the service as mentioned earlier (e.g. email vs. sales force automation).
- Application code sharing: If instance sharing is implemented at the application server level, then within the same application server instance either separate code modules can be deployed for each tenant or all tenants can share the same code module deployment (e.g. .war file). Again, more sharing means more savings, but the operational issues have to considered and a lot of thought has to go into the architecture and design of the shared application. All the rules should be externalized so that tenant-specific extensions to processes and policies can be incorporated in the shared codebase.
Application partitioning strategies can be implemented to improve performance and scalability of shared applications. Multiple partitions can be created to support large sets of tenants. Requests can be routed to the correct partition based on tenant ID and/or other predetermined criteria.
There are multiple ways to implement multi-tenancy. Which one you choose depends on the nature of the service being implemented. However, it is very important to spend the necessary time upfront during the architecture phase to determine your current and future multi-tenancy needs and to come up with the best design. After the approach has been decided and implemented, it can be extremely difficult and costly to change, much like converting a four-unit apartment complex into a multiplex would be almost impossible without starting from scratch.
In the next installment of the implementing a multi-tenant cloud architecture series, I drill down into the multi-tenancy approaches for each of the three application tiers.