16 minutes
Graf Node
Graf Node är komponenten som indexerar subgraffar och gör den resulterande datan tillgänglig för förfrågan via en GraphQL API. Som sådan är den central för indexeringsstacken, och korrekt drift av Graph Node är avgörande för att driva en framgångsrik indexerare.
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.
Graf Node
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-databas
Huvudlagret för Graph Node, här lagras subgrafdata, liksom metadata om subgraffar och nätverksdata som är oberoende av subgraffar, som blockcache och eth_call-cache.
Nätverkskunder
För att indexera ett nätverk behöver Graf Node åtkomst till en nätverksklient via ett EVM-kompatibelt JSON-RPC API. Denna RPC kan ansluta till en enda klient eller så kan det vara en mer komplex konfiguration som lastbalanserar över flera.
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-noder
Metadata för distribution av subgraffar lagras på IPFS-nätverket. Graf Node har främst åtkomst till IPFS-noden under distributionen av subgraffar för att hämta subgrafens manifest och alla länkade filer. Nätverksindexerare behöver inte värd sin egen IPFS-nod. En IPFS-nod för nätverket är värd på https://ipfs.network.thegraph.com.
Prometheus server för mätvärden
För att möjliggöra övervakning och rapportering kan Graf Node valfritt logga metrik till en Prometheus-metrisk server.
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.
sudo apt-get install -y clang libpq-dev libssl-dev pkg-config
Setup
- Start a PostgreSQL database server
initdb -D .postgrespg_ctl -D .postgres -l logfile startcreatedb 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:
cargo run -p graph-node --release -- \ --postgres-url postgresql://[USERNAME]:[PASSWORD]@localhost:5432/graph-node \ --ethereum-rpc [NETWORK_NAME]:[URL] \ --ipfs https://ipfs.network.thegraph.com
Komma igång med Kubernetes
A complete Kubernetes example configuration can be found in the indexer repository.
Portar
När Graph Node är igång exponerar den följande portar:
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.
Avancerad konfiguration av Graf Node
På sitt enklaste sätt kan Graph Node användas med en enda instans av Graph Node, en enda PostgreSQL-databas, en IPFS-nod och nätverksklienter som krävs av de subgrafer som ska indexeras.
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.
När du använder en konfigurationsfil är det inte möjligt att använda alternativen —postgres-url, —postgres-secondary-hosts och —postgres-host-weights.
A minimal config.toml
file can be provided; the following file is equivalent to using the —postgres-url command line option:
[store][store.primary]connection="<.. postgres-url argument ..>"[deployment][[deployment.rule]]indexers = [ "<.. list of all indexing nodes ..>" ]
Full documentation of config.toml
can be found in the Graph Node docs.
Flera Grafnoder
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.
Observera att flera Graph Nodes alla kan konfigureras att använda samma databas, som i sig kan skalas horisontellt via sharding.
Regler för utplacering
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.
Exempel på konfiguration av deployeringsregler:
[deployment][[deployment.rule]]match = { name = "(vip|important)/.*" }shard = "vip"indexers = [ "index_node_vip_0", "index_node_vip_1" ][[deployment.rule]]match = { network = "kovan" }# No shard, so we use the default shard called 'primary'indexers = [ "index_node_kovan_0" ][[deployment.rule]]match = { network = [ "xdai", "poa-core" ] }indexers = [ "index_node_other_0" ][[deployment.rule]]# There's no 'match', so any subgraph matchesshards = [ "sharda", "shardb" ]indexers = [ "index_node_community_0", "index_node_community_1", "index_node_community_2", "index_node_community_3", "index_node_community_4", "index_node_community_5" ]
Read more about deployment rules here.
Dedikerade frågenoder
Noder kan konfigureras för att uttryckligen vara frågenoder genom att inkludera följande i konfigurationsfilen:
[general]query = "<regular expression>"
Alla noder vars —node-id matchar reguljärt uttryck kommer att konfigureras för att endast svara på förfrågningar.
Skalning av databas via sharding
För de flesta användningsfall är en enda Postgres-databas tillräcklig för att stödja en graph-node-instans. När en graph-node-instans växer utöver en enda Postgres-databas är det möjligt att dela upp lagringen av graph-node-data över flera Postgres-databaser. Alla databaser tillsammans bildar lagringsutrymmet för graph-node-instansen. Varje individuell databas kallas en 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 blir användbart när din befintliga databas inte kan hålla jämna steg med belastningen som Graph Node sätter på den och när det inte längre är möjligt att öka databasens storlek.
Det är generellt sett bättre att göra en enda databas så stor som möjligt innan man börjar med shards. Ett undantag är när frågetrafiken är mycket ojämnt fördelad mellan subgrafer; i dessa situationer kan det hjälpa dramatiskt om högvolymsubgraferna hålls i en shard och allt annat i en annan, eftersom den konfigurationen gör det mer troligt att data för högvolymsubgraferna stannar i databasens interna cache och inte ersätts av data som inte behövs lika mycket från lågvolymsubgrafer.
När det gäller att konfigurera anslutningar, börja med max_connections i postgresql.conf som är inställt på 400 (eller kanske till och med 200) och titta på Prometheus-metrarna store_connection_wait_time_ms och store_connection_checkout_count. Märkbara väntetider (något över 5 ms) är en indikation på att det finns för få anslutningar tillgängliga; höga väntetider beror också på att databasen är mycket upptagen (som hög CPU-belastning). Om databasen verkar annars stabil, indikerar höga väntetider att antalet anslutningar behöver ökas. I konfigurationen är det en övre gräns för hur många anslutningar varje graph-node-instans kan använda, och Graph Node kommer inte att hålla anslutningar öppna om det inte behöver dem.
Read more about store configuration here.
Intag av dedikerade block
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:
[chains]ingestor = "block_ingestor_node"
Stöd för flera nätverk
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:
- Flera nätverk
- Flera leverantörer per nätverk (detta kan göra det möjligt att dela upp belastningen mellan leverantörer, och kan också möjliggöra konfiguration av fullständiga noder samt arkivnoder, där Graph Node föredrar billigare leverantörer om en viss arbetsbelastning tillåter det).
- Ytterligare information om leverantören, t. ex. funktioner, autentisering och typ av leverantör (för stöd för experimentell 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.
[chains]ingestor = "block_ingestor_node"[chains.mainnet]shard = "vip"provider = [ { label = "mainnet1", url = "http://..", features = [], headers = { Authorization = "Bearer foo" } }, { label = "mainnet2", url = "http://..", features = [ "archive", "traces" ] }][chains.kovan]shard = "primary"provider = [ { label = "kovan", url = "http://..", features = [] } ]
Read more about provider configuration here.
Miljö variabler
Graph Node supports a range of environment variables which can enable features, or change Graph Node behaviour. These are documented here.
Kontinuerlig driftsättning
Användare som driver en skalad indexering med avancerad konfiguration kan dra nytta av att hantera sina Graph Nodes med 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.
Hantera Graf Noder
Med en körande Graph Node (eller Graph Nodes!) är utmaningen sedan att hantera distribuerade subgrafer över dessa noder. Graph Node erbjuder en rad verktyg för att hjälpa till med hanteringen av subgrafer.
Loggning
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
Graph Node tillhandahåller metrikerna via Prometheus-endpunkt på port 8040 som standard. Grafana kan sedan användas för att visualisera dessa metriker.
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
Arbeta med undergrafer
Indexerings status API
Tillgänglig som standard på port 8030/graphql, exponerar indexeringstatus-API: en en rad metoder för att kontrollera indexeringstatus för olika subgrafer, kontrollera bevis för indexering, inspektera subgrafegenskaper och mer.
The full schema is available here.
Prestanda för indexering
Det finns tre separata delar av indexeringsprocessen:
- Hämta intressanta händelser från leverantören
- Bearbeta händelser i rätt ordning med lämpliga hanterare (detta kan innebära att kedjan anropas för status och att data hämtas från lagret)
- Skriva de resulterande data till butiken
Dessa stadier är pipelinerade (det vill säga de kan utföras parallellt), men de är beroende av varandra. När subgrafer är långsamma att indexera beror orsaken på den specifika subgrafgen.
Vanliga orsaker till indexeringslångsamhet:
- 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 - En stor mängd butiksinteraktion under exekvering
- En stor mängd data att spara i butiken
- Ett stort antal evenemang att bearbeta
- Långsam databasanslutningstid, för överbelastade noder
- Leverantören själv faller bakom kedjehuvudet
- Långsamhet vid hämtning av nya kvitton från leverantören vid kedjehuvudet
Subgrafindexeringsmetriker kan hjälpa till att diagnostisera grunden till indexeringens långsamhet. I vissa fall ligger problemet med subgrafgenen själv, men i andra fall kan förbättrade nätverksleverantörer, minskad databaskonflikt och andra konfigurationsförbättringar markant förbättra indexeringens prestanda.
Undergrafer som misslyckats
Under indexering kan subgrafer misslyckas om de stöter på data som är oväntad, om någon komponent inte fungerar som förväntat eller om det finns något fel i händelsehanterare eller konfiguration. Det finns två allmänna typer av misslyckande:
- Deterministiska fel: detta är fel som inte kommer att lösas med retries
- Icke-deterministiska fel: dessa kan bero på problem med leverantören eller något oväntat Graph Node-fel. När ett icke-deterministiskt fel inträffar kommer Graph Node att försöka igen med de felande hanterarna och backa över tid.
I vissa fall kan ett misslyckande vara lösbart av indexören (till exempel om felet beror på att det inte finns rätt typ av leverantör, kommer att tillåta indexering att fortsätta om den nödvändiga leverantören läggs till). Men i andra fall krävs en ändring i subgrafkoden.
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.
Blockera och anropa cache
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.
Om en blockcache-inkonsekvens misstänks, som att en tx-kvitto saknar händelse:
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>
. - Om blocket matchar leverantören kan problemet felsökas direkt mot leverantören.
- If there is a difference, it may be safer to truncate the whole cache with
Fråga frågor och fel
När en subgraf har indexeras kan indexörer förvänta sig att servera frågor via subgrafens dedikerade frågendpunkt. Om indexören hoppas på att betjäna en betydande mängd frågor rekommenderas en dedikerad frågenod, och vid mycket höga frågevolymer kan indexörer vilja konfigurera replikskivor så att frågor inte påverkar indexeringsprocessen.
Men även med en dedikerad frågenod och repliker kan vissa frågor ta lång tid att utföra, och i vissa fall öka minnesanvändningen och negativt påverka frågetiden för andra användare.
Det finns inte en “silverkula”, men en rad verktyg för att förebygga, diagnostisera och hantera långsamma frågor.
Fråge cachning
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.
Analyserar frågor
Problematiska frågor dyker oftast upp på ett av två sätt. I vissa fall rapporterar användare själva att en viss fråga är långsam. I det fallet är utmaningen att diagnostisera orsaken till långsamheten - om det är ett generellt problem eller specifikt för den subgraf eller fråga. Och naturligtvis att lösa det om det är möjligt.
I andra fall kan utlösaren vara hög minnesanvändning på en frågenod, i vilket fall utmaningen först är att identifiera frågan som orsakar problemet.
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.
Med en långsam fråga har indexörer några alternativ. Självklart kan de ändra sin kostnadsmodell för att kraftigt öka kostnaden för att skicka den problematiska frågan. Detta kan resultera i att frekvensen av den frågan minskar. Men det löser ofta inte grunden till problemet.
Kontoliknande optimering
Databastabeller som lagrar enheter verkar generellt komma i två varianter: ‘transaktionsliknande’, där enheter, när de väl är skapade, aldrig uppdateras, dvs. de lagrar något liknande en lista över finansiella transaktioner, och ‘konto-liknande’, där enheter uppdateras mycket ofta, dvs. de lagrar något som finansiella konton som ändras varje gång en transaktion registreras. Tabeller med konto-liknande tabeller karakteriseras av att de innehåller ett stort antal enhetsversioner, men relativt få distinkta enheter. Ofta är antalet distinkta enheter i sådana tabeller 1% av det totala antalet rader (enhetsversioner)
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.
Ta bort undergrafer
Detta är ny funktionalitet, som kommer att vara tillgänglig i Graf 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.