§14.6.

Partitioning

Partitioning, sometimes also known as sharding, is a scalability strategy that handles large numbers of incoming requests by spreading the workload over non-identical servers.

Partitioning is similar to the strategy used when collecting a name-badge at a conference, seminar or event. One person might help guests with family names starting with A–I, another may help guests with family names J–R, and the final person will help guests with family names S–Z. This partitioning of guests by surname triples the throughput of name-badge collection.

When building distributed systems, there are many ways of partitioning (other than family names). Some examples are as follows:

  • By geography (e.g., store all data for Australian customers in an Australian data center, and US customers in a US data center)

  • By user type (e.g., store all data for staff on one server, and all student data is on another server)

  • By object types (e.g., the user account table on one server and the current order table on another server) [1]

  • By object properties (e.g., sales transactions for 2019 on one server and 2020 on another server) [2]

  • By request (e.g, send requests for /api/authenticate to one server and requests for /api/purchase to a different server)

Reflection: Geographic partitions

Why would partitioning by geography be especially useful?

Tip
Any form of partitioning will increase throughput. Partitioning by geography provides other benefits, in addition to throughput.

Understanding partitioning

In mathematics, a partition refers to a grouping of elements of a set into subsets, such that each item in the original set occurs in exactly one subset.

In a distributed system, a partition is a mapping of requests or data requests onto distinct servers. For example, the following table depicts a partition of sales transactions onto four servers:

Partitioning expression

Server

date >= 2020

Server A

date == 2019

Server B

date == 2018

Server C

date <= 2017

Server D

Now, suppose a user needs to view sales where month == 'January' and year == 2019, then the partitioning can be used to direct that request to Server B.

The partitioning expression does not even need to be fixed. In dynamic partitioning, the expression can adjust over time. For example, if the start of 2021 is an unusually busy, then the system might automatically rebalance the partitions to combine 2019 and 2018 onto Server B to dedicate all of 2021’s sales to Server C.

Implementing partitioning

You can partition any layer of your application. Many technologies provide built-in support for partitioning or sharding:

PostgresSQL

PostgreSQL has support for partitioning table storage on a server. However, there are forks of PostgreSQL that support sophisticated partitioning in a cluster of database servers. The foreign data wrapper can also define a table partitioned across multiple servers.

MongoDB

MongoDB has built-in sharding capabilities for clusters.

Load balancers

Load balancers offer simple mechanisms to partition incoming HTTP requests. Most load balancers support partitioning by request path (i.e., /api/sales/2020/* to Server A and /api/sales/2019/* to Server B). More sophisticated load balancers, such as AWS Elastic Load Balancing allow advanced rules based on inspection of headers, IP addresses and query parameters.

DNS

The domain name system (DNS) provides a crude form of partitioning. For example, Amazon’s US customers typically visit amazon.com, while Australian customers use amazon.com.au.

However, partitioning can be as simple as an if-statement. The following code illustrates partitioning in domain logic. The if-statement chooses between two different database management systems (database1 and database2) based on the year:

app.get('/api/sales', async (req,res) => {

    // Choose between two separate partitions
    let db;
    if (req.body.year >= 2020)
        db = database1;
    else
        db = database2;


    // Query
    let results = await db.query({
        text: 'select sum(amount) from sales where year = ?',
        values: [req.body.year]
    });

    ...

    res.json(...);
});
Exercise: Implementing partitioning

Can you create Express middleware or an Express route that achieves partitioning using HTTP redirects?

Reflection: Partitioning in layered architectures

How does a three-layer architecture (Chapter 6) make it easier to add partitioning to an application?


1. This is also known as horizontal partitioning.
2. This is also known as vertical partitioning.