Ports and paths
One process serves multiple chains at the same time; chains are distinguished by the
chainId in the path. Hexadecimal IDs are normalized to decimal strings.
Request lifecycle
Pre-processing runs in a fixed order:Node selection
First decide the node pool by block context, then pick a specific node within the pool by strategy.
The chain head height comes from
{chainId}/lastBlockNumber in etcd, maintained by consistency-checker. When the chain height is unknown, it conservatively selects an Archive node.
The two pools fall back to each other: when the State pool is empty, the Archive pool is used, and vice versa. Within each pool, Available nodes are used first.
Load balancing strategies
- random (default)
- round_robin
Selects by weighted probability. Non-batch requests first filter candidate nodes by method routing rules, then select by weight. Nodes without an explicit weight default to
100.Automatic retries
Service discovery
Watches an etcd prefix (etcd_prefix is configurable); the following key suffixes are interpreted as runtime data:
The proxy watches
PUT / DELETE events to add and remove nodes and update configuration in real time, with no restart needed.
Health check
A node that newly appears in etcd does not join the node pool immediately:1
Probe
Send an RPC call to the node to verify reachability. State / Archive nodes use
getLatestBlock, Native nodes use eth_blockNumber.2
Retry
On failure, retry every 5 seconds until
node_health_check_max_wait (default 300 seconds).3
Join
Only after passing the check does the node enter the load balancing pool.
Version routing
When a request uses the base chain ID with no explicit version suffix, the proxy reads{chainId}/version from etcd and rewrites the request to the {chainId}-{version} node pool. This makes version switching transparent to clients.
Traffic governance
Usage reporting
Onceusage is configured, RPC time is aggregated locally by the client-id request header and written to Kafka when 10000 aggregation keys or report_interval (default 5s) is reached.
usageis the aggregated time in milliseconds, with a minimum of 1.- A missing
client-idis recorded asunknown. - Sending is best-effort: the last batch is sent on graceful shutdown; loss is acceptable when the process crashes or Kafka fails.
- The current number of aggregation keys is reflected by
jrpcx_usage_aggregation_keys.
Admin API
debug_chooseOneNode is useful when troubleshooting routing problems: it returns the node that would be selected under the current request conditions, without actually forwarding.
Metrics
Exposed at:8664/metrics, with common labels host, target, chain_id, chain_version.
Some metrics carry extra labels:
Running
Development
Related documents
docs/architecture_cn.md(Chinese) — Component boundaries and runtime architecturedocs/deployment_cn.md(Chinese) — Docker Compose, Kubernetes, systemd, and production tuning