Yandex ha recentemente open-source YaFF (Yet another Flat Format), un formato a zero-copy per Protobuf sviluppato in C++ ed utilizzabile in produzione. I dati derivano dal file .proto esistente, che rimane fonte di verità, solo la rappresentazione fisica in memoria cambia.

Come Funziona YaFF

YaFF non è una sostituzione completa del Protobuf, bensì un formato alternativo. Utilizza lo stesso schema .proto per generare un’API simile alla proto in C++. L’unica modifica è nel layout della memoria.

YaFF supporta quattro layout per la gestione dei dati. Fixed, Flat, Sparse e Dynamic permettono di scegliere tra velocità di lettura e flessibilità. Il layout Dynamic, utilizzato per default, sceglie in maniera intelligente tra Flat e Sparse in base alle esigenze di schema evoluzione.

    • Layout Fixed: è una struttura rigida, ottimizzata per dati piccoli e primitivi inlined
    • Layout Flat: ha un header a due byte; adatto per dati densi e caldi
    • Layout Sparse: utilizza una meta-tabella per accessi rari o sparse
    • Layout Dynamic: decide in tempo reale se utilizzare Flat o Sparse

Prestazioni e Benchmark

Il layout Flat di YaFF, su benchmark di Yandex, legge dati caldi ~3.8 volte più velocemente rispetto a FlatBuffers. In un’architettura con AMD EPYC 7713, YaFF ha ottenuto un tempo medio di 9.79 ns per lettura, rispetto a 219.35 ns del tradizionale Protobuf.

Ecco un confronto tra diversi formati:

    • Raw C++ Struct: 8.14 ns, rapporto 1.0×
    • YaFF Flat Layout: 9.79 ns, rapporto 1.2×
    • YaFF Sparse Layout: 21.23 ns, rapporto 2.6×
    • FlatBuffers: 37.30 ns, rapporto 4.6×
    • Protobuf: 219.35 ns, rapporto 26.9×

I dati confermano che YaFF è significativamente più veloce di FlatBuffers e Protobuf. Le performance si mantengono stabili su diverse piattaforme hardware.

Analisi del Compiler e Ottimizzazioni

YaFF affina la generazione del codice per collaborare meglio con i compilaori. Evita errori di aliasing grazie a ottimizzazioni specifiche. Ciò consente una maggiore utilizzazione di accessi ottimizzati e una cache migliore.

YaFF si differenzia da FlatBuffers anche per come gestisce le conversioni. Mantiene la struttura ProtoBuf invariata e permette di leggere dati direttamente dal buffer, evitando un passo di parsing.

Attualmente in Produzione

YaFF è utilizzato in sistemi di advertising di Yandex. Sull’architettura produttiva, Yandex ha riscontrato un risparmio di CPU variabile tra il 10% e il 20%. L’implementazione è modulare, permettendo di aggiornarne un solo modulo alla volta senza interrompere il resto del sistema.

Sono presenti diverse applicazioni ideali per YaFF:

    • Backend di raccomandazione e sistemi di advertising
    • Indici rammap-able per servizi di ricerca e dati
    • Pipeline ML e analisi dati grandi

Filo d’Azione Semplice e Intuitivo

Ogni implementazione di Yaff segue un modello chiaro:

    • Seriale un messaggio esistente in un buffer YaFF
    • Accedi direttamente ai campi senza parsing
    • Converte nuovamente in Protobuf quando necessario

Nel codice:

```cpp

#include "feed.pb.h" // generato da protoc

#include "feed.yaff.h" // generato da yaff_generate()

// 1. Serializza un messaggio Protobuf esistente in un buffer YaFF.

feed::FeedResponse proto = LoadFeedResponse();

const auto buffer = yaff::Serialize(proto);

// 2. Leggi i campi direttamente dal buffer. Nessun parsing richiesto.

const auto& response = yaff::ReadMessage(buffer.Data());

for (const auto& item : response.items()) {

std::string_view title = item.title();

std::string_view author = item.author().name(); // vuoto se author non impostato

}

// 3. Converte nuovamente in Protobuf quando necessario.

feed::FeedResponse restored;

response.ParseTo(restored);

```

Risorse e Avanzamenti

Per ulteriori informazioni, visita il repository GitHub di YaFF e la documentazione ufficiale. YaFF è rilasciato sotto licenza Apache 2.0, ed è attualmente sviluppato in C++ con versione 0.1.0.