Slow ledger fsync or chunk creation blocks `GET /node/ledger_chunk` on `Ledger::state_lock`, which can use up the worker threads and stop the node answering any request
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 8/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- cpp
- Área
- distributed-systems
Línea de trabajo
Start in src/host/ledger.h, where Ledger::commit(), LedgerFile::commit(), Ledger::write_entry() and committed_ledger_path_with_idx() all take state_lock around fsync and chunk creation. Then read the ledger_chunk handler in src/node/rpc/file_serving_handlers.h, which calls the lookup synchronously on a worker thread. Done means a delayed fsync no longer makes /node/version or a ledger_chunk request block all workers. The issue lists three candidate fixes, so the design choice needs maintainer input first.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Describe the bug
Since 7.0.19, ledger writes no longer go through the host-enclave ringbuffer (#8405), and ledger file I/O runs on the task worker threads. This works as intended for a slow disk on its own. When one ledger fsync or chunk open is blocked for 30 s, a 7.0.23 node keeps answering /node/version and /node/state, while a 7.0.17 node stops answering completely.
One case still freezes the node:
Ledger::commit()takesstate_lock(ledger.h#L2023-L2051), andLedgerFile::commit()then fsyncs the completed chunk while the lock is held (ledger.h#L1086-L1105). The comment there says this is deliberate, so thatcommitted_ledger_path_with_idx()only returns complete files.Ledger::write_entry()also holds the lock (ledger.h#L1845-L1850) while it creates the next chunk file.- The handler for
GET /node/ledger_chunk?since=N(file_serving_handlers.h#L1178-L1179) callscommitted_ledger_path_with_idx()synchronously on a worker thread (file_serving_handlers.h#L803-L804). That function takesstate_lock(ledger.h#L2078-L2081).
So while an fsync is slow, every ledger_chunk request holds a worker thread until the fsync finishes. With the default worker_threads: 1 (two task workers), one request is enough: the other worker is the one running the fsync. No worker is left, and the node stops answering every endpoint, including /node/version, until the fsync returns. With worker_threads: 3 (four workers), the node froze when the third concurrent ledger_chunk request arrived.
In Kubernetes, a liveness probe on a /node endpoint then restarts a node that is only waiting for slow storage. Any client that polls ledger_chunk, for example to archive committed chunks, makes this likely during storage latency spikes.
To Reproduce
- Start a 3-node network with the release
loggingsample app and the devel RPM (virtual build),--ledger-chunk-bytes 5KBand the defaultworker_threads: 1. Send about 20POST /app/log/publicper second. - On one node, delay the next ledger fsync by 30 s:
strace -f -p <cchost pid> -e trace=fsync,openat -e inject=fsync:delay_enter=30s:when=1. The node log confirms it:Operation took too long ( 30.02s): Committing ledger file - fsync(ledger_609). - Poll
GET /node/versionandGET /node/stateon that node every 0.5 s, with a 2 s timeout. All of them succeed during the delay. - Repeat, and during the delay send one
GET /node/ledger_chunk?since=100to the same node. From that request until the fsync returns, every poll times out. Theledger_chunkrequest itself takes about 27 s.
| Version | Delayed for 30 s | Polls during the delay that failed |
|---|---|---|
| 7.0.17 | fsync (primary or backup), chunk create (primary) | 112/112 in each test |
| 7.0.23 | fsync (primary or backup), chunk create (primary) | 0/112 (max latency 0.33 s) |
| 7.0.23 | fsync + 1 ledger_chunk request (two runs, two nodes) |
100/112, all after the request |
7.0.23, worker_threads: 3 |
fsync + 3 ledger_chunk requests 4 s apart |
68/112, all after the 3rd request |
Expected behavior
A slow ledger fsync shouldn't stop the node serving endpoints that don't need the ledger, and /node endpoints should stay responsive.
Environment information
- CCF 7.0.23.
src/host/ledger.his identical onmainat9cdc86cc78a42ee27ea167a7a347c9d924bf4841. - Reproduced with the virtual build in Azure Linux 3.0 containers. Production runs C++ applications on the SNP platform (confidential Azure Container Instances), with the ledger on an SMB file share, where single fsync or file-create calls sometimes take 40-55 s.
Frequency
Every time a ledger_chunk request reaches a node while its ledger fsync or chunk creation is blocked. In our deployment that depends on storage latency spikes, which happen several times a week on some file shares.
Additional context / possible fixes
- Don't hold
state_lockfor the fsync inLedger::commit(). For example, mark the file as being committed under the lock, fsync and rename it outside the lock, then publish it as committed under the lock.committed_ledger_path_with_idx()would only return published files, which keeps today's guarantee. - Or don't make
ledger_chunklookups wait for an in-progress commit. For example, try the lock and answer503withRetry-Afterwhen it's held, or keep the committed-chunk index under a separate lock. - Or serve
ledger_chunk, and other readers ofstate_locksuch as historical reads of committed ranges, without blocking a worker thread.
Related (not necessarily a bug): with 7.0.23, a primary whose ledger fsync or chunk create stalls loses leadership within about 3 s, although its HTTP endpoints stay up. Outbound node-to-node messages, including heartbeats, wait for all ledger mutations submitted before them (node_connections.h#L413-L423, ledger_subsystem.h#L210-L221). So a storage latency spike on the primary still causes an election.
- Lenguaje dominante
- C++
- Estrellas
- 876
- Forks
- 264
- Merge medio
- 1 d 16 h
- PR fusionados (30 d)
- 127
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de microsoft/CCF
-
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
microsoft/CCF#8688 · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
Los mantenedores suelen responder en 1 día
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
Los mantenedores suelen responder en 1 día
-
Make stderr output exclusive to fatal paths and consistent across all fatal pathsPosiblemente ocupada @achamayou la tomó hace 2 días. Abierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
Los mantenedores suelen responder en 1 día
-
raft.h hardeningAbierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 25/100
microsoft/CCF#8606 · 3 comentarios ·
Los mantenedores suelen responder en 1 día
Todos los issues de microsoft/CCF
Issues similares
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Niko1221/Strata#5560 · 2 comentarios ·
Los mantenedores suelen responder en 4 días
-
NVIDIA windows
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 1 día
-
[辞書] C/C++のプリプロセッサ指令名を英字のままにするAbierto要トリアージ 辞書
Dificultad 1/5 1-3 horas Aptitud para principiantes 86/100
yksr-melt/Meltype#1625 · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
[yugabyted] xcluster set_up and add_to_replication fail for database names containing - . or (Abiertokind/bug priority/medium qa_automation
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
yugabyte/yugabyte-db#37324 ·
Los mantenedores suelen responder en 1 día