感知主副本的路由

本页介绍了 Spanner 中的主副知情路由以及如何使用它。Spanner 使用主要副本感知路由在双区域和多区域实例配置中动态路由读写事务,以缩短延迟时间并提高数据库性能。默认情况下,系统会启用主副本感知型路由。

适用于读写事务的 Spanner 路由

Spanner 会复制数据,以提供额外的数据可用性和地理局部性。在 Spanner 双区域和多区域实例配置中,双区域和多区域实例配置中的某个区域会被指定为主主要区域,其中包含数据库的主副本。当您使用双区域或多区域实例配置,并且客户端从非主区域向数据库发出读写事务时,写入操作始终在主要区域处理,然后发回给非主区域。因此,从非主副本区域提交的读写事务需要多次往返主副本才能成功提交。

主副本感知型路由是一种机制,可通过智能地路由这些事务来缩短读写事务的延迟时间。如果启用了主副本感知型路由,即使写入操作并非来自主要区域,系统也会将会话创建请求路由到主要区域,以便将 Spanner 前端 (SpanFE) 与主要区域保持一致。这种路由机制可将非主副本区域(客户端应用所在的位置)与主要区域之间所需的网络往返次数减少到 2 次,从而缩短读写事务的延迟时间。

启用了主副知路由的 Spanner 路由的屏幕截图。 图 1. 启用了主副本感知型路由的 Spanner 路由示例。

如果停用了感知主副本的路由,客户端应用会先将请求路由到客户端应用区域(非主副本区域)内的 SpanFE 服务。然后,从客户端应用区域中的 SpanFE 到主要区域中的 Spanner 服务器 (SpanServer) 进行三次或更多往返,以提交写入,从而增加延迟时间。这些额外的往返需要支持次级索引、约束检查和读取写入。

屏幕截图:停用了主副知情型路由的 Spanner 路由。 图 2. 停用主副本感知型路由的 Spanner 路由示例。

使用场景

使用主副知情路由后,以下使用场景可获享更低的延迟时间:

  • 批量更新:从非主副本区域执行 Dataflow 导入或运行后台更改(例如批量 DML)。
  • 容灾和提高可用性:在主副本区域和非主副本区域部署客户端应用,以容忍区域级服务中断,同时从非主副本区域发起写入。
  • 全球应用:在全球范围内部署客户端应用,并在提交数据的广泛区域位置部署。

限制

如果您的客户端应用部署在主要区域之外,并且您在写入值时不读取数据(“盲写入”),那么如果启用了主副本感知型路由,您可能会观察到延迟时间回归。这是因为启用主副区知情路由后,非主副区中的客户端应用与主副区中的 SpanFE 之间会发生两次跨区域往返(beginTransactioncommit 请求)。不过,停用主副本感知型路由后,不进行读取的写入只需对 commit 请求进行一次跨区域往返(beginTransaction 在本地 SpanFE 中处理)。例如,如果您将文件数据批量加载到新创建的表中,事务不太可能从该表中读取数据。如果您经常在应用中提交写入操作,但不读取它,则不妨考虑停用主副本感知型路由。如需了解详情,请参阅停用主副本感知型路由

使用主副本感知型路由

Spanner 客户端库中默认启用主副本感知型路由。

我们建议您在启用主副本感知型路由的情况下处理读写请求。您可以停用此功能,以比较效果差异。

启用主副本感知型路由

您可以使用 Spanner 客户端库手动启用主副本感知型路由。

C++

使用 RouteToLeaderOption 结构配置启用了主副本感知路由的客户端应用:

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#

使用 EnableLeaderRouting 配置启用了主副本感知路由的客户端应用:

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

Go

使用 ClientConfig 配置启用了主副本感知路由的客户端应用:

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

使用 SpannerOptions.Builder 配置启用了主副本感知路由的客户端应用:

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

Node.js

使用 SpannerOptions 配置启用了主副本感知路由的客户端应用:

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

PHP

使用 routeToLeader 配置启用了主副本感知路由的客户端应用:

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

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

Python

使用 route_to_leader_enabled 配置启用了主副本感知路由的客户端应用:

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

Ruby

使用 self.new 配置启用了主副本感知路由的客户端应用:

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

停用主副本感知型路由

您可以使用 Spanner 客户端库停用主副本感知型路由。

C++

使用 RouteToLeaderOption 结构配置客户端应用,并停用主副本感知型路由:

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#

使用 EnableLeaderRouting 配置客户端应用,并停用主副本感知型路由:

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

Go

使用 ClientConfig 配置客户端应用,并停用主副本感知型路由:

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

使用 SpannerOptions.Builder 创建与已停用主副本感知型路由的 Spanner 数据库的连接:

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

Node.js

使用 SpannerOptions 配置客户端应用,并停用主副本感知型路由:

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

PHP

使用 routeToLeader 配置客户端应用,并停用主副本感知型路由:

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

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

Python

使用 route_to_leader_enabled 配置客户端应用,并停用主副本感知型路由:

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

Ruby

使用 self.new 配置客户端应用,并停用主副本感知型路由:

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

后续步骤