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