Module tower::balance

source ·
Expand description

Middleware that allows balancing load among multiple services.

In larger systems, multiple endpoints are often available for a given service. As load increases, you want to ensure that that load is spread evenly across the available services. Otherwise, clients could see spikes in latency if their request goes to a particularly loaded service, even when spare capacity is available to handle that request elsewhere.

This module provides two pieces of middleware that helps with this type of load balancing:

First, p2c implements the “Power of Two Random Choices” algorithm, a simple but robust technique for spreading load across services with only inexact load measurements. Use this if the set of available services is not within your control, and you simply want to spread load among that set of services.

Second, pool implements a dynamically sized pool of services. It estimates the overall current load by tracking successful and unsuccessful calls to poll_ready, and uses an exponentially weighted moving average to add (using MakeService) or remove (by dropping) services in response to increases or decreases in load. Use this if you are able to dynamically add more service endpoints to the system to handle added load.

§Examples

use tower::balance::p2c::Balance;
use tower::load::Load;
use tower::{Service, ServiceExt};
use futures_util::pin_mut;

async fn spread<Req, S: Service<Req> + Load>(svc1: S, svc2: S, reqs: impl Stream<Item = Req>)
where
    S::Error: Into<tower::BoxError>,
    S::Metric: std::fmt::Debug,
{
    // Spread load evenly across the two services
    let p2c = Balance::new(tower::discover::ServiceList::new(vec![svc1, svc2]));

    // Issue all the requests that come in.
    // Some will go to svc1, some will go to svc2.
    pin_mut!(reqs);
    let mut responses = p2c.call_all(reqs);
    while let Some(rsp) = responses.next().await {
        // ...
    }
}

Modules§