Data management
Distribute the workload for background tasksDistribute the workload for background tasks. Where there are many background tasks, or the tasks
require considerable time or resources, spread the work across multiple compute units (such as worker roles or
background jobs). For one possible solution, see the Competing Consumers pattern.
Consider moving toward a Consider moving toward a
shared-nothingshared-nothing
architecture architecture. A shared-nothing architecture uses
independent, self-sufficient nodes that have no single point of contention (such as shared services or storage). In
theory, such a system can scale almost indefinitely. While a fully shared-nothing approach is generally not
practical for most applications, it may provide opportunities to design for better scalability. For example,
avoiding the use of server-side session state, client affinity, and data partitioning are good examples of moving
toward a shared-nothing architecture.
Use data par titioningUse data par titioning. Divide the data across multiple databases and database servers, or design the
application to use data storage services that can provide this partitioning transparently (examples include Azure
SQL Database Elastic Database, and Azure Table storage). This approach can help to maximize performance and
allow easier scaling. There are different partitioning techniques, such as horizontal, vertical, and functional. You
can use a combination of these to achieve maximum benefit from increased query performance, simpler
scalability, more flexible management, better availability, and to match the type of store to the data it will hold.
Also, consider using different types of data store for different types of data, choosing the types based on how
well they are optimized for the specific type of data. This may include using table storage, a document database,
or a column-family data store, instead of, or as well as, a relational database. For more information, see Data
partitioning guidance.
Design for eventual consistencyDesign for eventual consistency. Eventual consistency improves scalability by reducing or removing the
time needed to synchronize related data partitioned across multiple stores. The cost is that data is not always
consistent when it is read, and some write operations may cause conflicts. Eventual consistency is ideal for
situations where the same data is read frequently but written infrequently. For more information, see the Data
Consistency Primer.
Reduce chatty interactions between components and ser vicesReduce chatty interactions between components and ser vices. Avoid designing interactions in which an
application is required to make multiple calls to a service (each of which returns a small amount of data), rather
than a single call that can return all of the data. Where possible, combine several related operations into a single
request when the call is to a service or component that has noticeable latency. This makes it easier to monitor
performance and optimize complex operations. For example, use stored procedures in databases to encapsulate
complex logic, and reduce the number of round trips and resource locking.
Use queues to level the load for high velocity data writesUse queues to level the load for high velocity data writes. Surges in demand for a service can
overwhelm that service and cause escalating failures. To prevent this, consider implementing the Queue-Based
Load Leveling pattern. Use a queue that acts as a buffer between a task and a service that it invokes. This can
smooth intermittent heavy loads that may otherwise cause the service to fail or the task to time out.
Minimize the load on the data storeMinimize the load on the data store. The data store is commonly a processing bottleneck, a costly resource,
and often not easy to scale out. Where possible, remove logic (such as processing XML documents or JSON
objects) from the data store, and perform processing within the application. For example, instead of passing
XML to the database (other than as an opaque string for storage), serialize or deserialize the XML within the
application layer and pass it in a form that is native to the data store. It's typically much easier to scale out the
application than the data store, so you should attempt to do as much of the compute-intensive processing as
possible within the application.
Minimize the volume of data retrievedMinimize the volume of data retrieved. Retrieve only the data you require by specifying columns and using
criteria to select rows. Make use of table value parameters and the appropriate isolation level. Use mechanisms
like entity tags to avoid retrieving data unnecessarily.
Aggressively use cachingAggressively use caching. Use caching wherever possible to reduce the load on resources and services that