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
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 8/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- cpp
- Ambito
- distributed-systems
Direzione di ricerca
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.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
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.
- Lingua principale
- C++
- Stelle
- 876
- Fork
- 264
- Merge medio
- 1g 16h
- PR unite (30g)
- 127
Preparare l'ambiente
Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di microsoft/CCF
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
microsoft/CCF#8688 · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
I maintainer di solito rispondono entro 1 giorno
-
Make stderr output exclusive to fatal paths and consistent across all fatal pathsForse già presa @achamayou l’ha presa 2 giorni fa. Aperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
I maintainer di solito rispondono entro 1 giorno
-
raft.h hardeningAperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 25/100
microsoft/CCF#8606 · 3 commenti ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di microsoft/CCF
Issue simili
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
Niko1221/Strata#5560 · 2 commenti ·
I maintainer di solito rispondono entro 4 giorni
-
NVIDIA windows
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 1 giorno
-
要トリアージ 辞書
Difficoltà 1/5 1-3 ore Idoneità per principianti 86/100
yksr-melt/Meltype#1625 · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
[yugabyted] xcluster set_up and add_to_replication fail for database names containing - . or (Apertakind/bug priority/medium qa_automation
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
yugabyte/yugabyte-db#37324 ·
I maintainer di solito rispondono entro 1 giorno