Toti es articles

Multi-tenant dès deth prumèr dia: es decisions d'arquitectura darrèr de Lueira

Publicat Dec 7, 20234 min de lectura
  • Engenharia
  • Lueira
Multi-tenant dès deth prumèr dia: es decisions d'arquitectura darrèr de Lueira

Idèes clau

  • Eth multi-tenant s'a de dissenhar dès eth prumèr dia: apondre er isolament entre clients sus un esquèma e consultas ja existentas ei fòrça mès car.
  • Tria un solet mecanisme canonic entà identificar eth client en cada peticion e resòlve-lo ua soleta viatge ath bòrd, non consulta per consulta.
  • Defen-te des bugs de huta entre clients en mès d'ua capa: un abast per defècte a nivèu d'ORM mès ua restriccion de basa de dades o ua politica de row-level security.

Quan començàm a bastir Lueira eth març de 2023, era prumèra decision d'esquèma que prenguérem non èra sus resèrves, pagaments o calendaris. Èra sus clients (tenants). Lueira existís entà hèr córrer eth dia a dia d'escòles d'espòrt independentas —escòles d'esquí, centres de caiac e busseig, camps de surf— e dès eth principi sabíem qu'ac aubergerie a dotzenes ena madeisha plataforma, non ua escòla per despleiament. Ua escòla d'esquí ath Pirenèu e un centre de busseig enes Illas Canàrias acabarien per compartir era madeisha basa de dades, es madeishi servidors d'aplicacion e eth madeish còdi, sense poder véder jamès ne ua soleta resèrva que non siguesse era sua.

Aguesta restriccion sone evidenta quan la dides en votz nauta, mès cambie gaireben totes es decisions primerenques d'ua manèra aisida de sostaximar. Eth multi-tenant ei ua d'aqueres causes que ei barat d'incorporar dès eth prumèr dia e brutaument car d'apondre dempús, pr'amor que quan t'encuentres qu'ac as besonh, cada consulta, cada clau de caché e cada prètzhèt en dusau plan ja supausen un mon d'un solet client.

1. Per qué non pòs apondre er isolament mès tard

Era trapèla deth multi-tenant ei qu'ua aplicacion d'un solet client "foncione gaireben ben" quitament dempús de començar a apondre clients — enquia que dèishe de har-ac en silenci. Se non dissenhes er isolament dès eth principi, acabes apondent ua colomna school_id as tues taules fòrça dempús des hèts, e dempús encauçant cada consulta deth còdi entà assegurar-te que filtre per era. En un còdi damb centenats de consultas, auditar-les totes ara man en cèrca d'un filtre que manque non ei ua estrategia, ei ua esperança.

Ja ac explicàrem en ua entrada anteriora, quan lancèrem eth motor de resèrves de Lueira en junh de 2023, quant de valor gessec de mantier era logica de resèrves modulara en lòc de supausar es particularitats d'ua soleta escòla. Eth multi-tenant ei era continuacion naturau d'aguesta madeisha leçon: era modularitat que permet qu'ua escòla configure es sòns pròpris espòrts, prètzi e oraris ei era madeisha modularitat que permet ara plataforma de rasonar sus "entà quin client ei aguesta peticion" coma un concèpte de prumèra classa, en lòc d'ua ahegida tardana sus un molon creishent de logica de negòci.

2. Hèr passar era identitat deth client per cada peticion

Un còp acceptes qu'er isolament a d'èster dissenhat dès de laguens, era proprèra decision ei coma sap ua peticion a quin client apertie. I a quauques opcions estandard, e cada ua a un mòde de fracàs diferent:

  • Sosdomeni (aransport.lueira.com): intuitiu entath client finau, e hè qu'era identificacion deth client se passe ena capa d'encaminament abans que corre cap còdi dera aplicacion. Er inconvenient ei que liga era tua infraestructura ath DNS e as certificats wildcard, e ei incomòde entàs escòles que vòlen un domeni pròpri.
  • Capçalera o segment de rota: flexibla e agnostica d'infraestructura, mès trantsmet era responsabilitat de fixar aguesta capçalera corrèctament a cada client, includint eth tòn pròpri "frontend" e quinsevolh escrit intèrn qu'ua persona escríue de prèssa.
  • Claim deth JWT: eth client viatge laguens dera session autenticada, çò que vò díder que cap client non lo pòt oblidar, mès tanben vò díder qu'un bug d'autenticacion vie a èster un bug d'isolament entre clients: t'engànhes un solet còp damb eth claim e as balhat a quauqu'un un "token" que suplante ua auta escòla.

Cap d'aguestes opcions non ei estrictament "corrècta" en abstracte; era tria corrècta depen d'a on vòs qu'era superfícia de fracàs víue. Çò qu'impòrte mès que quina tries ei que tries exactament un mecanisme canonic, lo resòlves ua soleta viatge ath bòrd dera peticion, e passes er identificador de client resultant entà baish coma un valor explicit, en lòc de quauquarren qu'eth còdi de consulta age de reconstruir.

3. Eth bug qu'ei especiaument perilhós enes sistèmas multi-tenant

I a ua classa especifica de bug que gaireben non impòrte en ua aplicacion d'un solet client e qu'ei vertadèraments perilhós en ua multi-tenant: ua consulta qu'oblide filtrar per client. En un sistèma d'un solet client, oblidar ua clausula WHERE retorne tròp des tues pròpries dades. En un sistèma multi-tenant, retorne —o piri, actualize— es d'un aute.

// Perilhós: compile sense problèmas, passe era revision se digun non
// i pare atencion, e retorne en silenci es resèrves confirmadas de
// totes es escòles, non solet d'ua.
bookings, err := client.Booking.Query().
    Where(booking.StatusEQ("confirmed")).
    All(ctx)

En rasonant açò de manèra generau, era solucion non ei ua soleta salvaguarda, ei superpausar capas:

// Milhor: er abast de client ei incorporat en com construïsses era
// consulta, non quauquarren qu'age de te'n brembar apondre dessús.
bookings, err := tenantClient.Booking.Query().
    Where(booking.StatusEQ("confirmed")).
    All(ctx) // tenantClient ja pòrte incorporat er abast dera escòla
-- E ua barrèra a nivèu de basa de dades, entà que quitament ua
-- consulta que se saute complètament era capa d'aplicacion non
-- pòsque trauessar es limits de client.
CREATE POLICY tenant_isolation ON bookings
    USING (school_id = current_setting('app.current_tenant')::uuid);

Un abast per defècte a nivèu d'ORM atrape er error abans que se desplegue. Ua restriccion de basa de dades o ua politica de row-level security l'atrape se era prumèra capa se saute quauque còp. Cap des dues soleta non basta; vòs es dues, pr'amor qu'es dues capas fracassen de manèra independenta.

4. Infraestructura compartida sense bifurcar eth còdi

Er aute miei deth multi-tenant ei eth problèma contrari: balhar a cada escòla pro marge entà èster diferenta sense balhar-li un còdi diferent. Cada escòla en Lueira a era sua pròpria marca, era sua pròpria combinason d'espòrts, es sòns pròpris prètzi e es sòns pròpris oraris, mès totes corren sus eth madeish despleiament e era madeisha basa de dades. Ath moment en qué bifurques eth còdi "solet aguest còp" entà un client damb exigéncias pòc abituaus, as creat ua branca de manteniment qu'a de mantier-se sincronizada ara man entà sèmpre.

Era sortida ei tractar eth compòrtament especific de cada client coma configuracion e dades, non coma còdi: es espòrts disponibles d'ua escòla, es sues règles de prètzi e eth sòn orari víuen en taules qu'era plataforma liegís e interprète, non en condicionaus escampilhadi pera aplicacion.

Arren d'açò non demorèc complètament resolgut eth prumèr dia; ua part l'auem encertat per instint e ua auta l'auem calut corregir quan escòles reaus comencèren a emplegar Lueira era ua ath costat dera auta. Mès era decision de fons —qu'er isolament e era identitat avien d'èster decisions arquitectonicas e non detalhs d'implementacion— ei era de qué sò mès content de non auer ajornat.