Hacker News

Hem interfície de C++ d'un sol fil amb Rust de diversos fils

Hem interfície de C++ d'un sol fil amb Rust de diversos fils Aquesta anàlisi exhaustiva de la interfície ofereix un examen detallat dels seus components bàsics i implicacions més àmplies. Àrees clau d'enfocament La discussió se centra en: Mecànica principal...

9 min read Via antithesis.com

Mewayz Team

Editorial Team

Hacker News
Aquí teniu la publicació completa del blog de SEO:

Hem interconnectat C++ d'un sol fil amb Rust multifil

La interfície de codi C++ d'un sol fil amb Rust no només és possible, sinó que és una de les maneres més pràctiques de modernitzar els sistemes heretats sense una reescriptura completa. A Mewayz, vam abordar aquest repte exacte quan vam escalar el nostre sistema operatiu empresarial de 207 mòduls per donar servei a 138.000 usuaris, i els resultats van canviar fonamentalment la nostra manera de pensar sobre la interoperabilitat dels sistemes.

Per què interfíciese amb C++ d'un sol fil amb Rust multifil?

La majoria dels sistemes de producció porten anys de codi C++ provat en batalla. Reescriure tot a Rust sembla atractiu en paper, però introdueix un risc massiu i mesos de temps d'enginyeria. L'enfocament pragmàtic és l'adopció incremental: embolicar la lògica C++ existent mentre es descarreguen càrregues de treball pesades en concurrència al model de propietat de Rust.

En el nostre cas, els mòduls bàsics de la lògica empresarial s'havien funcionat de manera fiable en C++ d'un sol fil durant anys. Van gestionar el processament de tasques seqüencials, la generació de documents i els càlculs financers. Però a mesura que la nostra base d'usuaris va créixer més enllà dels 100 000, necessitàvem un processament de dades paral·lel, una gestió simultània d'API i una gestió segura de l'estat compartit. Els trets Envia i Sync de Rust ens van donar garanties de concurrència en temps de compilació que C++ simplement no podria oferir sense una auditoria manual exhaustiva.

La motivació clau és la reducció de riscos. Conserveu allò que funciona i afegiu quina escala, sense apostar tota la vostra base de codi en una migració que potser no s'acabi mai.

Com funciona realment el límit FFI?

La interfície de funció estrangera (FFI) entre C++ i Rust funciona mitjançant signatures de funcions compatibles amb C. Els blocs extern "C" de Rust exposen funcions que C++ pot cridar directament, i viceversa. El repte crític sorgeix quan el temps d'execució de diversos fils de Rust necessita invocar codi C++ d'un sol fil de manera segura.

Ho hem resolt mitjançant una arquitectura dedicada:

  • Executor de C++ limitat a un fil: totes les trucades de C++ es canalitzen a través d'un únic fil dedicat mitjançant un canal de pas de missatges, assegurant-se que l'invariant d'un sol fil mai no es vulnera.
  • Capa pont aixíncron de Rust: les tasques de Tokio envien el treball a l'executor de C++ i esperen els resultats a través de canals d'un sol cop, mantenint el costat Rust totalment asíncron.
  • Gestió de punters opacs: els objectes C++ s'emboliquen en estructures Rust que implementen Drop per a una neteja determinista, evitant fuites de memòria a través del límit de l'idioma.
  • Serialització al límit: les estructures de dades complexes es serialitzen a FlatBuffers a la capa FFI, evitant la concordança d'estructura fràgil i permetent l'evolució independent de cada costat.
  • Aïllament del pànic: el catch_unwind de Rust embolcalla tots els punts d'entrada FFI de manera que un pànic mai traspassa el límit de l'idioma, cosa que seria un comportament indefinit.

Aquest patró ens va donar el rendiment de Rust multifil amb la fiabilitat de la lògica C++ provada, sense reescriure ni una sola línia de les regles comercials originals.

Quines són les trampes més grans que cal evitar?

L'error més perillós és suposar que el codi C++ és segur per a fils quan no ho és. L'estat global, les variables estàtiques i les trucades de biblioteques no reentrants provocaran curses de dades que el compilador de Rust no pot detectar a través del límit FFI. Les garanties de seguretat de Rust s'aturen al bloc insegur: tot el que hi ha dins és responsabilitat vostra.

Informació clau: Rust garanteix la seguretat de la memòria dins del seu propi codi, però en el moment que creueu un límit FFI cap a C++, hereteu tots els problemes de seguretat de fil que té C++. L'arquitectura al voltant d'aquest límit importa més que el codi a banda i banda.

💡 DID YOU KNOW?

Mewayz replaces 8+ business tools in one platform

CRM · Invoicing · HR · Projects · Booking · eCommerce · POS · Analytics. Free forever plan available.

Start Free →

Un altre error comú és la gestió de tota la vida. Els objectes C++ no participen en el verificador de préstecs de Rust. Si Rust deixa caure una referència mentre C++ encara té un punter, obteniu errors sense ús que són brutalment difícils de diagnosticar. Hem resolt això aplicant una semàntica de propietat estricta: els objectes C++ sempre són propietat d'un embolcall de Rust i l'accés compartit passa pel recompte de referències basades en Arc al costat de Rust.

En termes de rendiment, les trucades de FFI excessives generen sobrecàrrega a partir del canvi de context i la serialització. Fem lots d'operacions sempre que sigui possible, enviant una cua d'elements de treball a l'executor de C++ en lloc de fer trucades individuals en diversos idiomes.

Com va funcionar aquest enfocament a la producció?

Després de desplegar l'arquitectura híbrida a la nostra plataforma, vam mesurar millores concretes. El rendiment de les sol·licituds ha augmentat 3,4 vegades per als mòduls que abans es van coll d'ampolla en el processament seqüencial de C++. La latència de la cua (p99) va baixar un 61% perquè el temps d'execució asíncron de Rust podia processar sol·licituds independents simultàniament mentre que C++ gestionava tasques de càlcul pesat al seu fil dedicat.

Més important és que no vam tenir cap error relacionat amb la concurrència durant els primers sis mesos de producció. El patró de confinament de fils va fer estructuralment impossible que el codi C++ es cridés des de diversos fils, mentre que el sistema de tipus de Rust va impedir les curses de dades al seu costat del límit. Aquesta va suposar una millora significativa respecte al nostre enfocament anterior d'intentar afegir threading a C++ amb mutex, que havia produït tres incidents de condicions de carrera en un sol trimestre.

L'equip d'enginyeria també va informar de cicles d'iteració més ràpids. Es podrien crear noves funcions a Rust amb suport complet de concurrència, mentre que els mòduls C++ existents continuaven funcionant sense modificacions. Aquesta estratègia incremental va significar que mai no vam tenir una migració de "big bang" d'alt risc, només una millora constant i mesurable.

Preguntes més freqüents

El Rust pot trucar a biblioteques C++ d'un sol fil sense modificacions?

Sí, però us heu d'assegurar que totes les trucades a aquesta biblioteca es produeixin des d'un sol fil. El patró estàndard és crear un fil executor dedicat que serialitzi totes les trucades de C++ a través d'un canal. Les tasques asíncrones de Rust envien sol·licituds i esperen respostes sense bloquejar el temps d'execució multiprocés. El codi C++ en si no requereix canvis: la restricció de seguretat s'aplica completament al costat de Rust.

La sobrecàrrega FFI és prou significativa per afectar el rendiment de l'aplicació?

Les trucades FFI individuals tenen una sobrecàrrega mínima, normalment menys de 10 nanosegons per a una simple trucada de funció. Tanmateix, la serialització d'estructures de dades complexes i la sincronització de fils al límit s'acumulen si feu milers de trucades detallades. Les operacions per lots i l'ús de formats de serialització sense còpia com FlatBuffers o Cap'n Proto fan que la sobrecàrrega sigui insignificant fins i tot a escala.

Hem de reescriure la nostra base de codi C++ a Rust en lloc d'interfície?

Per a la majoria dels equips, la interfície incremental és el camí més segur i ràpid. Una reescriptura completa introdueix mesos de risc d'enginyeria sense cap valor per a l'usuari fins a la finalització. La interfície us permet enviar millores immediatament, validar l'enfocament Rust en producció i migrar els mòduls d'un en un segons on la concurrència produeix més impacte. Reescriu només els mòduls en què el cost de mantenir el límit FFI supera el cost de la reescriptura.


A Mewayz, construïm una infraestructura que s'escala, tant a nivell tècnic com operatiu. El nostre sistema operatiu empresarial de 207 mòduls ajuda a 138.000 equips a executar fluxos de treball més intel·ligents a partir de 19 dòlars al mes. Tant si estàs gestionant projectes, automatitzant operacions o ampliant el teu negoci, Mewayz s'adapta a la teva manera de treballar. Comenceu la vostra prova gratuïta a app.mewayz.com i vegeu què pot fer un sistema operatiu empresarial modern pel vostre equip.