Tecnologia

Construindo uma Solução D2C de WebSocket Escalável para o Dia do Jogo

Construindo uma Solução D2C de WebSocket Escalável para o Dia do Jogo

Construindo uma Solução D2C de WebSocket Escalável para o Dia do Jogo

Spicy Mango - Andrew Pearce

Leitura de 6 min

|

Na Spicy Mango, esforçamo-nos continuamente para melhorar os nossos produtos para responder às necessidades em constante evolução dos nossos clientes. A nossa plataforma de dados desportivos, Gameday, sempre se destacou na ingestão, transformação e distribuição de dados desportivos para empresas através de APIs REST e webhooks. No entanto, à medida que a procura de atualizações desportivas em tempo real para aplicações direcionadas diretamente ao consumidor (D2C) cresceu, reconhecemos a necessidade de uma solução escalável e de baixa latência. Isto levou-nos a explorar mecanismos de pub/sub baseados em WebSocket para distribuir eficazmente atualizações em tempo real, tais como golos marcados ou a posição de carros/motos de corrida, a milhões de clientes ligados.

Neste artigo, vamos guiá-lo através de:

  • Avaliação de tecnologias Websocket

  • O trabalho que realizámos para a integração e teste

  • A fundamentação para optar pela transição para a nossa própria implementação Websocket

  • Os desafios associados e os benefícios que trouxe


A Necessidade de uma Capacidade D2C Dedicada Baseada em WebSocket

Os fãs de desporto esperam atualizações instantâneas. A latência já não é medida em segundos, mas sim em milissegundos. Os nossos métodos de distribuição existentes - APIs REST e webhooks - são excelentes para a partilha de dados estruturados, mas não foram concebidos para atualizações push em tempo real à escala. Os WebSockets, por outro lado, fornecem um canal de comunicação bidirecional persistente, tornando-os ideais para fornecer atualizações instantâneas a milhões de clientes em todo o mundo.

Para apoiar esta transição, avaliámos várias abordagens, incluindo protocolos prontos a usar como o MQTT, antes de desenvolvermos, em última análise, a nossa própria solução de pub/sub baseada em WebSocket em Node.js.


Testar o MQTT: Uma Solução Poderosa, mas Inadequada

O MQTT é um protocolo de publicação-subscrição bem estabelecido, amplamente utilizado em aplicações IoT e mensagens em tempo real. No papel, parecia um forte candidato para as nossas necessidades. Suporta ambientes de baixa largura de banda, possui níveis integrados de qualidade de serviço (QoS) e facilita o encaminhamento eficiente de mensagens. No entanto, durante o nosso teste, deparámo-nos com vários desafios que o tornaram difícil para o caso de utilização D2C do Gameday.

  1. Configuração e Gestão Complexas à Escala

    1. A implementação do MQTT à escala revelou-se morosa. Gerir múltiplas instâncias de broker, garantir uma elevada disponibilidade e escalar dinamicamente em resposta a picos de tráfego exigiu um esforço operacional significativo. A nossa equipa de DevOps teve de investir tempo a afinar configurações, a lidar com a gestão de clusters e a otimizar o equilíbrio de carga, o que acrescentou uma sobrecarga desnecessária.

    2. Também investigámos soluções geridas por terceiros - tais como o HiveMQ - em vez de gerirmos as nossas próprias instâncias do Mosquitto. No entanto, o custo à escala rapidamente tornou esta opção inviável para as nossas necessidades.


  2. Dificuldade de Monitorização e Relatórios

    1. Embora o MQTT suporte o rastreio e registo de mensagens, depende fortemente das próprias mensagens MQTT para a monitorização. Os brokers de MQTT utilizam frequentemente tópicos especiais, tais como o tópico $SYS, para publicar o estado interno e métricas. Monitorizar estes brokers envolve subscrever estes tópicos para recolher informações sobre o estado de funcionamento e atividade do broker. Esta abordagem significa que as ferramentas de monitorização devem atuar como clientes MQTT, subscrevendo estes tópicos internos para recolher métricas, o que pode acrescentar complexidade à configuração de monitorização. Embora este método seja eficaz dentro do ecossistema MQTT, pode não se integrar perfeitamente com sistemas de monitorização externos que esperam métricas através de protocolos padrão como o HTTP. Isto tornou os relatórios em tempo real, a depuração e a análise de dados mais difíceis do que o previsto. Necessitávamos de um sistema que proporcionasse uma observabilidade mais profunda sobre o estado de funcionamento da ligação, taxas de sucesso de entrega e métricas de latência - funcionalidades que eram complexas de implementar ou que não estavam nativamente disponíveis no MQTT.


  3. Falta de Autenticação e Autorização Flexíveis

    1. Uma das desvantagens mais críticas foi a inflexibilidade na gestão de autenticação e autorização. Os brokers de MQTT oferecem mecanismos de autenticação, mas a implementação de um controlo de acesso detalhado para diferentes classes de utilizadores - como a diferenciação entre subscritores premium e gratuitos - revelou-se complexa. Além disso, a nossa dependência de plugins de terceiros no Mosquitto deixou-nos desconfortáveis, pois introduzia uma dependência externa sobre a qual tínhamos controlo limitado. Adicionalmente, observámos um declínio no desempenho, dado que os nossos requisitos complexos de autenticação e autorização exigiam o descarregamento e encaminhamento (proxying) destes processos para um serviço separado, desenvolvido e mantido pela Spicy Mango. Isto acrescentou latência e complexidade desnecessárias, reforçando a nossa decisão de procurar uma solução mais integrada e eficiente.


  4. Desalinhado com a Nossa Stack de Desenvolvimento

    1. Embora o MQTT seja robusto, o seu ecossistema está vocacionado principalmente para a IoT e aplicações industriais, com brokers frequentemente escritos em linguagens como C (Mosquitto), Erlang (emqttd) ou Java (Moquette). A nossa equipa de engenharia trabalha principalmente com Node.js para o desenvolvimento de backend, e manter uma solução MQTT exigia introduzir uma nova tecnologia na nossa stack ou depender de brokers de terceiros, o que não era o ideal para a sustentabilidade a longo prazo.


  5. Sobrecarga Desnecessária para o Nosso Caso de Utilização

    1. O MQTT foi concebido para um amplo conjunto de casos de utilização de mensagens em tempo real, incluindo aqueles com dispositivos limitados e redes não fiáveis. Embora se destaque nesses cenários, o nosso principal objetivo era a distribuição eficiente e escalável em tempo real de metadados desportivos através de ligações estáveis à Internet. As funcionalidades adicionais do MQTT, tais como a retenção de mensagens e a gestão complexa de QoS, acrescentaram sobrecarga e complexidade desnecessárias à nossa infraestrutura sem proporcionar benefícios proporcionais.


Desenvolver a Nossa Própria Solução de Pub/Sub Baseada em WebSocket

Depois de avaliar exaustivamente o MQTT, tomámos a decisão estratégica de construir o nosso próprio sistema pub/sub baseado em WebSocket utilizando Node.js. Esta decisão permitiu-nos otimizar para as nossas necessidades específicas, mantendo a nossa stack tecnológica consistente e sustentável. Eis porque é que a nossa solução interna se revelou a escolha certa:

  1. Integração Perfeita com a Arquitetura Existente do Gameday

    1. A nossa plataforma já corre em Node.js, tornando simples o desenvolvimento de um serviço WebSocket que se integra perfeitamente com os nossos microserviços existentes. Isto reduziu o tempo de integração dos nossos engenheiros e simplificou a manutenção contínua.


  2. Leve e Otimizado para Metadados Desportivos

    1. Ao controlar a implementação, pudemos otimizar as estruturas das mensagens e os tamanhos dos payloads para dados desportivos. Ao contrário do MQTT, que suporta vários níveis de QoS de que não necessitávamos, a nossa solução WebSocket fornece atualizações com uma sobrecarga mínima de processamento.


  3. Escalável e Mais Fácil de Gerir

    1. Com a nossa própria solução, pudemos tirar partido dos serviços AWS, tais como o Elastic Load Balancing e as funcionalidades de auto-scaling para garantir uma escala suave. Construímos ferramentas de monitorização adaptadas às nossas necessidades, gerámos dados em tempo real sobre a estabilidade da ligação, subscritores ativos e tempos de entrega de mensagens, e integrámos também no nosso sistema de logs padrão.


  4. Autenticação e Autorização Personalizadas

    1. A segurança era uma preocupação primordial, e a nossa solução personalizada permitiu-nos implementar controlos detalhados de autenticação e autorização. O nosso sistema de autenticação e autorização é alimentado pelo AuthIDConnect, uma solução desenvolvida pela Spicy Mango. O AuthIDConnect permite que utilizadores registados façam login através de palavras-passe ou TOTP, emitindo tokens de acesso de curta duração e tokens de atualização de longa duração (ambos JWTs assinados). Os utilizadores podem renovar os seus tokens de acesso utilizando o token de atualização, mantendo um acesso seguro e contínuo. O token de acesso contém permissões que definem as autorizações do utilizador.

    2. O AuthIDConnect também suporta utilizadores anónimos, uma funcionalidade crucial para empresas externas que integram os metadados desportivos do Gameday nas suas próprias soluções. Neste modelo, quando um utilizador final anónimo está autorizado a utilizar o serviço de terceiros, o pedido de autenticação é encaminhado (proxied) pelo terceiro para o AuthIDConnect com um ID de sessão. O AuthIDConnect emite então um token de acesso anónimo assinado contendo o ID da sessão, que o utilizador final utiliza para se autenticar e autorizar o seu acesso às APIs do Gameday e ao serviço pub/sub de WebSocket.

    3. A nossa solução WebSocket foi concebida para validar estes tokens de forma eficiente e rápida, garantindo uma latência mínima e uma experiência contínua para todos os clientes ligados.


  5. Redução da Complexidade da Infraestrutura

    1. Ao evitar uma camada de protocolo adicional, eliminámos dependências desnecessárias e simplificámos a sobrecarga operacional. O nosso serviço WebSocket reside na nossa infraestrutura AWS existente, reduzindo a necessidade de manutenção adicional e dependências de terceiros.


  6. Cumprimento dos Pilares de uma Estrutura Bem Arquitetada (Well-Architected Framework)

    1. A nossa solução alinha-se com os pilares fundamentais da Well-Architected Framework da AWS:

      1. Excelência Operacional: Gestão e monitorização simplificadas com ferramentas de observabilidade personalizadas.

      2. Segurança: Autenticação e autorização detalhadas para controlar o acesso e evitar a exposição de dados não autorizados.

      3. Fiabilidade: O auto-scaling da AWS e as APIs de WebSocket geridas garantem uma elevada disponibilidade e resiliência.

      4. Eficiência de Desempenho: Sobrecarga mínima de processamento e estruturas de mensagens otimizadas melhoram a latência e os tempos de resposta.

      5. Otimização de Custos: A eliminação de dependências de terceiros reduz os custos de licenciamento e a sobrecarga de infraestrutura.

      6. Sustentabilidade: A redução da complexidade operacional e o uso eficiente de recursos ajudam a manter uma arquitetura sustentável.


Uma Visão Geral a 10.000 Pés

Abaixo encontra-se uma imagem de nível (muito) geral do que criámos. Crucialmente, conseguimos gerir e escalar a solução de distribuição por web socket em várias Zonas de Disponibilidade e Regiões, enquanto a autenticação e a autorização são todas transportadas no token do AuthIDConnect. Se quisermos, podemos implementar num padrão fan-out de servidores de origem e edge, para escalar de modo a responder à procura em qualquer região - tudo com a mesma implementação de servidor WebSocket.



Lições Aprendidas e Considerações Finais

A nossa jornada rumo a uma solução D2C baseada em WebSocket ensinou-nos lições valiosas. O MQTT é um protocolo poderoso e versátil, bem adequado para a IoT e comunicação máquina para máquina. No entanto, para os requisitos específicos do Gameday — escalabilidade, mensagens de baixa latência, integração com a nossa stack Node.js e controlos de segurança detalhados — a nossa solução WebSocket personalizada foi a melhor opção.

Esta experiência reforçou a importância de selecionar tecnologias que se alinham com a nossa especialização principal e objetivos operacionais. Ao desenvolvermos a nossa própria solução, temos agora um sistema altamente otimizado, escalável e seguro que fornece atualizações de metadados desportivos em tempo real a milhões de utilizadores com uma latência mínima.

À medida que o Gameday continua a evoluir, mantemo-nos empenhados em explorar novas formas de melhorar a nossa plataforma. Quer se trate de otimizar ainda mais a nossa infraestrutura WebSocket, de incorporar computação de edge ou de tirar partido de novas tecnologias na nuvem, o nosso objetivo continua a ser o mesmo: fornecer a melhor experiência possível de dados desportivos em tempo real.

Na Spicy Mango, esforçamo-nos continuamente para melhorar os nossos produtos para responder às necessidades em constante evolução dos nossos clientes. A nossa plataforma de dados desportivos, Gameday, sempre se destacou na ingestão, transformação e distribuição de dados desportivos para empresas através de APIs REST e webhooks. No entanto, à medida que a procura de atualizações desportivas em tempo real para aplicações direcionadas diretamente ao consumidor (D2C) cresceu, reconhecemos a necessidade de uma solução escalável e de baixa latência. Isto levou-nos a explorar mecanismos de pub/sub baseados em WebSocket para distribuir eficazmente atualizações em tempo real, tais como golos marcados ou a posição de carros/motos de corrida, a milhões de clientes ligados.

Neste artigo, vamos guiá-lo através de:

  • Avaliação de tecnologias Websocket

  • O trabalho que realizámos para a integração e teste

  • A fundamentação para optar pela transição para a nossa própria implementação Websocket

  • Os desafios associados e os benefícios que trouxe


A Necessidade de uma Capacidade D2C Dedicada Baseada em WebSocket

Os fãs de desporto esperam atualizações instantâneas. A latência já não é medida em segundos, mas sim em milissegundos. Os nossos métodos de distribuição existentes - APIs REST e webhooks - são excelentes para a partilha de dados estruturados, mas não foram concebidos para atualizações push em tempo real à escala. Os WebSockets, por outro lado, fornecem um canal de comunicação bidirecional persistente, tornando-os ideais para fornecer atualizações instantâneas a milhões de clientes em todo o mundo.

Para apoiar esta transição, avaliámos várias abordagens, incluindo protocolos prontos a usar como o MQTT, antes de desenvolvermos, em última análise, a nossa própria solução de pub/sub baseada em WebSocket em Node.js.


Testar o MQTT: Uma Solução Poderosa, mas Inadequada

O MQTT é um protocolo de publicação-subscrição bem estabelecido, amplamente utilizado em aplicações IoT e mensagens em tempo real. No papel, parecia um forte candidato para as nossas necessidades. Suporta ambientes de baixa largura de banda, possui níveis integrados de qualidade de serviço (QoS) e facilita o encaminhamento eficiente de mensagens. No entanto, durante o nosso teste, deparámo-nos com vários desafios que o tornaram difícil para o caso de utilização D2C do Gameday.

  1. Configuração e Gestão Complexas à Escala

    1. A implementação do MQTT à escala revelou-se morosa. Gerir múltiplas instâncias de broker, garantir uma elevada disponibilidade e escalar dinamicamente em resposta a picos de tráfego exigiu um esforço operacional significativo. A nossa equipa de DevOps teve de investir tempo a afinar configurações, a lidar com a gestão de clusters e a otimizar o equilíbrio de carga, o que acrescentou uma sobrecarga desnecessária.

    2. Também investigámos soluções geridas por terceiros - tais como o HiveMQ - em vez de gerirmos as nossas próprias instâncias do Mosquitto. No entanto, o custo à escala rapidamente tornou esta opção inviável para as nossas necessidades.


  2. Dificuldade de Monitorização e Relatórios

    1. Embora o MQTT suporte o rastreio e registo de mensagens, depende fortemente das próprias mensagens MQTT para a monitorização. Os brokers de MQTT utilizam frequentemente tópicos especiais, tais como o tópico $SYS, para publicar o estado interno e métricas. Monitorizar estes brokers envolve subscrever estes tópicos para recolher informações sobre o estado de funcionamento e atividade do broker. Esta abordagem significa que as ferramentas de monitorização devem atuar como clientes MQTT, subscrevendo estes tópicos internos para recolher métricas, o que pode acrescentar complexidade à configuração de monitorização. Embora este método seja eficaz dentro do ecossistema MQTT, pode não se integrar perfeitamente com sistemas de monitorização externos que esperam métricas através de protocolos padrão como o HTTP. Isto tornou os relatórios em tempo real, a depuração e a análise de dados mais difíceis do que o previsto. Necessitávamos de um sistema que proporcionasse uma observabilidade mais profunda sobre o estado de funcionamento da ligação, taxas de sucesso de entrega e métricas de latência - funcionalidades que eram complexas de implementar ou que não estavam nativamente disponíveis no MQTT.


  3. Falta de Autenticação e Autorização Flexíveis

    1. Uma das desvantagens mais críticas foi a inflexibilidade na gestão de autenticação e autorização. Os brokers de MQTT oferecem mecanismos de autenticação, mas a implementação de um controlo de acesso detalhado para diferentes classes de utilizadores - como a diferenciação entre subscritores premium e gratuitos - revelou-se complexa. Além disso, a nossa dependência de plugins de terceiros no Mosquitto deixou-nos desconfortáveis, pois introduzia uma dependência externa sobre a qual tínhamos controlo limitado. Adicionalmente, observámos um declínio no desempenho, dado que os nossos requisitos complexos de autenticação e autorização exigiam o descarregamento e encaminhamento (proxying) destes processos para um serviço separado, desenvolvido e mantido pela Spicy Mango. Isto acrescentou latência e complexidade desnecessárias, reforçando a nossa decisão de procurar uma solução mais integrada e eficiente.


  4. Desalinhado com a Nossa Stack de Desenvolvimento

    1. Embora o MQTT seja robusto, o seu ecossistema está vocacionado principalmente para a IoT e aplicações industriais, com brokers frequentemente escritos em linguagens como C (Mosquitto), Erlang (emqttd) ou Java (Moquette). A nossa equipa de engenharia trabalha principalmente com Node.js para o desenvolvimento de backend, e manter uma solução MQTT exigia introduzir uma nova tecnologia na nossa stack ou depender de brokers de terceiros, o que não era o ideal para a sustentabilidade a longo prazo.


  5. Sobrecarga Desnecessária para o Nosso Caso de Utilização

    1. O MQTT foi concebido para um amplo conjunto de casos de utilização de mensagens em tempo real, incluindo aqueles com dispositivos limitados e redes não fiáveis. Embora se destaque nesses cenários, o nosso principal objetivo era a distribuição eficiente e escalável em tempo real de metadados desportivos através de ligações estáveis à Internet. As funcionalidades adicionais do MQTT, tais como a retenção de mensagens e a gestão complexa de QoS, acrescentaram sobrecarga e complexidade desnecessárias à nossa infraestrutura sem proporcionar benefícios proporcionais.


Desenvolver a Nossa Própria Solução de Pub/Sub Baseada em WebSocket

Depois de avaliar exaustivamente o MQTT, tomámos a decisão estratégica de construir o nosso próprio sistema pub/sub baseado em WebSocket utilizando Node.js. Esta decisão permitiu-nos otimizar para as nossas necessidades específicas, mantendo a nossa stack tecnológica consistente e sustentável. Eis porque é que a nossa solução interna se revelou a escolha certa:

  1. Integração Perfeita com a Arquitetura Existente do Gameday

    1. A nossa plataforma já corre em Node.js, tornando simples o desenvolvimento de um serviço WebSocket que se integra perfeitamente com os nossos microserviços existentes. Isto reduziu o tempo de integração dos nossos engenheiros e simplificou a manutenção contínua.


  2. Leve e Otimizado para Metadados Desportivos

    1. Ao controlar a implementação, pudemos otimizar as estruturas das mensagens e os tamanhos dos payloads para dados desportivos. Ao contrário do MQTT, que suporta vários níveis de QoS de que não necessitávamos, a nossa solução WebSocket fornece atualizações com uma sobrecarga mínima de processamento.


  3. Escalável e Mais Fácil de Gerir

    1. Com a nossa própria solução, pudemos tirar partido dos serviços AWS, tais como o Elastic Load Balancing e as funcionalidades de auto-scaling para garantir uma escala suave. Construímos ferramentas de monitorização adaptadas às nossas necessidades, gerámos dados em tempo real sobre a estabilidade da ligação, subscritores ativos e tempos de entrega de mensagens, e integrámos também no nosso sistema de logs padrão.


  4. Autenticação e Autorização Personalizadas

    1. A segurança era uma preocupação primordial, e a nossa solução personalizada permitiu-nos implementar controlos detalhados de autenticação e autorização. O nosso sistema de autenticação e autorização é alimentado pelo AuthIDConnect, uma solução desenvolvida pela Spicy Mango. O AuthIDConnect permite que utilizadores registados façam login através de palavras-passe ou TOTP, emitindo tokens de acesso de curta duração e tokens de atualização de longa duração (ambos JWTs assinados). Os utilizadores podem renovar os seus tokens de acesso utilizando o token de atualização, mantendo um acesso seguro e contínuo. O token de acesso contém permissões que definem as autorizações do utilizador.

    2. O AuthIDConnect também suporta utilizadores anónimos, uma funcionalidade crucial para empresas externas que integram os metadados desportivos do Gameday nas suas próprias soluções. Neste modelo, quando um utilizador final anónimo está autorizado a utilizar o serviço de terceiros, o pedido de autenticação é encaminhado (proxied) pelo terceiro para o AuthIDConnect com um ID de sessão. O AuthIDConnect emite então um token de acesso anónimo assinado contendo o ID da sessão, que o utilizador final utiliza para se autenticar e autorizar o seu acesso às APIs do Gameday e ao serviço pub/sub de WebSocket.

    3. A nossa solução WebSocket foi concebida para validar estes tokens de forma eficiente e rápida, garantindo uma latência mínima e uma experiência contínua para todos os clientes ligados.


  5. Redução da Complexidade da Infraestrutura

    1. Ao evitar uma camada de protocolo adicional, eliminámos dependências desnecessárias e simplificámos a sobrecarga operacional. O nosso serviço WebSocket reside na nossa infraestrutura AWS existente, reduzindo a necessidade de manutenção adicional e dependências de terceiros.


  6. Cumprimento dos Pilares de uma Estrutura Bem Arquitetada (Well-Architected Framework)

    1. A nossa solução alinha-se com os pilares fundamentais da Well-Architected Framework da AWS:

      1. Excelência Operacional: Gestão e monitorização simplificadas com ferramentas de observabilidade personalizadas.

      2. Segurança: Autenticação e autorização detalhadas para controlar o acesso e evitar a exposição de dados não autorizados.

      3. Fiabilidade: O auto-scaling da AWS e as APIs de WebSocket geridas garantem uma elevada disponibilidade e resiliência.

      4. Eficiência de Desempenho: Sobrecarga mínima de processamento e estruturas de mensagens otimizadas melhoram a latência e os tempos de resposta.

      5. Otimização de Custos: A eliminação de dependências de terceiros reduz os custos de licenciamento e a sobrecarga de infraestrutura.

      6. Sustentabilidade: A redução da complexidade operacional e o uso eficiente de recursos ajudam a manter uma arquitetura sustentável.


Uma Visão Geral a 10.000 Pés

Abaixo encontra-se uma imagem de nível (muito) geral do que criámos. Crucialmente, conseguimos gerir e escalar a solução de distribuição por web socket em várias Zonas de Disponibilidade e Regiões, enquanto a autenticação e a autorização são todas transportadas no token do AuthIDConnect. Se quisermos, podemos implementar num padrão fan-out de servidores de origem e edge, para escalar de modo a responder à procura em qualquer região - tudo com a mesma implementação de servidor WebSocket.



Lições Aprendidas e Considerações Finais

A nossa jornada rumo a uma solução D2C baseada em WebSocket ensinou-nos lições valiosas. O MQTT é um protocolo poderoso e versátil, bem adequado para a IoT e comunicação máquina para máquina. No entanto, para os requisitos específicos do Gameday — escalabilidade, mensagens de baixa latência, integração com a nossa stack Node.js e controlos de segurança detalhados — a nossa solução WebSocket personalizada foi a melhor opção.

Esta experiência reforçou a importância de selecionar tecnologias que se alinham com a nossa especialização principal e objetivos operacionais. Ao desenvolvermos a nossa própria solução, temos agora um sistema altamente otimizado, escalável e seguro que fornece atualizações de metadados desportivos em tempo real a milhões de utilizadores com uma latência mínima.

À medida que o Gameday continua a evoluir, mantemo-nos empenhados em explorar novas formas de melhorar a nossa plataforma. Quer se trate de otimizar ainda mais a nossa infraestrutura WebSocket, de incorporar computação de edge ou de tirar partido de novas tecnologias na nuvem, o nosso objetivo continua a ser o mesmo: fornecer a melhor experiência possível de dados desportivos em tempo real.

Na Spicy Mango, esforçamo-nos continuamente para melhorar os nossos produtos para responder às necessidades em constante evolução dos nossos clientes. A nossa plataforma de dados desportivos, Gameday, sempre se destacou na ingestão, transformação e distribuição de dados desportivos para empresas através de APIs REST e webhooks. No entanto, à medida que a procura de atualizações desportivas em tempo real para aplicações direcionadas diretamente ao consumidor (D2C) cresceu, reconhecemos a necessidade de uma solução escalável e de baixa latência. Isto levou-nos a explorar mecanismos de pub/sub baseados em WebSocket para distribuir eficazmente atualizações em tempo real, tais como golos marcados ou a posição de carros/motos de corrida, a milhões de clientes ligados.

Neste artigo, vamos guiá-lo através de:

  • Avaliação de tecnologias Websocket

  • O trabalho que realizámos para a integração e teste

  • A fundamentação para optar pela transição para a nossa própria implementação Websocket

  • Os desafios associados e os benefícios que trouxe


A Necessidade de uma Capacidade D2C Dedicada Baseada em WebSocket

Os fãs de desporto esperam atualizações instantâneas. A latência já não é medida em segundos, mas sim em milissegundos. Os nossos métodos de distribuição existentes - APIs REST e webhooks - são excelentes para a partilha de dados estruturados, mas não foram concebidos para atualizações push em tempo real à escala. Os WebSockets, por outro lado, fornecem um canal de comunicação bidirecional persistente, tornando-os ideais para fornecer atualizações instantâneas a milhões de clientes em todo o mundo.

Para apoiar esta transição, avaliámos várias abordagens, incluindo protocolos prontos a usar como o MQTT, antes de desenvolvermos, em última análise, a nossa própria solução de pub/sub baseada em WebSocket em Node.js.


Testar o MQTT: Uma Solução Poderosa, mas Inadequada

O MQTT é um protocolo de publicação-subscrição bem estabelecido, amplamente utilizado em aplicações IoT e mensagens em tempo real. No papel, parecia um forte candidato para as nossas necessidades. Suporta ambientes de baixa largura de banda, possui níveis integrados de qualidade de serviço (QoS) e facilita o encaminhamento eficiente de mensagens. No entanto, durante o nosso teste, deparámo-nos com vários desafios que o tornaram difícil para o caso de utilização D2C do Gameday.

  1. Configuração e Gestão Complexas à Escala

    1. A implementação do MQTT à escala revelou-se morosa. Gerir múltiplas instâncias de broker, garantir uma elevada disponibilidade e escalar dinamicamente em resposta a picos de tráfego exigiu um esforço operacional significativo. A nossa equipa de DevOps teve de investir tempo a afinar configurações, a lidar com a gestão de clusters e a otimizar o equilíbrio de carga, o que acrescentou uma sobrecarga desnecessária.

    2. Também investigámos soluções geridas por terceiros - tais como o HiveMQ - em vez de gerirmos as nossas próprias instâncias do Mosquitto. No entanto, o custo à escala rapidamente tornou esta opção inviável para as nossas necessidades.


  2. Dificuldade de Monitorização e Relatórios

    1. Embora o MQTT suporte o rastreio e registo de mensagens, depende fortemente das próprias mensagens MQTT para a monitorização. Os brokers de MQTT utilizam frequentemente tópicos especiais, tais como o tópico $SYS, para publicar o estado interno e métricas. Monitorizar estes brokers envolve subscrever estes tópicos para recolher informações sobre o estado de funcionamento e atividade do broker. Esta abordagem significa que as ferramentas de monitorização devem atuar como clientes MQTT, subscrevendo estes tópicos internos para recolher métricas, o que pode acrescentar complexidade à configuração de monitorização. Embora este método seja eficaz dentro do ecossistema MQTT, pode não se integrar perfeitamente com sistemas de monitorização externos que esperam métricas através de protocolos padrão como o HTTP. Isto tornou os relatórios em tempo real, a depuração e a análise de dados mais difíceis do que o previsto. Necessitávamos de um sistema que proporcionasse uma observabilidade mais profunda sobre o estado de funcionamento da ligação, taxas de sucesso de entrega e métricas de latência - funcionalidades que eram complexas de implementar ou que não estavam nativamente disponíveis no MQTT.


  3. Falta de Autenticação e Autorização Flexíveis

    1. Uma das desvantagens mais críticas foi a inflexibilidade na gestão de autenticação e autorização. Os brokers de MQTT oferecem mecanismos de autenticação, mas a implementação de um controlo de acesso detalhado para diferentes classes de utilizadores - como a diferenciação entre subscritores premium e gratuitos - revelou-se complexa. Além disso, a nossa dependência de plugins de terceiros no Mosquitto deixou-nos desconfortáveis, pois introduzia uma dependência externa sobre a qual tínhamos controlo limitado. Adicionalmente, observámos um declínio no desempenho, dado que os nossos requisitos complexos de autenticação e autorização exigiam o descarregamento e encaminhamento (proxying) destes processos para um serviço separado, desenvolvido e mantido pela Spicy Mango. Isto acrescentou latência e complexidade desnecessárias, reforçando a nossa decisão de procurar uma solução mais integrada e eficiente.


  4. Desalinhado com a Nossa Stack de Desenvolvimento

    1. Embora o MQTT seja robusto, o seu ecossistema está vocacionado principalmente para a IoT e aplicações industriais, com brokers frequentemente escritos em linguagens como C (Mosquitto), Erlang (emqttd) ou Java (Moquette). A nossa equipa de engenharia trabalha principalmente com Node.js para o desenvolvimento de backend, e manter uma solução MQTT exigia introduzir uma nova tecnologia na nossa stack ou depender de brokers de terceiros, o que não era o ideal para a sustentabilidade a longo prazo.


  5. Sobrecarga Desnecessária para o Nosso Caso de Utilização

    1. O MQTT foi concebido para um amplo conjunto de casos de utilização de mensagens em tempo real, incluindo aqueles com dispositivos limitados e redes não fiáveis. Embora se destaque nesses cenários, o nosso principal objetivo era a distribuição eficiente e escalável em tempo real de metadados desportivos através de ligações estáveis à Internet. As funcionalidades adicionais do MQTT, tais como a retenção de mensagens e a gestão complexa de QoS, acrescentaram sobrecarga e complexidade desnecessárias à nossa infraestrutura sem proporcionar benefícios proporcionais.


Desenvolver a Nossa Própria Solução de Pub/Sub Baseada em WebSocket

Depois de avaliar exaustivamente o MQTT, tomámos a decisão estratégica de construir o nosso próprio sistema pub/sub baseado em WebSocket utilizando Node.js. Esta decisão permitiu-nos otimizar para as nossas necessidades específicas, mantendo a nossa stack tecnológica consistente e sustentável. Eis porque é que a nossa solução interna se revelou a escolha certa:

  1. Integração Perfeita com a Arquitetura Existente do Gameday

    1. A nossa plataforma já corre em Node.js, tornando simples o desenvolvimento de um serviço WebSocket que se integra perfeitamente com os nossos microserviços existentes. Isto reduziu o tempo de integração dos nossos engenheiros e simplificou a manutenção contínua.


  2. Leve e Otimizado para Metadados Desportivos

    1. Ao controlar a implementação, pudemos otimizar as estruturas das mensagens e os tamanhos dos payloads para dados desportivos. Ao contrário do MQTT, que suporta vários níveis de QoS de que não necessitávamos, a nossa solução WebSocket fornece atualizações com uma sobrecarga mínima de processamento.


  3. Escalável e Mais Fácil de Gerir

    1. Com a nossa própria solução, pudemos tirar partido dos serviços AWS, tais como o Elastic Load Balancing e as funcionalidades de auto-scaling para garantir uma escala suave. Construímos ferramentas de monitorização adaptadas às nossas necessidades, gerámos dados em tempo real sobre a estabilidade da ligação, subscritores ativos e tempos de entrega de mensagens, e integrámos também no nosso sistema de logs padrão.


  4. Autenticação e Autorização Personalizadas

    1. A segurança era uma preocupação primordial, e a nossa solução personalizada permitiu-nos implementar controlos detalhados de autenticação e autorização. O nosso sistema de autenticação e autorização é alimentado pelo AuthIDConnect, uma solução desenvolvida pela Spicy Mango. O AuthIDConnect permite que utilizadores registados façam login através de palavras-passe ou TOTP, emitindo tokens de acesso de curta duração e tokens de atualização de longa duração (ambos JWTs assinados). Os utilizadores podem renovar os seus tokens de acesso utilizando o token de atualização, mantendo um acesso seguro e contínuo. O token de acesso contém permissões que definem as autorizações do utilizador.

    2. O AuthIDConnect também suporta utilizadores anónimos, uma funcionalidade crucial para empresas externas que integram os metadados desportivos do Gameday nas suas próprias soluções. Neste modelo, quando um utilizador final anónimo está autorizado a utilizar o serviço de terceiros, o pedido de autenticação é encaminhado (proxied) pelo terceiro para o AuthIDConnect com um ID de sessão. O AuthIDConnect emite então um token de acesso anónimo assinado contendo o ID da sessão, que o utilizador final utiliza para se autenticar e autorizar o seu acesso às APIs do Gameday e ao serviço pub/sub de WebSocket.

    3. A nossa solução WebSocket foi concebida para validar estes tokens de forma eficiente e rápida, garantindo uma latência mínima e uma experiência contínua para todos os clientes ligados.


  5. Redução da Complexidade da Infraestrutura

    1. Ao evitar uma camada de protocolo adicional, eliminámos dependências desnecessárias e simplificámos a sobrecarga operacional. O nosso serviço WebSocket reside na nossa infraestrutura AWS existente, reduzindo a necessidade de manutenção adicional e dependências de terceiros.


  6. Cumprimento dos Pilares de uma Estrutura Bem Arquitetada (Well-Architected Framework)

    1. A nossa solução alinha-se com os pilares fundamentais da Well-Architected Framework da AWS:

      1. Excelência Operacional: Gestão e monitorização simplificadas com ferramentas de observabilidade personalizadas.

      2. Segurança: Autenticação e autorização detalhadas para controlar o acesso e evitar a exposição de dados não autorizados.

      3. Fiabilidade: O auto-scaling da AWS e as APIs de WebSocket geridas garantem uma elevada disponibilidade e resiliência.

      4. Eficiência de Desempenho: Sobrecarga mínima de processamento e estruturas de mensagens otimizadas melhoram a latência e os tempos de resposta.

      5. Otimização de Custos: A eliminação de dependências de terceiros reduz os custos de licenciamento e a sobrecarga de infraestrutura.

      6. Sustentabilidade: A redução da complexidade operacional e o uso eficiente de recursos ajudam a manter uma arquitetura sustentável.


Uma Visão Geral a 10.000 Pés

Abaixo encontra-se uma imagem de nível (muito) geral do que criámos. Crucialmente, conseguimos gerir e escalar a solução de distribuição por web socket em várias Zonas de Disponibilidade e Regiões, enquanto a autenticação e a autorização são todas transportadas no token do AuthIDConnect. Se quisermos, podemos implementar num padrão fan-out de servidores de origem e edge, para escalar de modo a responder à procura em qualquer região - tudo com a mesma implementação de servidor WebSocket.



Lições Aprendidas e Considerações Finais

A nossa jornada rumo a uma solução D2C baseada em WebSocket ensinou-nos lições valiosas. O MQTT é um protocolo poderoso e versátil, bem adequado para a IoT e comunicação máquina para máquina. No entanto, para os requisitos específicos do Gameday — escalabilidade, mensagens de baixa latência, integração com a nossa stack Node.js e controlos de segurança detalhados — a nossa solução WebSocket personalizada foi a melhor opção.

Esta experiência reforçou a importância de selecionar tecnologias que se alinham com a nossa especialização principal e objetivos operacionais. Ao desenvolvermos a nossa própria solução, temos agora um sistema altamente otimizado, escalável e seguro que fornece atualizações de metadados desportivos em tempo real a milhões de utilizadores com uma latência mínima.

À medida que o Gameday continua a evoluir, mantemo-nos empenhados em explorar novas formas de melhorar a nossa plataforma. Quer se trate de otimizar ainda mais a nossa infraestrutura WebSocket, de incorporar computação de edge ou de tirar partido de novas tecnologias na nuvem, o nosso objetivo continua a ser o mesmo: fornecer a melhor experiência possível de dados desportivos em tempo real.

Na Spicy Mango, esforçamo-nos continuamente para melhorar os nossos produtos para responder às necessidades em constante evolução dos nossos clientes. A nossa plataforma de dados desportivos, Gameday, sempre se destacou na ingestão, transformação e distribuição de dados desportivos para empresas através de APIs REST e webhooks. No entanto, à medida que a procura de atualizações desportivas em tempo real para aplicações direcionadas diretamente ao consumidor (D2C) cresceu, reconhecemos a necessidade de uma solução escalável e de baixa latência. Isto levou-nos a explorar mecanismos de pub/sub baseados em WebSocket para distribuir eficazmente atualizações em tempo real, tais como golos marcados ou a posição de carros/motos de corrida, a milhões de clientes ligados.

Neste artigo, vamos guiá-lo através de:

  • Avaliação de tecnologias Websocket

  • O trabalho que realizámos para a integração e teste

  • A fundamentação para optar pela transição para a nossa própria implementação Websocket

  • Os desafios associados e os benefícios que trouxe


A Necessidade de uma Capacidade D2C Dedicada Baseada em WebSocket

Os fãs de desporto esperam atualizações instantâneas. A latência já não é medida em segundos, mas sim em milissegundos. Os nossos métodos de distribuição existentes - APIs REST e webhooks - são excelentes para a partilha de dados estruturados, mas não foram concebidos para atualizações push em tempo real à escala. Os WebSockets, por outro lado, fornecem um canal de comunicação bidirecional persistente, tornando-os ideais para fornecer atualizações instantâneas a milhões de clientes em todo o mundo.

Para apoiar esta transição, avaliámos várias abordagens, incluindo protocolos prontos a usar como o MQTT, antes de desenvolvermos, em última análise, a nossa própria solução de pub/sub baseada em WebSocket em Node.js.


Testar o MQTT: Uma Solução Poderosa, mas Inadequada

O MQTT é um protocolo de publicação-subscrição bem estabelecido, amplamente utilizado em aplicações IoT e mensagens em tempo real. No papel, parecia um forte candidato para as nossas necessidades. Suporta ambientes de baixa largura de banda, possui níveis integrados de qualidade de serviço (QoS) e facilita o encaminhamento eficiente de mensagens. No entanto, durante o nosso teste, deparámo-nos com vários desafios que o tornaram difícil para o caso de utilização D2C do Gameday.

  1. Configuração e Gestão Complexas à Escala

    1. A implementação do MQTT à escala revelou-se morosa. Gerir múltiplas instâncias de broker, garantir uma elevada disponibilidade e escalar dinamicamente em resposta a picos de tráfego exigiu um esforço operacional significativo. A nossa equipa de DevOps teve de investir tempo a afinar configurações, a lidar com a gestão de clusters e a otimizar o equilíbrio de carga, o que acrescentou uma sobrecarga desnecessária.

    2. Também investigámos soluções geridas por terceiros - tais como o HiveMQ - em vez de gerirmos as nossas próprias instâncias do Mosquitto. No entanto, o custo à escala rapidamente tornou esta opção inviável para as nossas necessidades.


  2. Dificuldade de Monitorização e Relatórios

    1. Embora o MQTT suporte o rastreio e registo de mensagens, depende fortemente das próprias mensagens MQTT para a monitorização. Os brokers de MQTT utilizam frequentemente tópicos especiais, tais como o tópico $SYS, para publicar o estado interno e métricas. Monitorizar estes brokers envolve subscrever estes tópicos para recolher informações sobre o estado de funcionamento e atividade do broker. Esta abordagem significa que as ferramentas de monitorização devem atuar como clientes MQTT, subscrevendo estes tópicos internos para recolher métricas, o que pode acrescentar complexidade à configuração de monitorização. Embora este método seja eficaz dentro do ecossistema MQTT, pode não se integrar perfeitamente com sistemas de monitorização externos que esperam métricas através de protocolos padrão como o HTTP. Isto tornou os relatórios em tempo real, a depuração e a análise de dados mais difíceis do que o previsto. Necessitávamos de um sistema que proporcionasse uma observabilidade mais profunda sobre o estado de funcionamento da ligação, taxas de sucesso de entrega e métricas de latência - funcionalidades que eram complexas de implementar ou que não estavam nativamente disponíveis no MQTT.


  3. Falta de Autenticação e Autorização Flexíveis

    1. Uma das desvantagens mais críticas foi a inflexibilidade na gestão de autenticação e autorização. Os brokers de MQTT oferecem mecanismos de autenticação, mas a implementação de um controlo de acesso detalhado para diferentes classes de utilizadores - como a diferenciação entre subscritores premium e gratuitos - revelou-se complexa. Além disso, a nossa dependência de plugins de terceiros no Mosquitto deixou-nos desconfortáveis, pois introduzia uma dependência externa sobre a qual tínhamos controlo limitado. Adicionalmente, observámos um declínio no desempenho, dado que os nossos requisitos complexos de autenticação e autorização exigiam o descarregamento e encaminhamento (proxying) destes processos para um serviço separado, desenvolvido e mantido pela Spicy Mango. Isto acrescentou latência e complexidade desnecessárias, reforçando a nossa decisão de procurar uma solução mais integrada e eficiente.


  4. Desalinhado com a Nossa Stack de Desenvolvimento

    1. Embora o MQTT seja robusto, o seu ecossistema está vocacionado principalmente para a IoT e aplicações industriais, com brokers frequentemente escritos em linguagens como C (Mosquitto), Erlang (emqttd) ou Java (Moquette). A nossa equipa de engenharia trabalha principalmente com Node.js para o desenvolvimento de backend, e manter uma solução MQTT exigia introduzir uma nova tecnologia na nossa stack ou depender de brokers de terceiros, o que não era o ideal para a sustentabilidade a longo prazo.


  5. Sobrecarga Desnecessária para o Nosso Caso de Utilização

    1. O MQTT foi concebido para um amplo conjunto de casos de utilização de mensagens em tempo real, incluindo aqueles com dispositivos limitados e redes não fiáveis. Embora se destaque nesses cenários, o nosso principal objetivo era a distribuição eficiente e escalável em tempo real de metadados desportivos através de ligações estáveis à Internet. As funcionalidades adicionais do MQTT, tais como a retenção de mensagens e a gestão complexa de QoS, acrescentaram sobrecarga e complexidade desnecessárias à nossa infraestrutura sem proporcionar benefícios proporcionais.


Desenvolver a Nossa Própria Solução de Pub/Sub Baseada em WebSocket

Depois de avaliar exaustivamente o MQTT, tomámos a decisão estratégica de construir o nosso próprio sistema pub/sub baseado em WebSocket utilizando Node.js. Esta decisão permitiu-nos otimizar para as nossas necessidades específicas, mantendo a nossa stack tecnológica consistente e sustentável. Eis porque é que a nossa solução interna se revelou a escolha certa:

  1. Integração Perfeita com a Arquitetura Existente do Gameday

    1. A nossa plataforma já corre em Node.js, tornando simples o desenvolvimento de um serviço WebSocket que se integra perfeitamente com os nossos microserviços existentes. Isto reduziu o tempo de integração dos nossos engenheiros e simplificou a manutenção contínua.


  2. Leve e Otimizado para Metadados Desportivos

    1. Ao controlar a implementação, pudemos otimizar as estruturas das mensagens e os tamanhos dos payloads para dados desportivos. Ao contrário do MQTT, que suporta vários níveis de QoS de que não necessitávamos, a nossa solução WebSocket fornece atualizações com uma sobrecarga mínima de processamento.


  3. Escalável e Mais Fácil de Gerir

    1. Com a nossa própria solução, pudemos tirar partido dos serviços AWS, tais como o Elastic Load Balancing e as funcionalidades de auto-scaling para garantir uma escala suave. Construímos ferramentas de monitorização adaptadas às nossas necessidades, gerámos dados em tempo real sobre a estabilidade da ligação, subscritores ativos e tempos de entrega de mensagens, e integrámos também no nosso sistema de logs padrão.


  4. Autenticação e Autorização Personalizadas

    1. A segurança era uma preocupação primordial, e a nossa solução personalizada permitiu-nos implementar controlos detalhados de autenticação e autorização. O nosso sistema de autenticação e autorização é alimentado pelo AuthIDConnect, uma solução desenvolvida pela Spicy Mango. O AuthIDConnect permite que utilizadores registados façam login através de palavras-passe ou TOTP, emitindo tokens de acesso de curta duração e tokens de atualização de longa duração (ambos JWTs assinados). Os utilizadores podem renovar os seus tokens de acesso utilizando o token de atualização, mantendo um acesso seguro e contínuo. O token de acesso contém permissões que definem as autorizações do utilizador.

    2. O AuthIDConnect também suporta utilizadores anónimos, uma funcionalidade crucial para empresas externas que integram os metadados desportivos do Gameday nas suas próprias soluções. Neste modelo, quando um utilizador final anónimo está autorizado a utilizar o serviço de terceiros, o pedido de autenticação é encaminhado (proxied) pelo terceiro para o AuthIDConnect com um ID de sessão. O AuthIDConnect emite então um token de acesso anónimo assinado contendo o ID da sessão, que o utilizador final utiliza para se autenticar e autorizar o seu acesso às APIs do Gameday e ao serviço pub/sub de WebSocket.

    3. A nossa solução WebSocket foi concebida para validar estes tokens de forma eficiente e rápida, garantindo uma latência mínima e uma experiência contínua para todos os clientes ligados.


  5. Redução da Complexidade da Infraestrutura

    1. Ao evitar uma camada de protocolo adicional, eliminámos dependências desnecessárias e simplificámos a sobrecarga operacional. O nosso serviço WebSocket reside na nossa infraestrutura AWS existente, reduzindo a necessidade de manutenção adicional e dependências de terceiros.


  6. Cumprimento dos Pilares de uma Estrutura Bem Arquitetada (Well-Architected Framework)

    1. A nossa solução alinha-se com os pilares fundamentais da Well-Architected Framework da AWS:

      1. Excelência Operacional: Gestão e monitorização simplificadas com ferramentas de observabilidade personalizadas.

      2. Segurança: Autenticação e autorização detalhadas para controlar o acesso e evitar a exposição de dados não autorizados.

      3. Fiabilidade: O auto-scaling da AWS e as APIs de WebSocket geridas garantem uma elevada disponibilidade e resiliência.

      4. Eficiência de Desempenho: Sobrecarga mínima de processamento e estruturas de mensagens otimizadas melhoram a latência e os tempos de resposta.

      5. Otimização de Custos: A eliminação de dependências de terceiros reduz os custos de licenciamento e a sobrecarga de infraestrutura.

      6. Sustentabilidade: A redução da complexidade operacional e o uso eficiente de recursos ajudam a manter uma arquitetura sustentável.


Uma Visão Geral a 10.000 Pés

Abaixo encontra-se uma imagem de nível (muito) geral do que criámos. Crucialmente, conseguimos gerir e escalar a solução de distribuição por web socket em várias Zonas de Disponibilidade e Regiões, enquanto a autenticação e a autorização são todas transportadas no token do AuthIDConnect. Se quisermos, podemos implementar num padrão fan-out de servidores de origem e edge, para escalar de modo a responder à procura em qualquer região - tudo com a mesma implementação de servidor WebSocket.



Lições Aprendidas e Considerações Finais

A nossa jornada rumo a uma solução D2C baseada em WebSocket ensinou-nos lições valiosas. O MQTT é um protocolo poderoso e versátil, bem adequado para a IoT e comunicação máquina para máquina. No entanto, para os requisitos específicos do Gameday — escalabilidade, mensagens de baixa latência, integração com a nossa stack Node.js e controlos de segurança detalhados — a nossa solução WebSocket personalizada foi a melhor opção.

Esta experiência reforçou a importância de selecionar tecnologias que se alinham com a nossa especialização principal e objetivos operacionais. Ao desenvolvermos a nossa própria solução, temos agora um sistema altamente otimizado, escalável e seguro que fornece atualizações de metadados desportivos em tempo real a milhões de utilizadores com uma latência mínima.

À medida que o Gameday continua a evoluir, mantemo-nos empenhados em explorar novas formas de melhorar a nossa plataforma. Quer se trate de otimizar ainda mais a nossa infraestrutura WebSocket, de incorporar computação de edge ou de tirar partido de novas tecnologias na nuvem, o nosso objetivo continua a ser o mesmo: fornecer a melhor experiência possível de dados desportivos em tempo real.

Para saber mais sobre o que leu aqui, ou para saber como a Spicy Mango pode ajudar, envie-nos uma nota para hello@spicymango.co.uk, ligue-nos ou envie-nos uma mensagem usando o nosso formulário de contacto e entraremos em contacto consigo.

Para saber mais sobre o que leu aqui, ou para saber como a Spicy Mango pode ajudar, envie-nos uma nota para hello@spicymango.co.uk, ligue-nos ou envie-nos uma mensagem usando o nosso formulário de contacto e entraremos em contacto consigo.

Para saber mais sobre o que leu aqui, ou para saber como a Spicy Mango pode ajudar, envie-nos uma nota para hello@spicymango.co.uk, ligue-nos ou envie-nos uma mensagem usando o nosso formulário de contacto e entraremos em contacto consigo.

Mais insights que você pode gostar

Mais insights que você pode gostar

Mais insights que você pode gostar

Continue a jornada - com mais algumas informações relacionadas que achamos que você pode gostar.

Continue a jornada - com mais algumas informações relacionadas que achamos que você pode gostar.