9 puntos por GN⁺ 2025-11-01 | 2 comentarios | Compartir por WhatsApp
  • Apache Fory Rust es un framework de serialización multiplataforma entre lenguajes que ofrece rendimiento de serialización ultrarrápido y gestión automática de referencias
  • Basado en la tecnología zero-copy y la seguridad de tipos de Rust, maneja automáticamente referencias circulares, objetos de trait y evolución de esquemas
  • Permite el intercambio de datos entre Rust, Python, Java, Go y otros lenguajes sin archivos IDL ni generación de código
  • Según los benchmarks, registró una velocidad de procesamiento 10~20 veces superior a JSON y Protobuf
  • Tiene un alto valor de uso en entornos de alto rendimiento como microservicios, pipelines de datos y sistemas en tiempo real

El dilema de la serialización y la llegada de Apache Fory Rust

  • Los métodos tradicionales de serialización tenían la limitación de que había que sacrificar velocidad, flexibilidad o compatibilidad entre lenguajes
    • Los formatos binarios hechos a mano son rápidos, pero frágiles ante cambios de esquema
    • JSON/Protobuf son flexibles, pero tienen un overhead de rendimiento de más de 10 veces
    • Las soluciones existentes tienen soporte limitado para funciones propias de cada lenguaje
  • Apache Fory Rust consigue al mismo tiempo rendimiento y flexibilidad, y elimina la necesidad de IDL y de gestión manual de esquemas

Características principales

  • 1. Verdadero soporte multiplataforma entre lenguajes

    • Comparte el mismo protocolo binario entre Java, Python, C++, Go y otros
    • Los datos serializados en Rust pueden deserializarse directamente en Python
    • Sin archivos de esquema, generación de código ni problemas de desajuste de versiones, simplifica el intercambio de datos entre microservicios multilenguaje
  • 2. Manejo automático de referencias circulares y compartidas

    • Rastrea y conserva automáticamente estructuras de referencias circulares con las que la mayoría de los frameworks fallan
    • Aunque se haga referencia al mismo objeto varias veces, solo se serializa una vez, manteniendo la identidad de referencia
    • Adecuado para bases de datos de grafos, ORM y modelos de dominio complejos
  • 3. Serialización de objetos de trait

    • Soporta la serialización de objetos de trait como Box en Rust
    • Permite registrar tipos polimórficos con la macro register_trait_type!
    • Soporta diversas formas como Box, Rc, Arc, dyn Any
    • Permite implementar sistemas de plugins, colecciones heterogéneas y arquitecturas extensibles
  • 4. Evolución de esquemas (modo compatible)

    • El modo Compatible permite cambios de esquema entre versiones del servicio
      • Se pueden agregar, eliminar o reordenar campos, así como convertir tipos opcionales
      • No se permite cambiar tipos
    • Es útil para despliegues sin downtime y la evolución independiente de microservicios

Base técnica

  • Diseño del protocolo

    • Estructura: | fory header | reference meta | type meta | value data |
    • Aplica enteros de longitud variable, metadatos comprimidos, seguimiento de referencias y layout little-endian
    • Mejora el rendimiento mediante deduplicación de objetos compartidos y compresión de metadatos de tipos
  • Generación de código en tiempo de compilación

    • Elimina el overhead en tiempo de ejecución con generación de código basada en macros en lugar de reflection
    • La macro #[derive(ForyObject)] genera automáticamente funciones de serialización y deserialización
    • Ofrece seguridad de tipos, tamaño mínimo del binario y soporte de autocompletado en el IDE
  • Arquitectura

    • fory/: API de alto nivel
    • fory-core/: motor de serialización (buffer I/O, registro de tipos, compresión de metadatos, etc.)
    • fory-derive/: definición de macros procedurales
    • La estructura modular mejora la mantenibilidad y la extensibilidad

Resultados de benchmarks

  • Velocidad de procesamiento 10~20 veces superior frente a JSON y Protobuf
  • Ejemplos:
    • 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
  • En todos los casos de prueba, Fory registró el mejor rendimiento

Escenarios de uso

  • Casos adecuados

    • Microservicios multilenguaje: intercambio de datos sin archivos de esquema
    • Pipelines de datos de alto rendimiento: procesamiento de millones de registros por segundo
    • Modelos de dominio complejos: soporte para referencias circulares y estructuras polimórficas
    • Sistemas en tiempo real: latencia inferior a 1 ms y deserialización zero-copy
  • Cuándo considerar alternativas

    • Si se necesita un formato legible por humanos → JSON/YAML
    • Si se necesita un formato para almacenamiento a largo plazo → Parquet
    • Para estructuras de datos simples → serde + bincode

Primeros pasos

  • Instalación

    • Agregar a Cargo.toml:
      [dependencies]  
      fory = "0.13"  
      
  • Ejemplo básico de serialización

    • Registrar la estructura con #[derive(ForyObject)] y luego usar serialize() / deserialize()
    • Mantener la consistencia de los datos mediante el registro de type IDs
  • Serialización entre lenguajes

    • Activar el modo de compatibilidad multilenguaje con compatible(true).xlang(true)
    • Soporta registro basado en ID o en nombre (register_by_namespace, register_by_name)

Tipos soportados

  • Básicos: bool, enteros, punto flotante, String
  • Colecciones: Vec, HashMap, BTreeMap, HashSet, Option
  • Smart pointers: Box, Rc, Arc, RcWeak, ArcWeak, RefCell, Mutex
  • Fecha/hora: tipos de chrono
  • Objetos definidos por el usuario: ForyObject, ForyRow
  • Objetos de trait: Box/Rc/Arc, Rc/Arc

Hoja de ruta

  • Disponible en v0.13

    • Generación estática de código, formato Row zero-copy, seguimiento de referencias circulares, serialización de objetos de trait y modo de compatibilidad de esquema
  • Funciones previstas

    • Serialización de referencias entre lenguajes y actualizaciones parciales de Row

Consideraciones para producción

  • Seguridad de hilos: después de completar el registro, se puede compartir con Arc (Send + Sync)
  • Manejo de errores: basado en Result, con distinción explícita de errores como incompatibilidad de tipos o falta de buffer

Documentación y comunidad

Conclusión

  • Apache Fory Rust es un framework de serialización de nueva generación que elimina el compromiso entre rendimiento, flexibilidad y compatibilidad entre lenguajes
  • Automatización basada en macros, soporte para objetos de trait y manejo de referencias circulares maximizan la eficiencia de desarrollo
  • Puede aprovecharse de inmediato en microservicios, pipelines de datos y sistemas en tiempo real

2 comentarios

 
qlghwp123 2025-11-01

¿Este rendimiento tiene sentido?

 
GN⁺ 2025-11-01
Opiniones en Hacker News
  • Ojalá se enfocaran en mejorar el tooling de tecnologías existentes como W3C EXI (Binary XML) en lugar de crear otro formato nuevo
    No basta con que solo sea rápido; un formato sin ecosistema, como Aeron/SBT, tiene difícil expandirse. XML ya cuenta con ese ecosistema

    • La codificación Binary XML puede ser útil en ciertos casos, pero no es tan eficiente como los formatos modernos de serialización binaria
      Además, no puede representar de forma natural grafos de objetos complejos como referencias compartidas o referencias circulares
      El formato Fory fue diseñado desde el inicio para resolver estos problemas y, al mismo tiempo, soportar compatibilidad entre lenguajes y evolución de esquemas
    • No sé cuál sea mejor entre W3C EXI y ASN.1 BER, pero creo que el enfoque de DOP (diseño orientado a datos) es el correcto
      Es decir, lo ideal es diseñar primero la codificación y luego extenderla de regreso hacia lenguajes o clientes
  • Tengo dudas de que el benchmark sea justo
    Viendo el código, cuando no se usa una struct de Fory, el proceso de serialización incluye una conversión to/from
    En esa conversión se producen copias de strings y reasignaciones de arreglos
    En un sistema real, tonic provee un buffer de 8 KB, así que sería más eficiente que simplemente usar Vec::default()

    • Este benchmark no es justo
      En un CPU Xeon Gold 6136 parece haber una mejora de 10x, pero si se eliminan las conversiones to/from y la clonación de Vec, y además se preasigna un buffer de 8 KB, en realidad queda más cerca de 3x
      El benchmark debería reescribirse con un estilo tower service/codec sin nada de código específico de Fory
      Fory está usando un writer pool durante las pruebas
      Ver código relacionado
  • A largo plazo, creo que para mantener compatibilidad entre lenguajes se necesita un contrato especificado basado en IDL
    Un enfoque que parte del lenguaje hacia la serialización es cómodo al inicio, pero con el tiempo se vuelve vulnerable a cambios en el runtime del lenguaje

    • Mientras más lenguajes haya, más importante se vuelve un esquema oficial
      Un proyecto de un solo lenguaje puede mantenerse simple sin IDL, pero a partir de tres o más lenguajes el IDL funciona como fuente única de verdad
      Apache Fory planea agregar soporte opcional para IDL, de modo que cada equipo pueda elegir entre un enfoque language-first o schema-first según su situación
  • Me pregunto cómo mantienen tipos compartidos entre lenguajes sin esquema

    • Existe una tabla de mapeo de tipos
      En lenguajes tipados, el esquema se infiere a partir de la definición de clase, y en lenguajes no tipados se agregan anotaciones directamente en el código
      Un ejemplo en Python puede verse aquí
    • Es confuso que se presenten los equipos políglotas como caso de uso principal y al mismo tiempo digan que no hace falta un archivo de esquema
      Ver esta entrada del blog
    • Soy escéptico de que este enfoque funcione bien a largo plazo
    • También falta una explicación clara de cuánto se usa realmente en producción, así que no me termina de inspirar confianza
  • Me pregunto por qué usar Fory en vez de formatos de serialización cero como CapnProto o Flatbuffers
    Si hace falta compresión, se puede usar zstd
    Aun así, su amplio soporte de lenguajes y facilidad de uso son impresionantes
    En Python sigo prefiriendo dill, porque incluso puede serializar objetos de código
    Enlace a dill

    • En benchmarks comparado con dill, Fory mostró ser 20 a 40 veces más rápido y con hasta 7 veces mayor tasa de compresión
      Ver el código del benchmark
    • Apache Fory también puede usarse como reemplazo de pickle/cloudpickle, y soporta serialización de objetos de código como funciones o clases locales
      Ejemplo aquí
      pyfory muestra una tasa de compresión 3 veces mayor que cloudpickle y, con su función de auditoría de seguridad, previene ataques maliciosos de deserialización
  • El enlace del benchmark daba 404, pero encontré el enlace correcto

  • Es una lástima que hayan cambiado el nombre de “Fury” a “Fory”
    Fury era un nombre perfecto para un framework de serialización rápida

    • “Fury” fue un nombre que yo mismo había puesto y le tenía cariño, pero no quedó otra que cambiarlo
  • La mayoría de los protocolos binarios buscan reducir el tamaño de los datos
    Protobuf usa compresión de enteros (varint, zigzag)
    Si solo comparas TPS puro, el enfoque de “no hacer nada” de mandar structs de C tal cual siempre va a ganar

    • Fory también soporta compresión de enteros, y el tamaño de los datos es casi igual al de Protobuf
      Se muestra una tabla comparativa con varios datasets
    • Existen dos modos de compatibilidad de esquema, pero no hay garantía de compatibilidad binaria entre versiones menores
  • Me pregunto si el límite de 4096 tipos de Fory es suficiente
    Ver código relacionado

    • Quizá no sea suficiente en todos los casos, pero si hace falta se puede ampliar
      De hecho, casi nunca he visto casos con más de 4096 mensajes de protocolo definidos
  • El enlace del benchmark de Rust devuelve 404
    En la raíz de la documentación no pude encontrar el directorio de benchmarks