Como economizar durante a colaboração em tempo real

10

Quero que vários usuários editem o mesmo documento. O problema que enfrento é que, quando um novo usuário entra, ele pode ver um documento desatualizado. Como garantir que os novos usuários obtenham as alterações mais recentes?

Pensei em algumas soluções:

  • Economize em todas as alterações. Eu não gosto desta solução, porque ela desacelerará as coisas na interface do usuário e sobrecarregará o banco de dados.

  • Quando um novo usuário ingressa, acione o save em todos os outros clientes. Após a gravação de outros clientes, carregue o documento. Com isso, ainda pode haver inconsistência.

Quaisquer outras sugestões seriam úteis.

ATUALIZAÇÃO: Depois de analisar a solução sugerida, a API do Google Realtime, descobri que:

  1. Os usuários do seu aplicativo devem ter o Google Drive e conceder acesso a eles . Isso poderia, na melhor das hipóteses, apresentar um fluxo estranho de interface do usuário ou impedir que usuários que não possuem o Google Drive usem o recurso em tempo real.

  2. Todas as configurações de compartilhamento feitas ao seu lado precisam ser replicadas para o documento do Google.

ATUALIZAÇÃO 2: Para atingir o objetivo, fui com o Firebase do Google

desenvolvedor
fonte
Por que existe uma diferença entre um novo usuário e usuários já ativos editando / visualizando o mesmo documento?
Andy
@ Andy O que estou fazendo atualmente é transmitir via sockets todas as alterações que os usuários fazem. Essas alterações atualizam a interface do usuário para usuários que têm seus navegadores abertos, mas eles não são salvos instantaneamente no banco de dados. Portanto, tenho uma situação: quando um novo usuário entra, ele carrega o documento do banco de dados e não vê todas as alterações recentes que ainda não foram salvas.
dev.e.loper
1
se você já está enviando alterações e deseja deixar o mesmo comportamento como está agora, pode solicitar a um dos clientes que envie a última visualização para um novo cliente ou pode ter um cliente virtual no servidor, que recebe todas as alterações e quando o novo cliente entra envia as últimas vista para isso.
Dainius

Respostas:

14

Google Drive

Se você está tentando criar sua própria versão do Google Docs, sugiro que você dê uma olhada na API do Google Realtime . O Google lançou recentemente isso com a intenção de permitir que outros desenvolvedores usem as mesmas ferramentas que eles usaram para permitir a colaboração em tempo real. Isso permitiria economizar tempo no seu desenvolvimento e obter um produto em funcionamento mais cedo.

Você pode facilmente pegar os dados que estão no documento e enviá-los para o banco de dados em intervalos regulares, ou fazer com que o próprio banco de dados seja um 'participante' da troca, simplesmente ouvindo e registrando todas as alterações. Ele também permite que um usuário defina suas próprias estruturas de dados que podem ser usadas na API em tempo real, para que você seja livre para estendê-lo como achar melhor.

Não pertencente ao Google Drive

Portanto, de acordo com sua pesquisa, o Google Drive não é uma opção. Tudo bem, mas será mais difícil e possivelmente não funcionará tão bem, dependendo de quanto você colocar nela.

Aqui está uma estratégia geral que eu usaria para solucionar esse problema:

  1. O servidor deve ser o multiplexador de comunicação. Cada pessoa conversa com o servidor e o servidor envia essas informações para todos os outros. Dessa forma, o servidor sempre tem a visualização mais atualizada do documento.

  2. Encontre um algoritmo / módulo de terceiros para resolução de conflitos. A resolução de conflitos é difícil e é algo que ainda não é perfeito. Fazer isso sozinho poderia facilmente aumentar o escopo do projeto para ser muito grande. Se você não puder usar um algoritmo de terceiros, sugiro que você permita apenas que um usuário edite uma área de cada vez, para que o usuário obtenha um bloqueio antes de editar uma área ou corre o risco de destruir o trabalho de outros usuários, o que vai ficar muito velho, muito rápido.

  3. Quando um novo usuário ingressar, forneça o documento mais recente e comece a transmitir automaticamente os comandos para ele. O servidor tem a visualização mais recente e, portanto, pode distribuir automaticamente.

  4. Faça backup no banco de dados em determinados intervalos. Decida com que frequência você deseja fazer backup (a cada 5 minutos ou talvez a cada 50 alterações). Isso permite que você mantenha o backup que deseja.

Problemas: esta não é uma solução perfeita, então, aqui estão alguns problemas que você pode enfrentar.

  1. A taxa de transferência do servidor pode prejudicar o desempenho

  2. Muitas pessoas que lêem / escrevem podem sobrecarregar o servidor

  3. As pessoas podem ficar fora de sincronia se uma mensagem for perdida; portanto, você deve sincronizar em pontos regulares. Isso significa enviar a mensagem inteira novamente, o que pode ser caro, mas, caso contrário, as pessoas podem não ter o mesmo documento e não o conhecer.

Ampt
fonte
Sim, as alterações são transmitidas a todos os clientes e eles têm sua versão (provavelmente a mesma) no navegador. Parece que você está dizendo que atualizar um documento a cada ação é um caminho a percorrer?
dev.e.loper
Ou pelo menos tenha prazos regulares de 'sincronização', onde o estado atual do documento é transmitido em segundo plano para garantir que todos estejam na mesma página. Quantas vezes dependeria da rapidez com que as pessoas mudariam o documento. Dessa forma, você já possui um método estabelecido para enviar para novas pessoas, além da capacidade de garantir que nunca diverja demais.
Ampt
1
+1. Não dificulte a vida. O Google faz isso bem sem precisar reinventar a roda.
Neil
O Google Realtime salva no Google Drive? Quero salvar no meu banco de dados, não no Google Drive.
dev.e.loper
@ dev.e.loper adicionou algumas informações sobre isso à resposta para você.
Ampt
3

Eu recomendaria 1 cópia persistente do documento no servidor. Quando um cliente se conecta ao servidor, você emite um UPDATEcomando para esse cliente com todas as alterações.

Atualizar fluxo de trabalho

O usuário causa o desencadeamento de alterações -> o cliente envia UPDATEpara o servidor -> o servidor envia UPDATEpara os clientes

Gatilhos viáveis

  1. O usuário clica em Salvar
  2. O usuário conclui uma tarefa específica
    • Finaliza a edição de uma célula
    • Finaliza a edição de uma frase / parágrafo / linha
  3. O usuário clica em Desfazer
  4. O usuário pressiona a tecla Return
  5. O usuário digita uma chave (economize em todas as alterações)

Implementação de atualização

Eu sugeriria a possibilidade de recriar o documento com uma série de UPDATEcomandos, para que o servidor armazene cada UPDATE e, quando um novo cliente se conectar, o cliente poderá receber a série de atualizações e ele próprio poderá recriar o documento a ser exibido. o usuário. Além disso, você pode alternativamente ter um SAVEcomando separado e fazer com que UPDATE sejam alterações temporárias que podem ser usadas para UNDOsolicitações e que o SAVE realmente o armazene para ser reaberto se o servidor estiver fechado ou todos os clientes desconectarem.

Korey Hinton
fonte
2
E a resolução de conflitos? E se duas pessoas editarem a mesma área de texto ao mesmo tempo? Além disso, isso parece sobrecarregar o banco de dados, algo que o OP estava procurando evitar. Pode ser viável para o que ele precisa.
Ampt
@Ampt Criei uma planilha usando esse modelo e, para conflitos, cada tarefa específica sendo atualizada foi completamente substituída pela versão mais recente. Portanto, a última pessoa a concluir a edição de uma célula substituirá completamente a atualizada anteriormente, sem mesclagem.
Korey Hinton 02/07
1
Portanto, uma frase substituirá outra se este for, digamos, um documento do Word?
Ampt
@Ampt sim, como alternativa, você pode implementar uma maneira de bloquear o que está sendo trabalhado, mas eu segui o caminho mais fácil.
Korey Hinton #
3

1) Dê uma olhada no Knockout.js

Ele segue um padrão MVVM e envia automaticamente notificações para a Visualização com base nas alterações no Modelo. Por exemplo, examine sua matriz observável para fornecer um pouco mais de informações sobre como eles fazem isso.

2) Misture isso com o SignalR e agora você poderá enviar notificações para outros usuários que trabalham no documento. Do site deles:

O SignalR também fornece uma API de alto nível muito simples para executar RPC de servidor para cliente (chame funções JavaScript nos navegadores dos seus clientes a partir do código .NET do lado do servidor) em seu aplicativo ASP.NET, além de adicionar ganchos úteis para o gerenciamento de conexões , por exemplo, conectar / desconectar eventos, agrupar conexões, autorização.

Portanto, você precisará ter alguns ganchos no nível do modelo no Knockout.js para fazer algumas chamadas do SignalR sempre que ocorrer uma alteração. Os outros clientes receberão o aviso do SignalR e, em seguida, acionarão uma alteração correspondente em sua cópia do Modelo, que retornará à sua Visualização.

É uma combinação interessante das duas estruturas, e você deve poder pesquisar e reunir mais informações para lidar com os detalhes.

Por exemplo, este exemplo de projeto de código aborda especificamente o Co Working UIs and Continuous Clientsque parece ser exatamente o que você está tentando fazer.

Os aplicativos da web da nova era podem precisar oferecer experiências de usuário da nova era - e devem lidar adequadamente com os cenários de trabalho e de clientes contínuos. Isso envolve garantir que a interface do usuário esteja sincronizando-se adequadamente entre dispositivos e usuários para garantir que o estado do aplicativo e da interface do usuário seja mantido "como está".

Esta postagem do blog parece ser um ponto de entrada para uma série de postagens discutindo o uso dos dois pacotes e contrastando isso com a abordagem tradicional do ASP.NET. Pode fornecer alguns pontos para consideração enquanto você cria seu site.

Esta postagem no blog parece ser um pouco mais básica e fornece as bases para combinar os dois pacotes.

Divulgação: eu não sou afiliado a nenhum dos links acima, nem procurei no conteúdo deles para ver como é correto ou correto.


fonte
2

A solução é Transformação Operacional (OT). Se você nunca ouviu falar, o OT é uma classe de algoritmos que fazem simultaneidade em vários sites em tempo real. OT é como um idiota em tempo real. Funciona com qualquer atraso (de zero a um feriado prolongado). Ele permite que os usuários façam edições simultâneas ao vivo com baixa largura de banda. O OT fornece a consistência eventual entre vários usuários, sem novas tentativas, sem erros e sem que nenhum dado seja sobrescrito.

Mas implementar o OT é uma tarefa difícil e demorada. Então, você pode querer usar uma biblioteca externa como http://sharejs.org/ .

aj_
fonte
1
A API do Google Realtime está fazendo OT youtu.be/hv14PTbkIs0?t=14m20s Eles fazem isso no cliente e no servidor. Não consegui uma resposta clara ao ler os documentos do ShareJS, mas estou assumindo que o ShareJS faz OT no cliente e no servidor?
dev.e.loper
1

Depende principalmente do tipo de seus documentos e de como seus usuários colaboram.

No entanto, eu:

  1. permita que todos os clientes enviem alterações não salvas ao servidor de vez em quando (depende de como os usuários trabalham com os documentos).
  2. o servidor armazena os deltas na sessão do usuário (mesmo para um cliente gordo, você precisa de algo como uma sessão)
  3. outros clientes editando / visualizando o mesmo documento recebem essas alterações temporárias ou pelo menos uma dica de que isso pode acontecer.

Vantagens:

  • nenhuma atualização de banco de dados, a menos que alguém clique em "salvar"
  • backup para o caso em que o cliente trava (para o período da sessão)
  • seu servidor decide como e quais dados encaminhar para qual cliente (por exemplo, você pode iniciar o recurso com apenas uma nota e posteriormente implementar uma mesclagem e destaque mais sofisticados)

Desvantagens:

  • não 'em tempo real' - por exemplo, você envia a cada 30 segundos, mas alguém digita três frases nesse período.
  • mais tráfego de rede - dependente de seus documentos e colaboração
  • sessões possivelmente grandes
  • esforço de computação possivelmente alto se muitos usuários colaborarem e fizerem muitas alterações
Andy
fonte
1

Essencialmente, o que você está perguntando é como lidar com o estado mutável compartilhado. Salvar é a parte fácil; mas como você lida com várias pessoas editando a mesma coisa ao mesmo tempo? Você deseja que todos os usuários visualizem o mesmo documento enquanto sincronizam edições simultâneas, tudo em tempo real.

Como você provavelmente já se reuniu, é um problema difícil! Existem algumas soluções pragmáticas:

  1. Modifique os requisitos do seu aplicativo para não permitir verdadeira edição simultânea. As edições podem ser mescladas como nos sistemas de controle de origem, com resultados transmitidos para cada cliente. Você mesmo pode criar isso, mas seria uma experiência pior para o usuário.
  2. Terceirize a sincronização de mutações de estado para uma solução de código aberto que se integra à sua tecnologia existente. O ShareDB é o líder atual neste espaço. É baseado em Transformação Operacional e usado em pelo menos um sistema de produção. Isso resolverá o problema de economia com o qual você está preocupado, mas não ajudará com nenhum dos recursos adicionais do UX obrigatórios para qualquer aplicativo colaborativo.
  3. Use uma plataforma pronta para uso, como Convergence (aviso: sou fundador), para lidar com todos os aspectos difíceis para você. Você também terá ferramentas adicionais para colaboração em tempo real, como rastreamento de cursor / mouse, seleções e bate-papo para criar uma experiência colaborativa superior rapidamente. Veja esta pergunta para obter um bom resumo de todas as ferramentas existentes.
alalonde
fonte