Arquitetura de aplicativo móvel para melhorar a velocidade e reduzir a transferência de dados

5

Contexto empresarial do problema

Nosso aplicativo para iPhone permite que os usuários paguem comerciantes e ganhem prêmios.

Os usuários também podem fazer coisas como:

  1. Ver histórico de transações
  2. Veja seus pontos e recompensas disponíveis ou reivindique prêmios.
  3. Ganhe dinheiro consultando amigos, veja um histórico de referências convertidas e não convertidas.
  4. Ver ofertas em execução em alguns comerciantes (especiais de happy hour, etc)
  5. Exibir informações sobre comerciantes (local, horário, etc.)

Como itens como ofertas ou prêmios disponíveis, histórico de transações e indicações podem ser alterados a qualquer momento, temos um problema clássico de invalidação de cache no dispositivo do usuário.

Solução insatisfatória atual

Nossa arquitetura atual é bastante padrão e consiste em endointes de API como "/ comerciantes", "/ recompensas", "/ transactions", "/ deals" e assim por diante.

Atualmente, resolvemos o problema de cache antigo:

  1. Pesquise o servidor com frequência enquanto o aplicativo está aberto (com a mesma frequência de cada minuto para algumas chamadas de API), bem como sempre que o aplicativo recupera o foco.
  2. Indicar dados possivelmente obsoletos com texto como Última atualização há 3 minutos

Usamos etags para evitar o reenvio de dados inteiros inalterados (por exemplo, toda a lista de comerciantes), mas ainda há muita largura de banda desperdiçada com a nossa abordagem atual. Por exemplo, se um único comerciante for alterado, todos os comerciantes serão reenviados. Se uma única nova transação for adicionada, todas as transações serão reenviadas.

Na prática, do ponto de vista do usuário, isso geralmente não é grande coisa, já que estamos falando de tamanhos de 1-200K no máximo, e normalmente menos. No entanto, pode ser um problema em áreas com pouca recepção de células, uma situação que surge com frequência suficiente para ouvir reclamações.

E no lado do servidor, toda essa pesquisa cria muita carga desnecessária, especialmente porque as consultas de processamento e banco de dados ocorrem mesmo quando os etags são inalterados,

Melhores soluções?

Estamos reformulando o aplicativo e o código do servidor e pensando em estratégias alternativas. Como esse é um problema bastante comum, gostaria de saber como os outros estão resolvendo isso.

Algumas ideias que tenho até agora:

  1. Para minimizar a transferência de dados : acompanhe, no servidor, os dados de cada usuário. Envie patches JSON de apenas dados alterados, em vez de cópias novas de todos os dados. Cópias dos dados de cada usuário podem ser armazenadas em redis e expirar após alguns dias ou uma semana. Isso manteria a "sessão ativa" rapidamente, enquanto o usuário sem um cache do servidor armazenado poderia apenas receber uma nova cópia de todos os seus dados ao fazer o login após um período inativo (o mesmo que agora). Embora, em teoria, isso possa funcionar, manter as cópias do servidor e do cliente em sincronia, remendando as duas, parece uma fonte rica de possíveis bugs, mesmo se eu estiver usando bibliotecas de correção JSON.

  2. Para minimizar a carga do servidor : estabeleça conexões de soquete da web com cada cliente, em vez de pesquisar. Deixe que os eventos que alteram o estado do cliente (por exemplo, uma compra, uma conversão de referência, uma finalização de transação etc.) abram mensagens websocket, que por sua vez acionam o cliente para atualizar. Isso pode ser usado em conjunto com a ideia 1 ou com o método atual de envio de cópias novas de todos os dados alterados. Mesmo com o método atual, isso ainda seria uma grande melhoria, já que os dados só seriam solicitados e enviados quando necessário.

Neste momento, estou inclinado para 2 sem 1, já que 1 parece muito potencialmente repleto de problemas. Eu tenho algumas preocupações sobre confiar em websockets em dispositivos móveis, mas depois de fazer pesquisas aqui, em SO e em outros lugares, parece que essa preocupação não é válida.

Eu adoraria ouvir outras sugestões, talvez radicalmente diferentes, para resolver esses problemas.

    
por Jonah 29.12.2015 / 07:18
fonte

1 resposta

2

Como é um aplicativo nativo, você pode ignorar completamente o HTTP se quiser.

Você pode usar o HTTP / 2.0, que permite fluxos. Os fluxos são uma solução parcial para o bloqueio de linha de frente (HOL), permitindo que várias solicitações compartilhem uma única conexão TCP e sejam fornecidas de forma incremental e concisa. Também permite alguma comunicação iniciada pelo servidor. Ainda é TCP, então não é uma solução completa para o bloqueio de HOL.

Você pode usar o WebRTC que usa o DTLS para evitar que o HOL bloqueie completamente e ative eventos de servidor ou ponto a ponto de maneira eficiente.

Estou inclinado a evitar o HTTP para esse tipo de caso de uso, pois ele impõe restrições artificiais e antipáticas aos fluxos de solicitação de dados do seu aplicativo. É uma necessidade no navegador, mas não em um aplicativo. O HTTP tem a vantagem de fornecer uma única interface de serviço para todos os clientes de aplicativos baseados em desktop, desktop e móveis, por isso leve isso em consideração.

Você pode usar o AMQP por TLS (com algo como o RabbitMQ) na porta 443 e fazer comunicações baseadas em eventos por meio de suas filas de mensagens. Os serviços de back-end enviariam atualizações para as filas ou um serviço intermediário de atualização chamaria os serviços REST e os atualizaria. Isso ainda sofreria com o bloqueio HOL no nível TCP.

Outra opção é o ZeroMQ com o CurveZMQ. É também uma solução orientada a mensagens, mas na qual você não precisa de um intermediário central separado, como o AMQP. Seu aplicativo pode falar diretamente com seu servidor por meio de mensagens. Seu servidor pode fazer o polling e o gerenciamento de estado REST e enviar atualizações para o cliente com a frequência ou frequência que você desejar. Isso permite degradação graciosa em situações de falha. Esta é a opção mais flexível e indiscutivelmente mais enxuta, mas também é sobre TCP, portanto, não evita totalmente o bloqueio de HOL.

Para o que vale a pena, o bloqueio HOL é improvável em qualquer lugar perto do seu problema imediato e a solução requer compromissos significativos.

    
por 30.12.2015 / 21:58
fonte