Zpět na domů

Asynchronní logování C++: skutečná omezení

Asynchronní logování v C++ přerozděluje zátěž, ale neodstraňuje kopírování dat a bottlenecků sinků. Analýza pipeline, problémů deferred formatting a chování při přetížení. Benchmarky spdlog, logme, Quill.

Proč async logy v C++ zklamávají: analýza bottlenecků
Advertisement 728x90

Omezení asynchronního logování v C++: analýza kritických bodů

Asynchronní logování v C++ se často považuje za univerzální řešení pro zrychlení aplikací. Ve skutečnosti však jen přesouvá zátěž, místo aby odstraňovalo základní omezení. Výkon je určen nejen frontami, ale také kopírováním dat, rychlostí sinků (cílových zařízení) a chováním při přetížení. Dobře optimalizované synchronní logování někdy překonává asynchronní variantu co do celkové propustnosti (throughput).

Struktura asynchronního logovacího kanálu

Asynchronní logování kombinuje dva klíčové kroky: zachycení a formátování argumentů plus asynchronní zápis.

Zachycení argumentů

  • Kopírování řetězců z string_view nebo char*.
  • Serializace složitých objektů.
  • Kontrola životnosti (lifetime) pro pozdější formátování.

Bezpečné obnovení dat v pozdější fázi je možné pouze při jejich kopírování. Jinak se formátování provádí synchronně.

Google AdInline article slot

Asynchronní zápis

  • Producenti (volající kódy) umisťují záznamy do fronty.
  • Jeden backendový vlákno zpracovává formátování a zápis do sinků (soubor, konzole).
  • Operace flush a fsync rozhodují o skutečné rychlosti zápisu.

Schéma:

Synchronně: volající → formátování → zápis
Asynchronně: volající → zachycení → zařazení do fronty → backend → formátování → zápis

Zavádí se režijní náklady na synchronizaci a paměť.

Problémy s odloženým formátováním

Odložené formátování (deferred formatting) ukládá argumenty pro zpracování v backendu. Avšak:

Google AdInline article slot
  • string_view sv = s; LOG_INFO("{}", sv); s.clear(); — data jsou neplatná.
  • Totéž platí pro char* na zásobníku, views na kontejnery nebo objekty obsahující ukazatele.

Možná řešení:

  • Kopírování: string_viewstd::string. Bezpečné, ale spotřebuje více CPU i paměti než synchronní formátování.
  • Synchronní formátování: Zvyšuje latenci volajícího kódu.
  • Uživatelská serializace: Vyžaduje vlastní kodeky, kopie dat nebo záruky životnosti.

Přetížení front a jeho důsledky

Asynchronní logování nezrychluje zápis do sinku. Pokud generujete 1 milion zpráv za sekundu, ale sink zvládne jen 100 tisíc, hromadí se zpoždění.

Jeden backendový vlákno je tvrdým úzkým místem ve scénářích s více producenty.

Google AdInline article slot

Při situaci „producent > spotřebitel“ dochází k:

  • Růstu front a potenciálnímu úniku paměti.
  • Blokování producentů a ztrátě výhod asynchronního přístupu.
  • Zahození zpráv — ztráta dat.
  • Přepisování starých záznamů — ztráta historie.

Pomalý sink (např. konzole: 200 µs vs. soubor: 10 µs) zpomaluje celý kanál.

Srovnání se synchronním přístupem

Synchronní formátování + asynchronní zápis je jednodušší:

  • Žádné problémy s životností nebo visícími referencemi (dangling references).
  • Předvídatelnost: „co jste zalogovali, to uvidíte“.
  • Méně chyb z podmínkových závodů (race conditions) nebo poškození řetězců.

Asynchronní logování je užitečné při:

  • Krátkodobých špičkách (burst) logů.
  • Vícevláknovosti s jednoduchými argumenty.

Nepoužitelné při:

  • Trvalém přetížení.
  • Složitých objektech.
  • Pomalých sinkech.

Benchmarky populárních logovacích knihoven

Testy na logbench ukazují:

| Logovací knihovna | Synchronní režim | Asynchronní režim |

|-------------------|------------------|-------------------|

| spdlog | Vysoká propustnost | + režijní náklady |

| logme | Vysoká propustnost | + režijní náklady |

| Quill | Není k dispozici | Blokování nebo zahození při přetížení |

Synchronní verze spdlog a logme jsou často rychlejší než jejich asynchronní protějšky kvůli absenci front a synchronizačních operací. Quill (plně asynchronní) postupně zaplňuje vyrovnávací paměti: backend → frontend → blokování nebo zahození.

Klíčové závěry

  • Asynchronní logování snižuje latenci p99 „horké cesty“, ale nezvyšuje celkovou propustnost.
  • Kopírování pro odložené formátování eliminuje potenciální výhodu.
  • Jeden backendový vlákno je limitní faktor škálovatelnosti.
  • Fronty maskují, ale neřeší přetížení.
  • Volba modelu závisí na charakteru zátěže: krátkodobé špičky vs. ustálený stav.

— Editorial Team

Advertisement 728x90

Číst dál