Partilhar via


Sugestões de design de aplicações principais de alto nível

Para criar uma aplicação principal de alto nível (HL) em bases sólidas, deve utilizar as melhores práticas fundamentais. Seguem-se as mais relevantes:

As aplicações principais de alto nível (HL) são executadas em contentores no SO do Azure Sphere. Durante as revisões de código e conceção de soluções de clientes, encontrámos vários problemas típicos com aplicações HL-core. Este tópico aborda sugestões de melhorias de design para resolver estes problemas.

Noções básicas gerais

Para criar uma aplicação HL-core em bases sólidas, deve utilizar as melhores práticas fundamentais. Seguem-se as mais relevantes:

  • Inicialização e terminação: Certifique-se sempre de que processa o sinal SIGTERM do SO do Azure Sphere e inicialize e destrua corretamente todos os processadores (como os de periféricos) após a saída, seja após falha ou erro. Para obter mais detalhes, veja Inicialização e terminação e a documentação da GNU sobre Sinais de Terminação.
  • Utilize sempre códigos de saída: Garantir que a aplicação HL-core fornece sempre um código de retorno significativo após a saída ou falha (por exemplo, utilizar o processador SIGTERM) é essencial para diagnosticar corretamente o comportamento do dispositivo, especialmente a partir da telemetria de informação de falha de sistema do dispositivo. Para obter mais informações, veja Códigos de saída e Recolher e interpretar dados de erro.
  • Certifique-se de que os casos de falha resultam sempre numa falha ou saída da aplicação em vez de num estado de impasse: A lógica de recuperação de falhas elaborada pode ser contraproducente, uma vez que pode introduzir erros ou comportamentos que resultam num impasse ou num estado difícil de diagnosticar. Uma aplicação do Azure Sphere bem concebida deve sempre preferir falhar ou sair (com um código de saída diferente de zero) para uma potencial situação de impasse, uma vez que isto resulta em ambos:
    • Telemetria de erros ao ativar o diagnóstico para este problema
    • Uma hipótese de recuperação imediata para um estado de trabalho, uma vez que o SO do Azure Sphere irá reiniciar a aplicação
  • Processamento e registo de erros: O processamento preciso de erros e o registo estão no centro do desenvolvimento de aplicações de qualidade. As implementações de funcionalidades rápidas podem permanecer enterradas em camadas de código e, em seguida, incorporadas à medida que a aplicação se desenvolve em grande escala. Para obter mais informações sobre as melhores práticas, veja Processamento e registo de erros.
  • Utilize um temporizador do sistema como um cão de guarda: Uma das melhores práticas mais cruciais é implementar uma chamada de retorno de "temporizador de cão de guarda" (tal como as de hardware disponíveis em MCUs bare-metal) que monitoriza estados críticos da aplicação, deteta impasse e age em conformidade (por exemplo, sair e enviar telemetria). Para obter mais informações, consulte Utilizar um temporizador do sistema como um cão de guarda.
  • Nunca implemente aplicações de produção criadas com um conjunto de ferramentas de versão beta: A utilização de conjuntos de ferramentas de versão beta não é recomendada porque não é possível garantir que o subconjunto beta não será alterado nas versões subsequentes do SO. Os conjuntos de ferramentas beta são lançados apenas para testar novas funcionalidades antes de uma versão oficial do SDK.

Lidar com a simultaneidade

  • Utilize o EventLoop sempre que possível: Os threads e objetos de sincronização (ou seja, mutexes, semáforos, etc.) são utilizados para realizar tarefas quase simultâneas, mas em sistemas incorporados estes são dispendiosos em termos de utilização de recursos do sistema. Por conseguinte, para melhorar o desempenho, considere a utilização de epolls em vez de threads, para as tarefas que não são estritamente críticas no tempo e não são sensíveis ao bloqueio mútuo. Veja Applibs eventloop.h para obter informações sobre como monitorizar e enviar eventos com o EventLoop, incluindo exemplos relacionados.
  • Procure eficiência em tarefas simultâneas: É importante garantir que as operações de bloqueio e os tempos limite são mantidos no mínimo nas chamadas de retorno epoll. Caso contrário, todas as outras chamadas de retorno epoll serão afetadas.
  • Quando utilizar threads (pthread): Para cenários específicos, como quando as chamadas de bloqueio são inevitáveis, a utilização de threads pode ser vantajosa, embora normalmente esses cenários tenham uma duração limitada e devam ser confinados a tarefas específicas. Por exemplo, dado que o SO do Azure Sphere (em execução no Linux) não expõe IRQs a aplicações de núcleo HL (esta opção está disponível apenas para Aplicações RT-core), a utilização de uma combinação de tarefas epoll e pthread pode ser ideal para processar, por exemplo, uma comunicação em série a jusante ao transferir dados da Internet.

Importante

O SO do Azure Sphere pode interromper as operações atempadamente, especialmente quando está a executar o atestado do dispositivo, a procurar atualizações ou a carregar telemetria. Para tarefas de controlo críticas para o tempo, considere movê-las para os núcleos M4 e coordená-las com um protocolo adequado através da caixa de correio entre núcleos. Para obter mais informações, veja o exemplo de comunicação Inter-core.

Além destas sugestões, reveja a documentação do Azure Sphere sobre eventos assíncronos e simultaneidade.

Monitorização da conectividade

Uma aplicação principal de alto nível (HL) bem concebida tem de implementar uma tarefa de Verificação do Estado de Funcionamento de Conectividade adequada, que deve basear-se num computador de estado robusto que verifica regularmente o estado da ligação à Internet (por exemplo, através de um temporizador epoll ) ao tirar partido da API Networking_IsNetworkingReady . Em alguns casos, pode utilizar a Função Networking_GetInterfaceConnectionStatus, uma vez que fornece um estado mais aprofundado do estado de conectividade relacionado com uma interface de rede específica que a aplicação HL-core pode utilizar para lidar melhor com o seu estado, embora isto tenha um custo, uma vez que não é recomendado chamá-lo com mais frequência do que a cada 90 segundos.

Normalmente, a chamada de retorno da máquina de estado deve ter os seguintes atributos:

  • Execute o mais rapidamente possível.
  • O intervalo de consulta tem de ser cuidadosamente concebido, com base no cenário de aplicação específico e nos requisitos gerais da solução (como tempo constante, atraso incremental, etc.).
  • Depois de detetada uma desconexão, pode ser útil chamar Networking_GetInterfaceConnectionStatus uma vez para registar o estado da interface de rede específica, que pode ser utilizada para diagnosticar o problema e notificar o utilizador através de uma IU (como LEDs, ecrã, terminal). Pode encontrar um exemplo desta abordagem no código principal do Exemplo DHCP do Azure Sphere.
  • Ative um mecanismo (por exemplo, através de uma variável global) que interrompe todas as outras tarefas na aplicação HL-core que executam (ou estão ligadas) comunicações de rede para otimizar o consumo de recursos até que uma ligação seja restabelecida.
  • O cURL atualizou recentemente o comportamento de chamada de retorno e as melhores práticas. Embora o Azure Sphere tenha envidado esforços para garantir que as versões mais antigas do comportamento cURL continuam a funcionar conforme esperado, recomenda-se que siga as orientações mais recentes sobre segurança e fiabilidade ao utilizar curl_multi, uma vez que a utilização de chamadas de retorno recursivas pode resultar em falhas inesperadas, falhas de conectividade e potenciais vulnerabilidades de segurança. Se um TimerCallback for acionado com um tempo limite de 0 ms, trate-o como um tempo limite de 1 ms para evitar chamadas de retorno recursivas. Certifique-se de que também chama curl_multi_socket_action explicitamente pelo menos uma vez após as chamadas para curl_multi_add_handle.

Para além das sugestões anteriores, deve considerar os seguintes cenários para a gestão de energia:

  • Desligue o chip do Azure Sphere depois de enviar dados. Para obter detalhes, veja Manage Power Down state for Azure Sphere devices (Gerir o estado do Power Down para dispositivos do Azure Sphere).
  • Uma vez que vários problemas podem resultar de tempos limite exponenciais longos, é fundamental controlar o tempo de atividade total e definir um temporizador de encerramento para um limite razoável para não drenar a bateria em condições em que a conectividade já não é possível devido a falhas externas ou outros fatores fora do controlo da aplicação.
  • Ao controlar a monitorização da conectividade durante as interrupções, o transcetor de Wi-Fi pode desligar ao desativar a wlan0 interface de rede (veja Networking_SetInterfaceState e aguarde até à próxima verificação de conectividade novamente, poupando aproximadamente 100 mW.

Gestão e utilização de memória

Nas plataformas com restrições de memória, as aplicações que executam alocações de memória frequentes e desalocação podem fazer com que a gestão da memória do SO se debata com a eficiência, o que faz com que a fragmentação excessiva e a memória se esbatam. Especificamente no MT3620 do Azure Sphere, isto pode levar a condições de memória esgotada que podem desencadear o início do assassino OOM do grupo OOM do SO do Azure Sphere.

Compreensivelmente, as aplicações são muitas vezes desenvolvidas a partir de uma prova de conceito inicial, que se torna mais abrangente com as funcionalidades necessárias para lançamentos progressivos, acabando por negligenciar pequenas funcionalidades que foram inicialmente incluídas. Seguem-se sugestões e otimizações que provaram ser eficazes para muitos cenários analisados no campo:

  • Especialmente em aplicações de núcleo HL que utilizam intensivamente a memória, é essencial controlar a utilização da memória da aplicação através da API do Azure Sphere, descrita em Determinar a utilização da RAM da aplicação em tempo de execução. Normalmente, isto é implementado num watchdog epoll-timer e a aplicação reage em conformidade à utilização inesperada da memória para reiniciar de forma razoável; por exemplo, sair com o código de saída adequado.

    Vários clientes e parceiros consideraram útil utilizar o utilitário de controlo de memória Heap Tracker , publicado na Galeria do Azure Sphere. Esta biblioteca liga de forma transparente a uma aplicação HL-core existente e controla as alocações de memória e os respetivos ponteiros relacionados, permitindo a deteção simplificada da maioria dos casos de fugas de memória e utilização indevida de ponteiros.

Importante

Esta prática pode reduzir a falta de resposta ou falhas aparentemente inexplicáveis do dispositivo ou frequentemente comunicadas a partir do campo. Estas falhas são normalmente causadas por fugas de memória ou excessos que não são devidamente processados pela aplicação HL-core e levam o assassino OOM a encerrar o processo da aplicação. Isto, juntamente com uma fraca conectividade que impede o SO do Azure Sphere de enviar telemetria, pode levar a potenciais incidentes de campo, uma vez que o diagnóstico só pode ser detetado ao solicitar os registos de diagnóstico do SO do Azure Sphere.

  • Em plataformas restritas de memória, geralmente é preferível evitar a alocação de memória dinâmica sempre que possível, especialmente em funções frequentemente chamadas. Isto reduzirá consideravelmente a fragmentação da memória da área dinâmica para dados e a probabilidade de falhas subsequentes de alocação de área dinâmica para dados. Considere também uma mudança de paradigma de alocar repetidamente memórias intermédias de trabalho temporárias para aceder diretamente à pilha (para variáveis de tamanhos razoáveis) ou memórias intermédias alocadas globalmente, que aumentam de tamanho (através reallocde ) após a capacidade excedida (veja Contentores dinâmicos e memórias intermédias). Se existir um requisito para descarregar memória, considere tirar partido da memória não utilizada nos núcleos M4 (veja Memória disponível no Azure Sphere), que tem 256KiB cada, com uma aplicação RT-core leve para colocação em cache de dados. Pode eventualmente utilizar cartões SD externos ou flash. Pode encontrar exemplos nos seguintes repositórios:

Seguir as sugestões acima também pode ajudar a estimar e reservar a memória que seria necessária para que a aplicação HL-core funcione em plena capacidade ao longo do ciclo de vida, ao mesmo tempo que lhe permite estimar melhor a quantidade de memória geral da aplicação para otimizações de design posteriores. Para obter mais informações sobre como otimizar a utilização da memória em aplicações HL-core, incluindo funcionalidades no SO do Azure Sphere e no Visual Studio, veja os seguintes artigos: