Você está usando um navegador antigo. Por favor, utilize versão suportada para ter acesso às melhores funções do MSN.

Construindo um backend baseado em nuvem para bilhetagem eletrônica com o Prodata

Logotipo do(a) Microsoft Tech Microsoft Tech 06/09/2018 Microsoft Tech

A Prodata e a Microsoft trabalharam juntas para arquitetar e construir um back-end de IoT na nuvem para processar eventos de telemetria e financeiros do sistema de tickets de ônibus da Prodata em São Paulo.

O problema

A emissão de bilhetes é utilizada mundialmente no transporte público para a compra antecipada de créditos de viagem gravados em dispositivos especiais, especialmente em cartões. É uma solução integrada de hardware e software desenvolvida para controlar e gerenciar a cobrança dos custos cobrados nos sistemas públicos de transporte de passageiros. Ajuda o cliente a minimizar fraudes, obter mais retenção e fornecer segurança aos usuários finais.

A Prodata é responsável por fornecer o sistema de bilhetagem para o sistema de transporte público de São Paulo. O back-end deste sistema é principalmente no local, hospedado no datacenter da Prodata.

Os dispositivos de bilhetagem de ônibus têm duas operações básicas:

  • Transações financeiras (como cobrança de carona ou recarga do cartão de passageiro);
  • Monitorização e telemetria.

Em São Paulo, a maior parte da população inicia seu trabalho entre as 6h e as 8h e volta para casa por volta das 17h ou 18h. Esse comportamento é mostrado no gráfico a seguir.

Carga média de passageiros por dia

Um gráfico da carga média de passageiros (gasto em reais) por horas do dia © Fornecido por Microsoft ICE Um gráfico da carga média de passageiros (gasto em reais) por horas do dia

Grande parte da população recebe, como benefício de seus empregos, créditos eletrônicos para uso no transporte público. Entre o dia 31 do mês e o dia 5 do mês seguinte, esse benefício é entregue aos funcionários, que podem reabastecer seus cartões dentro dos ônibus. A seguir, um gráfico mostrando a carga média de recargas durante um mês específico.

Carga média de recargas de cartão por mês

Gráfico da carga média por mês © Fornecido por Microsoft ICE Gráfico da carga média por mês

A tabela a seguir contém alguns números adicionais sobre a situação atual no sistema de São Paulo.

Uma tabela com informações sobre a situação atual do sistema de São Paulo © Fornecido por Microsoft ICE Uma tabela com informações sobre a situação atual do sistema de São Paulo

As empresas de transporte público agora estão expandindo suas operações e modernizando o sistema atual, o que faz com que mais veículos sejam manuseados pelo backend de emissão de bilhetes do Prodata. A situação estimada em seis meses é mostrada nesta tabela.

Tabela com dados estimados para os próximos seis meses © Fornecido por Microsoft ICE Tabela com dados estimados para os próximos seis meses

Como podemos ver, espera-se que o volume de mensagens seja 2,5 vezes o valor atual. A arquitetura e a infraestrutura atuais atendem bem às suas necessidades, mas o aumento de volume estimado nos próximos seis meses é crítico, e eles não têm certeza se conseguirão atendê-lo com uma solução local. Mesmo que isso aconteça, implicações de custo podem ser proibitivas. Isso os levou a explorar uma plataforma de nuvem como uma alternativa mais eficiente.

Solução e Etapas

Com base nesse requisito de escalabilidade, recriamos as partes críticas e sensíveis de sua infraestrutura no Azure. Hoje, a ingestão de dados é feita usando um Gateway TCP, que analisa as mensagens recebidas em um protocolo proprietário e as converte em HTTP. Isso é para permitir a comunicação com seu próprio back-end usando REST e também com o back-end da empresa de transporte público.

Este Gateway TCP na nuvem foi projetado conforme mostrado no diagrama a seguir.

Diagrama de arquitetura do Azure

Diagram da arquitetura da solução no Azure © Fornecido por Microsoft ICE Diagram da arquitetura da solução no Azure

Os elementos verdes são dispositivos/APIs do Prodata inalterados. O Azure IoT Hub e as Funções do Azure foram usadas ​​para fornecer a necessidade de escalabilidade, substituindo partes específicas de sua arquitetura original, enquanto a tabela e o Power BI foram usados ​​para registrar logs e fornecer a camada de apresentação para o painel de telemetria. Os elementos cinza representam a estrutura de tratamento de erros.

Os seguintes requisitos devem ser considerados para concluir essa alteração com êxito:

  • Garantir a comunicação do dispositivo diretamente com a nuvem;
  • Reutilizar o código Prodata existente para analisar e enviar mensagens para o back-end;
  • Certificar-se de que o atraso entre a solicitação feita pelo dispositivo e sua resposta seja menor que 1 segundo (hoje é cerca de 400 ms);
  • Permitir comunicação bidirecional com todos os dispositivos.

Entrega técnica

Os dispositivos usados ​​nos ônibus são uma placa proprietária com uma distro Linux adaptada. Cada placa tem um modem de 3 GB conectado a ela, o que torna o dispositivo capaz de se conectar diretamente à Internet. Por isso, não foi necessário utilizar um gateway para conectá-los. Na época do hackfest, os responsáveos pela solução não tínham um dispositivo físico para testar e desenvolver o aplicativo com o IoT Hub. Por isso, decidiram usar dispositivos simulados usando o SDK do dispositivo do Azure IoT escrito em C #.

Os recursos técnicos para os dispositivos incluem o seguinte.

Geral:

  • CPU Freescale i.MX6 Cortex-A9 Dual Core @ 1 GHz;
  • 1 GB de RAM;
  • Armazenamento em Flash de 1 GB.

Conectividade de rede:

  • 2 GB (GSM/GPRS/EDGE – 850/900/1800/1900 MHz);
  • 3 GB (UMTS/HSPA – 800/850/900/1700/1900/2100 MHz);
  • IEEE 802.11 b/g/ n 2,4 GHz;
  • IEEE 802.3 10/100/1000 Mbps.

Conectividade IO:

  • EIA / TIA RS232-C;
  • EIA / TIA RS485 Full / Half Duplex;
  • CAN;
  • USB;
  • Contact-less: ISO14443 + ICode: ISO14443 Tipo A/B e ISO15693, freq. 1356 MHz, modulação ASK 100%

Outras capacidades:

  • GPS.

As solicitações de recarga podem acontecer a qualquer hora do dia. As mensagens de monitoramento são enviadas a cada cinco minutos para mostrar o status e a integridade da máquina de emissão de bilhetes. A seguir, alguns detalhes sobre tamanhos de mensagens e consumo médio de largura de banda.

Uma tabela contendo mensagem, tamanho da mensagem e largura da banda © Fornecido por Microsoft ICE Uma tabela contendo mensagem, tamanho da mensagem e largura da banda

Como as mensagens são pequenas, foi desenvolvido um sistema em que vários dispositivos foram simulados de uma vez usando o SDK do dispositivo do Azure IoT com um pool de threads implementada. Foi escolhido o MQTT como o protocolo de aplicação devido ao seu excelente desempenho, segurança e confiabilidade.

A preocupação com a segurança nesse cenário é fundamental, pois é fundamental proteger o sistema de cobrança contra fraudes financeiras. Hoje, o cliente já implementou um sistema de segurança em sua infraestrutura que envolve o uso de criptografia em conjunto com os módulos de segurança de hardware (HSMs). Isso garante que o payload da mensagem seja criptografada até o seu destino final. Além disso, ao usar o IoT Hub com o MQTT, o próprio SDK do Azure IoT é responsável por gerar tokens de autenticação temporários para os dispositivos.

Depois que o dispositivo se registrou e enviou uma mensagem para o IoT Hub, é necessário manipulá-lo e fazer todos os processos de back-end. Como o time de desenvolvimento não precisava processar o caminho ativo e precisavam de um padrão de solicitação/resposta, optaram por não usar o Azure Stream Analytics, mesmo que ele pudesse ser estendido com User-Defined Funtions (UDF – Funções definidas pelo usuário) em JavaScript. Utilizaram então Azure Functions, para que, sempre que uma mensagem chegasse ao Hub IoT, ela acionasse a comunicação com o back-end do Prodata. O uso de Functions também garante a escalabilidade adequada para o processo de ingestão de dados – um requisito básico para essa migração.

Atualmente, as Azure Functions só podem ser acionadas por Event Hubs e não diretamente pelo IoT Hub. Como o IoT Hub tem uma interface compatível com o Event Hubs, a integração é possível.

Para facilitar a integração entre o IoT Hub e as Azure Functions, basta substituir o campo “Hostname” por “Endpoint” na seqüência de conexão que você usará em Funções.

Por exemplo, se você tiver o seguinte:

HostName=yoururl;SharedAccessKeyName=iothubowner;SharedAccessKey=yourkey 

Troque por:

Endpoint=yoururl;SharedAccessKeyName=iothubowner;SharedAccessKey=yourkey 

Depois de configurar um event hub como uma fonte de trigger para a função, ele pôde ler a carga útil da mensagem, mas não seu cabeçalho e outras propriedades porque, por padrão, os dados lidos da entrada das Azure Functions do event hub são plain text. Como era necessário ler todas essas informações, desserializar JSON e enviar mensagens de nuvem para dispositivo, foram adicionadas as seguintes dependências à definição das Azure Functions:

Definição das Azure Functions

{"frameworks": {"net46": {"dependencies": {"Microsoft.Azure.Devices": "1.2.5","Newtonsoft.Json": "10.0.2","WindowsAzure.ServiceBus": "4.0.0"}}}} 

Usando o assembly WindowsAzure.ServiceBus, era possível ler todas as mensagens entregues no event hub interno do IoT Hub. Uma mensagem interna típica (e seu esquema) é mostrada no snippet a seguir. A documentação respectiva pode ser encontrada em EventData Class.

Mensagem típica do Event hub

{"SerializedSizeInBytes": 54,"Offset": "2880","PartitionKey": null,"SequenceNumber": 9,"EnqueuedTimeUtc": "2017-04-11T17:29:10.075Z","Properties": {},"SystemProperties": {"x-opt-sequence-number": 9,"x-opt-offset": "2880","x-opt-enqueued-time": "2017-04-11T17:29:10.075Z","iothub-connection-device-id": "6c08208b-bda2-4219-ae9a-84807cd08c5b","iothub-connection-auth-method": "{ \"scope\": \"device\", \"type\": \"sas\", \"issuer\": \"iothub\" }","iothub-connection-auth-generation-id": "636275198245423531","EnqueuedTimeUtc": "2017-04-11T17:29:10.075Z","SequenceNumber": 9,"Offset": "2880","correlation-id": "083dc261-7504-49e7-9d9e-c3a433a75498"}} 

O time estava especialmente interessados ​​em SystemProperties, que o SDK do IoT Hub preenche automaticamente ao enviar uma mensagem. As duas propriedades que iríam utilizar eram:

  • “Iothub-connection-device-id”: o ID do dispositivo que enviou a mensagem atual. Esse valor foi utilizado para enviar uma resposta ao dispositivo por meio da mesma função que recebeu a solicitação;
  • “Correlation-id”: esta propriedade pode ser interpretada como o ID da mensagem. Ele pode ser usado para confirmar a qual mensagem a resposta pertence quando a nuvem envia uma mensagem ao dispositivo.

Ao escrever o corpo do código de função usando C # e tentando reutilizar o código existente do Prodata, a equipe enfrentou alguns problemas. Primeiro, não era possível usar arquivos .cs, apenas arquivos .csx, uma implementação por design das Azure Functions em C #. Segundo, Functions não suportam namespaces. Para resolver isso, foi criado um script PowerShell simples para remover todos os namespaces das classes antigas (com a premissa de que não haveria conflito entre os modelos) e salvá-lo como um grande arquivo .csx. Problema resolvido!

O resultado da função é mostrado aqui. Comentários sobre a importância de cada etapa também foram adicionados:

Corpo da função Azure

//Uses the legacy external file:#load "ProdataBackend.csx"using System;using System.Text;//Important reference to use the complete Event Hub functionally:using Microsoft.ServiceBus.Messaging;//Another important one, used to send Cloud to Devices messages from IoT Hub:using Microsoft.Azure.Devices;using Newtonsoft.Json;static string connectionString = "HERE GOES YOUR CONNECTION STRING";static ServiceClient serviceClient;//Some other state variables were omittedpublic static void Run(EventData inputEventData, ICollector outputTable, TraceWriter log){//Initialize:console = log;table = outputTable;eventData = inputEventData;//Verbose:Log("Event Data", LogType.Information);try{//Get input data payload from Event hub:var bodyBytes = inputEventData.GetBytes();//Thiese properties has information about the device ID and message ID sent to IoT Hub:var deviceId = inputEventData.SystemProperties["iothub-connection-device-id"].ToString();var correlationId = inputEventData.SystemProperties["correlation-id"].ToString();//Call Prodata backend:var result = ProdataBackendUtil.Process(bodyBytes);//Send the response to device:serviceClient = ServiceClient.CreateFromConnectionString(connectionString);SendCloudToDeviceMessageAsync(deviceId, correlationId, result).Wait();}//Error handling and Logging was collapsed to simplify the viewcatch{}}private async static Task SendCloudToDeviceMessageAsync(string deviceId, string correlationId, byte[] messageBytes){try{await serviceClient.SendAsync(deviceId, new Message(messageBytes) { CorrelationId = correlationId });}catch{}finally{await serviceClient.CloseAsync();serviceClient.Dispose();}}public static void Log(string message, LogType type){var eventSerialized = JsonConvert.SerializeObject(eventData);//Console log://console.Info($"Message: {message}");//console.Info($"Event: {eventSerialized}");//Azure Table log:table.Add(new LogRegistry(){PartitionKey = "AzureFunctionLogs",RowKey = Guid.NewGuid().ToString(),LogType = type.ToString(),Message = message,EventData = eventSerialized});}public enum LogType{Information,Warning,Critical}public class LogRegistry{public string PartitionKey { get; set; }public string RowKey { get; set; }public string LogType { get; set; }public string Message { get; set; }public string EventData { get; set; }} 

Como a equipe não tinha permissão de gravação no hub de eventos internos, eles não podiam marcar a mensagem como lida (redefinindo o deslocamento para um estado anterior). A solução para isso era colocar a mensagem com erros em um hub de eventos dedicado usado apenas para essa finalidade. Outra função pode ser acionada por isso para fazer o padrão de repetição (com alguma contagem de tempo de vida / repetição) e aplicar esse comportamento.

Conclusão

A arquitetura forneceu eficiência e escalabilidade, atingindo os requisitos iniciais para uma migração parcial da nuvem. Todos os testes que usaram essa arquitetura foram realizados com recursos provisionados no datacenter do Oeste dos EUA do Azure. Como o IoT Hub ainda não está disponível no Brasil, isso está criando um problema para a Prodata devido aos requisitos de atraso. Como uma alternativa imediata, foi testade uma Web API do ASP.NET para executar as Functions. Foi uma alternativa muito interessante como um sistema de ingestão de mensagens para seus dispositivos, especialmente devido à sua natureza síncrona intrínseca, mesmo que a Web API não tenha todos os recursos que o IoT Hub tem para gerenciamento de dispositivos, escalabilidade gerenciada e retenção de mensagens.

Os testes de carga foram feitos a partir de um único computador usando cerca de 40 threads, simulando solicitações de telemetria e recarga. O serviço de teste de carga do Visual Studio Team Services também foi usado para verificar o desempenho da arquitetura proposta. Ambos os testes renderam bons resultados em termos de desempenho e escalabilidade.

Além dos testes funcionais realizados durante o hackfest, um teste completo que usou o ambiente de homologação da Prodata é necessário e será realizado em breve. Uma tarefa futura também será criar um painel do Power BI para permitir a visualização de dados coletados e processados.

O post Construindo um backend baseado em nuvem para bilhetagem eletrônica com o Prodata apareceu primeiro em Microsoft Tech.

Mais de Microsoft Tech

image beaconimage beaconimage beacon