Passa al contenuto principale
Strategia dei dati

Una guida per sviluppatori per scalare le Databricks Apps

Come mantenere l'app veloce e affidabile man mano che cresce l'utilizzo

di Bruno Tafur e Tushar Madan

  • La scalabilità delle Databricks Apps inizia prima di scrivere il codice: stabilisci la velocità di risposta desiderata e il numero di utenti da supportare nei momenti di massimo carico, quindi invia i carichi di lavoro pesanti al servizio giusto. Il compute delle app gestisce l'interfaccia utente e coordina le chiamate.
  • Un codice scalabile mantiene l'app reattiva in attesa dei servizi, sfrutta la memorizzazione nella cache per singolo utente e assicura che lo stato sia recuperabile. Lo stato volatile può essere rigenerato; lo stato persistente risiede nelle tabelle di Lakebase o Unity Catalog, così qualsiasi istanza può ricostruire una sessione.
  • Usa test di carico e telemetria per scegliere le dimensioni delle istanze, il numero di worker e il numero di istanze. Gestisci con attenzione le connessioni a Lakebase e aggiungi risorse di calcolo per soddisfare la domanda misurata e gli obiettivi di disponibilità.

Congratulazioni, hai creato un'app su Databricks Apps ed è passata da pochi utenti a centinaia o migliaia in tutta la tua organizzazione. I tuoi utenti vogliono che risponda rapidamente e rimanga attiva. E al tuo capo potrebbe non piacere dover pagare per risorse di calcolo XLarge su un insieme di istanze.

Come si crea un'app che funzioni velocemente, rimanga attiva e gestisca la crescente domanda? La risposta intuitiva è aumentare le risorse di calcolo, ma questo aiuta solo quando sai dove le richieste sprecano tempo e se l'app è strutturata per scalare: il suo framework, il codice asincrono e la capacità di essere eseguita su più istanze, in modo che la piattaforma possa scalarla facilmente in alto o in orizzontale.

In questa guida esaminiamo come scalare Databricks Apps attraverso quattro fasi: progettazione; sviluppo; test e distribuzione; e gestione (Figura 1). 

L'obiettivo di questa guida è principalmente focalizzato sulle prestazioni e sulla resilienza dell'applicazione su larga scala; non copre l'automazione della distribuzione o l'ottimizzazione delle prestazioni e il dimensionamento di altri servizi Databricks che potrebbero interagire con l'app.

image1.png

Figura 1: Quattro fasi di scalabilità di una Databricks App.

Le buone decisioni di scalabilità iniziano prima che venga scritto qualsiasi codice: concordate ciò di cui gli utenti hanno bisogno dall'app, quindi decidete dove verrà eseguito il carico di lavoro e dove risiederanno i dati.

Inizia con gli obiettivi: picchi di utenti e latenza

Prima di scegliere un'architettura, è utile stabilire quanta mole di lavoro l'app debba gestire e quale sia una buona esperienza utente. Suggeriamo di concordare due obiettivi principali:

  • Prestazioni: con che rapidità devono rispondere le azioni chiave? Consigliamo obiettivi di latenza end-to-end basati su un percentile, come il p95, che cattura le esperienze più lente che una media non mostrerebbe. Includi il rendering della UI e tratta gli avvi a freddo separatamente. Per le risposte AI in streaming, conta anche il tempo impiegato per il primo token.
  • Scalabilità: quanti utenti sono attivi durante i picchi, quanto spesso la usano e quale crescita dovrebbe supportare l'app? I periodi di intenso traffico come la fine del mese rientrano in questa stima perché è il carico che l'app deve gestire rispettando i suoi obiettivi di latenza e tasso di errore.

Accanto a questi, decidi quale lavoro deve sopravvivere a un riavvio e verifica che le dipendenze critiche possano supportarlo. Questo determina come suddividi lo stato e quante istanze esegui.

Successivamente, delinea alcuni percorsi utente, come l'apertura di una dashboard o l'invio di una domanda. Per ogni azione, annota i servizi che richiama, all'incirca quante chiamate effettua e quali dipendono l'una dall'altra, quanto velocemente dovrebbe completarsi e quanto possono essere obsoleti i dati memorizzati nella cache. Queste ipotesi definiscono l'architettura e i primi obiettivi di test. Una volta eseguito un prototipo, puoi misurare le chiamate reali e rivederle.

Immagina che un rivenditore offra ai suoi 2.000 store manager un'app per controllare le scorte, supportata da Lakebase. Durante l'ora più trafficata del Black Friday, 200 di loro la stanno usando contemporaneamente. Se ciascuno effettua in media due controlli delle scorte al minuto, si tratta di 400 controlli al minuto. Se ogni controllo esegue tre istruzioni SQL su Lakebase, aspettati 1.200 istruzioni al minuto, ovvero una media di 20 al secondo durante quell'ora.

Questo stima la frequenza delle query, non la concorrenza. Testa i picchi e la crescita, convalida rispetto all'utilizzo reale e pianifica il budget delle connessioni separatamente (vedi "Pianifica il budget delle connessioni a Lakebase").

Progettazione: pianifica l'architettura

Mantieni le risorse di calcolo dell'app dedicate alla gestione dell'app

Le risorse di calcolo dell'app servono a gestire la UI e a coordinare le chiamate, non a svolgere il lavoro pesante. Consigliamo di inviare ogni tipo di lavoro al servizio creato appositamente per esso (Figura 2). Per le chiamate di lunga durata, esegui il lavoro in background, ad esempio come un job, e consenti alla UI di verificare lo stato tramite polling o di ricevere aggiornamenti in streaming, anziché mantenere aperta una richiesta fino al suo completamento.

Se l'app deve eseguire codice che non controlla, come codice scritto dagli utenti o generato da un agente, non eseguirlo nell'app. Eseguilo in Databricks Sandbox, un ambiente isolato che può essere avviato da un'immagine personalizzata, in modo che l'utilizzo di CPU e memoria rimanga separato dalle istanze che servono gli utenti.

image4.png

Figura 2: Dove viene eseguito ciascun tipo di lavoro e dove risiede lo stato.

Pianifica la scalabilità e scegli un framework

Quando più persone usano la tua app, puoi aggiungere capacità in due modi: scalando verso l'alto (scalabilità verticale) passando a una dimensione di calcolo più grande, che offre a ogni istanza più CPU e memoria, oppure scalando verso l'esterno (scalabilità orizzontale) aggiungendo istanze per condividere il carico delle richieste. Con il lavoro pesante eseguito al di fuori dell'app, ciò che solitamente ne limita le capacità è il numero di richieste che può gestire contemporaneamente.

Ad esempio, nel caso del Black Friday, ogni controllo delle scorte è leggero, ma i controlli di 200 store manager possono arrivare insieme in picchi improvvisi. Più istanze distribuiscono tali richieste, e un'istanza più grande aiuta se l'app può utilizzare i core extra, in genere eseguendo più worker. Un'app che mantiene in memoria un grande set di dati di riferimento o un modello raggiunge un limite diverso. Un'istanza più grande le fornisce la memoria di cui ha bisogno; aggiungere istanze non aiuta, poiché ogni istanza carica la propria copia. Puoi iniziare su Medium e lasciare che il test di carico descritto più avanti in questa guida mostri di cosa hai bisogno.

Il framework è più difficile da cambiare in seguito, quindi vale la pena sceglierlo ora. Databricks Apps esegue app basate su Python o Node.js e non sei limitato ai framework seguenti. Per la maggior parte delle nuove app, consigliamo AppKit, l'SDK TypeScript che databricks apps init e le competenze degli agenti Databricks utilizzano per impostazione predefinita. Caching, telemetria, logica di tentativi e gestione degli errori sono integrati, offrendoti un punto di partenza per diverse pratiche descritte in questa guida. AppKit esegue un processo Node.js per istanza per impostazione predefinita, quindi il modo più semplice per scalare è aggiungere istanze.

Se possiedi già un'app o il tuo back-end richiede Python:

  • Front-end JavaScript con back-end API (FastAPI, Flask o Express): mantieni lo stato della UI nel browser e rendi lo stato lato server recuperabile tra worker e istanze. I back-end Python possono eseguire più worker per istanza, ad esempio con Uvicorn o Gunicorn. I back-end Node.js eseguono un processo per istanza per impostazione predefinita, quindi scalali aggiungendo istanze.
  • Framework Streamlit o Gradio: ottimi per strumenti di dati e AI creati rapidamente in Python. Streamlit viene eseguito come singolo processo egu entrambi dipendono dalla gestione delle sessioni a livello di istanza, quindi testa la continuità delle sessioni durante i riavvii e la scalabilità. Per le app che devono scalare tra istanze con un recupero trasparente, preferisci uno degli approcci precedenti poiché questi framework non sono consigliati.

Qualunque tu scelga, se mantiene lo stato della sessione nella memoria del server, vale la pena testare cosa succede quando una sessione si sposta su un'altra istanza prima di scalare.

Pianifica lo stato dell'applicazione che sopravvive ai riavvii e al ridimensionamento

La maggior parte delle Databricks Apps mantiene parte dello stato in memoria, e va bene finché sai quali parti puoi permetterti di perdere. Un primo passo utile è elencare ciò che ogni sessione contiene e ciò che deve sopravvivere a un riavvio, quindi dividerlo in stato leggero e stato pesante:

Cosa èStato leggeroStato pesanteCosa èDati di lavoro temporanei, conservati per velocità o contestoLa fonte di verità, conservata in modo durevoleEsempiContesto in memoria, cache, lavoro in corsoRegistri aziendali, checkpoint, preferenze salvateDove risiedeSolitamente memoria dell'istanza o disco locale, associato a una singola istanzaTabelle Lakebase o Unity Catalog, disponibili per ogni istanzaSe viene persoRicostruito dallo stato pesante quando possibileDeve sopravvivere a riavvii e guasti, in base alle esigenze di ripristino

Il funzionamento di questa divisione dipende dal tipo di app:

  • Agente AI: mantieni il contesto della conversazione, gli output degli strumenti e i piani nello stato leggero mentre il ciclo è in esecuzione e salva un checkpoint dopo ogni passaggio significativo.
  • App di flusso di lavoro: trasmetti in streaming o verifica tramite polling lo stato in corso sulla UI e salva ogni passaggio completato.
  • Dashboard: mantieni valori di filtri, elenchi di riferimento e piccoli set di dati in memoria e salva le preferenze utente e i filtri salvati come stato pesante.

image3.png

Figura 3: Quando una sessione si sposta, un'altra istanza può ricostruirla dallo stato pesante.

Databricks Apps mantiene ciascun utente sulla stessa istanza su base best-effort (affinità di sessione) e rebilancia le sessioni quando necessario, quindi qualsiasi cache per utente mantenuta localmente dalla tua app di solito rimane disponibile. Riavvii, guasti e modifiche di scalabilità possono comunque spostare una sessione, quindi un'altra istanza deve essere in grado di ricostruirla dallo stato pesante (Figura 3).

Sviluppo: scrivi codice che scala e sopravvive ai riavvii

Con gli obiettivi e un'architettura definiti, il passo successivo è scrivere codice che regga sotto carico, anche quando una sessione si sposta o un'istanza si arresta.

Strumenta l'app prima che ti serva

Consigliamo di attivare la telemetria fin dall'inizio, in modo che i dati siano disponibili prima di esserne effettivamente bisognosi. La telemetria dell'app scrive log, tracce e metriche nelle tabelle di Unity Catalog tramite OpenTelemetry. Una volta abilitata per un'app, i log arrivano automaticamente, ma tracce e metriche richiedono strumentazione.

Dovresti creare span personalizzati attorno alle chiamate SQL, di database, di modelli e API per mostrare dove viene impiegato il tempo. Registra anche le eccezioni intercettate sullo span, in modo che compaiano nelle tue tracce. Gli ID di traccia e di richiesta ti consentono quindi di seguire le richieste di un singolo utente attraverso le istanze. Ad esempio, uno span attorno a una chiamata SQL:

Usa codice async e riduci le chiamate superflue

La maggior parte delle app trascorre il proprio tempo in attesa di un altro servizio: una query SQL, la chiamata a un modello, un'API esterna. Con le chiamate bloccanti, ogni attesa occupa uno slot di esecuzione per l'intera chiamata. Un gruppo di chiamate lente può esaurire tale capacità. Ecco perché gli handler async sono importanti per il lavoro intensivo di I/O. Quando gli handler attendono chiamate a modelli e database, un worker può continuare a gestire altre richieste mentre attende, a patto che tali chiamate siano non bloccanti. Le tue tracce e le metriche di sistema mostreranno quando si applica questa condizione: se la maggior parte del tempo di una richiesta viene spesa in span SQL, di modelli o API, e la latenza aumenta con gli utenti concorrenti mentre la CPU rimane bassa, è probabile che le richieste siano in coda dietro chiamate bloccanti.

Anche con async, una richiesta può comunque essere lenta se esegue le sue query una dopo l'altra. Avvia query indipendenti insieme (ad esempio, con asyncio.gather o Promise.all), in modo che la richiesta impieghi un tempo vicino a quello della sua query più lenta. Conviene anche limitare quante ne vengono eseguite in parallelo, in modo che una singola richiesta non sovraccarichi il warehouse o il database. Spesso è meglio combinare le query piuttosto che eseguire query N+1, in cui l'app recupera un elenco e poi esegue un'ulteriore query per elemento: una clausola join o IN svolge lo stesso lavoro in una o due.

Memorizza i dati nella cache per utente per impostazione predefinita

Una cache velocizza un'app, ma può anche causare fughe di dati: una cache a livello di app non applica le autorizzazioni di Unity Catalog, quindi una cache condivisa può mostrare a un utente i dati di un altro. Definisci l'ambito delle chiavi della cache in base all'identità verificata dell'utente e ai parametri della query, e per sessione dove necessario; non basare mai la chiave su un'identità inviata dal client senza averla verificata. Condividi i dati memorizzati nella cache solo quando sono identici per tutti. Per le voci condivise lette contemporaneamente da molti utenti, consenti a una richiesta di aggiornare una voce scaduta mentre le altre attendono, in modo che non colpiscano tutte insieme il warehouse. La cache di AppKit, ad esempio, deduplica i cache miss concorrenti all'interno di ciascuna istanza.

In caso di riavvii del container dell'app o spostamenti di sessione

La messa in pratica della progettazione dello stato software e dello stato hardware si riduce ad alcune raccomandazioni:

  • Mantieni persistente tutto ciò che deve sopravvivere a un riavvio o a un deployment. La sola memoria va bene per le cache usa e getta, ma non per il lavoro che gli utenti non possono permettersi di perdere.
  • Crea checkpoint ovunque non vorresti ripetere il lavoro e rendi i passaggi idempotenti in modo che un nuovo tentativo sia sicuro.
  • Rendi le sessioni portabili, in modo che qualsiasi istanza possa ricostruirle dallo stato hardware (Figura 3). Ricarica solo ciò di cui hai bisogno e memorizzalo nella cache per evitare letture ripetute.
  • Le app per browser ottengono automaticamente l'affinità di sessione. Per i client API stateful, invia un header stabile X-Routing-Key e impostalo sulla chiave di ciò che possiede lo stato software. Scegli una chiave sufficientemente specifica da distribuire il carico, come una conversazione o un ID utente anziché un ID tenant. Il client imposta l'header, quindi usalo solo per il routing, mai per decidere chi sia l'utente.
  • Aspettati che anche le connessioni al database vengano interrotte. Si interrompono quando il database si riavvia o esegue il failover. Riconnettiti con backoff limitato e jitter, in modo che le istanze non si riconnettano tutte in una volta causando un picco di connessioni. Prima di riprovare una scrittura, controlla il database per confermare che non sia già andata a buon fine.
  • Mantieni l'avvio leggero. Ogni riavvio, deployment e nuova istanza paga il costo del caricamento di modelli o dataset, del riscaldamento delle cache e dell'apertura dei pool prima di poter gestire il traffico. Evita installazioni di grandi dimensioni e chiamate esterne bloccanti all'avvio, e carica le risorse pesanti solo quando necessario.

Arresta correttamente

Quando ridistribuisci un'app, Databricks invia SIGTERM, seguito da SIGKILL se l'app non si è chiusa entro 15 secondi. Quella finestra è riservata ai checkpoint finali. Il lavoro importante dovrebbe essere già stato salvato durante il normale funzionamento.

Ad esempio, con FastAPI, Uvicorn completa le richieste aperte prima di eseguire la pulizia della durata del ciclo di vita. save_in_progress_sessions() sostituisce la tua funzione che salva il lavoro non terminato:

Questo presuppone un pool async (ad esempio, AsyncConnectionPool di psycopg). Il tutorial Apps-to-Lakebase utilizza un pool sincrono, che chiudi senza await.

Imposta il parametro --timeout-graceful-shutdown di Uvicorn al di sotto dei 15 secondi (ad esempio, 10) in modo che una richiesta a esecuzione prolungata non consumi il tempo del checkpoint, e testa l'arresto con il tuo carico di lavoro. Il plugin Lakebase di AppKit chiude i suoi pool all'arresto; qualsiasi checkpoint personalizzato deve comunque rientrare nella stessa finestra.

Testa e distribuisci: test di carico e dimensionamento per il picco

image2.png

Figura 4: Metriche di sistema durante un test di carico a gradini: la latenza subisce un picco all'ultimo passaggio mentre CPU e memoria rimangono al di sotto dei loro limiti.

Prima del lancio, un test di carico ti aiuterà a trasformare le tue stime in decisioni più vicine alla realtà: la dimensione dell'istanza, i worker per istanza e il numero di istanze.

Come eseguire test di carico su Databricks Apps

Consigliamo di eseguire test di carico prima della produzione, utilizzando percorsi utente reali in base al picco previsto. Uno strumento come Locust riporta le richieste al secondo, i percentili di latenza e il tasso di errore a ogni passaggio, e il test viene superato o fallito in base agli obiettivi di latenza e tasso di errore concordati per le azioni chiave. Durante l'esecuzione del test, le metriche di sistema integrate dell'app mostrano le richieste al minuto, la latenza, la CPU e la memoria rispetto ai rispettivi limiti, consentendoti di vedere quale limite l'app raggiunge per primo (Figura 4).

Aumenta gradualmente gli utenti concorrenti in passaggi successivi finché il throughput smette di aumentare o la latenza e i tassi di errore superano i tuoi obiettivi. Conviene provare diverse dimensioni di istanza e numeri di worker, perché una configurazione più grande non è sempre più veloce. Suggeriamo anche di testare il ripristino in un ambiente di test: arresta e avvia l'app, senza limitarti a ridistribuirla o a modificare il numero di istanze durante un'esecuzione, quindi verifica se gli utenti possono continuare, quanto tempo richiede il ripristino e se è andato perso del lavoro. Per le app con agenti, la guida ai test di carico illustra come eseguire il test prima con un LLM mockato per misurare il throughput dell'app stessa, e poi con il modello reale per la latenza end-to-end.

Il generatore di carico stesso può rappresentare il collo di bottiglia: può esaurire prima la CPU o le connessioni, e gli errori di autenticazione o le risposte di limitazione della frequenza possono sembrare rallentamenti. Ciò che conta sono le richieste riuscite e continuative entro l'obiettivo di latenza, non un breve picco.

Il test di carico dovrebbe anche mostrare se i servizi dietro l'app riescono a tenere il passo. Se il warehouse inizia a mettere in coda le richieste o un endpoint di modello applica la limitazione (throttling), scala quel servizio, non l'app.

Scegli la dimensione dell'istanza

Databricks Apps offre tre dimensioni: Medium (predefinita, fino a 2 vCPU e 6 GB), Large (fino a 4 vCPU, 12 GB) e XLarge (fino a 12 vCPU, 48 GB). Quella giusta dipende da quale limite la tua app raggiunge per prima, quindi inizia con Medium e lascia che il test di carico ti mostri quale scegliere:

Cosa mostra il test di caricoCausa probabileCosa fare
Richieste lente con CPU dell'app bassaL'app è in attesa di qualcosa a monte o a valle, oppure le chiamate bloccanti stanno occupando i workerMantieni le dimensioni. Correggi prima la query, il warehouse, il pool di connessioni o le chiamate bloccanti e controlla anche la CPU per singolo processo: un singolo core al massimo può sembrare una CPU bassa in generale
CPU vicina al limite, il server esegue diversi worker (ad esempio, FastAPI con Uvicorn)L'app può utilizzare più corePassa a Large
CPU vicina al limite, app a singolo processo (Streamlit o AppKit per impostazione predefinita)La profilazione mostra il carico di lavoro associato a un solo coreAggiungi istanze. Dimensioni maggiori aiutano solo se l'app può sfruttare core extra, ad esempio tramite thread worker o librerie native
Memoria vicina al limiteGrandi dataset o modelli mantenuti in memoriaAumenta le dimensioni per la memoria: Large raddoppia Medium, XLarge offre 48 GB in una singola istanza
Test di ripristino: l'app si interrompe quando si riavvia la sua unica istanzaNessuna istanza di riserva per subentrareAggiungi istanze, non una dimensione maggiore

Quanti worker deve eseguire ciascuna istanza?

I worker sono processi server all'interno di ogni istanza. Per i server Python che supportano questo modello, imposti il conteggio all'avvio (ad esempio, uvicorn --workers 2), e si applica per singola istanza.

Un singolo worker può lasciare la CPU inattiva, ma worker extra competono anche per la CPU e la memoria. Nel benchmark della nostra guida ai test di carico, Medium ha ottenuto risultati migliori con due worker rispetto a quattro, e Large ha offerto circa 2,2 volte il throughput di Medium. Considera i punti di partenza documentati, due worker su Medium o otto su Large, come una stima iniziale: il benchmark simulava l'LLM ed era limitato dalla CPU, e un'app reale che attende principalmente le chiamate ai model potrebbe trarre maggiori vantaggi da worker extra. Scegli il conteggio dal tuo test di carico, con il model reale.

Quante istanze deve eseguire l'app?

Con l'horizontal scaling, imposti tu stesso il conteggio delle istanze. Il limite predefinito è cinque istanze per app, e il tuo referente Databricks può aumentarlo se i test di carico dimostrano che te ne servono di più. Dimensiona il conteggio in base ai picchi previsti e alla crescita. L'app continua a rispondere mentre il conteggio cambia e il costo di calcolo scala linearmente con il numero di istanze. Se stai convertendo un'app esistente, provala prima su un duplicato.

Per una maggiore disponibilità, consigliamo almeno due istanze, con capacità sufficiente per gestire il carico di picco dopo la perdita di una: se il picco richiede due istanze, eseguine tre. Le istanze extra proteggono dal guasto di un'istanza, non dai problemi nei servizi dietro l'app.

Dimensiona il budget per le connessioni a Lakebase

Per una Databricks App che si connette a Lakebase con OAuth, consigliamo di iniziare con un pool di connessioni lato app sulla stringa di connessione standard del database (non PgBouncer). Riutilizza le connessioni e recupera nuove credenziali OAuth man mano che ne apre di nuove, come mostra il tutorial su Apps-to-Lakebase per Python. Imposta il timeout del pool in modo da lasciare abbastanza tempo per la query stessa prima della scadenza della richiesta.

Queste connessioni si sommano, quindi calcola il budget prima di aggiungere istanze o worker. Con un pool per worker, il limite superiore è istanze × worker per istanza × dimensione massima del pool: cinque istanze con otto worker e un pool massimo di dieci possono aprire fino a 400 connessioni. Aggiungi altri client e qualsiasi connessione aperta dall'app per conto degli utenti, quindi confronta il totale con il limite documentato del database, lasciando un margine per le distribuzioni, quando le versioni vecchie e nuove vengono eseguite fianco a fianco.

Le query per conto dell'utente (OBO) richiedono capacità di identità. Ciò significa che ogni utente che esegue query su Lakebase come se stesso ha bisogno del proprio ruolo Postgres, e Lakebase consente 500 ruoli per branch. Per basi di utenti più ampie, decidi in anticipo quali query richiedono effettivamente l'accesso per utente. L'aggiunta di istanze non modifica questo limite. Laddove le autorizzazioni a livello di gruppo sono sufficienti, un ruolo Postgres per un gruppo Databricks consente ai suoi membri di connettersi con i propri token OAuth, in modo che un unico ruolo copra l'intero gruppo.

Distribuisci senza tempi di inattività e ripristina in sicurezza

Per le app con scalabilità orizzontale, Databricks aggiorna prima un'istanza e le altre dopo che la prima ha avuto successo, in modo che l'app continui a funzionare. Conviene comunque verificare dopo ogni distribuzione che l'app sia integra e che le sessioni si ripristinino. Mantenere il codice in Git significa poter effettuare il rollback ridistribuendo un tag o un commit noto e funzionante. Durante una distribuzione, le versioni vecchie e nuove vengono eseguite fianco a fianco, quindi mantieni i formati di database e checkpoint leggibili da entrambi e non rimuovere i campi di cui la versione precedente ha bisogno finché non sei sicuro di non dover effettuare il rollback.

Funzionamento: monitoraggio, diagnosi e risoluzione basati sui dati

Dopo il lancio, il lavoro diventa un ciclo: trova il passaggio più lento, correggilo e misura di nuovo. Ecco perché manteniamo la telemetria attiva in produzione. Nelle app con scalabilità orizzontale, la visualizzazione Live nella scheda Logs mostra un'istanza alla volta; con la telemetria abilitata, App Telemetry Logs le mostra tutte.

Quando qualcosa è lento, traccia la richiesta end-to-end (Figura 5).

image5.png

Figura 5: Dove una richiesta impiega il suo tempo e i principali colli di bottiglia.

Inizia dal sintomo

Questi sono i sintomi che riscontriamo più spesso e a cosa solitamente fanno riferimento:

SintomoDove cercareCausa probabileCosa fare
Prima richiesta lenta dopo un periodo di inattività o una distribuzioneScheda Insights, metriche di sistema e tracce nella telemetria dell'appAvvio a freddo: avvio dell'app o servizio che si riattiva dopo l'inattivitàControlla il tempo di avvio dell'app e se Lakebase o il SQL warehouse si fermano quando sono inattivi, e mantieni leggero l'avvio
Richieste lente con CPU dell'app bassaScheda Insights, metriche di sistema e tracce nella telemetria dell'appL'app è in attesa di qualcosa a monte o a valle, oppure le chiamate bloccanti stanno occupando i worker

Controlla le tracce per ritardi di query, warehouse o pool di connessioni prima di aggiungere risorse di calcolo all'app

Per le app a singolo processo, considera che una CPU complessiva bassa può comunque significare che un core è al massimo

CPU o memoria dell'app vicine al limiteScheda Insights, metriche di sistemaL'app stessa è il collo di bottiglia o trattiene troppi dati in memoriaEffettua il profilo del lavoro intensivo per la CPU, sposta lo stato di grandi dimensioni fuori dalla memoria, quindi consulta la guida in "Scegli la dimensione dell'istanza"
Timeout in attesa di una connessione al databaseLog dell'app e metriche di LakebaseContesa del pool, transazioni lunghe o limiti di connessione del databaseIspeziona l'utilizzo delle connessioni e la durata delle transazioni, quindi regola i pool o la capacità del database entro il budget di connessione
Gli utenti perdono il lavoro o visualizzano errori durante le distribuzioni o il ridimensionamentoScheda Insights, metriche di sistemaStato software che non può essere ricostruito o arresto che non si completa entro 15 secondiCrea checkpoint del lavoro importante, rendi le sessioni ricostruibili su qualsiasi istanza e testa l'arresto con le tue richieste e flussi reali

Configura gli avvisi di integrità

Consigliamo di pianificare gli avvisi come parte della configurazione: decidi chi viene avvisato quando l'app si interrompe e invia app_status.state e compute_status.state dalle API delle app al tuo strumento di monitoraggio. Lo stato dell'app da solo non dimostra che gli utenti possano lavorare, quindi controlla anche un percorso utente rappresentativo, con la sua latenza e i tassi di errore. Tieni conto di brevi variazioni di stato durante le distribuzioni quando imposti le soglie.

Riepilogo

Scalare le Databricks Apps significa dimensionare l'intero percorso della richiesta, non solo il server dell'app: imposta obiettivi di latenza e carico di picco, invia il lavoro pesante al servizio creato appositamente, mantieni lo stato recuperabile e lascia che i test di carico e la telemetria decidano dove indirizzare la capacità. Aggiungi risorse di calcolo quando le misurazioni mostrano che ne hai bisogno, non come prima reazione.

Per approfondire, leggi come creare app di dati e AI pronte per la produzione con Databricks Apps e Lakebase. Per ulteriori dettagli, consulta Best practices for Databricks Apps e Logging and Monitoring for Databricks Apps nella documentazione. Per i pattern architetturali per tipo di app, come strumenti interni, AI copilot e flussi di lavoro agentici, guarda Building Better Apps e Stateful Apps for Thousands of Users dal Data + AI Summit 2026.

FAQ

Come faccio a scalare una Databricks App?

Scalala in quattro fasi: progettazione, creazione, test e distribuzione, e funzionamento. Imposta prima gli obiettivi di latenza e carico di picco, mantieni le risorse di calcolo dell'app per servire l'interfaccia utente e scrivi codice asincrono con stato recuperabile. Quindi lascia che i test di carico e la telemetria decidano se passare a un'istanza più grande o aggiungere più istanze.

Dovrei scalare verso l'alto (scale up) o verso l'esterno (scale out) la mia Databricks App?

Dipende da quale limite l'app raggiunge per prima. Esegui lo scale-out aggiungendo istanze quando le richieste arrivano in picchi o un'app a singolo processo è limitata a un solo core. Esegui lo scale-up a Large o XLarge quando l'app ha bisogno di più memoria o quando esegue diversi worker che possono usare core extra.

Quali dimensioni di istanza offre Databricks Apps?

Databricks Apps offre Medium (predefinita, fino a 2 vCPU e 6 GB), Large (fino a 4 vCPU e 12 GB) e XLarge (fino a 12 vCPU e 48 GB). Inizia con Medium e lascia che un test di carico mostri di quale dimensione ha bisogno la tua app.

Come posso mantenere attive le sessioni utente quando un'app viene riavviata o ridimensionata?

Suddividi lo stato della sessione in soft state, che può essere ricostruito, e hard state, che viene memorizzato in modo persistente in tabelle Lakebase o Unity Catalog. Databricks Apps fa il possibile per mantenere ciascun utente sulla stessa istanza, ma i riavvii e il ridimensionamento possono comunque spostare una sessione, quindi qualsiasi istanza deve essere in grado di ricostruirla dall'hard state.

Quante connessioni a Lakebase può aprire un'app scalata?

Con un pool per worker, il limite superiore è istanze × worker per istanza × dimensione massima del pool. Ad esempio, cinque istanze con otto worker e un pool massimo di dieci possono aprire fino a 400 connessioni. Confronta questo totale con il limite documentato del database e lascia un margine per i rilasci.

Pronto a passare da pochi utenti a migliaia? Consulta le Best practices for Databricks Apps e lo horizontal scaling for Databricks Apps nella documentazione.

"Esplora Databricks Apps" →

(Questo post sul blog è stato tradotto utilizzando strumenti basati sull'intelligenza artificiale) Post originale

Tag correlati:

Best practice

Ricevi gli ultimi articoli nella tua casella di posta

Iscriviti al nostro blog e ricevi gli ultimi articoli direttamente nella tua casella di posta.