Wednesday, May 8, 2013

Federation Architecture

While creating web applications with large, multi-tenant data sets, it becomes an immediate architectural need to plan for scaling data storage.  This plan cannot be an afterthought, but must be a paramount consideration at the outset of the project.  Performance and scalability issues on the data layer can create an array of issues that each manifests themselves as a poor user experience, and ultimately damage the brand of the application.  One such approach for handling this need is to scale horizontally using a technique known as 'Sharding'.  Sharding allows one to separate the rows of storage across multiple physical databases, which enables much scalability and should result in better performance on the data layer.  This process enables one to plan for scale, build for speed and control capacity.  Sharding also allows the operational aspect of the web application to scale, increase performance, and add additional capacity dynamically to the data layer with no downtime, which is vital to a thriving user base.

Federations are individual data partitions, which have their individual scheme centrally managed by a single distribution (or federation) scheme.  That scheme defines and controls the single keying mechanism for cross-partition distribution.  While a handful of data types are acceptable for the distribution key, I like the simplicity of a bigint as defining key (of any kind actually).

The individual partitions are members of the federation, each with their own schema.  As such, they are responsible for any inclusive subset of the values in a federated table covered by the data type of the federation distribution key.  The individual can be responsible for all of the values or a range of the values giving the architecture the ability to scale dynamically to match the current need.   While each partition has its own schema, the table keys correspond to the federation scheme. A federation member may also contain tables that are not part of the federation, known as reference tables.  Reference tables can be including in results that along with federation aware data.  It is important to note that each partition controls its own schema.  As such, it may or may not match the schema of other member partitions.

When building a federation plan, a paramount decision to make is deciding value upon which value to federate. I think the best practice may be to use a value that is meaningful to the data separation you are trying to achieve. In my world, the thing that makes the most sense is the customer or tenant identifier.  This gives us the ability to centrally reference all data for querying, yet provide each customer with what amounts to a singularly responsible and sovereign data set.

While sharding is a great solution for these types of application, it is important to understand the complexity that accompanies the sharding process. Depending on the individual implementation flavor, sharding may developers handle rollbacks, constraints, and referential integrity across tables when historically those items have been handled by the database itself.   It also makes joins, global searches and other high-level insight more difficult.  Even knowing the trade-offs being made for the ability to scale data, it is hard to argue a properly executed sharding strategy for serving multi-tenant data in a web-mobile application world.  The process checks all of the boxes required by the various user stories and operational concerns.

Sharding is a good example of a core belief of mine; It really should not matter how difficult or easy, how fancy or how simple a given technique or design is. The right answer should be the right answer.  You should not over-design because one thing seems too simple, nor should you under-design because it seems too hard.  The entirety of the platform truth should become self-evident and then pursued as the goal.