有向読み取り

このページでは、Spanner の有向読み取りとその使用方法について説明します。

Spanner の有向読み取りでは、マルチリージョン インスタンス構成またはカスタム リージョン構成(オプションの読み取り専用リージョンを含む)内の特定のレプリカ タイプまたはリージョンに、読み取り専用トランザクション単一読み取りを柔軟にルーティングできます。

一般的なユースケース

有向読み取りの一般的なユースケースは次のとおりです。

  • 複数のリージョン間でワークロードをロード バランシングして、CPU 使用率を均等にする。
  • トランザクション ワークロードへの影響を最小限に抑えることで、アプリケーション内で分析を分離する。
  • 変更ストリームの読み取りを部分的に分離する。 Spanner API を使用して Spanner データの変更をストリーミングする場合、有向読み取りを使用することで、トランザクション ワークロードへの影響を最小限に抑えることができます。

サポートされているクエリ オペレーション

クエリ オペレーション 有向読み取りはサポートされていますか?
ステイル読み取り
強力な読み取り
読み取り / 書き込みトランザクション いいえ

読み取り / 書き込みトランザクションパーティション化 DML タイプの一括更新では、有向読み取りはサポートされていません。これは、読み取り / 書き込みトランザクションをリーダー リージョンで処理する必要があるためです。読み取り / 書き込みトランザクションで有向読み取りが使用されている場合、トランザクションは BAD_REQUEST エラーで失敗します。

制限事項

Spanner の有向読み取りには次の制限があります。

  • 有向読み取りは、マルチリージョン インスタンス構成、またはカスタム リージョン構成(オプションの読み取り専用リージョンを含む)内の Spanner インスタンスでのみ使用できます。
  • 書き込みリクエストは常にリーダー リージョンによって処理されるため、読み取り / 書き込みリクエストでは有向読み取りを使用できません。
  • Google Cloud コンソールまたは Google Cloud CLI では、有向読み取りを使用できません。REST API と RPC API および Spanner クライアント ライブラリで使用できます。
  • 1 回の有向読み取りで最大 10 個のレプリカを指定できます。
  • システム分析情報ダッシュボードまたは Metrics Explorer を使用する場合、1 秒あたりのオペレーション数、データベースごとの 1 秒あたりのオペレーション数、API メソッドごとの 1 秒あたりのオペレーション数のグラフには、指定した以外の場所での有向読み取りリクエストが表示されることがあります。この場合、グラフの情報が正しくない可能性があります。CPU 使用率の指標を使用して、読み取りリクエストが選択したリージョンにルーティングされていることを確認できます。これらの指標は、有向読み取りトラフィックがルーティングされる場所に関する最も正確な情報を示します。

準備

有向読み取りを使用する前に、次のことを考慮してください。

  • アプリケーションに最も近いレプリカまたはリージョン以外のレプリカまたはリージョンに読み取りをルーティングすると、アプリケーションで追加のレイテンシが発生する可能性があります。
  • 以下に基づいてトラフィックをルーティングできます。
    • リージョン名(例: us-central1)。
    • レプリカの種類(有効な値: READ_ONLYREAD_WRITE)。
  • 有向読み取りにおける自動フェイルオーバー オプションはデフォルトで有効になっています。自動フェイルオーバー オプションが有効で、指定されたすべてのレプリカが使用不能または異常な場合、Spanner は includeReplicas リスト外のレプリカにリクエストをルーティングします。自動フェイルオーバー オプションを無効にし、指定したすべてのレプリカが使用不能であるか、異常な場合、有向読み取りリクエストは失敗します。

有向読み取りパラメータ

REST または RPC API を使用して有向読み取りを実行する場合は、これらのフィールドを directedReadOptions パラメータで定義する必要があります。includeReplicas または excludeReplicas のいずれか 1 つだけを含めることができます。

  • includeReplicas: replicaSelections の繰り返しセットが含まれます。このリストは、特定のリージョンまたはレプリカタイプへの有向読み取りを考慮する順序を示しています。最大 10 個の includeReplicas を指定できます。
    • replicaSelections: 有向読み取りリクエストを処理する location またはレプリカ type で構成されます。includeReplicas を使用する場合は、次のフィールドのうち少なくとも 1 つを指定する必要があります。
      • location: 有向読み取りリクエストを処理するロケーション。ロケーションは、データベースのマルチリージョン構成内のいずれかのリージョンにする必要があります。ロケーションがデータベースのマルチリージョン構成内のどのリージョンにもない場合、リクエストは想定どおりにルーティングされません。代わりに、最も近いリージョンによって処理されます。たとえば、マルチリージョン インスタンス構成 nam6 のデータベース上のロケーション us-central1 に読み取りを指定することができます。
      • type: 有向読み取りリクエストを処理するレプリカタイプ。有効なタイプは READ_WRITEREAD_ONLY です。
    • autoFailoverDisabled: これはデフォルトで False に設定されています。つまり、自動フェイルオーバーが有効になります。自動フェイルオーバー オプションが有効で、指定されたすべてのレプリカが使用不能であるか異常である場合、Spanner は includeReplicas リスト外のレプリカにリクエストをルーティングします。自動フェイルオーバー オプションを無効にし、指定したすべてのレプリカが使用不能であるか、異常な場合、有向読み取りリクエストは失敗します。有効な値は、TRUE(無効)、FALSE(有効)です。
  • excludeReplicas: リクエストの処理から除外される replicaSelections の繰り返しセットが含まれます。Spanner は、このリストのレプリカにリクエストをルーティングしません。
    • replicaSelections: 有向読み取りリクエストの処理から除外されるロケーションまたはレプリカタイプ。excludeReplicas を使用する場合は、次のフィールドのうち少なくとも 1 つを指定する必要があります。
      • location: 有効読み取りリクエストの処理から除外されるロケーション。
      • type: 有向読み取りリクエストの処理から除外されるレプリカタイプ。有向なタイプは READ_WRITEREAD_ONLY です。

REST リクエスト本文の例を表示するには、[有向読み取りを使用する] セクションの [REST] タブをクリックします。

有向読み取りを使用する

Spanner クライアント ライブラリ、REST API、RPC API を使用して、有向読み取りを実行できます。

クライアント ライブラリ

C++

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

  // Create a client with a DirectedReadOption.
  auto client = spanner::Client(
      spanner::MakeConnection(
          spanner::Database(project_id, instance_id, database_id)),
      google::cloud::Options{}.set<spanner::DirectedReadOption>(
          spanner::ExcludeReplicas({spanner::ReplicaSelection("us-east4")})));

  spanner::SqlStatement select(
      "SELECT SingerId, AlbumId, AlbumTitle FROM Albums");
  using RowType = std::tuple<std::int64_t, std::int64_t, std::string>;

  // A DirectedReadOption on the operation will override the option set
  // at the client level.
  auto rows = client.ExecuteQuery(
      std::move(select),
      google::cloud::Options{}.set<spanner::DirectedReadOption>(
          spanner::IncludeReplicas(
              {spanner::ReplicaSelection(spanner::ReplicaType::kReadWrite)},
              /*auto_failover_disabled=*/true)));
  for (auto& row : spanner::StreamOf<RowType>(rows)) {
    if (!row) throw std::move(row).status();
    std::cout << "SingerId: " << std::get<0>(*row)
              << " AlbumId: " << std::get<1>(*row)
              << " AlbumTitle: " << std::get<2>(*row) << "\n";
  }
  std::cout << "Read completed for [spanner_directed_read]\n";
}

C#


using Google.Cloud.Spanner.Data;
using Google.Cloud.Spanner.V1;
using System.Collections.Generic;
using System.Threading.Tasks;

public class DirectedReadsAsyncSample
{
    public class Album
    {
        public int SingerId { get; set; }
        public int AlbumId { get; set; }
        public string AlbumTitle { get; set; }
    }

    public async Task<List<Album>> DirectedReadsAsync(string projectId, string instanceId, string databaseId)
    {
        string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
        using var connection = new SpannerConnection(connectionString);

        using var cmd = connection.CreateSelectCommand("SELECT SingerId, AlbumId, AlbumTitle FROM Albums");
        // Set directed read options on a query or read command.
        cmd.DirectedReadOptions = new DirectedReadOptions
        {
            IncludeReplicas = new DirectedReadOptions.Types.IncludeReplicas
            {
                AutoFailoverDisabled = true,
                ReplicaSelections =
                {
                    new DirectedReadOptions.Types.ReplicaSelection
                    {
                        Location = "us-central1",
                        Type = DirectedReadOptions.Types.ReplicaSelection.Types.Type.ReadOnly
                    }
                }
            }
        };

        var albums = new List<Album>();
        using var reader = await cmd.ExecuteReaderAsync();
        while (await reader.ReadAsync())
        {
            albums.Add(new Album
            {
                AlbumId = reader.GetFieldValue<int>("AlbumId"),
                SingerId = reader.GetFieldValue<int>("SingerId"),
                AlbumTitle = reader.GetFieldValue<string>("AlbumTitle")
            });
        }
        return albums;
    }
}

Go


import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/spanner"
	sppb "cloud.google.com/go/spanner/apiv1/spannerpb"
	"google.golang.org/api/iterator"
)

//	Shows how to run a query with directed read options.
//	Only one of ExcludeReplicas or IncludeReplicas can be set
//	Each accepts a list of ReplicaSelections which contains Location and Type
//	* `location` - The location must be one of the regions within the
//	multi-region configuration of your database.
//	* `type` - The type of the replica
//	Some examples of using replica_selectors are:
//	* `location:us-east1` --> The "us-east1" replica(s) of any available type
//		will be used to process the request.
//	* `type:READ_ONLY`    --> The "READ_ONLY" type replica(s) in nearest
//	available location will be used to process the
//	request.
//	* `location:us-east1 type:READ_ONLY` --> The "READ_ONLY" type replica(s)
//	in location "us-east1" will be used to process the request.
//		IncludeReplicas also contains an option for AutoFailoverDisabled which when set
//	Spanner will not route requests to a replica outside the
//	IncludeReplicas list when all the specified replicas are unavailable
//	or unhealthy. The default value is `false`

func directedReadOptions(w io.Writer, db string) error {
	// db = `projects/<project>/instances/<instance-id>/database/<database-id>`
	ctx := context.Background()
	directedReadOptionsForClient := &sppb.DirectedReadOptions{
		Replicas: &sppb.DirectedReadOptions_ExcludeReplicas_{
			ExcludeReplicas: &sppb.DirectedReadOptions_ExcludeReplicas{
				ReplicaSelections: []*sppb.DirectedReadOptions_ReplicaSelection{
					{
						Location: "us-east4",
					},
				},
			},
		},
	}
	// DirectedReadOptions can be set at client level and will be used in all read-only transaction requests
	client, err := spanner.NewClientWithConfig(ctx, db, spanner.ClientConfig{DirectedReadOptions: directedReadOptionsForClient})
	if err != nil {
		return err
	}
	defer client.Close()

	// DirectedReadOptions set at Request level will override the options set at Client level.
	directedReadOptionsForRequest := &sppb.DirectedReadOptions{
		Replicas: &sppb.DirectedReadOptions_IncludeReplicas_{
			IncludeReplicas: &sppb.DirectedReadOptions_IncludeReplicas{
				ReplicaSelections: []*sppb.DirectedReadOptions_ReplicaSelection{
					{
						Type: sppb.DirectedReadOptions_ReplicaSelection_READ_ONLY,
					},
				},
				AutoFailoverDisabled: true,
			},
		},
	}

	statement := spanner.Statement{SQL: `SELECT SingerId, AlbumId, AlbumTitle FROM Albums`}
	// // Read rows while passing directedReadOptions directly to the query.
	iter := client.Single().QueryWithOptions(ctx, statement, spanner.QueryOptions{DirectedReadOptions: directedReadOptionsForRequest})
	defer iter.Stop()
	for {
		row, err := iter.Next()
		if err == iterator.Done {
			return nil
		}
		if err != nil {
			return err
		}
		var singerID, albumID int64
		var albumTitle string
		if err := row.Columns(&singerID, &albumID, &albumTitle); err != nil {
			return err
		}
		fmt.Fprintf(w, "%d %d %s\n", singerID, albumID, albumTitle)
	}
}

Java

import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Options;
import com.google.cloud.spanner.ResultSet;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
import com.google.spanner.v1.DirectedReadOptions;
import com.google.spanner.v1.DirectedReadOptions.ExcludeReplicas;
import com.google.spanner.v1.DirectedReadOptions.IncludeReplicas;
import com.google.spanner.v1.DirectedReadOptions.ReplicaSelection;

public class DirectedReadSample {
  static void directedRead() {
    // TODO(developer): Replace these variables before running the sample.
    final String projectId = "my-project";
    final String instanceId = "my-instance";
    final String databaseId = "my-database";
    directedRead(projectId, instanceId, databaseId);
  }

  static void directedRead(String projectId, String instanceId, String databaseId) {
    // Only one of excludeReplicas or includeReplicas can be set
    // Each accepts a list of replicaSelections which contains location and type
    //   * `location` - The location must be one of the regions within the
    //      multi-region configuration of your database.
    //   * `type` - The type of the replica
    // Some examples of using replicaSelectors are:
    //   * `location:us-east1` --> The "us-east1" replica(s) of any available type
    //                             will be used to process the request.
    //   * `type:READ_ONLY`    --> The "READ_ONLY" type replica(s) in nearest
    // .                            available location will be used to process the
    //                             request.
    //   * `location:us-east1 type:READ_ONLY` --> The "READ_ONLY" type replica(s)
    //                          in location "us-east1" will be used to process
    //                          the request.
    //  includeReplicas also contains an option called autoFailoverDisabled, which when set to true
    //  will instruct Spanner to not route requests to a replica outside the
    //  includeReplicas list when all the specified replicas are unavailable
    //  or unhealthy. Default value is `false`.
    final DirectedReadOptions directedReadOptionsForClient =
        DirectedReadOptions.newBuilder()
            .setExcludeReplicas(
                ExcludeReplicas.newBuilder()
                    .addReplicaSelections(
                        ReplicaSelection.newBuilder().setLocation("us-east4").build())
                    .build())
            .build();

    // You can set default `DirectedReadOptions` for a Spanner client. These options will be applied
    // to all read-only transactions that are executed by this client, unless specific
    // DirectedReadOptions are set for a query.
    // Directed read can only be used for read-only transactions. The default options will be
    // ignored for any read/write transaction that the client executes.
    try (Spanner spanner =
        SpannerOptions.newBuilder()
            .setProjectId(projectId)
            .setDirectedReadOptions(directedReadOptionsForClient)
            .build()
            .getService()) {
      final DatabaseClient dbClient =
          spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId));

      // DirectedReadOptions at request level will override the options set at
      // client level (through SpannerOptions).
      final DirectedReadOptions directedReadOptionsForRequest =
          DirectedReadOptions.newBuilder()
              .setIncludeReplicas(
                  IncludeReplicas.newBuilder()
                      .addReplicaSelections(
                          ReplicaSelection.newBuilder()
                              .setType(ReplicaSelection.Type.READ_WRITE)
                              .build())
                      .setAutoFailoverDisabled(true)
                      .build())
              .build();

      // Read rows while passing DirectedReadOptions directly to the query.
      try (ResultSet rs =
          dbClient
              .singleUse()
              .executeQuery(
                  Statement.of("SELECT SingerId, AlbumId, AlbumTitle FROM Albums"),
                  Options.directedRead(directedReadOptionsForRequest))) {
        while (rs.next()) {
          System.out.printf(
              "SingerId: %d, AlbumId: %d, AlbumTitle: %s\n",
              rs.getLong(0), rs.getLong(1), rs.getString(2));
        }
        System.out.println("Successfully executed read-only transaction with directedReadOptions");
      }
    }
  }
}

Node.js

// Imports the Google Cloud Spanner client library
const {Spanner, protos} = require('@google-cloud/spanner');

// Only one of excludeReplicas or includeReplicas can be set
// Each accepts a list of replicaSelections which contains location and type
//   * `location` - The location must be one of the regions within the
//      multi-region configuration of your database.
//   * `type` - The type of the replica
// Some examples of using replicaSelectors are:
//   * `location:us-east1` --> The "us-east1" replica(s) of any available type
//                             will be used to process the request.
//   * `type:READ_ONLY`    --> The "READ_ONLY" type replica(s) in nearest
//.                            available location will be used to process the
//                             request.
//   * `location:us-east1 type:READ_ONLY` --> The "READ_ONLY" type replica(s)
//                          in location "us-east1" will be used to process
//                          the request.
//  includeReplicas also contains an option for autoFailover which when set
//  Spanner will not route requests to a replica outside the
//  includeReplicas list when all the specified replicas are unavailable
//  or unhealthy. The default value is `false`
const directedReadOptionsForClient = {
  excludeReplicas: {
    replicaSelections: [
      {
        location: 'us-east4',
      },
    ],
  },
};

// Instantiates a client with directedReadOptions
const spanner = new Spanner({
  projectId: projectId,
  directedReadOptions: directedReadOptionsForClient,
});

async function spannerDirectedReads() {
  // Gets a reference to a Cloud Spanner instance and backup
  const instance = spanner.instance(instanceId);
  const database = instance.database(databaseId);
  const directedReadOptionsForRequest = {
    includeReplicas: {
      replicaSelections: [
        {
          type: protos.google.spanner.v1.DirectedReadOptions.ReplicaSelection
            .Type.READ_ONLY,
        },
      ],
      autoFailoverDisabled: true,
    },
  };

  await database.getSnapshot(async (err, transaction) => {
    if (err) {
      console.error(err);
      return;
    }
    try {
      // Read rows while passing directedReadOptions directly to the query.
      // These will override the options passed at Client level.
      const [rows] = await transaction.run({
        sql: 'SELECT SingerId, AlbumId, AlbumTitle FROM Albums',
        directedReadOptions: directedReadOptionsForRequest,
      });
      rows.forEach(row => {
        const json = row.toJSON();
        console.log(
          `SingerId: ${json.SingerId}, AlbumId: ${json.AlbumId}, AlbumTitle: ${json.AlbumTitle}`
        );
      });
      console.log(
        'Successfully executed read-only transaction with directedReadOptions'
      );
    } catch (err) {
      console.error('ERROR:', err);
    } finally {
      transaction.end();
      // Close the database when finished.
      await database.close();
    }
  });
}
spannerDirectedReads();

PHP

use Google\Cloud\Spanner\SpannerClient;
use Google\Cloud\Spanner\V1\DirectedReadOptions\ReplicaSelection\Type as ReplicaType;

/**
 * Queries sample data from the database with directed read options.
 * Example:
 * ```
 * directed_read($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function directed_read(string $instanceId, string $databaseId): void
{
    $directedReadOptionsForClient = [
        'directedReadOptions' => [
            'excludeReplicas' => [
                'replicaSelections' => [
                    [
                        'location' => 'us-east4'
                    ]
                ]
            ]
        ]
    ];

    $directedReadOptionsForRequest = [
        'directedReadOptions' => [
            'includeReplicas' => [
                'replicaSelections' => [
                    [
                        'type' => ReplicaType::READ_WRITE
                    ]
                ],
                'autoFailoverDisabled' => true
            ]
        ]
    ];

    $spanner = new SpannerClient($directedReadOptionsForClient);
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);
    $snapshot = $database->snapshot();

    // directedReadOptions at Request level will override the options set at
    // Client level
    $results = $snapshot->execute(
        'SELECT SingerId, AlbumId, AlbumTitle FROM Albums',
        $directedReadOptionsForRequest
    );

    foreach ($results as $row) {
        printf('SingerId: %s, AlbumId: %s, AlbumTitle: %s' . PHP_EOL,
            $row['SingerId'], $row['AlbumId'], $row['AlbumTitle']);
    }
}

Python

# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"

directed_read_options_for_client = {
    "exclude_replicas": {
        "replica_selections": [
            {
                "location": "us-east4",
            },
        ],
    },
}

# directed_read_options can be set at client level and will be used in all
# read-only transaction requests
spanner_client = spanner.Client(
    directed_read_options=directed_read_options_for_client
)
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

directed_read_options_for_request = {
    "include_replicas": {
        "replica_selections": [
            {
                "type_": DirectedReadOptions.ReplicaSelection.Type.READ_ONLY,
            },
        ],
        "auto_failover_disabled": True,
    },
}

with database.snapshot() as snapshot:
    # Read rows while passing directed_read_options directly to the query.
    # These will override the options passed at Client level.
    results = snapshot.execute_sql(
        "SELECT SingerId, AlbumId, AlbumTitle FROM Albums",
        directed_read_options=directed_read_options_for_request,
    )

    for row in results:
        print("SingerId: {}, AlbumId: {}, AlbumTitle: {}".format(*row))

Ruby

require "google/cloud/spanner"

##
# This is a snippet for showcasing how to pass in directed read options.
#
# @param project_id  [String] The ID of the Google Cloud project.
# @param instance_id [String] The ID of the spanner instance.
# @param database_id [String] The ID of the database.
#
def spanner_directed_read project_id:, instance_id:, database_id:
  # Only one of exclude_replicas or include_replicas can be set.
  # Each accepts a list of replica_selections which contains location and type
  #   * `location` - The location must be one of the regions within the
  #      multi-region configuration of your database.
  #   * `type` - The type of the replica
  # Some examples of using replicaSelectors are:
  #   * `location:us-east1` --> The "us-east1" replica(s) of any available type
  #                             will be used to process the request.
  #   * `type:READ_ONLY`    --> The "READ_ONLY" type replica(s) in the nearest
  # .                            available location will be used to process the
  #                             request.
  #   * `location:us-east1 type:READ_ONLY` --> The "READ_ONLY" type replica(s)
  #                          in location "us-east1" will be used to process
  #                          the request.
  #  include_replicas also contains an option for auto_failover_disabled. If set
  #  Spanner will not route requests to a replica outside the
  #  include_replicas list even if all the specified replicas are
  #  unavailable or unhealthy. The default value is `false`.
  directed_read_options_for_client = {
    include_replicas: {
      replica_selections: [{ location: "us-east4" }]
    }
  }

  # Instantiates a client with directedReadOptions
  spanner = Google::Cloud::Spanner.new project: project_id
  client  = spanner.client instance_id, database_id, directed_read_options: directed_read_options_for_client

  directed_read_options = {
    include_replicas: {
      replica_selections: [{ type: "READ_WRITE" }],
      auto_failover_disabled: true
    }
  }

  result = client.execute_sql "SELECT SingerId, AlbumId, AlbumTitle FROM Albums", directed_read_options: directed_read_options
  result.rows.each do |row|
    puts "SingerId: #{row[:SingerId]}"
    puts "AlbumId: #{row[:AlbumId]}"
    puts "AlbumTitle: #{row[:AlbumTitle]}"
  end
  puts "Successfully executed read-only transaction with directed_read_options"
end

REST

次の REST API を使用して、有向読み取りを実行できます。

たとえば、executeSQL を使用して us-central1 で有向読み取りを実行するには、次のようにします。

  1. [projects.instances.databases.sessions.executeSql] をクリックします。

  2. [session] に以下のように入力します。

    projects/<VAR>PROJECT-ID</VAR>/instances/<VAR>INSTANCE-ID</VAR>/databases/<VAR>DATABASE-ID</VAR>/sessions/<VAR>SESSION-ID</VAR>
    

    次のように置き換えます。

    • PROJECT-ID: プロジェクト ID。
    • INSTANCE-ID: インスタンス ID。
    • DATABASE-ID: データベース ID。
    • SESSION-ID: セッション ID。 セッションを作成するときに SESSION-ID の値を取得します。
  3. [Request body] で以下のように入力します。

    {
      "directedReadOptions": {
        "includeReplicas": {
          "replicaSelections": [
            {
              "location": "us-central1",
            }
          ]
        }
      },
      "sql": "SELECT SingerId, AlbumId, AlbumTitle FROM Albums"
    }
    
  4. [実行] をクリックします。レスポンスにクエリの結果が表示されます。

RPC

次の RPC API を使用して、有向読み取りを実行できます。

次のステップ