Docs
検索⌘ K
  • Home
  • The Graphについて
  • サポートされているネットワーク
  • Protocol Contracts
  • サブグラフ
    • サブストリーム
      • Token API
        • AI Suite
          • インデクシング
            • リソース
              サブグラフ > クエリ

              7 分

              分散システム

              グラフは、分散システムとして実装されたプロトコルです。

              接続に失敗する。リクエストの順番が狂う。時計や状態が同期していない別のコンピュータが、関連するリクエストを処理する。サーバーが再起動する。リクエストとリクエストの間に「再衝突」が起こる。これらの問題は、すべての分散システムに固有のものですが、グローバルな規模で運用されているシステムでは、さらに悪化します。

              re-org 中にクライアントがインデクサに最新のデータを要求した場合の例を考えてみましょう。

              1. インデクサーがブロック 8 を取り込む
              2. クライアントにブロック 8 のリクエストを送信
              3. インデクサーがブロック 9 を取り込む
              4. インデクサーがブロック 10A を取り込む
              5. ブロック 10A のクライアントにリクエストが提供される
              6. インデクサーは 10B への reorg を検出し、10A をロールバックする
              7. ブロック 9 に対してクライアントへのリクエストを提供
              8. インデクサーがブロック 10B を取り込む
              9. インデクサーがブロック 11 を取り込む
              10. ブロック 11 のクライアントにリクエストを提供

              インデクサーの視点では、物事が論理的に進んでいます。時間は進んでいますが、アンクルブロックを巻き戻して、その上にコンセンサス中のブロックを再生する必要がありました。その間、インデクサーは、その時点で知っている最新の状態を使ってリクエストに対応します。

              クライアントから見ると、事態は混沌としているように見えます。クライアントは、ブロック 8、10、9、11 の順に応答があったことを確認します。これを「block wobble」問題と呼んでいます。block wobble が発生すると、データが時間とともに矛盾していくように見えることがあります。インデクサがすべての最新ブロックを同時に取り込むわけではないことを考えると、状況は悪化し、クライアントのリクエストは複数のインデクサーにルーティングされる可能性があります。

              一貫性のあるデータをユーザーに提供するには、クライアントとサーバーが協力して取り組む必要があります。すべての問題に対して正しいプログラムは存在しないため、必要な一貫性に応じて異なるアプローチを使用する必要があります。

              分散システムの意味を理解するのは難しいですが、解決するのは難しいことではありません。私たちは、一般的な使用例をナビゲートするための API とパターンを確立しました。以下の例では、これらのパターンを説明していますが、本番コードで必要とされる詳細(エラー処理やキャンセルなど)は省略していますので、主旨を理解していただくことはできません。

              更新データのポーリング

              The Graph provides the block: { number_gte: $minBlock } API, which ensures that the response is for a single block equal or higher to $minBlock. If the request is made to a graph-node instance and the min block is not yet synced, graph-node will return an error. If graph-node has synced min block, it will run the response for the latest block. If the request is made to an Edge & Node Gateway, the Gateway will filter out any Indexers that have not yet synced min block and make the request for the latest block the Indexer has synced.

              We can use number_gte to ensure that time never travels backward when polling for data in a loop. Here is an example:

              1/// Updates the protocol.paused variable to the latest2/// known value in a loop by fetching it using The Graph.3async function updateProtocolPaused() {4  // It's ok to start with minBlock at 0. The query will be served5  // using the latest block available. Setting minBlock to 0 is the6  // same as leaving out that argument.7  let minBlock = 089  for (;;) {10    // Schedule a promise that will be ready once11    // the next Ethereum block will likely be available.12    const nextBlock = new Promise((f) => {13      setTimeout(f, 14000)14    })1516    const query = `17        query GetProtocol($minBlock: Int!) {18            protocol(block: { number_gte: $minBlock }  id: "0") {19              paused20            }21            _meta {22                block {23                    number24                }25            }26        }`2728    const variables = { minBlock }29    const response = await graphql(query, variables)30    minBlock = response._meta.block.number3132    // TODO: Do something with the response data here instead of logging it.33    console.log(response.protocol.paused)3435    // Sleep to wait for the next block36    await nextBlock37  }38}

              関連するアイテムのセットの取得

              もうひとつのケースは、大規模なセットを取得することで、一般的には、複数のリクエストにわたって関連するアイテムを取得するケースです。ポーリングの場合(時間を進めて一貫性を保つ必要があった)とは異なり、必要な一貫性はある時点でのものです。

              Here we will use the block: { hash: $blockHash } argument to pin all of our results to the same block.

              1/// Gets a list of domain names from a single block using pagination2async function getDomainNames() {3  // Set a cap on the maximum number of items to pull.4  let pages = 55  const perPage = 100067  // The first query will get the first page of results and also get the block8  // hash so that the remainder of the queries are consistent with the first.9  const listDomainsQuery = `10    query ListDomains($perPage: Int!) {11        domains(first: $perPage) {12            name13            id14        }15        _meta {16            block {17                hash18            }19        }20    }`2122  let data = await graphql(listDomainsQuery, { perPage })23  let result = data.domains.map((d) => d.name)24  let blockHash = data._meta.block.hash2526  let query27  // Continue fetching additional pages until either we run into the limit of28  // 5 pages total (specified above) or we know we have reached the last page29  // because the page has fewer entities than a full page.30  while (data.domains.length == perPage && --pages) {31    let lastID = data.domains[data.domains.length - 1].id32    query = `33        query ListDomains($perPage: Int!, $lastID: ID!, $blockHash: Bytes!) {34            domains(first: $perPage, where: { id_gt: $lastID }, block: { hash: $blockHash }) {35                name36                id37            }38        }`3940    data = await graphql(query, { perPage, lastID, blockHash })4142    // Accumulate domain names into the result43    for (domain of data.domains) {44      result.push(domain.name)45    }46  }47  return result48}

              なお、re-org が発生した場合、クライアントは最初のリクエストから再試行して、ブロックハッシュをアンクルではないブロックに更新する必要があります。

              ⁠GitHubで編集する⁠

              Querying from an AppGraphQL API
              このページでは
              • 更新データのポーリング
              • 関連するアイテムのセットの取得
              The GraphStatusTestnetBrand AssetsForumSecurityプライバシーポリシーTerms of Service