9 pontos por GN⁺ 2025-11-01 | 2 comentários | Compartilhar no WhatsApp
  • Apache Fory Rust é um framework de serialização cross-language que oferece desempenho de serialização ultrarrápido e gerenciamento automático de referências
  • Com base na tecnologia zero-copy e na segurança de tipos do Rust, lida automaticamente com referências circulares, objetos de trait e evolução de schema
  • Suporta troca de dados entre várias linguagens, como Rust, Python, Java e Go, sem arquivos IDL nem geração de código
  • Segundo os benchmarks, registrou velocidade de processamento 10 a 20 vezes maior que JSON e Protobuf
  • Tem alto potencial de uso em ambientes de alto desempenho, como microsserviços, pipelines de dados e sistemas em tempo real

O dilema da serialização e o surgimento do Apache Fory Rust

  • Os métodos tradicionais de serialização tinham a limitação de precisar abrir mão de um entre velocidade, flexibilidade e compatibilidade entre linguagens
    • Formatos binários manuais são rápidos, mas frágeis diante de mudanças de schema
    • JSON/Protobuf são flexíveis, mas têm overhead de desempenho superior a 10x
    • Soluções existentes têm suporte insuficiente para recursos específicos de cada linguagem
  • O Apache Fory Rust garante desempenho e flexibilidade ao mesmo tempo, sem exigir IDL nem gerenciamento manual de schema

Principais recursos

  • 1. Verdadeiro suporte cross-language

    • Compartilha o mesmo protocolo binário entre Java, Python, C++, Go e outras linguagens
    • Dados serializados em Rust podem ser desserializados diretamente em Python
    • Sem arquivos de schema, geração de código ou problemas de incompatibilidade de versão, simplificando a troca de dados entre microsserviços multilíngues
  • 2. Tratamento automático de referências circulares e compartilhadas

    • Rastreia e preserva automaticamente estruturas com referências circulares, nas quais a maioria dos frameworks falha
    • Mesmo que o mesmo objeto seja referenciado várias vezes, ele é serializado apenas uma vez, preservando a identidade da referência
    • Adequado para bancos de dados em grafo, ORM e modelos de domínio complexos
  • 3. Serialização de objetos de trait

    • Suporta serialização de objetos de trait como Box no Rust
    • É possível registrar tipos polimórficos com a macro register_trait_type!
    • Suporta vários formatos, como Box, Rc, Arc e dyn Any
    • Permite implementar sistemas de plugins, coleções heterogêneas e arquiteturas extensíveis
  • 4. Evolução de schema (modo compatível)

    • O modo Compatible permite mudanças de schema entre versões de serviço
      • É possível adicionar, remover e reordenar campos, além de converter tipos opcionais
      • Mudança de tipo não é permitida
    • Útil para deploy sem downtime e evolução independente de microsserviços

Base técnica

  • Design do protocolo

    • Estrutura: | fory header | reference meta | type meta | value data |
    • Aplica inteiros de tamanho variável, metadados compactados, rastreamento de referências e layout little-endian
    • Melhora o desempenho com eliminação de duplicação de objetos compartilhados e compressão de metadados de tipo
  • Geração de código em tempo de compilação

    • Elimina overhead em runtime com geração de código baseada em macros em vez de reflection
    • A macro #[derive(ForyObject)] gera automaticamente funções de serialização e desserialização
    • Garante segurança de tipos, tamanho mínimo de binário e suporte a autocompletar da IDE
  • Estrutura da arquitetura

    • fory/: API de alto nível
    • fory-core/: engine de serialização (buffer I/O, registro de tipos, compressão de metadados etc.)
    • fory-derive/: definição de macros procedurais
    • Estrutura modularizada para melhor manutenção e extensibilidade

Resultados de benchmark

  • Velocidade de processamento 10 a 20 vezes maior que JSON e Protobuf
  • Exemplos:
    • simple_struct(small) → Fory 35,729,598 TPS / JSON 10,167,045 / Protobuf 8,633,342
    • person(medium) → Fory 3,839,656 TPS / JSON 337,610 / Protobuf 369,031
  • Em todos os casos de teste, o Fory registrou o melhor desempenho

Cenários de uso

  • Casos de uso adequados

    • Microsserviços multilíngues: troca de dados sem arquivos de schema
    • Pipelines de dados de alto desempenho: processamento de milhões de registros por segundo
    • Modelos de domínio complexos: suporte a referências circulares e estruturas polimórficas
    • Sistemas em tempo real: latência abaixo de 1 ms, desserialização zero-copy
  • Consideração de alternativas

    • Quando for necessário um formato legível por humanos → JSON/YAML
    • Quando for necessário um formato para armazenamento de longo prazo → Parquet
    • Para estruturas de dados simples → serde + bincode

Primeiros passos

  • Instalação

    • Adicione ao Cargo.toml:
      [dependencies]  
      fory = "0.13"  
      
  • Exemplo básico de serialização

    • Registre a struct com #[derive(ForyObject)] e use serialize() / deserialize()
    • Mantenha a consistência dos dados registrando o ID do tipo
  • Serialização cross-language

    • Ative o modo de compatibilidade multilíngue com compatible(true).xlang(true)
    • Suporta registro baseado em ID ou nome (register_by_namespace, register_by_name)

Tipos suportados

  • Tipos primitivos: bool, inteiros, ponto flutuante, String
  • Coleções: Vec, HashMap, BTreeMap, HashSet, Option
  • Smart pointers: Box, Rc, Arc, RcWeak, ArcWeak, RefCell, Mutex
  • Data/hora: tipos do chrono
  • Objetos definidos pelo usuário: ForyObject, ForyRow
  • Objetos de trait: Box/Rc/Arc, Rc/Arc

Roadmap

  • Disponível no v0.13

    • Geração estática de código, formato Row zero-copy, rastreamento de referências circulares, serialização de objetos de trait, modo de compatibilidade de schema
  • Recursos planejados

    • serialização cross-language de referências, atualizações parciais de Row

Considerações para produção

  • Segurança de thread: após concluir o registro, pode ser compartilhado com Arc (Send + Sync)
  • Tratamento de erros: baseado em Result, com distinção explícita entre erros como incompatibilidade de tipo e buffer insuficiente

Documentação e comunidade

  • Documentação oficial: fory.apache.org/docs
  • Documentação da API: docs.rs/fory
  • Comunidade: GitHub, Slack e Issue Tracker
  • Open source sob a Apache License 2.0

Conclusão

  • O Apache Fory Rust é um framework de serialização de próxima geração que elimina o compromisso entre desempenho, flexibilidade e compatibilidade entre linguagens
  • Com automação baseada em macros, suporte a objetos de trait e tratamento de referências circulares, maximiza a eficiência de desenvolvimento
  • Pode ser aplicado imediatamente em microsserviços, pipelines de dados e sistemas em tempo real

2 comentários

 
qlghwp123 2025-11-01

Esse desempenho faz sentido?

 
GN⁺ 2025-11-01
Opiniões do Hacker News
  • Eu gostaria que houvesse mais foco em melhorar o tooling de tecnologias existentes, como W3C EXI (Binary XML), em vez de criar um novo formato
    Ser apenas rápido não basta, e formatos sem ecossistema, como Aeron/SBT, têm dificuldade para se espalhar. XML já tem esse ecossistema

    • A codificação Binary XML pode ser útil em certos cenários, mas não é tão eficiente quanto os formatos modernos de serialização binária
      Além disso, ela não representa naturalmente grafos de objetos complexos, como referências compartilhadas ou referências cíclicas
      O formato Fory foi projetado desde o início para resolver esses problemas, ao mesmo tempo em que oferece compatibilidade entre linguagens e evolução de esquema
    • Não sei qual é melhor entre W3C EXI e ASN.1 BER, mas acho que a abordagem de DOP (design orientado a dados) faz mais sentido
      Ou seja, é preferível projetar primeiro a codificação e depois expandi-la de volta para linguagens ou clientes
  • Tenho dúvidas se o benchmark é justo
    Pelo link do código, quando não se trata de uma struct do Fory, o processo de serialização inclui conversões to/from
    Nesse processo ocorrem cópias de strings e realocação de arrays
    Em sistemas reais, o tonic fornece um buffer de 8 KB, então deve ser mais eficiente do que um simples Vec::default()

    • Esse benchmark não é justo
      Em um Xeon Gold 6136 parece haver um ganho de 10x, mas removendo as conversões to/from e a cópia de Vec, e pré-alocando um buffer de 8 KB, na prática fica mais perto de 3x
      O benchmark deveria ser reescrito em um estilo de tower service/codec sem nenhum código específico do Fory
      O Fory está usando um writer pool durante os testes
      Veja o código relacionado
  • Acho que, para manter compatibilidade entre linguagens no longo prazo, é necessário um contrato especificado com base em IDL
    A abordagem que começa na linguagem e vai para a serialização é conveniente no início, mas com o tempo fica vulnerável a mudanças no runtime da linguagem

    • Quanto mais linguagens houver, mais importante se torna um esquema oficial
      Projetos de linguagem única podem se manter simples sem IDL, mas a partir de três linguagens ou mais o IDL passa a funcionar como fonte única da verdade
      O Apache Fory pretende adicionar suporte opcional a IDL, para que equipes possam escolher uma abordagem language-first ou schema-first de acordo com sua situação
  • Tenho curiosidade sobre como mantêm tipos compartilhados entre linguagens sem esquema

    • Existe uma tabela de mapeamento de tipos
      Em linguagens tipadas, o esquema é inferido a partir da definição da classe; em linguagens não tipadas, a abordagem é adicionar anotações diretamente no código
      Um exemplo em Python pode ser visto aqui
    • É confuso dizer que equipes polyglot são um caso de uso principal e, ao mesmo tempo, afirmar que não é necessário um arquivo de esquema
      Veja o post relacionado no blog
    • Sou cético quanto a esse tipo de abordagem funcionar bem no longo prazo
    • A explicação sobre o quanto isso é usado em produção não foi suficiente para me passar confiança
  • Gostaria de entender por que eu usaria o Fory em vez de formatos sem desserialização como CapnProto ou Flatbuffers
    Se for preciso compressão, basta usar zstd
    Ainda assim, o amplo suporte a linguagens e a facilidade de uso do Fory são impressionantes
    No Python, eu ainda prefiro dill — porque ele consegue serializar até objetos de código
    Link do dill

    • Em benchmarks comparando com dill, o Fory mostrou ser 20 a 40 vezes mais rápido e ter até 7x mais compressão
      Veja o código do benchmark
    • O Apache Fory também pode ser usado como substituto de pickle/cloudpickle e oferece suporte à serialização de objetos de código, como funções locais e classes locais
      Link com exemplos
      O pyfory mostra uma compressão 3x melhor que o cloudpickle e oferece recursos de auditoria de segurança para evitar ataques maliciosos de desserialização
  • O link do benchmark dava 404, mas encontrei o link correto

  • É uma pena terem mudado o nome de “Fury” para “Fory”
    Fury era um nome perfeito para um framework de serialização rápida

    • “Fury” foi originalmente um nome que eu dei e ao qual eu tinha apego, mas tivemos que mudá-lo
  • A maioria dos protocolos binários tenta reduzir o tamanho dos dados
    O Protobuf usa compressão de inteiros (varint, zigzag)
    Se comparar apenas TPS puro, a abordagem de “não fazer nada” de enviar a struct C como está sempre acaba vencendo

    • O Fory também oferece compressão de inteiros, e o tamanho dos dados é quase igual ao do Protobuf
      Foi apresentada uma tabela comparativa em vários conjuntos de dados
    • Existem dois modos de compatibilidade de esquema, mas não há garantia de compatibilidade binária entre versões minor
  • Fico pensando se o limite de 4096 tipos do Fory é suficiente
    Veja o código relacionado

    • Talvez não seja suficiente em todos os casos, mas pode ser ampliado se necessário
      Na prática, quase nunca vi casos com mais de 4096 mensagens de protocolo definidas
  • O link do benchmark de Rust retorna 404
    No diretório raiz da documentação não foi possível encontrar o diretório de benchmarks