Tengo una página web que muestra una gran cantidad de datos del servidor. La comunicación se realiza a través de ajax.
Cada vez que el usuario interactúa y cambia estos datos (digamos que el usuario A cambia el nombre de algo), le dice al servidor que realice la acción y el servidor devuelve los nuevos datos modificados.
Si el usuario B accede a la página al mismo tiempo y crea un nuevo objeto de datos, se lo dirá nuevamente al servidor a través de ajax y el servidor regresará con el nuevo objeto para el usuario.
En la página de A tenemos los datos con un objeto renombrado. Y en la página de B tenemos los datos con un nuevo objeto. En el servidor, los datos tienen un objeto renombrado y un objeto nuevo.
¿Cuáles son mis opciones para mantener la página sincronizada con el servidor cuando varios usuarios la usan al mismo tiempo?
Más bien se evitan opciones como bloquear toda la página o volcar el estado completo al usuario en cada cambio.
Si ayuda, en este ejemplo específico la página web llama a un método web estático que ejecuta un procedimiento almacenado en la base de datos. El procedimiento almacenado devolverá cualquier dato que haya cambiado y no más. Luego, el método web estático reenvía la devolución del procedimiento almacenado al cliente.
Edición de recompensa:
¿Cómo se diseña una aplicación web multiusuario que usa Ajax para comunicarse con el servidor pero evita problemas de concurrencia?
Es decir, acceso simultáneo a la funcionalidad y a los datos de una base de datos sin riesgo de corrupción de datos o estado
Respuestas:
Visión general:
Hola Raynos,
No discutiré ningún producto en particular aquí. Lo que otros mencionaron es un buen conjunto de herramientas para echar un vistazo (tal vez agregue node.js a esa lista).
Desde un punto de vista arquitectónico, parece que tiene el mismo problema que se puede ver en el software de control de versiones. Un usuario registra un cambio en un objeto, otro usuario quiere alterar el mismo objeto de otra manera => conflicto. Debe integrar los cambios de los usuarios en los objetos y, al mismo tiempo, poder entregar actualizaciones de manera oportuna y eficiente, detectando y resolviendo conflictos como el anterior.
Si estuviera en tu lugar, desarrollaría algo como esto:
1. Lado del servidor:
Determine un nivel razonable en el que definiría lo que yo llamaría "artefactos atómicos" (¿la página? ¿Objetos en la página? ¿Valores dentro de los objetos?). Esto dependerá de sus servidores web, base de datos y hardware de almacenamiento en caché, número de usuarios, número de objetos, etc. No es una decisión fácil de tomar.
Para cada artefacto atómico tiene:
Un servidor o componente pseudo-servidor que puede entregar registros de cambios relevantes a un usuario conectado de manera eficiente. Observer-Pattern es tu amigo para esto.
2. Lado del cliente:
Un cliente javascript que puede tener una conexión HTTP de larga duración a dicho servidor anterior, o utiliza un sondeo ligero.
Un componente de actualización de artefactos de JavaScript que actualiza el contenido de los sitios cuando el cliente de JavaScript conectado notifica cambios en el historial de artefactos observados. (de nuevo, un patrón de observador podría ser una buena opción)
Un componente de confirmación de artefactos de JavaScript que puede solicitar cambiar un artefacto atómico, tratando de adquirir un bloqueo mutex. Detectará si el estado del artefacto ha sido cambiado por otro usuario unos segundos antes (latencia del cliente javascript y factores de proceso de confirmación) comparando el identificador de versión de artefacto conocido del lado del cliente y el identificador de versión de artefacto actual del lado del servidor.
Un solucionador de conflictos de JavaScript que permite una decisión humana sobre cuál es el cambio correcto. Es posible que no desee simplemente decirle al usuario "Alguien fue más rápido que usted. Eliminé su cambio. Ve a llorar". Parecen posibles muchas opciones de diferencias bastante técnicas o soluciones más fáciles de usar.
Entonces, ¿cómo iría?
Caso 1: tipo de diagrama de secuencia para actualización:
Caso 2: Ahora para comprometerse:
Caso 3: para conflictos:
Algunas palabras sobre rendimiento y escalabilidad
Sondeo HTTP frente a "empuje" HTTP
escalado de backend
escala de frontend
ajustes "creativos"
Bueno, espero que esto pueda ser un comienzo para sus propias ideas. Estoy seguro de que hay muchas más posibilidades. Estoy más que agradecido por cualquier crítica o mejora a esta publicación, wiki está habilitado.
Christoph Strasen
fuente
Sé que esta es una vieja pregunta, pero pensé en intervenir.
OT (transformaciones operativas) parece una buena opción para su requisito de edición multiusuario simultánea y consistente. Es una técnica utilizada en Google Docs (y también se utilizó en Google Wave):
Hay una biblioteca basada en JS para usar Operational Transforms: ShareJS ( http://sharejs.org/ ), escrita por un miembro del equipo de Google Wave.
Y si lo desea, hay un marco web MVC completo: DerbyJS ( http://derbyjs.com/ ) construido en ShareJS que lo hace todo por usted.
Utiliza BrowserChannel para la comunicación entre el servidor y los clientes (y creo que la compatibilidad con WebSockets debería estar en proceso; estaba allí anteriormente a través de Socket.IO, pero se eliminó debido a problemas del desarrollador con Socket.io). un poco escaso en este momento, sin embargo.
fuente
Consideraría agregar un sello modificado basado en el tiempo para cada conjunto de datos. Por lo tanto, si está actualizando tablas de base de datos, debería cambiar la marca de tiempo modificada en consecuencia. Con AJAX, puede comparar la marca de tiempo modificada del cliente con la marca de tiempo de la fuente de datos; si el usuario se retrasa, actualice la pantalla. Similar a cómo este sitio revisa una pregunta periódicamente para ver si alguien más ha respondido mientras usted escribe una respuesta.
fuente
Debe utilizar técnicas de empuje (también conocidas como Comet o Ajax inverso) para propagar los cambios al usuario tan pronto como se realicen en la base de datos. La mejor técnica disponible actualmente para esto parece ser el sondeo largo Ajax, pero no es compatible con todos los navegadores, por lo que necesita alternativas. Afortunadamente, ya existen soluciones que se encargan de esto por usted. Entre ellos se encuentran: orbited.org y el ya mencionado socket.io.
En el futuro, habrá una forma más fácil de hacer esto que se llama WebSockets, pero aún no se sabe cuándo estará listo ese estándar para el horario de máxima audiencia, ya que existen preocupaciones de seguridad sobre el estado actual del estándar.
No debería haber problemas de concurrencia en la base de datos con nuevos objetos. Pero cuando un usuario edita un objeto, el servidor necesita tener alguna lógica que verifique si el objeto ha sido editado o eliminado mientras tanto. Si el objeto ha sido eliminado, la solución es, nuevamente, simple: simplemente descarte la edición.
Pero el problema más difícil aparece cuando varios usuarios están editando el mismo objeto al mismo tiempo. Si el usuario 1 y 2 comienzan a editar un objeto al mismo tiempo, ambos realizarán sus ediciones en los mismos datos. Digamos que los cambios realizados por el Usuario 1 se envían primero al servidor mientras el Usuario 2 todavía está editando los datos. Entonces tiene dos opciones: puede intentar fusionar los cambios del Usuario 1 con los datos del Usuario 2 o puede decirle al Usuario 2 que sus datos están desactualizados y mostrarle un mensaje de error tan pronto como sus datos sean enviados al servidor. La última opción no es muy fácil de usar aquí, pero la primera es muy difícil de implementar.
Una de las pocas implementaciones que realmente hizo esto bien por primera vez fue EtherPad , que fue adquirida por Google. Creo que luego usaron algunas de las tecnologías de EtherPad en Google Docs y Google Wave, pero no puedo asegurarlo. Google también abrió EtherPad, por lo que tal vez valga la pena echarle un vistazo, dependiendo de lo que intente hacer.
Realmente no es fácil hacer estas cosas de edición simultáneamente, porque no es posible realizar operaciones atómicas en la web debido a la latencia. Quizás este artículo te ayude a aprender más sobre el tema.
fuente
Tratar de escribir todo esto usted mismo es un gran trabajo y es muy difícil hacerlo bien. Una opción es utilizar un marco creado para mantener a los clientes sincronizados con la base de datos y entre sí, en tiempo real.
Descubrí que el marco Meteor lo hace bien ( http://docs.meteor.com/#reactivity ).
"Meteor adopta el concepto de programación reactiva. Esto significa que puede escribir su código en un estilo imperativo simple, y el resultado se recalculará automáticamente siempre que los datos cambien de los que depende su código".
"Este patrón simple (cálculo reactivo + fuente de datos reactiva) tiene una amplia aplicabilidad. El programador no tiene que escribir llamadas de cancelación de suscripción / resuscripción y asegurarse de que se llaman en el momento correcto, eliminando clases enteras de código de propagación de datos que, de otro modo, obstruirían su aplicación con lógica propensa a errores ".
fuente
No puedo creer que nadie haya mencionado a Meteor . Es un marco nuevo e inmaduro con seguridad (y solo admite oficialmente una base de datos), pero requiere todo el trabajo pesado y el pensamiento de una aplicación multiusuario como la que describe el póster. De hecho, NO puede crear una aplicación de actualización en vivo para múltiples usuarios. Aquí hay un resumen rápido:
Meteor es lo suficientemente simple como para sugerirle que al menos le eche un vistazo en busca de ideas para robar.
fuente
Estas páginas de Wikipedia pueden ayudar perspectiva añadir a aprender acerca de la concurrencia y computación concurrente para el diseño de un ajax aplicación web que, o bien tirones o se empujaron Estado de eventos ( EDA ) mensajes en un patrón de mensajería . Básicamente, los mensajes se replican en los suscriptores del canal que responden a eventos de cambio y solicitudes de sincronización.
Hay muchas formas de software colaborativo simultáneo basado en la web .
Hay una serie de bibliotecas cliente HTTP API para etherpad-lite , un editor colaborativo en tiempo real .
django-realtime-playground implementa una aplicación de chat en tiempo real en Django con varias tecnologías en tiempo real como Socket.io .
Tanto AppEngine como AppScale implementan la API del canal AppEngine ; que es diferente de la API de Google Realtime , que se demuestra mediante googledrive / realtime-playground .
fuente
Las técnicas de inserción del lado del servidor son el camino a seguir aquí. Cometa es (¿o era?) Una palabra de moda.
La dirección particular que tome depende en gran medida de su pila de servidores y de su flexibilidad. Si puede, echaría un vistazo a socket.io , que proporciona una implementación de websockets entre navegadores, que proporciona una forma muy ágil de tener comunicación bidireccional con el servidor, lo que permite que el servidor envíe actualizaciones a los clientes.
En particular, vea esta demostración del autor de la biblioteca, que demuestra casi exactamente la situación que describe.
fuente