16 minutes
Uzel Graf
Graf Uzel je komponenta, která indexuje podgrafy a zpřístupňuje výsledná data k dotazování prostřednictvím rozhraní GraphQL API. Jako taková je ústředním prvkem zásobníku indexeru a její správná činnost je pro úspěšný provoz indexeru klíčová.
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.
Uzel Graf
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.
Databáze PostgreSQL
Hlavní úložiště pro uzel Graf Uzel, kde jsou uložena data podgrafů, metadata o podgraf a síťová data týkající se podgrafů, jako je bloková cache a cache eth_call.
Síťoví klienti
Aby mohl uzel Graph Node indexovat síť, potřebuje přístup k síťovému klientovi prostřednictvím rozhraní API JSON-RPC kompatibilního s EVM. Toto RPC se může připojit k jedinému klientovi nebo může jít o složitější nastavení, které vyrovnává zátěž mezi více klienty.
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 uzly
Metadata nasazení podgrafů jsou uložena v síti IPFS. Uzel Graf přistupuje během nasazení podgrafu především k uzlu IPFS, aby načetl manifest podgrafu a všechny propojené soubory. Síťové indexery nemusí hostit vlastní uzel IPFS. Uzel IPFS pro síť je hostován na adrese https://ipfs.network.thegraph.com.
Metrický server Prometheus
Aby bylo možné monitorovat a podávat zprávy, může uzel Graf volitelně zaznamenávat metriky na metrický server 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
Začínáme s Kubernetes
A complete Kubernetes example configuration can be found in the indexer repository.
Ports
Když je Graf Uzel spuštěn, zpřístupňuje následující ports:
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.
Pokročilá konfigurace uzlu Graf
V nejjednodušším případě lze Graf Uzel provozovat s jednou instancí Graf Uzel, jednou databází PostgreSQL, uzlem IPFS a síťovými klienty podle potřeby indexovaných podgrafů.
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.
Při použití konfiguračního souboru není možné použít volby —postgres-url, —postgres-secondary-hosts a —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.
Více uzlů graf
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.
Všimněte si, že více graf uzlů lze nakonfigurovat tak, aby používaly stejnou databázi, kterou lze horizontálně škálovat pomocí sharding.
Pravidla nasazení
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.
Příklad konfigurace pravidla nasazení:
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.
Vyhrazené dotazovací uzly
Uzly lze nakonfigurovat tak, aby byly explicitně dotazovacími uzly, a to tak, že do konfiguračního souboru vložíte následující údaje:
1[general]2query = "<regular expression>"
Každý uzel, jehož —node-id odpovídá regulárnímu výrazu, bude nastaven tak, aby odpovídal pouze na dotazy.
Škálování databáze pomocí sharding
Pro většinu případů použití postačuje k podpoře instance graf uzlu jedna databáze Postgres. Pokud instance graf uzlu přeroste rámec jedné databáze Postgres, je možné rozdělit ukládání dat grafového uzlu do více databází Postgres. Všechny databáze dohromady tvoří úložiště instance graf uzlu. Každá jednotlivá databáze se nazývá 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.
Sharding se stává užitečným, když vaše stávající databáze nedokáže udržet krok se zátěží, kterou na ni Graf Uzel vyvíjí, a když už není možné zvětšit velikost databáze.
Obecně je lepší vytvořit jednu co největší databázi, než začít s oddíly. Jednou z výjimek jsou případy, kdy je provoz dotazů rozdělen velmi nerovnoměrně mezi dílčí podgrafy; v těchto situacích může výrazně pomoci, pokud jsou dílčí podgrafy s velkým objemem uchovávány v jednom shardu a vše ostatní v jiném, protože toto nastavení zvyšuje pravděpodobnost, že data pro dílčí podgrafu s velkým objemem zůstanou v interní cache db a nebudou nahrazena daty, která nejsou tolik potřebná z dílčích podgrafů s malým objemem.
Pokud jde o konfiguraci připojení, začněte s max_connections v souboru postgresql.conf nastaveným na 400 (nebo možná dokonce 200) a podívejte se na metriky store_connection_wait_time_ms a store_connection_checkout_count Prometheus. Výrazné čekací doby (cokoli nad 5 ms) jsou známkou toho, že je k dispozici příliš málo připojení; vysoké čekací doby tam budou také způsobeny tím, že databáze je velmi vytížená (například vysoké zatížení procesoru). Pokud se však databáze jinak jeví jako stabilní, vysoké čekací doby naznačují potřebu zvýšit počet připojení. V konfiguraci je horní hranicí, kolik připojení může každá instance graf uzlu používat, a graf uzel nebude udržovat otevřená připojení, pokud je nepotřebuje.
Read more about store configuration here.
Vyhrazené zpracování bloků
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"
Podpora více sítí
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:
- Více sítí
- Více poskytovatelů na síť (to může umožnit rozdělení zátěže mezi poskytovatele a také konfiguraci plných uzlů i archivních uzlů, přičemž Graph Node může preferovat levnější poskytovatele, pokud to daná pracovní zátěž umožňuje).
- Další údaje o poskytovateli, jako jsou funkce, ověřování a typ poskytovatele (pro experimentální podporu 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.
Proměnná prostředí
Graph Node supports a range of environment variables which can enable features, or change Graph Node behaviour. These are documented here.
Průběžné nasazování
Uživatelé, kteří provozují škálované nastavení indexování s pokročilou konfigurací, mohou využít správu svých graf uzlů pomocí 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.
Správa uzlu graf
Vzhledem k běžícímu uzlu Graf (nebo uzlům Graf Uzel!) je pak úkolem spravovat rozmístěné podgrafy v těchto uzlech. Graf Uzel nabízí řadu nástrojů, které pomáhají se správou podgrafů.
Protokolování
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
Graf Uzel poskytuje metriky prostřednictvím koncového bodu Prometheus na portu 8040 ve výchozím nastavení. K vizualizaci těchto metrik lze pak použít nástroj 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
Práce s podgrafy
Stav indexování API
API pro stav indexování, které je ve výchozím nastavení dostupné na portu 8030/graphql, nabízí řadu metod pro kontrolu stavu indexování pro různé podgrafy, kontrolu důkazů indexování, kontrolu vlastností podgrafů a další.
The full schema is available here.
Výkonnost indexování
Proces indexování má tři samostatné části:
- Získávání zajímavých událostí od zprostředkovatele
- Zpracování událostí v pořadí pomocí příslušných obslužných (to může zahrnovat volání řetězce pro zjištění stavu a načtení dat z úložiště)
- Zápis výsledných dat do úložiště
Tyto fáze jsou spojeny do potrubí (tj. mohou být prováděny paralelně), ale jsou na sobě závislé. Pokud se podgrafy indexují pomalu, bude příčina záviset na konkrétním podgrafu.
Běžné příčiny pomalého indexování:
- 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 - Velké množství interakcí s úložištěm během provádění
- Velké množství dat k uložení do úložiště
- Velký počet událostí ke zpracování
- Pomalá doba připojení k databázi u přeplněných uzlů
- Samotný poskytovatel se dostává za hlavu řetězu
- Pomalé načítání nových účtenek od poskytovatele v hlavě řetězce
Metriky indexování podgrafů mohou pomoci diagnostikovat hlavní příčinu pomalého indexování. V některých případech spočívá problém v samotném podgrafu, ale v jiných případech mohou zlepšení síťových poskytovatelů, snížení konfliktů v databázi a další zlepšení konfigurace výrazně zlepšit výkon indexování.
Neúspěšné podgrafy
Během indexování mohou dílčí graf selhat, pokud narazí na neočekávaná data, pokud některá komponenta nefunguje podle očekávání nebo pokud je chyba ve zpracovatelích událostí nebo v konfiguraci. Existují dva obecné typy selhání:
- Deterministická selhání: jedná se o selhání, která nebudou vyřešena opakovanými pokusy
- Nedeterministická selhání: mohou být způsobena problémy se zprostředkovatelem nebo neočekávanou chybou grafického uzlu. Pokud dojde k nedeterministickému selhání, uzel Graf zopakuje selhání obsluhy a postupně se vrátí zpět.
V některých případech může být chyba řešitelná indexátorem (například pokud je chyba důsledkem toho, že není k dispozici správný typ zprostředkovatele, přidání požadovaného zprostředkovatele umožní pokračovat v indexování). V jiných případech je však nutná změna v kódu podgrafu.
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.
Bloková a volací mezipaměť
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.
Pokud existuje podezření na nekonzistenci blokové mezipaměti, například chybějící událost tx receipt:
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>
. - Pokud se blok shoduje s poskytovatelem, lze problém ladit přímo proti poskytovateli.
- If there is a difference, it may be safer to truncate the whole cache with
Problémy a chyby při dotazování
Jakmile je podgraf indexován, lze očekávat, že indexery budou obsluhovat dotazy prostřednictvím koncového bodu vyhrazeného pro dotazy podgrafu. Pokud indexátor doufá, že bude obsluhovat značný objem dotazů, doporučuje se použít vyhrazený uzel pro dotazy a v případě velmi vysokého objemu dotazů mohou indexátory chtít nakonfigurovat oddíly replik tak, aby dotazy neovlivňovaly proces indexování.
I s vyhrazeným dotazovacím uzlem a replikami však může provádění některých dotazů trvat dlouho a v některých případech může zvýšit využití paměti a negativně ovlivnit dobu dotazování ostatních uživatelů.
Neexistuje jedna “stříbrná kulka”, ale celá řada nástrojů pro prevenci, diagnostiku a řešení pomalých dotazů.
Ukládání dotazů do mezipaměti
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.
Analýza dotazů
Problematické dotazy se nejčastěji objevují jedním ze dvou způsobů. V některých případech uživatelé sami hlásí, že daný dotaz je pomalý. V takovém případě je úkolem diagnostikovat příčinu pomalosti - zda se jedná o obecný problém, nebo o specifický problém daného podgrafu či dotazu. A pak ho samozřejmě vyřešit, pokud je to možné.
V jiných případech může být spouštěcím faktorem vysoké využití paměti v uzlu dotazu a v takovém případě je třeba nejprve identifikovat dotaz, který problém způsobuje.
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.
Při pomalém dotazu mají indexátory několik možností. Samozřejmě mohou změnit svůj nákladový model a výrazně zvýšit náklady na odeslání problematického dotazu. To může vést ke snížení četnosti tohoto dotazu. To však často neřeší hlavní příčinu problému.
Optimalizace podobná účtu
Zdá se, že databázové tabulky, které uchovávají entity, se obecně vyskytují ve dvou variantách: Jsou to tabulky “transakční”, kde entity, jakmile jsou jednou vytvořeny, nejsou nikdy aktualizovány, tj. ukládají něco podobného seznamu finančních transakcí, a “účetní”, kde jsou entity aktualizovány velmi často, tj. ukládají něco podobného finančním účtům, které se mění při každé zaznamenané transakci. Tabulky podobné účtům se vyznačují tím, že obsahují velké množství verzí entit, ale relativně málo odlišných entit. Často je v takových tabulkách počet odlišných entit 1 % z celkového počtu řádků (verzí entit)
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.
Odstranění podgrafů
Jedná se o novou funkci, která bude k dispozici v uzlu Graf 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.