Tenho uma página da web que mostra uma grande quantidade de dados do servidor. A comunicação é feita via ajax.
Cada vez que o usuário interage e altera esses dados (digamos que o usuário A renomeie algo), ele instrui o servidor a fazer a ação e o servidor retorna os novos dados alterados.
Se o usuário B acessar a página ao mesmo tempo e criar um novo objeto de dados, ele informará novamente ao servidor via ajax e o servidor retornará com o novo objeto para o usuário.
Na página de A, temos os dados com um objeto renomeado. E na página de B temos os dados com um novo objeto. No servidor, os dados têm um objeto renomeado e um novo objeto.
Quais são minhas opções para manter a página em sincronia com o servidor quando vários usuários a estão usando ao mesmo tempo?
Opções como bloquear a página inteira ou despejar todo o estado para o usuário a cada alteração são evitadas.
Se ajudar, neste exemplo específico, a página da web chama um método da web estático que executa um procedimento armazenado no banco de dados. O procedimento armazenado retornará todos os dados alterados e nada mais. O webmethod estático então encaminha o retorno do procedimento armazenado para o cliente.
Edição Bounty:
Como você projeta um aplicativo da web multiusuário que usa Ajax para se comunicar com o servidor, mas evita problemas de simultaneidade?
Ou seja, acesso simultâneo à funcionalidade e aos dados em um banco de dados sem nenhum risco de corrupção de dados ou estado
Respostas:
Visão geral:
Oi Raynos,
Não vou discutir nenhum produto em particular aqui. O que outros mencionaram é um bom conjunto de ferramentas para já dar uma olhada (talvez adicionar node.js a essa lista).
Do ponto de vista arquitetônico, você parece ter o mesmo problema que pode ser visto no software de controle de versão. Um usuário faz check-in de uma alteração em um objeto, outro usuário deseja alterar o mesmo objeto de outra forma => conflito. Você deve integrar as alterações dos usuários aos objetos e, ao mesmo tempo, ser capaz de fornecer atualizações oportunas e eficientes, detectando e resolvendo conflitos como o acima.
Se eu estivesse no seu lugar, desenvolveria algo assim:
1. Lado do servidor:
Determine um nível razoável no qual você definiria o que eu chamaria de "artefatos atômicos" (a página? Objetos na página? Valores dentro dos objetos?). Isso dependerá de seus servidores web, banco de dados e hardware de cache, número de usuário, número de objetos, etc. Não é uma decisão fácil de tomar.
Para cada artefato atômico, tenha:
Um servidor ou componente de pseudo-servidor que é capaz de entregar registros de mudanças relevantes a um usuário conectado de forma eficiente. Observer-Pattern é seu amigo para isso.
2. Lado do cliente:
Um cliente javascript que é capaz de ter uma conexão HTTP de longa duração com o servidor mencionado acima, ou usa polling leve.
Um componente atualizador de artefato javascript que atualiza o conteúdo dos sites quando o cliente javascript conectado notifica sobre as mudanças no histórico de artefatos observados. (novamente um padrão de observador pode ser uma boa escolha)
Um componente de confirmação de artefato javascript que pode solicitar a alteração de um artefato atômico, tentando adquirir o bloqueio mutex. Ele detectará se o estado do artefato foi alterado por outro usuário apenas alguns segundos antes (latância do cliente javascript e fatores de processo de confirmação), comparando o artefato-versão-id do cliente conhecido e o artefato-versão-id atual do servidor.
Um solucionador de conflitos javascript que permite uma decisão humana qual-mudança-é-a-certa. Você pode não querer apenas dizer ao usuário "Alguém foi mais rápido do que você. Excluí sua alteração. Vá chorar.". Muitas opções de diferenças bastante técnicas ou soluções mais amigáveis ao usuário parecem possíveis.
Então, como seria ...
Caso 1: diagrama tipo-sequência para atualização:
Caso 2: agora para comprometer:
Caso 3: para conflitos:
Algumas palavras sobre desempenho e escalabilidade
Sondagem HTTP vs. "envio" de HTTP
escala de backend
dimensionamento de front-end
ajustes "criativos"
Bem, espero que isso possa ser um começo para suas próprias ideias. Tenho certeza de que existem muitas outras possibilidades. Estou mais do que bem-vindo qualquer crítica ou aprimoramento a este post, o wiki está habilitado.
Christoph Strasen
fonte
Eu sei que esta é uma pergunta antiga, mas pensei em apenas interromper.
OT (transformações operacionais) parece ser uma boa opção para seus requisitos de edição multiusuário simultânea e consistente. É uma técnica usada no Google Docs (e também foi usada no Google Wave):
Há uma biblioteca baseada em JS para usar Operational Transforms - ShareJS ( http://sharejs.org/ ), escrita por um membro da equipe do Google Wave.
E se você quiser, existe uma estrutura web MVC completa - DerbyJS ( http://derbyjs.com/ ) construída no ShareJS que faz tudo para você.
Ele usa o BrowserChannel para comunicação entre o servidor e os clientes (e acredito que o suporte a WebSockets deve estar em andamento - estava lá anteriormente via Socket.IO, mas foi retirado devido a problemas do desenvolvedor com Socket.io). Documentos para iniciantes são um um pouco esparso no momento, no entanto.
fonte
Eu consideraria adicionar um carimbo modificado baseado em tempo para cada conjunto de dados. Portanto, se você estiver atualizando tabelas de banco de dados, deverá alterar o carimbo de data / hora modificado de acordo. Usando AJAX, você pode comparar o timestamp modificado do cliente com o timestamp da fonte de dados - se o usuário estiver atrasado, atualize a exibição. Semelhante a como este site verifica uma pergunta periodicamente para ver se alguém respondeu enquanto você digita uma resposta.
fonte
Você precisa usar técnicas de push (também conhecidas como Comet ou Ajax reverso) para propagar as alterações para o usuário assim que forem feitas no banco de dados. A melhor técnica atualmente disponível para isso parece ser a sondagem longa do Ajax, mas não é suportada por todos os navegadores, então você precisa de alternativas. Felizmente, já existem soluções que tratam disso para você. Entre eles estão: orbited.org e o já citado socket.io.
No futuro, haverá uma maneira mais fácil de fazer isso, que é chamada de WebSockets, mas ainda não se sabe quando esse padrão estará pronto para o horário nobre, pois há questões de segurança sobre o estado atual do padrão.
Não deve haver problemas de simultaneidade no banco de dados com novos objetos. Mas quando um usuário edita um objeto, o servidor precisa ter alguma lógica que verifique se o objeto foi editado ou excluído nesse meio tempo. Se o objeto foi excluído, a solução é, novamente, simples: basta descartar a edição.
Mas o problema mais difícil aparece, quando vários usuários estão editando o mesmo objeto ao mesmo tempo. Se os usuários 1 e 2 começarem a editar um objeto ao mesmo tempo, os dois farão suas edições nos mesmos dados. Digamos que as alterações feitas pelo usuário 1 sejam enviadas ao servidor primeiro, enquanto o usuário 2 ainda está editando os dados. Você tem então duas opções: Você pode tentar mesclar as alterações do Usuário 1 nos dados do Usuário 2 ou pode informar ao Usuário 2 que seus dados estão desatualizados e exibir uma mensagem de erro assim que seus dados forem enviados ao servidor. A última opção não é muito amigável aqui, mas a primeira é muito difícil de implementar.
Uma das poucas implementações que realmente acertou pela primeira vez foi o EtherPad , que foi adquirido pelo Google. Acredito que eles usaram algumas das tecnologias EtherPad no Google Docs e Google Wave, mas não posso dizer com certeza. O Google também abre o EtherPad com recursos, então talvez valha a pena dar uma olhada, dependendo do que você está tentando fazer.
Realmente não é fácil fazer isso editando coisas simultaneamente, porque não é possível fazer operações atômicas na web por causa da latência. Talvez este artigo ajude você a aprender mais sobre o assunto.
fonte
Tentar escrever tudo isso sozinho é um trabalho árduo e é muito difícil acertar. Uma opção é usar uma estrutura construída para manter os clientes sincronizados com o banco de dados e entre si em tempo real.
Descobri que a estrutura do Meteor faz isso bem ( http://docs.meteor.com/#reactivity ).
"O Meteor adota o conceito de programação reativa. Isso significa que você pode escrever seu código em um estilo imperativo simples e o resultado será recalculado automaticamente sempre que houver alterações de dados das quais seu código depende."
"Este padrão simples (computação reativa + fonte de dados reativa) tem ampla aplicabilidade. O programador evita escrever chamadas de cancelar / resubscribe e garantir que sejam chamadas no momento certo, eliminando classes inteiras de código de propagação de dados que, de outra forma, obstruiriam seu aplicativo com lógica sujeita a erros. "
fonte
Não acredito que ninguém mencionou o Meteor . É uma estrutura nova e imatura com certeza (e oficialmente suporta apenas um banco de dados), mas leva todo o trabalho pesado e pensar em um aplicativo multiusuário como o pôster está descrevendo. Na verdade, você NÃO pode construir um aplicativo de atualização ao vivo com vários usuários. Aqui está um breve resumo:
O Meteor é tão simples que eu sugiro que você pelo menos dê uma olhada nele para ter ideias para roubar.
fonte
Estas páginas da Wikipedia pode ajudar a perspectiva add para aprender sobre a simultaneidade e programação concorrente para a concepção de um ajax aplicação web que ou puxa ou é empurrado estado de eventos ( EDA ) mensagens em um padrão de mensagens . Basicamente, as mensagens são replicadas para assinantes de canal que respondem a eventos de mudança e solicitações de sincronização.
Existem muitas formas de software colaborativo simultâneo baseado na web .
Existem várias bibliotecas cliente de API HTTP para etherpad-lite , um editor colaborativo em tempo real .
django-realtime-playground implementa um aplicativo de bate-papo em tempo real no Django com várias tecnologias de tempo real como Socket.io .
Tanto o AppEngine quanto o AppScale implementam a API AppEngine Channel ; que é diferente da API do Google Realtime , que é demonstrada por googledrive / realtime-playground .
fonte
As técnicas de push do lado do servidor são o caminho a percorrer aqui. Cometa é (ou era?) Uma palavra da moda.
A direção específica que você toma depende muito da pilha do seu servidor e de quão flexível você é. Se você puder, eu daria uma olhada em socket.io , que fornece uma implementação cross-browser de websockets, que fornece uma maneira muito simplificada de comunicação bidirecional com o servidor, permitindo que o servidor envie atualizações para os clientes.
Em particular, veja esta demonstração do autor da biblioteca, que demonstra quase exatamente a situação que você descreve.
fonte