Leader-aware routing

This page describes leader-aware routing in Spanner and how to use it. Spanner uses leader-aware routing to dynamically route read-write transactions in dual-region and multi-region instance configurations to reduce latency and improve performance in your database. Leader-aware routing is enabled by default.

Spanner routing for read-write transactions

Spanner replicates data to provide additional data availability and geographic locality. In Spanner dual-region and multi-region instance configurations, one region in the dual-region and multi-region instance configuration is designated as the leader region and it contains the leader replicas of the database. When you use a dual-region or multi-region instance configuration and your client issues a read-write transaction to your database from a non-leader region, the write is always processed in the leader region and then sent back to the non-leader region. Therefore, read-write transactions committed from a non-leader region require multiple round trips to the leader replica to be committed successfully.

Leader-aware routing is a mechanism that improves latency for read-write transactions by intelligently routing these transactions. If leader-aware routing is enabled, even if the write doesn't originate from the leader region, the session creation requests are routed to the leader region to align Spanner Front End (SpanFE) with the leader region. This routing mechanism improves latency for read-write transactions by reducing the number of network round trips required between the non-leader region (where the client application is located) and the leader region to two.

Screenshot Spanner routing with leader-aware-routing enabled. Figure 1. Example of Spanner routing with leader-aware-routing enabled.

If leader-aware routing is disabled, the client application first routes the request to a SpanFE service within the client application region (non-leader region). Then, from the SpanFE in the client application region, three or more round trips are made to the Spanner server (SpanServer) in the leader region to commit the write, increasing latency. These additional round trips are needed to support secondary indexes, constraint checks, and read your writes.

Screenshot Spanner routing with leader-aware-routing disabled. Figure 2. Example of Spanner routing with leader-aware-routing disabled.

Use cases

As a result of using leader-aware routing, the following use cases benefits from lower latency:

  • Bulk updates: Executing Dataflow imports or running background changes (for example, batch DMLs) from a non-leader region.
  • Disaster tolerance and increased availability: Deploying client applications in both leader and non-leader regions to tolerate regional outages while initiating writes from non-leader regions.
  • Global application: Deploying client applications globally with widespread region locations that commit data.

Limitations

If your client application is deployed outside of the leader region and you write values without reading the data ("blind writes"),you might observe latency regression if leader-aware routing is enabled. This is because when leader-aware routing is enabled, there are two inter-region round trips (beginTransaction and the commit request) between the client application in the non-leader region and the SpanFE in the leader region. However, with leader-aware routing disabled, writes without reads only require one inter-region round trip for the commit request (beginTransaction is processed in the local SpanFE). For example, if you bulk load file data into a newly created table, the transactions are unlikely to read data from the table. If you frequently commit write operations without reading it in your application, you might want to consider disabling leader-aware routing. For more information, see Disable leader-aware routing.

Use leader-aware routing

Leader-aware routing is enabled by default in the Spanner client libraries.

We recommend processing your read-write requests with leader-aware routing enabled. You can disable it to compare performance differences.

Enable leader-aware routing

You can use the Spanner client libraries to enable leader-aware routing manually.

C++

Use the RouteToLeaderOption structure to configure your client application with leader-aware routing enabled:

void RouteToLeaderOption(std::string const& project_id, std::string const& instance_id,
              std::string const& database_id) {
namespace spanner = ::google::cloud::spanner;

// Create a client with RouteToLeaderOption enabled.
auto client = spanner::Client(
  spanner::MakeConnection(
      spanner::Database(project_id, instance_id, database_id)),
  google::cloud::Options{}.set<spanner::RouteToLeaderOption>(
      spanner::true));

C#

Use EnableLeaderRouting to configure your client application with leader-aware routing enabled:

// Create a client with leader-aware routing enabled.
SpannerConnectionStringBuilder builder = new
SpannerConnectionStringBuilder();
Builder.EnableLeaderRouting = true;

Go

Use ClientConfig to configure your client application with leader-aware routing enabled:

type ClientConfig struct {
    // DisableRouteToLeader specifies if all the requests of type read-write
    // and PDML need to be routed to the leader region.
    // Default: false
    DisableRouteToLeader false
}

Java

Use SpannerOptions.Builder to configure your client application with leader-aware routing enabled:

SpannerOptions options = SpannerOptions.newBuilder().enableLeaderAwareRouting.build();
Spanner spanner = options.getService();
String instance = "my-instance";
String database = "my-database";

Node.js

Use SpannerOptions to configure your client application with leader-aware routing enabled:

// Instantiates a client with routeToLeaderEnabled enabled
const spanner = new Spanner({
projectId: projectId,
routeToLeaderEnabled: true;
});

PHP

Use routeToLeader to configure your client application with leader-aware routing enabled:

// Instantiates a client with leader-aware routing enabled
use Google\Cloud\Spanner\SpannerClient;

$routeToLeader = true;
$spanner = new SpannerClient($routeToLeader);

Python

Use route_to_leader_enabled to configure your client application with leader-aware routing enabled:

spanner_client = spanner.Client(
route_to_leader_enabled=true
)
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

Ruby

Use self.new to configure your client application with leader-aware routing enabled:

def self.new(project_id: nil, credentials: nil, scope: nil, timeout: nil,
     endpoint: nil, project: nil, keyfile: nil, emulator_host: nil,
    lib_name: nil, lib_version: nil, enable_leader_aware_routing: true) ->
    Google::Cloud::Spanner::Project

Disable leader-aware routing

You can use the Spanner client libraries to disable leader-aware routing.

C++

Use the RouteToLeaderOption structure to configure your client application with leader-aware routing disabled:

void RouteToLeaderOption(std::string const& project_id, std::string const& instance_id,
              std::string const& database_id) {
namespace spanner = ::google::cloud::spanner;

// Create a client with RouteToLeaderOption disabled.
auto client = spanner::Client(
  spanner::MakeConnection(
      spanner::Database(project_id, instance_id, database_id)),
  google::cloud::Options{}.set<spanner::RouteToLeaderOption>(
      spanner::false));

C#

Use EnableLeaderRouting to configure your client application with leader-aware routing disabled:

// Create a client with leader-aware routing disabled.
SpannerConnectionStringBuilder builder = new
SpannerConnectionStringBuilder();
Builder.EnableLeaderRouting = false;

Go

Use ClientConfig to configure your client application with leader-aware routing disabled:

type ClientConfig struct {
    // DisableRouteToLeader specifies if all the requests of type read-write
    // and PDML need to be routed to the leader region.
    // Default: false
    DisableRouteToLeader true
}

Java

Use SpannerOptions.Builder to create a connection to a Spanner database with leader aware routing disabled:

SpannerOptions options = SpannerOptions.newBuilder().disableLeaderAwareRouting.build();
Spanner spanner = options.getService();
String instance = "my-instance";
String database = "my-database";

Node.js

Use SpannerOptions to configure your client application with leader-aware routing disabled:

// Instantiates a client with routeToLeaderEnabled disabled
const spanner = new Spanner({
projectId: projectId,
routeToLeaderEnabled: false;
});

PHP

Use routeToLeader to configure your client application with leader-aware routing disabled:

// Instantiates a client with leader-aware routing disabled
use Google\Cloud\Spanner\SpannerClient;

$routeToLeader = false;
$spanner = new SpannerClient($routeToLeader);

Python

Use route_to_leader_enabled to configure your client application with leader-aware routing disabled:

spanner_client = spanner.Client(
route_to_leader_enabled=false
)
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

Ruby

Use self.new to configure your client application with leader-aware routing disabled:

def self.new(project_id: nil, credentials: nil, scope: nil, timeout: nil,
     endpoint: nil, project: nil, keyfile: nil, emulator_host: nil,
    lib_name: nil, lib_version: nil, enable_leader_aware_routing: false) ->
    Google::Cloud::Spanner::Project

What's next