23 minutes
グラフノード
グラフノードはサブグラフのインデックスを作成し、得られたデータをGraphQL API経由でクエリできるようにするコンポーネントです。そのため、インデクサースタックの中心的存在であり、グラフノードの正しい動作はインデクサーを成功させるために非常に重要です。
This provides a contextual overview of Graph Node, and some of the more advanced options available to indexers. Detailed documentation and instructions can be found in the Graph Node repository.
グラフノード
Graph Node is the reference implementation for indexing Subgraphs on The Graph Network, connecting to blockchain clients, indexing subgraphs and making indexed data available to query.
Graph Node (and the whole indexer stack) can be run on bare metal, or in a cloud environment. This flexibility of the central indexing component is crucial to the robustness of The Graph Protocol. Similarly, Graph Node can be built from source, or indexers can use one of the provided Docker Images.
PostgreSQLデータベース
グラフノードのメインストアで、サブグラフデータ、サブグラフに関するメタデータ、ブロックキャッシュやeth_callキャッシュなどのサブグラフに依存しないネットワークデータが格納されます。
ネットワーククライアント
ネットワークにインデックスを付けるために、グラフ ノードは EVM 互換の JSON-RPC API を介してネットワーク クライアントにアクセスする必要があります。この RPC は単一のクライアントに接続する場合もあれば、複数のクライアントに負荷を分散するより複雑なセットアップになる場合もあります。
While some subgraphs may just require a full node, some may have indexing features which require additional RPC functionality. Specifically subgraphs which make eth_calls
as part of indexing will require an archive node which supports EIP-1898, and subgraphs with callHandlers
, or blockHandlers
with a call
filter, require trace_filter
support (see trace module documentation here).
Network Firehoses - a Firehose is a gRPC service providing an ordered, yet fork-aware, stream of blocks, developed by The Graph’s core developers to better support performant indexing at scale. This is not currently an Indexer requirement, but Indexers are encouraged to familiarise themselves with the technology, ahead of full network support. Learn more about the Firehose here.
IPFSノード
IPFS ノード(バージョン 未満) - サブグラフのデプロイメタデータは IPFS ネットワーク上に保存されます。 グラフノードは、サブグラフのデプロイ時に主に IPFS ノードにアクセスし、サブグラフマニフェストと全てのリンクファイルを取得します。 ネットワーク・インデクサーは独自の IPFS ノードをホストする必要はありません。 ネットワーク用の IPFS ノードは、https://ipfs.network.thegraph.com でホストされています。
Prometheus メトリクスサーバー
監視とレポート作成を可能にするため、Graph NodeはオプションでPrometheusのメトリクスサーバーにメトリクスを記録することができます。
Getting started from source
Install prerequisites
-
Rust
-
PostgreSQL
-
IPFS
-
Additional Requirements for Ubuntu users - To run a Graph Node on Ubuntu a few additional packages may be needed.
1sudo apt-get install -y clang libpq-dev libssl-dev pkg-config
Setup
- Start a PostgreSQL database server
1initdb -D .postgres2pg_ctl -D .postgres -l logfile start3createdb graph-node
-
Clone Graph Node repo and build the source by running
cargo build
-
Now that all the dependencies are setup, start the Graph Node:
1cargo run -p graph-node --release -- \2 --postgres-url postgresql://[USERNAME]:[PASSWORD]@localhost:5432/graph-node \3 --ethereum-rpc [NETWORK_NAME]:[URL] \4 --ipfs https://ipfs.network.thegraph.com
Kubernetesを始めるにあたって
A complete Kubernetes example configuration can be found in the indexer repository.
Port
グラフノードは起動時に以下のポートを公開します。
Port | Purpose | Routes | CLI Argument | Environment Variable |
---|---|---|---|---|
8000 | GraphQL HTTP server (for subgraph queries) | /subgraphs/id/… /subgraphs/name/…/… | —http-port | - |
8001 | GraphQL WS (for subgraph subscriptions) | /subgraphs/id/… /subgraphs/name/…/… | —ws-port | - |
8020 | JSON-RPC (for managing deployments) | / | —admin-port | - |
8030 | Subgraph indexing status API | /graphql | —index-node-port | - |
8040 | Prometheus metrics | /metrics | —metrics-port | - |
Important: Be careful about exposing ports publicly - administration ports should be kept locked down. This includes the the Graph Node JSON-RPC endpoint.
グラフノードの高度な設定
最も単純な場合、Graph Node は、Graph Node の単一のインスタンス、単一の PostgreSQL データベース、IPFS ノード、およびサブグラフのインデックス作成に必要なネットワーク クライアントで操作できます。
This setup can be scaled horizontally, by adding multiple Graph Nodes, and multiple databases to support those Graph Nodes. Advanced users may want to take advantage of some of the horizontal scaling capabilities of Graph Node, as well as some of the more advanced configuration options, via the config.toml
file and Graph Node’s environment variables.
config.toml
A TOML configuration file can be used to set more complex configurations than those exposed in the CLI. The location of the file is passed with the —config command line switch.
設定ファイルを使用する場合、-postgres-url、-postgres-secondary-hosts、および —postgres-host-weights オプションを使用することはできません。
A minimal config.toml
file can be provided; the following file is equivalent to using the —postgres-url command line option:
1[store]2[store.primary]3connection="<.. postgres-url argument ..>"4[deployment]5[[deployment.rule]]6indexers = [ "<.. list of all indexing nodes ..>" ]
Full documentation of config.toml
can be found in the Graph Node docs.
複数のグラフノード
Graph Node indexing can scale horizontally, running multiple instances of Graph Node to split indexing and querying across different nodes. This can be done simply by running Graph Nodes configured with a different node_id
on startup (e.g. in the Docker Compose file), which can then be used in the config.toml
file to specify dedicated query nodes, block ingestors, and splitting subgraphs across nodes with deployment rules.
なお、複数のGraph Nodeはすべて同じデータベースを使用するように設定することができ、Shardingによって水平方向に拡張することができます。
デプロイメントルール
Given multiple Graph Nodes, it is necessary to manage deployment of new subgraphs so that the same subgraph isn’t being indexed by two different nodes, which would lead to collisions. This can be done by using deployment rules, which can also specify which shard
a subgraph’s data should be stored in, if database sharding is being used. Deployment rules can match on the subgraph name and the network that the deployment is indexing in order to make a decision.
デプロイメントルールの設定例:
1[deployment]2[[deployment.rule]]3match = { name = "(vip|important)/.*" }4shard = "vip"5indexers = [ "index_node_vip_0", "index_node_vip_1" ]6[[deployment.rule]]7match = { network = "kovan" }8# No shard, so we use the default shard called 'primary'9indexers = [ "index_node_kovan_0" ]10[[deployment.rule]]11match = { network = [ "xdai", "poa-core" ] }12indexers = [ "index_node_other_0" ]13[[deployment.rule]]14# There's no 'match', so any subgraph matches15shards = [ "sharda", "shardb" ]16indexers = [17 "index_node_community_0",18 "index_node_community_1",19 "index_node_community_2",20 "index_node_community_3",21 "index_node_community_4",22 "index_node_community_5"23 ]
Read more about deployment rules here.
専用クエリノード
設定ファイルに以下を記述することで、ノードを明示的にクエリノードに設定することができます。
1[general]2query = "<regular expression>"
正規表現に —node-id がマッチするノードは、クエリーにのみ応答するように設定されます。
シャーディングによるデータベースのスケーリング
ほとんどの場合、1つのPostgresデータベースでグラフノードインスタンスをサポートするのに十分です。グラフノードインスタンスが1つのPostgresデータベースを使い切った場合、グラフノードデータを複数のPostgresデータベースに分割して保存することが可能です。全てのデータベースが一緒になってグラフノードインスタンスのストアを形成します。個々のデータベースはシャード(shard)と呼ばれます。
Shards can be used to split subgraph deployments across multiple databases, and can also be used to use replicas to spread query load across databases. This includes configuring the number of available database connections each graph-node
should keep in its connection pool for each database, which becomes increasingly important as more subgraphs are being indexed.
グラフノードの負荷に既存のデータベースが追いつかず、これ以上データベースサイズを大きくすることができない場合に、シャーディングが有効になります。
一般的には、シャードを作成する前に、単一のデータベースを可能な限り大きくすることをお勧めします。例外は、クエリのトラフィックがサブグラフ間で非常に不均一に分割される場合です。このような状況では、ボリュームの大きいサブグラフを1つのシャードに、それ以外を別のシャードに保存すると劇的に効果があります。この設定により、ボリュームの大きいサブグラフのデータがdb内部キャッシュに残り、ボリュームの小さいサブグラフからそれほど必要とされていないデータに置き換えられる可能性が少なくなるためです。
接続の設定に関しては、まずpostgresql.confのmax_connectionsを400(あるいは200)に設定し、store_connection_wait_time_msとstore_connection_checkout_count Prometheusメトリクスを見てみてください。顕著な待ち時間(5ms以上)は、利用可能な接続が少なすぎることを示しています。高い待ち時間は、データベースが非常に忙しいこと(CPU負荷が高いなど)によっても引き起こされます。しかし、データベースが安定しているようであれば、待ち時間が長いのは接続数を増やす必要があることを示しています。設定上、各グラフノードインスタンスが使用できるコネクション数は上限であり、グラフノードは必要ないコネクションはオープンにしておきません。
Read more about store configuration here.
専用ブロックインジェスト
If there are multiple nodes configured, it will be necessary to specify one node which is responsible for ingestion of new blocks, so that all configured index nodes aren’t polling the chain head. This is done as part of the chains
namespace, specifying the node_id
to be used for block ingestion:
1[chains]2ingestor = "block_ingestor_node"
複数のネットワークに対応
The Graph Protocol is increasing the number of networks supported for indexing rewards, and there exist many subgraphs indexing unsupported networks which an indexer would like to process. The config.toml
file allows for expressive and flexible configuration of:
- 複数のネットワーク
- ネットワークごとに複数のプロバイダ(プロバイダ間で負荷を分割することができ、また、フルノードとアーカイブノードを構成することができ、作業負荷が許す限り、Graph Nodeはより安価なプロバイダを優先することができます)。
- 機能、認証、プロバイダの種類など、プロバイダの詳細(実験的なFirehoseのサポートのため)
The [chains]
section controls the ethereum providers that graph-node connects to, and where blocks and other metadata for each chain are stored. The following example configures two chains, mainnet and kovan, where blocks for mainnet are stored in the vip shard and blocks for kovan are stored in the primary shard. The mainnet chain can use two different providers, whereas kovan only has one provider.
1[chains]2ingestor = "block_ingestor_node"3[chains.mainnet]4shard = "vip"5provider = [6 { label = "mainnet1", url = "http://..", features = [], headers = { Authorization = "Bearer foo" } },7 { label = "mainnet2", url = "http://..", features = [ "archive", "traces" ] }8]9[chains.kovan]10shard = "primary"11provider = [ { label = "kovan", url = "http://..", features = [] } ]
Read more about provider configuration here.
環境変数について
Graph Node supports a range of environment variables which can enable features, or change Graph Node behaviour. These are documented here.
継続的なデプロイ
高度な構成でスケーリングされたインデックス作成セットアップを運用しているユーザーは、Kubernetes を使用してグラフ ノードを管理することでメリットが得られる場合があります。
- The indexer repository has an example Kubernetes reference
- Launchpad is a toolkit for running a Graph Protocol Indexer on Kubernetes maintained by GraphOps. It provides a set of Helm charts and a CLI to manage a Graph Node deployment.
グラフノードの管理
グラフノードが動作している場合、それらのノードに展開されたサブグラフを管理することが課題となります。グラフノードは、サブグラフを管理するための様々なツールを提供します。
ロギング
Graph Node’s logs can provide useful information for debugging and optimisation of Graph Node and specific subgraphs. Graph Node supports different log levels via the GRAPH_LOG
environment variable, with the following levels: error, warn, info, debug or trace.
In addition setting GRAPH_LOG_QUERY_TIMING
to gql
provides more details about how GraphQL queries are running (though this will generate a large volume of logs).
Monitoring & alerting
グラフノードは、デフォルトで8040ポートのPrometheusエンドポイント経由でメトリクスを提供します。そして、Grafanaを使用してこれらのメトリクスを可視化することができます。
The indexer repository provides an example Grafana configuration.
Graphman
graphman
is a maintenance tool for Graph Node, helping with diagnosis and resolution of different day-to-day and exceptional tasks.
The graphman command is included in the official containers, and you can docker exec into your graph-node container to run it. It requires a config.toml
file.
Full documentation of graphman
commands is available in the Graph Node repository. See [/docs/graphman.md] (https://github.com/graphprotocol/graph-node/blob/master/docs/graphman.md) in the Graph Node /docs
サブグラフの操作
インデックスステータスAPI
デフォルトではポート8030/graphqlで利用可能なindexing status APIは、異なるサブグラフのindexing statusのチェック、indexing proofのチェック、サブグラフの特徴の検査など、様々なメソッドを公開しています。
The full schema is available here.
インデックスのパフォーマンス
インデックス作成は、3つのパートに分かれています:
- プロバイダから興味のあるイベントを取得
- 適切なハンドラで順番にイベントを処理する(これには、状態のためにチェーンを呼び出したり、ストアからデータを取得したりすることが含まれます)。
- 出来上がったデータをストアに書き込む
これらのステージはパイプライン化されていますが(つまり、並列に実行することができます)、互いに依存し合っています。サブグラフのインデックス作成に時間がかかる場合、その根本的な原因は、特定のサブグラフに依存します。
インデックス作成が遅くなる一般的な原因:
- Time taken to find relevant events from the chain (call handlers in particular can be slow, given the reliance on
trace_filter
) - Making large numbers of
eth_calls
as part of handlers - 実行中に大量のストアインタラクションが発生
- ストアに保存するデータ量が多い場合
- 処理するイベントの数が多い場合
- データベースへの接続時間が遅い(混雑したノード)
- プロバイダー自体がチェーンヘッドに遅れる場合
- チェーンヘッドでプロバイダーから新しいレシートを取得する際の遅延
サブグラフのインデックス作成指標は、インデックス作成の遅さの根本的な原因を診断するのに役立ちます。あるケースでは、問題はサブグラフ自体にありますが、他のケースでは、ネットワークプロバイダーの改善、データベースの競合の減少、その他の構成の改善により、インデックス作成性能を著しく向上させることができます。
失敗したサブグラフ
インデックス作成中、サブグラフは予期しないデータに遭遇したり、あるコンポーネントが期待通りに動作しなかったり、イベントハンドラや設定に何らかのバグがあったりすると、失敗することがあります。失敗には一般に2つのタイプがあります。
- 決定論的失敗:再試行では解決できない失敗
- 非決定論的失敗:プロバイダの問題や、予期しないグラフノードのエラーに起因する可能性があります。非決定論的失敗が発生すると、グラフノードは失敗したハンドラを再試行し、時間をかけて後退させます。
いくつかのケースでは、失敗はインデクサーによって解決できるかもしれません(例えば、エラーが正しい種類のプロバイダを持っていない結果である場合、必要なプロバイダを追加することでインデックス作成を継続することが可能になります)。しかし、サブグラフのコードを変更する必要がある場合もあります。
Deterministic failures are considered “final”, with a Proof of Indexing generated for the failing block, while non-deterministic failures are not, as the subgraph may manage to “unfail” and continue indexing. In some cases, the non-deterministic label is incorrect, and the subgraph will never overcome the error; such failures should be reported as issues on the Graph Node repository.
ブロックキャッシュとコールキャッシュ
Graph Node caches certain data in the store in order to save refetching from the provider. Blocks are cached, as are the results of eth_calls
(the latter being cached as of a specific block). This caching can dramatically increase indexing speed during “resyncing” of a slightly altered subgraph.
However, in some instances, if an Ethereum node has provided incorrect data for some period, that can make its way into the cache, leading to incorrect data or failed subgraphs. In this case indexers can use graphman
to clear the poisoned cache, and then rewind the affected subgraphs, which will then fetch fresh data from the (hopefully) healthy provider.
TX受信欠落イベントなど、ブロックキャッシュの不整合が疑われる場合。
graphman chain list
to find the chain name.graphman chain check-blocks <CHAIN> by-number <NUMBER>
will check if the cached block matches the provider, and deletes the block from the cache if it doesn’t.- If there is a difference, it may be safer to truncate the whole cache with
graphman chain truncate <CHAIN>
. - ブロックがプロバイダに一致する場合、問題はプロバイダに対して直接デバッグすることができます。
- If there is a difference, it may be safer to truncate the whole cache with
問題やエラーのクエリ
サブグラフがインデックス化されると、インデクサはサブグラフの専用クエリエントポイントを介してクエリを提供することが期待できます。もしインデクサがかなりの量のクエリを提供することを望むなら、専用のクエリノードを推奨します。また、クエリ量が非常に多い場合、インデクサーはレプリカシャードを構成して、クエリがインデックス作成プロセスに影響を与えないようにしたいと思うかもしれません。
ただし、専用のクエリ ノードとレプリカを使用しても、特定のクエリの実行に時間がかかる場合があり、場合によってはメモリ使用量が増加し、他のユーザーのクエリ時間に悪影響を及ぼします。
「銀の弾丸」は一つではなく、遅いクエリを防止、診断、対処するための様々なツールがあります。
クエリキャッシング
Graph Node caches GraphQL queries by default, which can significantly reduce database load. This can be further configured with the GRAPH_QUERY_CACHE_BLOCKS
and GRAPH_QUERY_CACHE_MAX_MEM
settings - read more here.
クエリの分析
問題のあるクエリが表面化するのは、ほとんどの場合、次の2つの方法のどちらかです。あるケースでは、ユーザー自身があるクエリが遅いと報告します。この場合、一般的な問題なのか、そのサブグラフやクエリに固有の問題なのか、遅さの理由を診断することが課題となります。そしてもちろん、可能であればそれを解決することです。
また、クエリノードでメモリ使用量が多いことが引き金になる場合もあり、その場合は、まず問題の原因となっているクエリを特定することが課題となります。
Indexers can use qlog to process and summarize Graph Node’s query logs. GRAPH_LOG_QUERY_TIMING
can also be enabled to help identify and debug slow queries.
クエリが遅い場合、インデクサーにはいくつかのオプションがあります。もちろん、コスト モデルを変更して、問題のあるクエリを送信するコストを大幅に増やすことができます。これにより、そのクエリの頻度が減少する可能性があります。ただし、これでは問題の根本原因が解決しないことがよくあります。
アカウントライクな最適化
エンティティを格納するデータベーステーブルには、一般に2つの種類があるようです。エンティティは一度作成されると更新されない「トランザクションライク」なもの、 つまり金融取引のリストのようなものを格納するものと、エンティティが頻繁に更新される「アカウント ライク」なもの、つまり取引が記録されるたびに変更される金融口座のようなものを格納するものである。口座のようなテーブルの特徴は、多くのバージョンの実体を含むが、異なる実体は 比較的少ないということである。このようなテーブルでは、別個のエンティティの数は行(エンティティバージョン)の総数の1%であることがよくある。
For account-like tables, graph-node
can generate queries that take advantage of details of how Postgres ends up storing data with such a high rate of change, namely that all of the versions for recent blocks are in a small subsection of the overall storage for such a table.
The command graphman stats show <sgdNNNN
> shows, for each entity type/table in a deployment, how many distinct entities, and how many entity versions each table contains. That data is based on Postgres-internal estimates, and is therefore necessarily imprecise, and can be off by an order of magnitude. A -1
in the entities
column means that Postgres believes that all rows contain a distinct entity.
In general, tables where the number of distinct entities are less than 1% of the total number of rows/entity versions are good candidates for the account-like optimization. When the output of graphman stats show
indicates that a table might benefit from this optimization, running graphman stats show <sgdNNN> <table>
will perform a full count of the table - that can be slow, but gives a precise measure of the ratio of distinct entities to overall entity versions.
Once a table has been determined to be account-like, running graphman stats account-like <sgdNNN>.<table>
will turn on the account-like optimization for queries against that table. The optimization can be turned off again with graphman stats account-like --clear <sgdNNN>.<table>
It takes up to 5 minutes for query nodes to notice that the optimization has been turned on or off. After turning the optimization on, it is necessary to verify that the change does not in fact make queries slower for that table. If you have configured Grafana to monitor Postgres, slow queries would show up in pg_stat_activity
in large numbers, taking several seconds. In that case, the optimization needs to be turned off again.
For Uniswap-like subgraphs, the pair
and token
tables are prime candidates for this optimization, and can have a dramatic effect on database load.
サブグラフの削除
これは新しい機能で、Graph Node 0.29.xで利用可能になる予定です。
At some point an indexer might want to remove a given subgraph. This can be easily done via graphman drop
, which deletes a deployment and all it’s indexed data. The deployment can be specified as either a subgraph name, an IPFS hash Qm..
, or the database namespace sgdNNN
. Further documentation is available here.