---
layout: docs
page_title: Network Coordinates
description: A Decentralized Network Coordinate System, with several improvements based on several follow-on papers.
---

# Network Coordinates

Consul uses a [network tomography](https://en.wikipedia.org/wiki/Network_tomography)
system to compute network coordinates for nodes in the cluster. These coordinates
allow the network round trip time to be estimated between any two nodes using a
very simple calculation. This allows for many useful applications, such as finding
the service node nearest a requesting node, or failing over to services in the next
closest datacenter.

All of this is provided through the use of the [Serf library](https://www.serf.io/).
Serf's network tomography is based on ["Vivaldi: A Decentralized Network Coordinate System"](http://www.cs.ucsb.edu/~ravenben/classes/276/papers/vivaldi-sigcomm04.pdf),
with some enhancements based on other research. There are more details about
[Serf's network coordinates here](https://www.serf.io/docs/internals/coordinates.html).

## Network Coordinates in Consul

Network coordinates manifest in several ways inside Consul:

- The [`consul rtt`](/commands/rtt) command can be used to query for the
  network round trip time between any two nodes.

- The [Catalog endpoints](/api-docs/catalog) and
  [Health endpoints](/api-docs/health) can sort the results of queries based
  on the network round trip time from a given node using a "?near=" parameter.

- [Prepared queries](/api-docs/query) can automatically fail over services
  to other Consul datacenters based on network round trip times. See the
  [Geo Failover](/consul/tutorials/developer-discovery/automate-geo-failover?utm_source=docs) for some examples.

- The [Coordinate endpoint](/api-docs/coordinate) exposes raw network
  coordinates for use in other applications.

Consul uses Serf to manage two different gossip pools, one for the LAN with members
of a given datacenter, and one for the WAN which is made up of just the Consul servers
in all datacenters. It's important to note that **network coordinates are not compatible
between these two pools**. LAN coordinates only make sense in calculations with other
LAN coordinates, and WAN coordinates only make sense with other WAN coordinates.

## Working with Coordinates

Computing the estimated network round trip time between any two nodes is simple
once you have their coordinates. Here's a sample coordinate, as returned from the
[Coordinate endpoint](/api-docs/coordinate).

<CodeBlockConfig heading="Sample coordinate from Coordinate endpoint" hideClipboard>

```json
...
  "Coord": {
      "Adjustment": 0.1,
      "Error": 1.5,
      "Height": 0.02,
      "Vec": [0.34,0.68,0.003,0.01,0.05,0.1,0.34,0.06]
  }
...
```

</CodeBlockConfig>

All values are floating point numbers in units of seconds, except for the error
term which isn't used for distance calculations.

Here's a complete example in Go showing how to compute the distance between two
coordinates:

<CodeBlockConfig heading="Computing distance between two coordinates with Go">

```go
import (
    "math"
    "time"

    "github.com/hashicorp/serf/coordinate"
)

func dist(a *coordinate.Coordinate, b *coordinate.Coordinate) time.Duration {
    // Coordinates will always have the same dimensionality, so this is
    // just a sanity check.
    if len(a.Vec) != len(b.Vec) {
        panic("dimensions aren't compatible")
    }

    // Calculate the Euclidean distance plus the heights.
    sumsq := 0.0
    for i := 0; i < len(a.Vec); i++ {
        diff := a.Vec[i] - b.Vec[i]
        sumsq += diff * diff
    }
    rtt := math.Sqrt(sumsq) + a.Height + b.Height

    // Apply the adjustment components, guarding against negatives.
    adjusted := rtt + a.Adjustment + b.Adjustment
    if adjusted > 0.0 {
        rtt = adjusted
    }

    // Go's times are natively nanoseconds, so we convert from seconds.
    const secondsToNanoseconds = 1.0e9
    return time.Duration(rtt * secondsToNanoseconds)
}
```

</CodeBlockConfig>
