Skip to content

High sustained MDBX COW writes at mainnet tip (110-140 MiB/block) #23199

Description

@mbg033

System information

Erigon version:

erigon version 3.5.4-28bc52d6

The same behavior was also observed on Erigon 3.4.2.

OS & Version:

Guest: Ubuntu 24.04.4 LTS, Linux 6.8.0-137-generic, x86_64
Host:  Proxmox VE 9.2.0, Linux 7.0.14-6-pve, x86_64
VM:    8 vCPU, 40 GiB RAM
Disk:  WD_BLACK SN850X 4 TB NVMe
Host filesystem: ext4, noatime
Guest data mount: virtiofs

There is no btrfs, ZFS, or autodefrag layer in the data path. SMART reports no
media or data integrity errors. The node has very low JSON-RPC traffic during
the measurements.

Commit hash: 28bc52d6

Erigon command (addresses shortened; all other relevant flags are unchanged):

/usr/bin/erigon \
  --chain=mainnet \
  --datadir=/var/lib/eth/erigon \
  --authrpc.addr=127.0.0.1 \
  --authrpc.port=8551 \
  --authrpc.jwtsecret=/var/lib/eth/jwt/jwt.hex \
  --http \
  --http.addr=<private-ip> \
  --http.port=8545 \
  --http.api=eth,net,web3,erigon,trace,ots \
  --port=30303 \
  --torrent.port=42069 \
  --nat=stun \
  --caplin.nat=stun \
  --metrics \
  --metrics.addr=<private-ip> \
  --metrics.port=6060 \
  --sync.loop.block.limit=10000 \
  --batchSize=1g \
  --caplin.max-peer-count=64

Consensus Layer: embedded Caplin. I also reproduced the execution-layer write
rate with Caplin disabled (--externalcl) and Lighthouse BN 8.2.1 connected to
the Engine API.

Consensus Layer command for the external-CL control:

lighthouse bn \
  --network=mainnet \
  --datadir=/var/lib/eth/lighthouse \
  --execution-endpoint=http://127.0.0.1:8551 \
  --execution-jwt=/var/lib/eth/jwt/jwt.hex \
  --checkpoint-sync-url=https://mainnet.checkpoint.sigp.io

Chain/Network: Ethereum mainnet

Expected behaviour

I expected steady-state writes at chain tip to be substantially lower than
110-140 MiB of MDBX copy-on-write pages and 160-180 MiB of physical NVMe
writes per execution block, especially while the MDBX file and total database
size remain constant.

If this write volume is expected for Erigon 3 at mainnet tip, please confirm it
and consider documenting the expected steady-state write rate or write
amplification. At the observed rate, the host writes approximately
1.2-1.4 TB/day if the workload remains constant.

Actual behaviour

Erigon stays fully synced and healthy, but continuously writes approximately
13-15 MiB/s to the physical NVMe at chain tip. The write activity continues
without meaningful RPC load and stops when execution stops processing new
blocks.

The strongest 30-minute baseline on Erigon 3.5.4 processed 150 blocks with
zero head lag and zero restarts:

Metric Result
Physical NVMe writes 13.522 MiB/s
Physical NVMe writes per block 162.26 MiB/block
MDBX COW writes 9.166 MiB/s
MDBX COW writes per block 109.99 MiB/block
MDBX page splits 361.59/block
MDBX file size delta 0

The following controls were run on the same node and data directory:

Test Duration Blocks Physical NVMe MDBX COW Notes
--externalcl, no CL input 300s 0 0.369 MiB/s 0 Execution head intentionally static
Embedded Caplin 300s 25 12.30 MiB/s 10.57 MiB/s Chain tip, lag 0
Caplin, parallel execution 1800s 150 13.522 MiB/s 9.166 MiB/s Chain tip, lag 0
Caplin, --exec.serial 1800s 149 13.358 MiB/s 10.180 MiB/s Chain tip, lag 0
External Lighthouse 1812s 151 14.955 MiB/s 11.565 MiB/s Chain tip, lag 0; Lighthouse was backfilling

Normalizing the two 30-minute Caplin execution modes by block:

Metric Parallel Serial Serial change
Physical NVMe write/block 162.26 MiB 161.37 MiB -0.55%
MDBX COW/block 109.99 MiB 122.97 MiB +11.81%
MDBX page splits/block 361.59 415.05 +14.78%

Therefore --exec.serial does not reduce the write amplification. Replacing
Caplin with Lighthouse also does not reduce Erigon MDBX COW. The external
Lighthouse physical-disk result includes its checkpoint backfill, but the MDBX
COW metric is emitted by Erigon and remains high independently of that CL I/O.

During longer observation periods:

  • mdbx.dat remained approximately 6.26 GiB;
  • total db_size{db="chaindata"} remained constant;
  • ReclaimableSpace, CommitmentVals, and ChangeSets3 changed in both
    directions instead of growing without bound;
  • db_rotx_overloaded_total remained 0;
  • the execution head remained at the public head;
  • running Erigon with --externalcl and no CL input reduced physical writes to
    the host background level while the execution head remained static.

This looks like sustained MDBX COW/page-split churn caused by per-block
execution state and commitment updates rather than database growth, Caplin,
pruning backlog, or RPC traffic.

Steps to reproduce the behaviour

  1. Sync Erigon 3.5.4 on Ethereum mainnet and wait for eth_syncing=false and
    zero public-head lag.
  2. Wait at least five minutes after catch-up so catch-up execution is excluded.
  3. Enable Erigon Prometheus metrics and scrape them every 15 seconds.
  4. Measure an uninterrupted 30-minute chain-tip window.
  5. Record the start and end execution block numbers and normalize all counters
    by the number of processed blocks.
  6. Calculate MDBX COW bytes from the 16 KiB MDBX page counter:
increase(db_pgops{db="chaindata",phase="cow"}[30m]) * 16384
  1. Measure physical device writes using node-exporter or Linux diskstats:
increase(node_disk_written_bytes_total{device="nvme0n1"}[30m])
  1. Confirm that the physical write rate falls to the host background level
    when execution is intentionally held static with --externalcl and no CL.

For a control that isolates consensus input, start Erigon with --externalcl
and no CL. MDBX COW remains zero while the execution head is static. Then attach
a synced external CL: MDBX COW returns as execution resumes at chain tip.

Related work

This report may be an operator-visible measurement of the work already tracked
in:

Could you confirm whether 110-140 MiB of MDBX COW per mainnet block is
expected on 3.5.4 and whether these two changes are intended to address this
steady-state write volume? I can provide raw Prometheus series, a longer test
window, selected Erigon logs, or test a specific branch/build if useful.

Backtrace

There is no crash or backtrace. Erigon remains synced, has no automatic
restarts, and logs no errors during the measurement windows.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions