Procedure consigliate per distribuzioni di dispositivi IoT su larga scala

La scalabilità di una soluzione IoT a milioni di dispositivi può risultare complessa. Spesso le soluzioni su larga scala devono essere progettate in base ai limiti dei servizi e delle sottoscrizioni. Quando i clienti usano il servizio Device Provisioning IoT di Azure, lo usano in combinazione con altri servizi e componenti della piattaforma Azure IoT, ad esempio hub IoT e Azure IoT SDK per dispositivi. Questo articolo descrive procedure consigliate, modelli e codice di esempio che è possibile incorporare nella progettazione per sfruttare questi servizi e consentire alle distribuzioni di aumentare il numero di istanze. Seguendo questi modelli e procedure a partire dalla fase di progettazione del progetto, è possibile ottimizzare le prestazioni dei dispositivi IoT.

Effettuare il provisioning di nuovi dispositivi

Il provisioning per la prima volta è il processo di onboarding di un dispositivo per la prima volta come parte di una soluzione IoT. Quando si lavora con distribuzioni su larga scala, è importante pianificare il processo di provisioning per evitare situazioni di overload causate da tutti i dispositivi che tentano di connettersi contemporaneamente.

Usare una pianificazione del provisioning sfalsata

Per la distribuzione di dispositivi su larga scala di milioni, la registrazione di tutti i dispositivi contemporaneamente può comportare il sovraccarico dell'istanza dps a causa della limitazione (codice 429, Too Many Requestsdi risposta HTTP) e di un errore di registrazione dei dispositivi. Per evitare tale limitazione, usare una pianificazione di registrazione non aggiornata per i dispositivi. Configurare le dimensioni batch di registrazione del dispositivo in base alle quote e ai limiti del servizio Device Provisioning. Ad esempio, se la frequenza di registrazione è di 200 dispositivi al minuto, le dimensioni batch per l'onboarding saranno 200 dispositivi per batch.

Operazioni di ripetizione dei tentativi

Se si verificano errori temporanei a causa di un servizio occupato, la logica di ripetizione dei tentativi consente ai dispositivi di connettersi correttamente al cloud IoT. Tuttavia, un numero elevato di tentativi potrebbe compromettere ulteriormente un servizio occupato in esecuzione vicino o alla sua capacità. Come per qualsiasi servizio di Azure, è necessario implementare un meccanismo di ripetizione intelligente dei tentativi con backoff esponenziale. Altre informazioni sui diversi modelli di ripetizione dei tentativi sono disponibili nel modello di progettazione dei tentativi e nella gestione degli errori temporanei.

Anziché ritentare immediatamente una distribuzione quando viene limitata, attendere fino all'ora specificata nell'intestazione retry-after . Se non è disponibile alcuna intestazione di ripetizione dei tentativi dal servizio, questo algoritmo consente di ottenere un'esperienza di onboarding dei dispositivi più fluida:

min_retry_delay_msec = 1000
max_retry_delay_msec = (1.0 / <load>) * <T> * 1000
max_random_jitter_msec = max_retry_delay_msec

Con questa logica, i dispositivi ritardano la riconnessione per un periodo di tempo casuale, compreso tra min_retry_delay_msec e max_retry_delay_msec. Il ritardo massimo dei tentativi viene calcolato con le variabili seguenti:

  • <load> è un fattore configurabile con valori > 0, che indica che il carico verrà eseguito in una media del tempo di caricamento moltiplicato per il numero di connessioni al secondo
  • <T> è il tempo minimo assoluto per l'avvio sporadico dei dispositivi (calcolato come T = N / cps dove N è il numero totale di dispositivi ed cps è il limite di servizio per il numero di connessioni al secondo).

Per altre informazioni sulla tempistica delle operazioni di ripetizione dei tentativi, vedere Intervallo tentativi.

Effettuare di nuovo il provisioning dei dispositivi

Il provisioning è il processo in cui è necessario effettuare il provisioning di un dispositivo a un hub IoT dopo essere stato connesso in precedenza. Esistono molti motivi per cui un dispositivo deve riconnettersi a un hub IoT, ad esempio:

  • Un dispositivo potrebbe essere riavviato a causa di interruzioni dell'alimentazione, perdita di connettività di rete, rilocazione geografica, aggiornamenti del firmware, ripristino delle impostazioni predefinite o rotazione delle chiavi del certificato.
  • L'istanza di hub IoT potrebbe non essere disponibile a causa di un'interruzione hub IoT non pianificata.

Non è necessario eseguire il processo di provisioning ogni volta che un dispositivo viene riavviato. La maggior parte dei dispositivi di cui viene eseguito il reprovisioning finisce connessa allo stesso hub IoT. Al contrario, un dispositivo deve tentare di connettersi direttamente all'hub IoT usando le informazioni memorizzate nella cache da una connessione riuscita precedente.

Dispositivi in grado di archiviare un stringa di connessione

I dispositivi che hanno la possibilità di archiviare il stringa di connessione dopo il provisioning iniziale devono eseguire questa operazione e tentare di riconnettersi direttamente a hub IoT dopo il riavvio. Questo modello riduce la latenza nella connessione corretta al hub IoT appropriato. Ecco due casi possibili:

  • Il hub IoT per la connessione al riavvio del dispositivo è uguale al hub IoT connesso in precedenza.

    Il stringa di connessione recuperato dalla cache dovrebbe funzionare correttamente e il dispositivo può riconnettersi allo stesso endpoint. Non è necessario un nuovo avvio per il processo di provisioning.

  • Il hub IoT per la connessione al riavvio del dispositivo è diverso dal hub IoT connesso in precedenza.

    Il stringa di connessione archiviato in memoria non è accurato. Il tentativo di connessione allo stesso endpoint non riesce e quindi viene attivato il meccanismo di ripetizione dei tentativi per la connessione hub IoT. Una volta raggiunta la soglia per l'errore di connessione hub IoT, il meccanismo di ripetizione dei tentativi attiva automaticamente un nuovo avvio al processo di provisioning.

Dispositivi che non possono archiviare un stringa di connessione

Alcuni dispositivi non hanno un footprint o una memoria sufficientemente grande per supportare la memorizzazione nella cache del stringa di connessione da una connessione hub IoT riuscita. Questi dispositivi devono eseguire nuovamente il provisioning tramite DPS dopo il riavvio. Usare l'API di registrazione del servizio Device Provisioning per ripetere la registrazione. Tenere presente che il numero di registrazioni al minuto è limitato in base al limite di registrazione del dispositivo DPS.

Esempio di reprovisioning

Gli esempi di codice in questa sezione mostrano una classe per la lettura e la scrittura dalla cache del dispositivo, seguita dal codice che tenta di riconnettere un dispositivo al hub IoT se viene trovato un stringa di connessione e riprovisioning tramite DPS, se non lo è.

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace ProvisioningCache
{
  public class ProvisioningDetailsFileStorage : IProvisioningDetailCache
  {
    private string dataDirectory = null;

    public ProvisioningDetailsFileStorage()
    {
      dataDirectory = Environment.GetEnvironmentVariable("ProvisioningDetailsDataDirectory");
    }

    public ProvisioningResponse GetProvisioningDetailResponseFromCache(string registrationId)
    {
      try
        {
          var provisioningResponseFile = File.ReadAllText(Path.Combine(dataDirectory, registrationId));

          ProvisioningResponse response = JsonConvert.DeserializeObject<ProvisioningResponse>(provisioningResponseFile);

          return response;
        }
      catch (Exception ex)
      {
        return null;
      }
    }

    public void SetProvisioningDetailResponse(string registrationId, ProvisioningResponse provisioningDetails)
    {
      var provisioningDetailsJson = JsonConvert.SerializeObject(provisioningDetails);

      File.WriteAllText(Path.Combine(dataDirectory, registrationId), provisioningDetailsJson);
    }
  }
}

È possibile usare codice simile al seguente per determinare come procedere con la riconnessione di un dispositivo dopo aver determinato se nella cache sono presenti informazioni di connessione:

IProvisioningDetailCache provisioningDetailCache = new ProvisioningDetailsFileStorage();

var provisioningDetails = provisioningDetailCache.GetProvisioningDetailResponseFromCache(registrationId);

// If no info is available in cache, go through DPS for provisioning
if(provisioningDetails == null)
{
  logger.LogInformation($"Initializing the device provisioning client...");
  using var transport = new ProvisioningTransportHandlerAmqp();
  ProvisioningDeviceClient provClient = ProvisioningDeviceClient.Create(dpsEndpoint, dpsScopeId, security, transport);
  logger.LogInformation($"Initialized for registration Id {security.GetRegistrationID()}.");
  logger.LogInformation("Registering with the device provisioning service... ");

  // This method will attempt to retry in case of a transient fault
  DeviceRegistrationResult result = await registerDevice(provClient);
  provisioningDetails = new ProvisioningResponse() { iotHubHostName = result.AssignedHub, deviceId = result.DeviceId };
  provisioningDetailCache.SetProvisioningDetailResponse(registrationId, provisioningDetails);
}

// If there was IoT Hub info from previous provisioning in the cache, try connecting to the IoT Hub directly
// If trying to connect to the IoT Hub returns status 429, make sure to retry operation honoring
//   the retry-after header
// If trying to connect to the IoT Hub returns a 500-series server error, have an exponential backoff with
//   at least 5 seconds of wait-time
// For all response codes 429 and 5xx, reprovision through DPS
// Ideally, you should also support a method to manually trigger provisioning on demand
if (provisioningDetails != null)
{
  logger.LogInformation($"Device {provisioningDetails.deviceId} registered to {provisioningDetails.iotHubHostName}.");
  logger.LogInformation("Creating TPM authentication for IoT Hub...");
  IAuthenticationMethod auth = new DeviceAuthenticationWithTpm(provisioningDetails.deviceId, security);
  logger.LogInformation($"Testing the provisioned device with IoT Hub...");
  DeviceClient iotClient = DeviceClient.Create(provisioningDetails.iotHubHostName, auth, TransportType.Amqp);
  logger.LogInformation($"Registering the Method Call back for Reprovisioning...");
  await iotClient.SetMethodHandlerAsync("Reprovision",reprovisionDirectMethodCallback, iotClient);

  // Now you should start a thread into this method and do your business while the DeviceClient is still connected
  await startBackgroundWork(iotClient);
  logger.LogInformation("Wait until closed...");

  // Wait until the app unloads or is cancelled
  var cts = new CancellationTokenSource();
  AssemblyLoadContext.Default.Unloading += (ctx) => cts.Cancel();
  Console.CancelKeyPress += (sender, cpe) => cts.Cancel();

  await WhenCancelled(cts.Token);
  await iotClient.CloseAsync();
  Console.WriteLine("Finished.");
}

hub IoT considerazioni sulla connettività

Qualsiasi singolo hub IoT è limitato a 1 milione di dispositivi più moduli. Se si prevede di avere più di un milione di dispositivi, limitare il numero di dispositivi a 1 milione per hub e aggiungere hub in base alle esigenze quando si aumenta la scalabilità della distribuzione. Per altre informazioni, vedere hub IoT quote. Se hai piani per più di un milione di dispositivi e devi supportarli in un'area specifica (ad esempio in un'area dell'UE per i requisiti di residenza dei dati), puoi contattarci per assicurarti che l'area in cui stai distribuendo abbia la capacità di supportare la scalabilità attuale e futura.

Quando ci si connette a hub IoT tramite DPS, i dispositivi devono usare la logica seguente in risposta ai codici di errore durante la connessione:

  • Quando si riceve una delle 500 serie di risposte di errore del server, ripetere la connessione usando le credenziali memorizzate nella cache o i risultati di una chiamata API Device Registration Status Lookup.
  • Quando si riceve 401, Unauthorized o 404, Not Found403, Forbidden , eseguire una nuova registrazione completa chiamando l'API di registrazione del servizio Device Provisioning.

In qualsiasi momento, i dispositivi devono essere in grado di rispondere a un comando di reprovisioning avviato dall'utente.

Se i dispositivi vengono disconnessi da hub IoT, i dispositivi devono provare a riconnettersi direttamente allo stesso hub IoT per 15-30 minuti prima di tentare di tornare al servizio Device Provisioning.

Altri scenari di hub IoT quando si usa dps:

  • hub IoT failover: i dispositivi devono continuare a funzionare perché le informazioni di connessione non devono cambiare e la logica è stata eseguita per ritentare la connessione dopo che l'hub è nuovamente disponibile.
  • Modifica delle hub IoT: l'assegnazione di dispositivi a un hub IoT diverso deve essere eseguita usando un criterio di allocazione personalizzato.
  • Riprovare hub IoT connessione: non è consigliabile usare una strategia di ripetizione aggressiva dei tentativi. Consentire invece un intervallo di almeno un minuto prima di un nuovo tentativo.
  • hub IoT partizioni: se la strategia del dispositivo si basa pesantemente sui dati di telemetria, è necessario aumentare il numero di partizioni da dispositivo a cloud.

Monitorare i dispositivi

Una parte importante della distribuzione complessiva è il monitoraggio della soluzione end-to-end per assicurarsi che il sistema funzioni in modo appropriato. Esistono diversi modi per monitorare l'integrità di un servizio per la distribuzione su larga scala dei dispositivi IoT. I modelli seguenti si sono dimostrati efficaci nel monitoraggio del servizio:

  • Creare un'applicazione per eseguire query su ogni gruppo di registrazione in un'istanza del servizio Device Provisioning, ottenere i dispositivi totali registrati in tale gruppo e quindi aggregare i numeri da diversi gruppi di registrazione. Questo numero fornisce un conteggio esatto dei dispositivi attualmente registrati tramite DPS e può essere usato per monitorare lo stato del servizio.
  • Monitorare le registrazioni dei dispositivi in un periodo specifico. Ad esempio, monitorare le tariffe di registrazione per un'istanza del servizio Device Provisioning nei cinque giorni precedenti. Si noti che questo approccio fornisce solo una figura approssimativa e viene anche limitato a un periodo di tempo.

Passaggi successivi