Commit Graph

50 Commits

Author SHA1 Message Date
Jon Gjengset 650e5be58e balance: Add a stress test for p2c
The hope for this was to reproduce #415 (which it does not sadly), but
at least it adds a test for p2c!
2020-02-20 16:01:19 -05:00
Lucio Franco 86eef82d2f
Remove default features for futures dep (#399)
* Remove default features for futures dep

* Add missing alloc feature
2019-12-19 14:20:41 -05:00
Lucio Franco 1e87d7ca8b
Bump crates and changelog dates (#397) 2019-12-19 13:44:40 -05:00
Lucio Franco 2fede40bdb
balance: Upgrade rand to 0.7 (#398) 2019-12-19 13:44:07 -05:00
Juan Alvarez 1843416dfe remove service, make and layer path deps (#382) 2019-12-06 11:59:56 -05:00
Lucio Franco e2f1a49cf3
Update the rest of the crates and upgrade ready cache to `std::f… (#379)
* Update hedge, filter, load, load-shed, and more

* Update ready cache

* Prepare release for ready-cache

* fix merge

* Update balance

* Prepare balance release
2019-12-05 14:21:47 -05:00
Lucio Franco 7fa1054892
make: Bump version to alpha.2a (#356) 2019-09-30 20:40:28 -04:00
Jon Gjengset 2653f70884 Bumps for 0.3.0-alpha.2 (#355)
* Bump all to futures-* alpha.19

* Prepare for alpha.2 release

* Make tower-service also a path dep

* Use new tokio alpha
2019-09-30 18:56:26 -04:00
Taiki Endo 03dc7069aa Update pin-project to 0.4 (#350) 2019-09-30 14:58:27 -04:00
Sean McArthur 55b5150a89 tower-make:v0.3.0-alpha.2 2019-09-20 15:09:09 -07:00
Sean McArthur 52075f3c6f Update tower-make to tokio-io v0.2.0-alpha.5 2019-09-20 15:09:09 -07:00
Lucio Franco ca951d56f4
Prepare `tower-buffer` 0.3.0-alpha.1b release (#345)
* buffer: Fix unused Stream warning

* Prepare `tower-buffer` 0.3.0-alpha.1b release

* Update buffer version in balance
2019-09-14 12:47:38 -04:00
Lucio Franco 206f3d9941
Prepare `tower-buffer` 0.3.0-alpha.1a release (#343)
Signed-off-by: Lucio Franco <luciofranco14@gmail.com>
2019-09-13 16:36:35 -04:00
Lucio Franco bd62f64d6c
balance: Add changelog entry and remove publish false 2019-09-11 16:21:34 -04:00
Jon Gjengset 395889c763
Make Ready only take Service by reference (#340)
Rather than consuming `self` and returning `(Self, _)`. This did mean
that a few crates that depended on `Ready` to own the `Service` and
provide it once it was ready had to change to call `poll_ready`
directly. Which in turn meant adding in some PhantomData<Request> so
that the impl blocks wouldn't be under-constrainted. Take, for example:

```
impl<K, S: Service<Req>, Req> Future for UnreadyService<K, S>
```

would fail to compile with

```
error[E0207]: the type parameter `Req` is not constrained by the impl trait, self type, or predicates
```
2019-09-11 15:49:51 -04:00
Lucio Franco fb124a14f0
Pin all the alpha based dependencies (#339)
Signed-off-by: Lucio Franco <luciofranco14@gmail.com>
2019-09-11 13:57:27 -04:00
Taiki Endo 921325ac2d Pin the version of pin-project 2019-09-11 10:00:27 -07:00
Taiki Endo 65e07064db Update pin-project to 0.4.0-alpha.11 2019-09-11 10:00:27 -07:00
Jon Gjengset 87976ae418
Update tower-balance to std::future (#335)
This bumps tower-balance to 0.3.0-alpha.1

It also adds delegate impls for `Discover` through `Pin`, and makes `tower-load::Constant: Debug`.
2019-09-10 18:15:32 -04:00
Jon Gjengset 40fbb85c4b
Notify Pool when Services are dropped (#301)
Prior to this change, when `Balance` dropped a failing service, `Pool`
would not be notified of this fact. This meant that it never updated
`.services`, and so it might not add a new backing `Service` (e.g., due
to `max_services`) even though no working backing exist.

With this change, dropped services notify the `Pool` so that it knows to
re-check its limits. It also gains some much-needed tests.
2019-07-15 13:50:01 -04:00
Jon Gjengset 491dfbe634
Early push to bring tracing into tower (#298)
Of particular note is that this change lets spans trace requests through `tower::Buffer` by internally carrying the `Span` at the time of `call` along with the request to the worker.
2019-07-12 14:46:50 -04:00
Oliver Gould 18b30eb70e
balance: Only balance over ready endpoints (#293)
In 03ec4aa, the balancer was changed to make a quick endpoint decision.
This, however, means that the balancer can return NotReady when it does
in fact have a ready endpoint.

This changes the balancer to separate unready endpoints, only
performing p2c over ready endpoints. Unready endpoints are tracked with
a FuturesUnordered that supports eviction via oneshots.

The main downside of this change is that the Balancer must become
generic over the Request type.
2019-07-05 20:46:33 -07:00
Jon Gjengset 67a11f27ff
Fix some simple compile-time warnings (#297) 2019-07-05 17:10:11 -04:00
Oliver Gould 03ec4aafa8
balance: Specialize the balancer for P2C (#288)
As described in #286, `Balance` had a few problems:
- it is responsible for driving all inner services to readiness, making
  its `poll_ready` O(n) and not O(1);
- the `choose` abstraction was a hinderance. If a round-robin balancer
  is needed it can be implemented separately without much duplicate
  code; and
- endpoint errors were considered fatal to the balancer.

This changes replaces `Balance` with `p2c::Balance` and removes the
`choose` module.

Endpoint service failures now cause the service to be removed from the
balancer gracefully.

Endpoint selection is now effectively constant time, though it biases
for availability in the case when random selection does not yield an
available endpoint.

`tower-test` had to be updated so that a mocked service could fail after
advertising readiness.
2019-06-04 13:59:47 -07:00
Oliver Gould a496fbf72c
Extract tower-load from tower-balance (#285)
The tower-balance crate includes the `Load` and `Instrument` traits,
which are likely useful outside of balancers; and certainly have no
tight coupling with any specific balancer implementation. This change
extracts these protocol-agnostic traits into a dedicated crate.

The `Load` trait includes a latency-aware _PeakEWMA_ load strategy as
well as a simple _PendingRequests_ strategy for latency-agnostic
applications.

The `Instrument` trait is used by both of these strategies to track
in-flight requests without knowing protocol details. It is expected that
protocol-specific crates will provide, for instance, HTTP
time-to-first-byte latency strategies.

A default `NoInstrument` implementation tracks the a request until its
response future is satisfied.

This crate should only be published once tower-balance is published.

Part of https://github.com/tower-rs/tower/issues/286
2019-05-29 10:32:02 -07:00
Carl Lerche 716bafd922
chore: fix small errors in Cargo files 2019-04-26 22:31:07 -07:00
Carl Lerche 14f4259518
Prepare release (#273)
The following crates are to be released:

- tower
- tower-buffer
- tower-discover
- tower-layer
- tower-limit
- tower-load-shed
- tower-retry
- tower-service
- tower-test
- tower-timeout
- tower-util
2019-04-26 21:31:25 -07:00
Jake Shadle b42a365828 Add license field to all crates (#241) 2019-04-09 10:59:30 -07:00
David Barsky 17860191d7 Move Tower to 2018 Edition (#238) 2019-04-08 20:11:09 -07:00
Carl Lerche 16f2d2b4fa
Consolidate `limit` layers (#235)
* Consolidate `limit` layers

- `InFlightLimit` and `RateLimit` are moved into `tower-limit` crate.
- `InFlightLimit` is renamed to `ConcurrencyLimit`.

Fixes #225
2019-04-05 20:08:43 -07:00
Carl Lerche 2448ca9cdc
balance: cleanup example (#211) 2019-03-29 14:24:43 -07:00
Carl Lerche f1bb22a296
util: rename tower-service-util -> tower-util (#212) 2019-03-27 16:34:56 -07:00
Carl Lerche acda5a75b9
Initial introduction of tower-service-util (#193) 2019-03-14 11:27:36 -07:00
Jon Gjengset ac9488f5f2
Add a dynamically-sized load-balanced pool (#119)
This patch adds a new type, `Pool`, which wraps a
`tower_balance::Balance` and a `tower_service::NewService` together so
that new `Service` instances are added when load is high, and removed
again if load is low.

The pool uses an exponentially weighted moving average of successful
calls to `poll_ready` on the underlying `Balance` to estimate whether
there are enough services available. If `poll_ready` frequently returns
`NotReady`, then a new service is produced, whereas if `poll_ready`
pretty much never returns `NotReady`, the most recently added service is
removed from the pool (down to a minimum of 1).
2019-03-08 12:23:34 -05:00
Carl Lerche bdcce9677b
depend on tower-service from crates.io (#186) 2019-03-06 13:38:58 -08:00
Jon Gjengset 8390a1d288 Remove DirectService from tower-{balance,buffer} (#159) 2019-02-15 14:52:00 -08:00
Eliza Weisman dc306602eb
balance: Update `rand` dependency (#142)
This branch updates `tower-balance` to depend on the latest 
released `rand` version.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
2019-01-11 10:12:24 -08:00
Sean McArthur ffa6f03618 tower-service v0.2.0 (#135) 2018-12-12 16:14:05 -05:00
Jon Gjengset 9bae225918 Add the DirectService trait (#118)
This patch adds the `DirectService` trait, and related implementations
over it in `tower_balance` and `tower_buffer`. `DirectService` is
similar to a `Service`, but must be "driven" through calls to
`poll_service` for the futures returned by `call` to make progress.

The motivation behind adding this trait is that many current `Service`
implementations spawn long-running futures when the service is created,
which then drive the work necessary to turn requests into responses. A
simple example of this is a service that writes requests over a
`TcpStream` and reads responses over that same `TcpStream`. The
underlying stream must be read from to discover new responses, but there
is no single entity to drive that task. The returned futures would share
access to the stream (and worse yet, may get responses out of order),
and then service itself is not guaranteed to see any more calls to it as
the client is waiting for its requests to finish.

`DirectService` solves this by introducing a new method, `poll_service`,
which must be called to make progress on in-progress futures.
Furthermore, like `Future::poll`, `poll_service` must be called whenever
the associated task is notified so that the service can also respect
time-based operations like heartbeats.

The PR includes changes to both `tower_balance::Balance` and
`tower_buffer::Buffer` to add support for wrapping `DirectService`s. For
`Balance` this is straightforward: if the inner service is a `Service`,
the `Balance` also implements `Service`; if the inner service is a
`DirectService`, the `Balance` is itself also a `DirectService`. For
`Buffer`, this is more involved, as a `Buffer` turns any `DirectService`
*into* a `Service`. The `Buffer`'s `Worker` is spawned, and will
therefore drive the wrapped `DirectService`.

One complication arises in that `Buffer<T>` requires that `T: Service`,
but you can safely construct a `Buffer` over a `DirectService` per the
above. `Buffer` works around this by exposing

```rust
impl Service for HandleTo<S> where S: DirectService {}
```

And giving out `Buffer<HandleTo<S>>` when the `new_directed(s: S)`
constructor is invoked. Since `Buffer` never calls any methods on the
service it wraps, `HandleTo`'s implementation just consists of calls to
`unreachable!()`.

Note that `tower_buffer` now also includes a `DirectedService` type,
which is a wrapper around a `Service` that implements `DirectService`.
In theory, we could do away with this by adding a blanket impl:

```rust
impl<T> DirectedService for T where T: Service {}
```

but until we have specialization, this would prevent downstream users
from implementing `DirectService` themselves.

Finally, this also makes `Buffer` use a bounded mpsc channel, which
introduces a new capacity argument to `Buffer::new`.

Fixes #110.
2018-11-19 09:30:45 -08:00
Oliver Gould fcdc9d2777
balance: Implement a Peak-EWMA load metric (#76)
The balancer provides an implementation of two load balancing strategies: RoundRobin and
P2C+LeastLoaded.  The round-robin strategy is extremely simplistic and not sufficient for
most production systems. P2C+LL is a substantial improvement, but relies exclusively on
instantaneous information.

This change introduces P2C+PeakEWMA strategy. P2C+PE improves over P2C+LL by maintaining
an exponentially-weighted moving average of response latencies for each endpoint so that
the recent history directly factors into load balancing decisions. This technique was
pioneered by Finagle for use at Twitter. [Finagle's P2C+PE implementation][finagle] was
referenced heavily while developing this.

The provided demo can be used to illustrate the differences between load balacing
strategies. For example:

```
REQUESTS=50000
CONCURRENCY=50
ENDPOINT_CAPACITY=50
MAX_ENDPOINT_LATENCIES=[1ms, 10ms, 10ms, 10ms, 10ms, 100ms, 100ms, 100ms, 100ms, 1000ms, ]
P2C+PeakEWMA
  wall   15s
  p50     5ms
  p90    56ms
  p95    78ms
  p99    96ms
  p999  105ms
P2C+LeastLoaded
  wall   18s
  p50     5ms
  p90    57ms
  p95    80ms
  p99    98ms
  p999  857ms
RoundRobin
  wall   72s
  p50     9ms
  p90    98ms
  p95   496ms
  p99   906ms
  p999  988ms
````

[numbers]: https://people.eecs.berkeley.edu/~rcs/research/interactive_latency.html
[finagle]: 9cc08d1521/finagle-core/src/main/scala/com/twitter/finagle/loadbalancer/PeakEwma.scala
2018-06-06 23:16:49 -07:00
Oliver Gould 01fd57c053
balance: Update demo (#79)
In preparation for additional load balancing strategies, the demo is
being updated to allow for richer testing in several important ways:

- Adopt the new `tokio` multithreaded runtime.

- Use `tower-buffer` to drive each simulated endpoint on an independent
  task. This fixes a bug where requests appeared active longer than
  intended (while waiting for the SendRequests task process responses).

- A top-level concurrency has been added (by wrapping the balancer in
  `tower-in-flight-limit`) so that `REQUESTS` futures were not created
  immediately. This also caused incorrect load measurements.

- Endpoints are also constrained with `tower-in-flight-limit`. By
  default, the limit is that of the load balancer (so endpoints are
  effectively unlimited).

- The `demo.rs` script has been reorganized to account for the new
  runtime, such that all examples are one task chain.

- New output format:
```
REQUESTS=50000
CONCURRENCY=50
ENDPOINT_CAPACITY=50
MAX_ENDPOINT_LATENCIES=[1ms, 10ms, 10ms, 10ms, 10ms, 100ms, 100ms, 100ms, 100ms, 1000ms, ]
P2C+LeastLoaded
  wall   18s
  p50     5ms
  p90    56ms
  p95    80ms
  p99    98ms
  p999  900ms
RoundRobin
  wall   72s
  p50     9ms
  p90    98ms
  p95   488ms
  p99   898ms
  p999  989ms
```
2018-06-04 17:54:07 -07:00
Oliver Gould 9352fc417d
balance: Do not require RNG to build a P2C balancer (#78)
`PowerOfTwoChoices` requires a Random Number Generator. In order for
this randomization source to be configurable (i.e. for tests),
`PowerOfTwoChoices` is generic over its implementation of `rand::Rng`;
however, this leads to needless boilerplate when building P2C balancers.

Because load balancers do not need a cryptographically strong RNG, we
can use `rand::SmallRng` (which is `Send + Sync`). `PowerOfTwoChoices`
exposes constructors that take a `SmallRng`.

In order to do this, the `tower-balance` crate now requires `rand = "0.5"`.
2018-06-04 10:01:38 -07:00
Carl Lerche 5369879af6
Extract `Service` trait and related into crate. (#67)
This makes the `tower` crate available to be a "batteries included"
facade.
2018-04-25 12:35:52 -07:00
Brian Smith 11b591b6e0 Upgrade indexmap dependency to version 1. (#64)
Signed-off-by: Brian Smith <brian@briansmith.org>
2018-03-15 21:33:20 -07:00
Brian Smith 1efa622b6e Replace ordermap dependency with indexmap. (#55)
indexmap is the new ordermap.

Signed-off-by: Brian Smith <brian@briansmith.org>
2018-02-26 20:43:04 -08:00
Brian Smith e0ca6545bb Upgrade to env_logger 0.5 and log 0.4 so that projects that use those (#52)
versions don't have to build both those versions and the older ones
that h2 is currently using.

Don't enable the regex support in env_logger. Applications that want
the regex support can enable it themselves; this will happen
automatically when they add their env_logger dependency.

Disable the env_logger dependency in quickcheck.

The result of this is that there are fewer dependencies. For example,
regex and its dependencies are no longer required at all, as can be
seen by observing the changes to the Cargo.lock. That said,
env_logger 0.5 does add more dependencies itself; however it seems
applications are going to use env_logger 0.5 anyway so this is still
a net gain.

Submitted on behalf of Buoyant, Inc.

Signed-off-by: Brian Smith <brian@briansmith.org>
2018-02-23 20:24:22 -08:00
Oliver Gould 777888da7d
Add an examples that demonstrates p2c & rr behavior (#39)
The new _demo_ example sends a million simulated requests through each
load balancer configuration and records the observed latency
distributions.

Furthermore, this fixes a critical bug in `Balancer`, where we did not
properly iterate through not-ready nodes.

* Use (0..n-1).rev() to iterate from right-to-left
2018-01-25 12:51:33 -08:00
Oliver Gould 4bedc52077
Make tower-balance load-aware (#35)
Previously, tower-balance used a fixed round-robin strategy for load
distribution.

This change makes `Balance` generic over its load metric and selection
strategy. The following new traits have been introduced to satisfy this:

- `tower_balance::Load` provides a concrete load metric (i.e. for a service);
- `tower_balance::Choose` provides a strategy for selecting a node;

There are two load balancing configurations supported out-of-the-box:

- `tower_balance::round_robin` provides a load-ignorant round-robin balancer.
- `tower_balance::power_of_two_choices` uses the Power of Two Choices to
  distribute requests to the least-loaded node. This should be used in conjunction
  with `tower_balance::load::WithPendingRequests` to decorate a `Discover` instance
  so that all services it produces implement `Load`.
2018-01-24 20:18:12 +00:00
Carl Lerche 8d6daa45ea Prevent accidental publishing of the crates 2017-11-16 09:40:32 -08:00
Carl Lerche 50905b330f Initial discovery, balance, and reconnect sketchs (#12) 2017-10-05 13:41:44 -07:00