Questo articolo fornisce indicazioni per ottimizzare la scalabilità e le prestazioni quando si usano Hub eventi di Azure e Funzioni di Azure insieme nelle applicazioni.
Raggruppamento di funzioni
In genere, una funzione incapsula un'unità di lavoro in un flusso di elaborazione eventi. Ad esempio, una funzione può trasformare un evento in una nuova struttura di dati o arricchire i dati per le applicazioni downstream.
In Funzioni un'app per le funzioni fornisce il contesto di esecuzione per le funzioni. I comportamenti dell'app per le funzioni si applicano a tutte le funzioni ospitate dall'app per le funzioni. Le funzioni in un'app per le funzioni vengono distribuite insieme e ridimensionate insieme. Tutte le funzioni in un'app per le funzioni devono condividere lo stesso linguaggio.
Il modo in cui si raggruppano le funzioni nelle app per le funzioni può influire sulle funzionalità di prestazioni e ridimensionamento delle app per le funzioni. È possibile raggruppare in base ai diritti di accesso, alla distribuzione e ai modelli di utilizzo che richiamano il codice.
Per indicazioni sulle procedure consigliate per le funzioni per il raggruppamento e altri aspetti, vedere Procedure consigliate per l'Funzioni di Azure affidabile e Migliorare le prestazioni e l'affidabilità di Funzioni di Azure.
L'elenco seguente include indicazioni per il raggruppamento delle funzioni. Le linee guida considerano gli aspetti relativi all'archiviazione e al gruppo di consumer:
Ospitare una singola funzione in un'app per le funzioni: se Hub eventi attiva una funzione, è possibile, per ridurre i conflitti tra tale funzione e altre funzioni, isolare la funzione nella propria app per le funzioni. L'isolamento è particolarmente importante se le altre funzioni sono a elevato utilizzo di CPU o memoria. Questa tecnica è utile perché ogni funzione ha un proprio footprint di memoria e modelli di utilizzo che possono influire direttamente sul ridimensionamento dell'app per le funzioni che lo ospita.
Assegnare a ogni app per le funzioni il proprio account di archiviazione: evitare di condividere gli account di archiviazione tra le app per le funzioni. Inoltre, se un'app per le funzioni usa un account di archiviazione, non usare tale account per altre operazioni di archiviazione o esigenze. Può essere particolarmente importante evitare di condividere gli account di archiviazione per le funzioni attivate da Hub eventi, perché tali funzioni possono avere un volume elevato di transazioni di archiviazione a causa del checkpoint.
Creare un gruppo di consumer dedicato per ogni app per le funzioni: un gruppo di consumer è una visualizzazione di un hub eventi. I diversi gruppi di consumer hanno visualizzazioni diverse, il che significa che gli stati, le posizioni e gli offset possono differire. I gruppi di consumer consentono a più applicazioni di utilizzare di avere visualizzazioni personalizzate del flusso di eventi e di leggere il flusso in modo indipendente in base al proprio ritmo e con i propri offset. Per altre informazioni sui gruppi di consumer, vedere Funzionalità e terminologia in Hub eventi di Azure.
A un gruppo di consumer sono associate una o più applicazioni consumer e un'applicazione consumer può usare uno o più gruppi di consumer. In una soluzione di elaborazione dei flussi ogni applicazione consumer equivale a un gruppo di consumer. Un'app per le funzioni è un esempio principale di un'applicazione consumer. Il diagramma seguente fornisce un esempio di due app per le funzioni che leggono da un hub eventi, in cui ogni app ha un proprio gruppo di consumer dedicato:
Non condividere gruppi di consumer tra le app per le funzioni e altre applicazioni consumer. Ogni app per le funzioni deve essere un'applicazione distinta con un proprio gruppo di consumer assegnato per garantire l'integrità offset per ogni consumer e semplificare le dipendenze in un'architettura di streaming di eventi. Una configurazione di questo tipo, oltre a fornire a ogni funzione attivata dall'hub eventi la propria app per le funzioni e l'account di archiviazione, consente di impostare le basi per prestazioni e scalabilità ottimali.
Piani di hosting delle funzioni
Sono disponibili diverse opzioni di hosting per le app per le funzioni ed è importante esaminarne le funzionalità. Per informazioni su queste opzioni di hosting, vedere Funzioni di Azure opzioni di hosting. Prendere nota della scalabilità delle opzioni.
Il piano a consumo è l'impostazione predefinita. Le app per le funzioni nel piano a consumo vengono ridimensionate in modo indipendente e sono più efficaci quando evitano attività a esecuzione prolungata.
I piani Premium e Dedicato vengono spesso usati per ospitare più app per le funzioni e funzioni che richiedono un utilizzo maggiore di CPU e memoria. Con il piano dedicato, si eseguono le funzioni in un piano di servizio app Azure a tariffe regolari servizio app piano. È importante notare che tutte le app per le funzioni in questi piani condividono le risorse allocate al piano. Se le funzioni hanno profili di carico o requisiti univoci diversi, è consigliabile ospitarli in piani diversi, soprattutto nelle applicazioni di elaborazione dei flussi.
App Azure Container offre supporto integrato per lo sviluppo, la distribuzione e la gestione di app per le funzioni in contenitori in Funzioni di Azure. In questo modo è possibile eseguire le funzioni guidate dagli eventi in un ambiente basato su Kubernetes completamente gestito con supporto predefinito per il monitoraggio open source, mTLS, Dapr e KEDA.
Ridimensionamento di Hub eventi
Quando si distribuisce uno spazio dei nomi di Hub eventi, è necessario impostare correttamente diverse impostazioni importanti per garantire prestazioni e scalabilità ottimali. Questa sezione è incentrata sul livello Standard di Hub eventi e sulle funzionalità univoche di tale livello che influiscono sul ridimensionamento quando si usano anche Funzioni. Per altre informazioni sui livelli di Hub eventi, vedere Livelli Basic e Standard rispetto a Premium e Dedicati.
Uno spazio dei nomi di Hub eventi corrisponde a un cluster Kafka. Per informazioni sulla correlazione tra Hub eventi e Kafka, vedere Che cos'è Hub eventi di Azure per Apache Kafka.
Informazioni sulle unità elaborate (UR)
Nel livello Standard di Hub eventi la velocità effettiva viene classificata come quantità di dati immessi e letti dallo spazio dei nomi per unità di tempo. Le unità elaborate sono unità di capacità pre-acquistate.
Le UR vengono fatturate su base oraria.
Tutti gli hub eventi in uno spazio dei nomi condividono le UR. Per calcolare correttamente le esigenze di capacità, è necessario considerare tutte le applicazioni e i servizi, sia gli editori che i consumer. Le funzioni influiscono sul numero di byte ed eventi pubblicati in e letti da un hub eventi.
L'enfasi per determinare il numero di UR è sul punto di ingresso. Tuttavia, l'aggregazione per le applicazioni consumer, inclusa la frequenza di elaborazione di tali eventi, deve essere inclusa anche nel calcolo.
Per altre informazioni sulle unità elaborate di Hub eventi, vedere Unità elaborate.
Aumentare le prestazioni con aumento automatico
L'aumento automatico può essere abilitato in uno spazio dei nomi di Hub eventi per gestire situazioni in cui il carico supera il numero configurato di UR. L'uso dell'aumento automatico impedisce la limitazione della limitazione dell'applicazione e garantisce che l'elaborazione, inclusa l'inserimento di eventi, continui senza interruzioni. Poiché l'impostazione del TU influisce sui costi, l'uso dell'aumento automatico consente di risolvere i problemi relativi all'overprovisioning.
L'aumento automatico è una funzionalità di Hub eventi spesso confusa con la scalabilità automatica, soprattutto nel contesto delle soluzioni serverless. Tuttavia, l'aumento automatico, a differenza della scalabilità automatica, non aumenta quando la capacità aggiunta non è più necessaria.
Se l'applicazione necessita di capacità superiore al numero massimo consentito di unità elaborate, prendere in considerazione l'uso del livello Premium di Hub eventi o del livello Dedicato.
Partizioni e funzioni simultanee
Quando viene creato un hub eventi, è necessario specificare il numero di partizioni . Il numero di partizioni rimane fisso e non può essere modificato ad eccezione dei livelli Premium e Dedicato. Quando Hub eventi attiva le app per le funzioni, è possibile che il numero di istanze simultanee sia uguale al numero di partizioni.
Nei piani di hosting a consumo e Premium, le istanze dell'app per le funzioni aumentano in modo dinamico per soddisfare il numero di partizioni, se necessario. Il piano di hosting dedicato esegue funzioni in un piano di servizio app e richiede di configurare manualmente le istanze o configurare uno schema di scalabilità automatica. Per altre informazioni, vedere Piani di hosting dedicati per Funzioni di Azure.
In definitiva, una relazione uno-a-uno tra il numero di partizioni e istanze di funzione, o consumer, è la destinazione ideale per la velocità effettiva massima in una soluzione di elaborazione del flusso. Per ottenere un parallelismo ottimale, avere più consumer in un gruppo di consumer. Per Funzioni, questo obiettivo si traduce in molte istanze di una funzione nel piano. Il risultato viene definito parallelismo a livello di partizione o il grado massimo di parallelismo, come illustrato nel diagramma seguente:
Potrebbe sembrare opportuno configurare il maggior numero possibile di partizioni per ottenere la velocità effettiva massima e tenere conto della possibilità di un volume maggiore di eventi. Esistono tuttavia diversi fattori importanti da considerare quando si configurano molte partizioni:
- Più partizioni possono portare a una maggiore velocità effettiva: poiché il grado di parallelismo è il numero di consumer (istanze di funzione), maggiore è il numero di partizioni presenti, maggiore è la velocità effettiva simultanea. Questo fatto è importante quando si condivide un numero designato di UR per un hub eventi con altre applicazioni consumer.
- Altre funzioni possono richiedere più memoria: man mano che aumenta il numero di istanze di funzione, il footprint di memoria delle risorse nel piano. A un certo punto, troppe partizioni possono peggiorare le prestazioni per i consumer.
- C'è un rischio di back pressure dai servizi downstream: man mano che viene generata una maggiore velocità effettiva, si rischia di sovraccaricare i servizi downstream o di ricevere un sovraccarico da tali servizi. Il fan-out dei consumatori deve essere tenuto conto quando si considerano le conseguenze per le risorse circostanti. Le possibili conseguenze includono la limitazione da altri servizi, la saturazione della rete e altre forme di contesa delle risorse.
- Le partizioni possono essere popolate in modo sparse: la combinazione di molte partizioni e un volume ridotto di eventi può portare a dati distribuiti in modo sparse tra le partizioni. Al contrario, un numero minore di partizioni può offrire prestazioni migliori e un utilizzo delle risorse.
Disponibilità e coerenza
Quando non è specificata una chiave di partizione o un ID, Hub eventi instrada un evento in ingresso alla partizione disponibile successiva. Questa procedura offre disponibilità elevata e consente di aumentare la velocità effettiva per i consumer.
Quando è necessario ordinare un set di eventi, il producer di eventi può specificare che una determinata partizione deve essere utilizzata per tutti gli eventi del set. L'applicazione consumer che legge dalla partizione riceve gli eventi in ordine corretto. Questo compromesso garantisce coerenza, ma compromette la disponibilità. Non usare questo approccio a meno che non sia necessario mantenere l'ordine degli eventi.
Per Funzioni, l'ordinamento viene ottenuto quando gli eventi vengono pubblicati in una determinata partizione e una funzione attivata da Hub eventi ottiene un lease alla stessa partizione. Attualmente, la possibilità di configurare una partizione con l'associazione di output di Hub eventi non è supportata. L'approccio migliore consiste invece nell'usare uno degli SDK di Hub eventi per pubblicare in una partizione specifica.
Per altre informazioni su come Hub eventi supporta la disponibilità e la coerenza, vedere Disponibilità e coerenza in Hub eventi.
Trigger per Hub eventi
Questa sezione è incentrata sulle impostazioni e sulle considerazioni per l'ottimizzazione delle funzioni attivate da Hub eventi. I fattori includono l'elaborazione batch, il campionamento e le funzionalità correlate che influenzano il comportamento di un'associazione di trigger dell'hub eventi.
Invio in batch per le funzioni attivate
È possibile configurare le funzioni attivate da un hub eventi per elaborare un batch di eventi o un evento alla volta. L'elaborazione di un batch di eventi può essere più efficiente quando riduce il sovraccarico delle chiamate di funzione. A meno che non sia necessario elaborare solo un singolo evento, la funzione deve essere configurata per elaborare più eventi quando viene richiamato.
L'abilitazione dell'invio in batch per l'associazione di trigger di Hub eventi varia in base alle lingue seguenti:
- JavaScript, Python e altri linguaggi consentono l'invio in batch quando la proprietà di cardinalità è impostata su molti nel file function.json per la funzione.
- In C# la cardinalità viene configurata automaticamente quando viene designata una matrice per il tipo nell'attributo EventHubTrigger .
Per altre informazioni sull'abilitazione dell'invio in batch, vedere trigger Hub eventi di Azure per Funzioni di Azure.
Impostazioni di trigger
Diverse impostazioni di configurazione nel file host.json svolgono un ruolo chiave nelle caratteristiche delle prestazioni dell'associazione di trigger di Hub eventi per Funzioni:
- maxEventBatchSize: questa impostazione rappresenta il numero massimo di eventi che la funzione può ricevere quando viene richiamata. Se il numero di eventi ricevuti è minore di questo importo, la funzione viene comunque richiamata con il numero di eventi disponibili. Non è possibile impostare una dimensione minima del batch.
- prefetchCount: il conteggio dei prelettura è una delle impostazioni più importanti quando si ottimizzano le prestazioni. Il canale AMQP sottostante fa riferimento a questo valore per determinare il numero di messaggi da recuperare e memorizzare nella cache per il client. Il numero di prelettura deve essere maggiore o uguale al valore maxEventBatchSize ed è in genere impostato su un multiplo di tale importo. L'impostazione di questo valore su un numero minore dell'impostazione maxEventBatchSize può compromettere le prestazioni.
- batchCheckpointFrequency: quando la funzione elabora i batch, questo valore determina la frequenza con cui vengono creati i checkpoint. Il valore predefinito è 1, il che significa che è presente un checkpoint ogni volta che una funzione elabora correttamente un singolo batch. Viene creato un checkpoint a livello di partizione per ogni lettore nel gruppo di consumer. Per informazioni su come questa impostazione influisce sulle riproduzioni e i tentativi di eventi, vedere Funzione di Azure attivata dall'hub eventi: Riesecuzioni e tentativi (post di blog).
Eseguire diversi test delle prestazioni per determinare i valori da impostare per l'associazione di trigger. È consigliabile modificare le impostazioni in modo incrementale e misurare in modo coerente per ottimizzare queste opzioni. I valori predefiniti sono un punto di partenza ragionevole per la maggior parte delle soluzioni di elaborazione degli eventi.
Checkpoint
I checkpoint contrassegnano o eseguono il commit delle posizioni del lettore in una sequenza di eventi di partizione. È responsabilità dell'host di Funzioni eseguire il checkpoint quando vengono elaborati gli eventi e viene soddisfatta l'impostazione per la frequenza del checkpoint batch. Per altre informazioni sul checkpoint, vedere Funzionalità e terminologia in Hub eventi di Azure.
I concetti seguenti consentono di comprendere la relazione tra il checkpoint e il modo in cui la funzione elabora gli eventi:
- Le eccezioni continuano a essere considerate riuscite: se il processo della funzione non si arresta in modo anomalo durante l'elaborazione degli eventi, il completamento della funzione viene considerato riuscito, anche se si sono verificate eccezioni. Al termine della funzione, l'host di Funzioni valuta batchCheckpointFrequency. Se è il momento di un checkpoint, ne crea uno, indipendentemente dal fatto che ci siano eccezioni. Il fatto che le eccezioni non influiscano sul checkpoint non dovrebbero influire sull'uso corretto del controllo e della gestione delle eccezioni.
- Frequenza batch importante: nelle soluzioni di streaming di eventi con volume elevato, può essere utile modificare l'impostazione batchCheckpointFrequency su un valore maggiore di 1. L'aumento di questo valore può ridurre la frequenza di creazione del checkpoint e, di conseguenza, il numero di operazioni di I/O di archiviazione.
- Le riproduzioni possono verificarsi: ogni volta che viene richiamata una funzione con l'associazione di trigger di Hub eventi, usa il checkpoint più recente per determinare dove riprendere l'elaborazione. L'offset per ogni consumer viene salvato a livello di partizione per ogni gruppo di consumer. Le riproduzioni si verificano quando non si verifica un checkpoint durante l'ultima chiamata della funzione e la funzione viene richiamata di nuovo. Per altre informazioni sulle tecniche di duplicazione e duplicati, vedere Idempotency.
La comprensione del checkpoint diventa fondamentale quando si considerano le procedure consigliate per la gestione degli errori e i tentativi, un argomento descritto più avanti in questo articolo.
Campionamento dei dati di telemetria
Funzioni offre il supporto predefinito per Application Insights, un'estensione di Monitoraggio di Azure che offre funzionalità di monitoraggio delle prestazioni delle applicazioni. Con questa funzionalità è possibile registrare informazioni sulle attività di funzione, sulle prestazioni, sulle eccezioni di runtime e altro ancora. Per maggiori informazioni, consultare la sezione Panoramica di Application Insights.
Questa potente funzionalità offre alcune scelte di configurazione chiave che influiscono sulle prestazioni. Alcune delle impostazioni e considerazioni rilevanti per il monitoraggio e le prestazioni sono:
- Abilitare il campionamento dei dati di telemetria: per scenari con velocità effettiva elevata, è consigliabile valutare la quantità di dati di telemetria e informazioni necessarie. Provare a usare la funzionalità di campionamento dei dati di telemetria in Application Insights per evitare di ridurre le prestazioni della funzione con dati di telemetria e metriche non necessari.
- Configurare le impostazioni di aggregazione: esaminare e configurare la frequenza di aggregazione e invio di dati ad Application Insights. Questa impostazione di configurazione si trova nel file host.json insieme a molte altre opzioni correlate al campionamento e alla registrazione. Per altre informazioni, vedere Configurare l'aggregatore.
- Disabilitare AzureWebJobDashboard: per le app destinate alla versione 1.x del runtime di Funzioni, questa impostazione archivia il stringa di connessione a un account di archiviazione usato da Azure SDK per conservare i log per il dashboard dei processi Web. Se Application Insights viene usato invece del dashboard dei processi Web, questa impostazione deve essere rimossa. Per altre informazioni, vedere AzureWebJobsDashboard.
Quando Application Insights è abilitato senza campionamento, vengono inviati tutti i dati di telemetria. L'invio di dati su tutti gli eventi può avere un effetto negativo sulle prestazioni della funzione, soprattutto negli scenari di streaming di eventi a velocità effettiva elevata.
Sfruttare il campionamento e valutare continuamente la quantità appropriata di dati di telemetria necessari per il monitoraggio è fondamentale per ottenere prestazioni ottimali. I dati di telemetria devono essere usati per la valutazione generale dell'integrità della piattaforma e per la risoluzione dei problemi occasionali, non per acquisire le metriche aziendali principali. Per altre informazioni, vedere Configurare il campionamento.
Associazione di output
Usare l'associazione di output di Hub eventi per Funzioni di Azure per semplificare la pubblicazione in un flusso di eventi da una funzione. I vantaggi dell'uso di questa associazione includono:
- Gestione delle risorse: l'associazione gestisce i cicli di vita del client e della connessione e riduce il rischio di problemi che possono verificarsi con l'esaurimento delle porte e la gestione del pool di connessioni.
- Meno codice: l'associazione astrae l'SDK sottostante e riduce la quantità di codice che è necessario pubblicare gli eventi. Consente di scrivere codice più semplice da scrivere e gestire.
- Invio in batch: per diversi linguaggi, l'invio in batch è supportato per pubblicare in modo efficiente in un flusso di eventi. L'invio in batch può migliorare le prestazioni e semplificare il codice che invia gli eventi.
È consigliabile esaminare l'elenco dei linguaggi supportati da Funzioni e le guide per gli sviluppatori per tali linguaggi. La sezione Bindings per ogni linguaggio fornisce esempi dettagliati e documentazione.
Invio in batch durante la pubblicazione di eventi
Se la funzione pubblica solo un singolo evento, la configurazione dell'associazione per restituire un valore è un approccio comune utile se l'esecuzione della funzione termina sempre con un'istruzione che invia l'evento. Questa tecnica deve essere usata solo per le funzioni sincrone che restituiscono un solo evento.
L'invio in batch è consigliato per migliorare le prestazioni quando si inviano più eventi a un flusso. L'invio in batch consente all'associazione di pubblicare eventi nel modo più efficiente possibile.
Il supporto per l'uso dell'associazione di output per inviare più eventi a Hub eventi è disponibile in C#, Java, Python e JavaScript.
Generare più eventi con il modello in-process (C#)
Usare i tipi ICollector e IAsyncCollector quando si inviano più eventi da una funzione in C#.
- ICollector<T>. Il metodo Add() può essere usato sia in funzioni sincrone che asincrone. Esegue l'operazione di aggiunta non appena viene chiamato.
- IAsyncCollector<T>. Il metodo AddAsync() prepara gli eventi da pubblicare nel flusso di eventi. Se si scrive una funzione asincrona, è consigliabile usare IAsyncCollector per gestire meglio gli eventi pubblicati.
Per esempi di uso di C# per pubblicare eventi singoli e multipli, vedere Hub eventi di Azure binding di output per Funzioni di Azure.
Output di più eventi con il modello di lavoro isolato (C#)
A seconda della versione del runtime di Funzioni, il modello di lavoro isolato supporterà tipi diversi per i parametri passati all'associazione di output. Per più eventi, viene usata una matrice per incapsulare il set. È consigliabile esaminare gli attributi di associazione di output e i dettagli di utilizzo per il modello isolato e prendere nota delle differenze tra le versioni dell'estensione.
Limitazione e back pressure
Le considerazioni sulla limitazione si applicano alle associazioni di output, non solo per Hub eventi, ma anche per i servizi di Azure, ad esempio Azure Cosmos DB. È importante acquisire familiarità con i limiti e le quote applicabili a tali servizi e pianificare di conseguenza.
Per gestire gli errori downstream con il modello in-process, è possibile eseguire il wrapping di AddAsync e FlushAsync in un gestore eccezioni per le funzioni .NET per rilevare le eccezioni da IAsyncCollector. Un'altra opzione consiste nell'usare direttamente gli SDK di Hub eventi anziché usare associazioni di output.
Se si usa il modello isolato per le funzioni, la gestione delle eccezioni strutturata deve essere usata per rilevare in modo responsabile le eccezioni quando si restituiscono i valori di output.
Codice della funzione
Questa sezione illustra le aree chiave che devono essere considerate durante la scrittura di codice per elaborare gli eventi in una funzione attivata da Hub eventi.
Programmazione asincrona
È consigliabile scrivere la funzione per usare il codice asincrono ed evitare di bloccare le chiamate, soprattutto quando sono coinvolte chiamate di I/O.
Ecco le linee guida da seguire quando si scrive una funzione per l'elaborazione asincrona:
- Tutte le chiamate asincrone o sincrone: se una funzione è configurata per l'esecuzione asincrona, tutte le chiamate di I/O devono essere asincrone. Nella maggior parte dei casi, il codice parzialmente asincrono è peggiore del codice completamente sincrono. Scegliere asincrona o sincrona e attenersi alla scelta fino all'altro.
- Evitare chiamate di blocco: il blocco delle chiamate torna al chiamante solo dopo il completamento della chiamata, a differenza delle chiamate asincrone che restituiscono immediatamente. Un esempio in C# è la chiamata di Task.Result o Task.Wait su un'operazione asincrona.
Altre informazioni sul blocco delle chiamate
L'uso di chiamate di blocco per le operazioni asincrone può causare l'arresto anomalo del processo del pool di thread. L'arresto anomalo si verifica perché una chiamata di blocco richiede la creazione di un altro thread per compensare la chiamata originale in attesa. Di conseguenza, richiede il doppio del numero di thread per completare l'operazione.
Evitare questo approccio asincrono è particolarmente importante quando è coinvolto Hub eventi, perché un arresto anomalo della funzione non aggiorna il checkpoint. La volta successiva che la funzione viene richiamata, potrebbe finire in questo ciclo e sembra essere bloccata o spostarsi lentamente mentre le esecuzioni di funzioni alla fine si verifica un timeout.
La risoluzione di questo fenomeno inizia in genere con la revisione delle impostazioni del trigger e l'esecuzione di esperimenti che possono comportare l'aumento del numero di partizioni. Le indagini possono anche causare la modifica di diverse opzioni di invio in batch, ad esempio la dimensione massima del batch o il numero di prelettura. L'impressione è che si tratti di un problema di velocità effettiva o di un'impostazione di configurazione che deve essere ottimizzata di conseguenza. Tuttavia, il problema principale si trova nel codice stesso e deve essere risolto in tale posizione.
Collaboratori
Questo articolo viene gestito da Microsoft. Originariamente è stato scritto dai seguenti contributori.
Autore principale:
- David Barkol | GbB principale specialista della soluzione
Per visualizzare i profili LinkedIn non pubblici, accedere a LinkedIn.
Passaggi successivi
Prima di continuare, prendere in considerazione la revisione di questi articoli correlati: