运营Graph节点
Reading time: 26 min
Graph节点是索引子图的组件,并使生成的数据可通过GraphQL API进行查询。因此,它是索引人堆栈的中心,Graph节点的正确运作对于运行成功的索引人至关重要。
这提供了Graph节点的背景概述,以及索引人可用的一些更高级的选项。可以在中找到详细的文档和说明。
是Graph Network上索引子图、连接到区块链客户端、索引子图并使索引数据可供查询的参考实现。
Graph节点(以及整个索引人堆栈)可以在裸机上运行,也可以在云环境中运行。中央索引组件的这种灵活性对于图形协议的有力性至关重要。类似地,Graph 节点可以从,或者索引人可以使用之一。
Graph节点的主存储区,这是存储子图数据、子图元数据以及子图不可知的网络数据(如区块缓存和eth_call缓存)的地方。
为了索引网络,Graph节点需要通过以太坊兼容的JSON-RPC访问网络客户端。此RPC可能连接到单个以太坊客户端,也可能是跨多个客户端进行负载平衡的更复杂的设置。
虽然有些子图可能只需要一个完整的节点,但有些子图的索引功能可能需要额外的RPC功能。特别是,将eth_calls
作为索引的一部分的子图需要一个支持的归档节点,而带有callHandlers
或带有调用
筛选器的blockHandlers
的子图则需要trace_filter
支持。
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 .
子图部署元数据存储在IPFS网络上。Graph节点主要在子图部署期间访问IPFS节点,以获取子图清单和所有链接文件。网络索引人不需要托管自己的IPFS节点。网络的IPFS节点托管于
为了实现监控和报告,Graph节点可以选择将指标记录到Prometheus指标服务器。
-
锈
-
PostgreSQL
-
IPFS
-
Ubuntu 用户的附加要求 - 要在 Ubuntu 上运行 Graph 节点,可能需要一些附加的软件包。
sudo apt-get install -y clang libpq-dev libssl-dev pkg-config
- 启动 PostgreSQL 数据库服务器
initdb -D .postgrespg_ctl -D .postgres -l logfile startcreatedb 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
当运行Graph Node时,会暴露以下端口:
端口 | 用途 | 路径 | CLI 参数 | 环境 变量 |
---|---|---|---|---|
8000 | GraphQL HTTP 服务 (用于子图查询) | /subgraphs/id/... /subgraphs/name/.../... | --http-port | - |
8001 | GraphQL WS (用于子图订阅) | /subgraphs/id/... /subgraphs/name/.../... | --ws-port | - |
8020 | JSON-RPC (用于管理部署) | / | --admin-port | - |
8030 | 子图索引状态 API | /graphql | --index-node-port | - |
8040 | Prometheus 指标 | /metrics | --metrics-port | - |
重要: 公开暴露端口时要小心 - 管理端口 应保持锁定。 这包括下面详述的 Graph 节点 JSON-RPC 和索引人管理端点。
最简单的是,Graph节点可以使用Graph节点的单个实例、单个PostgreSQL数据库、IPFS节点和要索引的子图所需的网络客户端来操作。
通过添加多个Graph节点和多个数据库以支持这些Graph节点,可以水平扩展此设置。高级用户可能希望通过config.toml
文件和Graph节点的环境变量,利用Graph节点的一些水平扩展功能以及一些更高级的配置选项。
配置文件可用于设置比CLI中公开的配置更复杂的配置。文件的位置通过--config命令行开关传递。
使用配置文件时,不能使用选项--postgres-url、--postgres-secondary-hosts和--postgres-host-weights。
可以提供最小的config.toml
文件;以下文件等效于使用--postgres-url命令行选项:
[store][store.primary]connection="<.. postgres-url argument ..>"[deployment][[deployment.rule]]indexers = [ "<.. list of all indexing nodes ..>" ]
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 , , and splitting subgraphs across nodes with .
请注意,可以将多个Graph节点配置为使用同一个数据库,该数据库本身可以通过分片进行水平扩展。
给定多个Graph节点,有必要管理新子图的部署,以便同一子图不会被两个不同的节点索引, 这会导致冲突。这可以通过使用部署规则来实现,如果正在使用数据库shard
,部署规则还可以指定子图的数据应该存储在哪个分片中。部署规则可以与子图名称和部署所索引的网络相匹配,以便做出决策。
部署规则配置示例:
[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"]
通过在配置文件中包含以下内容,可以将节点配置为显式查询节点:
[general]query = "<regular expression>"
任何--node-id与正则表达式匹配的节点都将被设置为只响应查询。
对于大多数用例,单个Postgres数据库足以支持graph节点实例。当一个graph节点实例超过一个Postgres数据库时,可以将graph节点的数据存储拆分到多个Postgres数据库中。所有数据库一起构成graph节点实例的存储。每个单独的数据库都称为分片。
分片可用于在多个数据库中拆分子图部署,也可用于使用副本在数据库之间分散查询负载。这包括配置每个graph-node
应在其连接池中为每个数据库保留的可用数据库连接,随着索引的子图越来越多,这一点变得越来越重要。
当您的现有数据库无法跟上Graph节点给它带来的负载时,以及当无法再增加数据库大小时,分片变得非常有用。
在开始使用分片之前,通常最好使单个数据库尽可能大。一个例外是查询流量在子图之间分配非常不均匀;在这些情况下,如果将高容量子图保存在一个分片中,而将其他所有内容都保存在另一个分片上,这会有很大的帮助,因为这种设置使高容量子图的数据更有可能保留在数据库内部缓存中,而不会被低容量子图中不需要的数据所取代。
在配置连接方面,首先将 postgresql.conf 中的 max_connections 设置为400(或甚至200),然后查看 store_connection_wait_time_ms 和 store_connecion_checkout_count Prometheus 度量。明显的等待时间(任何超过5ms的时间)表明可用连接太少;高等待时间也将由数据库非常繁忙(如高CPU负载)引起。然而,如果数据库在其他方面看起来很稳定,那么高等待时间表明需要增加连接数量。在配置中,每个graph节点实例可以使用的连接数是一个上限,如果不需要,Graph节点将不会保持连接打开。
如果配置了多个节点,则需要指定一个负责接收新区块的节点,这样所有配置的索引节点都不会轮询链头。这是作为chains
命名空间的一部分完成的,指定用于区块摄取的node_id
:
[chains]ingestor = "block_ingestor_node"
Graph协议正在增加支持索引奖励的网络数量,并且存在许多索引不支持的网络的子图,索引人希望处理这些子图。config.toml
文件允许表达和灵活配置:
- 多个网络。
- 每个网络有多个提供程序(这可以允许跨提供程序分配负载,也可以允许配置完整节点和归档节点,如果给定的工作负载允许,Graph Node更喜欢便宜些的提供程序)。
- 其他提供商详细信息,如特征、身份验证和提供程序类型(用于实验性Firehose支持)。
[chains]
部分控制graph节点连接到的以太坊提供程序,以及每个链的区块和其他元数据的存储位置。以下示例配置了两个链,mainnet和kovan,其中mainnet的区块存储在vip分片中,而kovan的区块则存储在主分片中。主网链可以使用两个不同的提供商,而kovan只有一个提供商。
[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 = [] } ]
Graph节点支持一系列环境变量,这些变量可以启用特征或更改Graph节点的行为。这些都记录在。
使用高级配置操作缩放索引设置的用户可以从使用Kubernetes管理Graph节点中受益。
- 索引人存储库有一个示例
- 是一个工具包,用于在GraphOps维护的Kubernetes上运行Graph Protocol Indexer。它提供了一组Helm图表和一个CLI来管理Graph Node部署。
给定一个正在运行的 Graph 节点(或多個 Graph 节点!),接下来的挑战是如何跨这些节点管理部署的子图。Graph 节点覆盖了一系列工具,以帮助管理子图。
Graph节点的日志可以为Graph节点和特定子图的调试和优化提供有用的信息。Graph节点通过GRAPH_LOG
环境变量支持不同的日志级别,具有以下级别:错误、警告、信息、调试或跟踪。
此外,将GRAPH_LOG_QUERY_TIMING
设置为gql
提供了有关GraphQL查询如何运行的更多详细信息(尽管这将生成大量日志)。
默认情况下,Graph Node通过8040端口上的Prometheus端点提供指标。然后可以使用Grafana来可视化这些指标。
graphman
是Graph节点的维护工具,帮助诊断和解决不同的日常和异常任务。
Graphman命令包含在官方容器中,您可以将docker exec插入到 Graph 节点容器中运行它。它需要一个config.toml
文件。
Graph节点存储库中提供了graphman
命令的完整文档。参见[/docs/graphman.md] (
默认情况下,在端口8030/graphql上可用,索引状态API公开了一系列方法,用于检查不同子图的索引状态、检查索引证明、检查子图特征等。
索引过程有三个独立的部分:
- 正在从提供程序获取感兴趣的事件
- 使用适当的处理程序按顺序处理事件(这可能涉及调用状态链,并从存储中获取数据)
- 将生成的数据写入存储
这些阶段是流水线的(即可以并行执行),但它们彼此依赖。如果子图索引速度慢,则根本原因将取决于特定的子图。
索引速度慢的常见原因:
- 从链中查找相关事件所需的时间(特别是调用处理程序可能慢,因为依赖
trace_filter
) - 将大量
eth_calls
作为处理程序的一部分 - 执行期间大量的存储交互
- 要保存到存储的大量数据
- 要处理的大量事件
- 拥挤节点的数据库连接时间慢
- 提供商本身落后于链头
- 在链头从提供商获取新收据的速度较慢
子图索引度量可以帮助诊断索引速度慢的根本原因。在某些情况下,问题在于子图本身,但在其他情况下,改进的网络提供商、减少的数据库冲突和其他配置改进可以显著提高索引性能。
在为子图编制索引期间,如果遇到意外数据、某些组件未按预期工作,或者事件处理程序或配置中存在错误,则子图可能会失败。有两种常见的故障类型:
- 确定性故障:这些故障不会通过重试解决
- 非确定性故障:这些故障可能是由于提供程序的问题,或者是一些意外的Graph节点错误。当发生非确定性故障时,Graph节点将重试失败的处理程序,并随着时间的推移而后退。
在某些情况下,索引人可能会解决故障(例如,如果错误是由于没有正确类型的提供程序导致的,则添加所需的提供程序将允许继续索引)。然而,在其他情况下,需要更改子图代码。
确定性故障被视为“最终”,并为故障区块生成索引证明,而非确定性故障则不是,因为子图可能会“可靠”并继续索引。在某些情况下,非确定性标签是不正确的,子图永远无法克服错误;此类故障应报告为Graph节点存储库中的问题。
Graph节点在存储中缓存某些数据,以保存来自提供程序的重新绘制。区块被缓存,eth_calls
的结果也被缓存(后者作为特定区块被缓存)。这种缓存可以在稍微改变的子图的“重新同步”期间显著提高索引速度。
然而,在某些情况下,如果以太坊节点在一段时间内提供了错误的数据,这可能会进入缓存,导致错误的数据或失败子图。在这种情况下,索引人可以使用graphman
清除不良的缓存,倒回受影响的子图,然后从(希望)健康提供程序获取新数据。
如果怀疑区块缓存不一致,例如tx收据丢失事件:
graphman链列表
以查找链名称。graphman chain check-blocks <CHAIN> by-number <NUMBER>
将检查缓存的块是否与提供程序匹配,如果不匹配,则从缓存中删除该块。- 如果存在差异,则使用
graphman chain truncate <CHAIN>
截断整个缓存可能更安全。 - 如果区块与提供程序匹配,则可以直接针对提供程序调试问题。
一旦子图被索引,索引人就可以期望通过子图的专用查询端点来服务查询。如果索引人希望为大量查询量提供服务,建议使用专用查询节点,如果查询量非常大,索引人可能需要配置副本分片,以便查询不会影响索引过程。
然而,即使使用专用的查询节点和副本,某些查询也可能需要很长时间才能执行,在某些情况下还会增加内存使用量,并对其他用户的查询时间产生负面影响。
没有一个"万灵丹",而是一系列用于预防、诊断和处理慢速查询的工具。
默认情况下,Graph 节点缓存GraphQL查询,这可以显著减少数据库负载。这可以进一步使用GRAPH_QUERY_CACHE_BLOCKS
和GRAPH_QUERY_CACHE-MAX_MEM
设置进行配置-请在阅读更多信息。
有问题的查询通常以两种方式之一出现。在某些情况下,用户自己报告给定的查询很慢。在这种情况下,挑战是诊断缓慢的原因——无论是一般问题,还是特定于子图或查询。如果可能的话,当然要解决它。
在其他情况下,触发因素可能是查询节点上的高内存使用率,在这种情况下,首要挑战是要确定导致问题的查询。
索引器可以使用来处理和汇总Graph Node的查询日志。 GRAPH_LOG_QUERY_TIMING
也可以启用以帮助识别和调试慢速查询
针对慢查询,索引器有几个选项。当然,他们可以改变成本模型,显著增加发送有问题查询的成本。这可能导致该查询的频率降低。然而,这通常并不能解决问题的根本原因。
存储实体的数据库表通常有两种类型:“类交易”,即实体一旦创建,就永远不会更新,即存储类似于金融交易列表的内容;“类账户”,即经常更新实体,即存储每次记录交易时都会修改的类似金融账户的内容。类账户表的特点是,它们包含大量实体版本,但不同的实体相对较少。通常,在这种表中,不同实体的数量是行总数的1%(实体版本)。
对于类似账户的表,graph-node
可以生成查询,利用Postgres如何以如此高的变化率存储数据的细节,即最近区块的所有版本都位于此类表的总存储的一小部分中。
命令graphman stats show <sgdNNNN
> 显示部署中每个实体类型/表的不同实体数量以及每个表包含的实体版本。该数据基于Postgres的内部估计,因此必然是不精确的,可能会偏离一个数量级。entity
列中的-1
表示Postgres认为所有行都包含一个不同的实体。
通常,不同实体的数量小于行/实体版本总数的1%的表是类似账户的优化的好候选表。当graphman stats show
的输出表明表可能从该优化中受益时,运行graphman stats show <sgdNNN> <table>
将执行表的完整计数-这可能会很慢,但可以精确测量不同实体与整体实体版本的比率。
一旦一个表被确定为类似账户,运行graphman stats account-like <sgdNNN> <table>
将为针对该表的查询启用类似账户的优化。可以使用graphman stats account-like --clear <sgdNNN><table>)
再次关闭优化查询节点,最多需要5分钟才能注意到优化已打开或关闭。打开优化后,需要验证更改实际上不会使该表的查询变慢。如果您已经将Grafana配置为监视Postgres,那么在pg_stat_activity
中会出现大量缓慢的查询,需要几秒钟。在这种情况下,需要再次关闭优化。
对于类似Uniswap的子图,pair
和 token
表是这种优化的主要候选项,并且可以对数据库负载产生显著影响。
这是一项新功能,将在Graph Node 0.29.x中提供。
在某个时刻,索引人可能想要删除给定的子图。这可以通过删除部署及其所有索引数据的graphman drop
, 轻松完成。部署可以被指定为子图名称、IPFS has、Qm..
,或数据库命名空间sgdNNN
。提供了更多文档。