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
// 2. Leggi i campi direttamente dal buffer. Nessun parsing richiesto.
const auto& response = yaff::ReadMessage
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.