2009-11-03 17 views
13

Estoy buscando un patrón de diseño que maneje grandes conjuntos de datos a través de Internet, y realiza actualizaciones periódicas de estos objetos. Estoy desarrollando una aplicación que mostrará miles de registros en la interfaz de usuario a la vez. Además, varias propiedades de estos objetos son bastante transitorias y deben actualizarse en el cliente para mantener al usuario al tanto del estado cambiante de estos registros en el sistema. Tengo algunas ideas de cómo abordar este problema, pero pensé que podría haber un patrón de diseño (o patrones) que maneje este tipo de escenario.¿Existe un patrón de diseño para manejar grandes conjuntos de datos a través de Internet?

Limitaciones:

  1. el lado del cliente para esto se escribe en Silverlight.
  2. Los objetos en sí mismos no son muy grandes (alrededor de 15 propiedades de tipo de valor y cadena), pero consultar todos los datos es costoso. Las 15 o más propiedades contienen datos de varias fuentes; ninguna declaración de unión inteligente o indexación va a acelerar la consulta. Estoy pensando en rellenar solo un subconjunto de las propiedades en la carga inicial y luego completar los detalles más caros a medida que el usuario amplía una agrupación de objetos determinada. Piense en los mapas de Google, pero en lugar de calles y edificios, muestra los objetos.
  3. Podré limitar la parte de los miles de objetos que se están actualizando. Sin embargo, necesitaré que el usuario pueda "alejarse" de un contexto que permite la actualización granular a una que muestra todos los miles de objetos. Me imagino que la actualización se desactivará de nuevo para los objetos cuando dejan un contexto de zoom suficiente.

¿Ideas sobre cómo abordar todo o parte de este problema? Como mencioné, ya estoy considerando algunas ideas, pero nada de lo que he reunido hasta ahora me da una buena impresión sobre el éxito de este proyecto.

Editar:

creo que las partes difíciles realmente se reducen a dos cosas por las que pueden necesitar dos distintos patrones/prácticas/estrategias:

  1. Cargar un gran número de registros sobre el internet (~ 5k).
  2. Mantener actualizado un subconjunto de estos objetos (~ 500) a través de Internet.

Hay varios patrones de diseño que se pueden utilizar para todo lo demás.

Edición 2:

Gracias por los enlaces en diversos sistemas de aplicación "push" en Silverlight. Podría jurar que los enchufes habían sido eliminados de Silverlight, pero encontré una referencia de Silverlight 3 basada en una respuesta a continuación. Realmente, este no era un gran problema para mí y no había dedicado mucho tiempo a investigar, así que lo estoy editando fuera del texto original. Ya sea que las actualizaciones bajen en encuestas o por medio de push, los problemas generales de diseño todavía están allí. Es bueno saber que tengo opciones.

Edición 3: Seguimiento de las tecnologías push.

Como sospechaba, la implementación dúplex Silverlight WCF es comet-like push. Esto no se escalará, y hay numerosos artículos sobre cómo no funciona en el mundo real.

La implementación de sockets en Silverlight está paralizada de varias maneras. Parece que va a ser inútil en nuestro escenario ya que el servidor web puede ubicarse detrás de cualquier firewall de cliente dado que no permitirá puertos no estándar y los conectores Silverlight no se conectarán en 80, 443, etc.

Todavía estoy pensando en usar el enfoque WCFduplex de alguna manera limitada, pero parece que la respuesta será la votación.

Editar 4: Se encuentra un patrón para resolver la mitad de mi problema

he encontrado this pattern (PDF) que ilustra el uso de un iterador para recuperar las páginas de datos del servidor y presentarlos como un simple repetidor. En .Net land, imagino que esto se implementaría como IEnumerable (el código de las muestras está en Java y Oracle SQL). De particular interés para mí fue la búsqueda previa de página asíncrona, básicamente el buffer del conjunto de resultados del lado del cliente. Con objetos de 5k, todo no cabe en la pantalla de una vez, así que puedo usar una estrategia de no obtener todo a la vez y ocultar los detalles de implementación desde la interfaz de usuario. Los objetos principales que la aplicación recuperará se encuentran en una base de datos, luego se requieren otras búsquedas para completar completamente estos objetos. Esta metodología parece ser un buen enfoque para enviar rápidamente algunos de los datos al cliente.

Ahora estoy pensando en usar este patrón + algún tipo de patrón de objeto proxy que escuche los deltas en el conjunto de resultados y actualiza el objeto en consecuencia. Hay un par de estrategias que uno podría tomar aquí. Podría cargar todos los datos por adelantado, luego enviar deltas de cambios (que probablemente necesitarán algún código adicional en los subsistemas para proporcionar notificaciones de cambios). Este podría ser mi primer enfoque. Todavía estoy buscando. Gracias por todas las ideas hasta ahora.

+0

¡Problema muy interesante! Me encantaría trabajar en algo así alguna vez. ¿Puedo preguntar sobre los detalles de lo que estás construyendo? – andyp

+0

Es un sistema patentado que aún no hemos lanzado (obviamente) y he ofuscado algunos de los detalles debido a eso. En general, es una forma de controlar lo que está sucediendo en una aplicación que maneja un gran conjunto de "dispositivos" (la instalación más grande actual de alrededor de 5k). Esta herramienta le permitirá a un administrador observar la "red del dispositivo" en su totalidad y detectar problemas, y luego tomar medidas en áreas problemáticas. Lo siento, no puedo ser más específico. ¡Cuando salgamos, puedo mostrártelo! –

Respuesta

0

He votado un par de buenas respuestas, pero se me ocurrió una solución con algunos cambios en los datos de back-end y una nueva forma de recuperar los datos de Silverlight. Esto es lo que se está haciendo para solucionar esto:

  1. Estoy usando frijoles para representar ese gran gráfico de datos. Esto eliminó mucho de transmisión XML. Solo me preocupa un subconjunto de los datos, aunque es un subconjunto bastante significativo. Al aplanar los datos en un bean, creo que he reducido mi tamaño de objeto serializado a aproximadamente 20 - 25% del gráfico original del objeto.
  2. Casi todos los datos en el back-end ahora tendrán un campo por última vez que fue modificado. Pude obtener esto para todos los grandes datos. Hay algunos datos que no tendrán esto, pero los problemas reales del rendimiento de las consultas y la agregación de datos se resolvieron con esto. Como una solución general para otros, parece que esto es bastante simple de implementar en una cantidad de DBMS.
  3. Estoy escribiendo nuevas API para recuperar datos que se han actualizado después de un DateTime proporcionado. Esto me permite consultar solo los objetos nuevos y modificados del sistema de fondo (este es el servicio web que llama a estas API, y Silverlight llama al servicio web).
  4. Agregue cambios en el servicio web y detecte si una parte del datagrama ha cambiado. Para simplificar, simplemente envío todo el diagrama de datos si algo ha cambiado. Esta fue en realidad la parte más difícil de entender. Una parte del datagrama podría tener un nuevo tiempo actualizado, pero el objeto principal del gráfico no se ha actualizado. Terminé escribiendo API para buscar los cambios de los sub-objetos, y luego API para encontrar los objetos raíz basados ​​en esos sub-objetos (si se habían cambiado). Se puede devolver un gráfico de objetos con un objeto raíz (y en realidad gran parte del gráfico de objetos) que no se ha actualizado desde la última encuesta. La lógica del servicio web está consultando un pequeño número de cambios, por lo que, aunque las consultas no son baratas individualmente, es posible que solo se ejecuten unas pocas veces por encuesta. Incluso en instalaciones muy grandes de nuestro producto, este ciclo de consulta solo se ejecutará 10 o 20 veces por ciclo de votación (consulte a continuación sobre mi solución de sondeo). Si bien nuestros sistemas son muy dinámicos, no que cambia mucho en 30 segundos. La llamada al servicio web que maneja todo esto reacciona de la misma manera a una llamada de carga inicial que a un sondeo. Todo lo que le preocupa es recuperar datos más nuevos que un tiempo determinado.
  5. Escribí una colección que hereda de ObservableCollection que maneja la consulta y el sondeo. El código de cliente que usa esta colección proporciona un delegado que consulta los datos. La fecha se devuelve asincrónicamente y en páginas. No me he decidido por el tamaño de una página. Sigue volviendo a consultar páginas hasta que el servidor devuelve una página que es más pequeña que el tamaño máximo de página. La colección también proporciona información sobre cómo determinar la fecha más reciente del objeto más nuevo en la colección. Realiza sondeos periódicamente para las actualizaciones que son más recientes que el elemento más nuevo en la colección. En realidad, esta "última fecha" es en realidad un objeto que contiene varias fechas de varias partes del gráfico de objetos original. Si vuelve un elemento del servidor que existe en la colección, el elemento de la colección se actualiza con los datos devueltos. Hice esto en lugar de insertar el nuevo elemento y eliminar el anterior, ya que funciona en situaciones más vinculadas a datos.

Este patrón podría mejorarse. Podría enviar solo deltas a Silverlight para cambios. Todavía podría intentar usar algún tipo de tecnología de empuje. Pero esta solución me da una llamada de servicio web que puede devolver datos para varios casos. El sondeo también es muy simple, y solo hay una cosa que hace toda la recuperación de datos. No hay muchas partes móviles.Esto maneja los cambios de estado del objeto tanto durante la carga de datos inicial como durante el sondeo a través del mismo mecanismo. Esto también parece escalar bien. La llamada inicial parece ser la más cara y las llamadas posteriores se ejecutan cada vez más rápido. Supongo que esto se debe a que los datos que quedan en el back-end son cada vez más pequeños con cada pase.

Todavía tengo una pregunta sobre mi implementación de esto que I have posted here.

Gracias por todas las sugerencias. Si bien no hice caso de todos los consejos, varias ideas me ayudaron directamente o hicieron que mi mente pensara en un camino diferente sobre cómo hacerlo funcionar.

+0

¿Puedes aclarar/explicar lo que quieres decir con "frijoles"? – Buzz

+0

Bean es un término común para una clase persistente que está destinada al consumo de UI. Las clases estándar de negocio/modelo pueden ser engorrosas para el consumo de UI, por lo que un bean se llena con sus valores y es utilizado por la UI. En mi caso, el nivel de negocios en el servidor tenía una variedad de objetos modelo que tenían algunos gráficos de objetos bastante ricos. Los traduzco a frijoles para el consumo de Silverlight. –

0

Creo que le puede faltar algo: desde Silverlight 3 existe la capacidad de enviar datos al cliente. Here es un artículo que podría ser útil con eso.

+0

Había pensado en eso pero no es realmente push (aunque probablemente funcionaría) y realmente no soluciona mi problema de diseño. El sistema del servidor no sabe que las actualizaciones están listas hasta que consulte los subsistemas, lo que significa un sondeo del lado del servidor. Podría almacenar en caché los resultados en el servidor para acelerarlo ... gracias por el enlace. –

+0

Un seguimiento: leí mucho más sobre esa clase de encuestas de encuestas. Parece que tiene problemas de escala reales. –

2

El proxy design pattern es el patrón que ayudará a transferir datos de un punto a otro. El patrón de diseño de proxy le permitirá tratar objetos remotos como si fueran locales.

+0

Creo que este patrón general podría funcionar, pero el problema que tengo es un poco más de tuercas y tornillos. Aún así, esto me da la idea de mantener todos los objetos en la memoria caché en algún lugar del servidor y actualizarlos allí, y luego proporcionar deltas para los servidores proxy que se sientan en el cliente cuando el cliente sondea ... –

+0

Para ser más claros, el proxy en este caso por naturaleza, debe desconectarse y, por lo tanto, debe mantener cierto estado. No estoy seguro del mejor patrón para actualizar ni para la carga inicial. He discutido el problema con compañeros de trabajo y una idea ha sido servir el objeto utilizando un patrón de repositorio/fábrica y esos objetos actuarían como servidores proxy, invalidando sus propios datos y volviendo a llamar al repositorio (y por lo tanto al servidor) en ciclo. –

1

Aquí he encontrado un artículo que parece explicar cómo crear tomas en Silverlight 2 Silverlight 2 and System.Net.Sockets.Socket

No he leído muy profundamente (que es un poco demasiado tarde para que haga eso) pero parece que podría ser útil en tu caso. La principal limitación que he visto es que su aplicación Silverlight solo puede conectarse al servidor desde el que se descargó.

Aquí un tutorial en el canal 9 Silverlight using socket

espero que esto ayudará

+0

Investigué bastante sobre enchufes en Silverlight. Hay algunas restricciones severas que me impiden usarlas. Una restricción es que hay un rango de puertos muy pequeño bajo el cual funcionarán, lo cual me parece una tontería. –

1

En general creo que la respuesta a su pregunta es que no hay uno o más patrones de diseño que realmente va a resolver su problema . En cambio, este es un gran ejemplo de una aplicación decente a gran escala que solo necesita una gran cantidad de trabajo de planificación y diseño.

Cuando diseñe, creo que encontrará algunos DP que pueden ayudarlo en un nivel pequeño, pero los detalles de cómo debería funcionar este gigante es más un problema de diseño general (e interesante).

Tal vez aclarar sus preguntas ligeramente puede ayudar a las personas a dar consejos sobre el diseño general de este sistema.Además, una vez que haya puesto un poco de esfuerzo/diseño en crear un diseño de alto nivel sobre cómo debería funcionar esto, podría solicitar críticas/sugerencias. Es difícil que alguien presente esto por completo como una respuesta a una pregunta de StackOverflow. :)

2

2 soluciones propuestas pueden ser

1) comprimir su recogida y descomprimirlo después de la transferencia.

2) Utilice el patrón de proxy Flyweight +.

+0

Tuve un error tipográfico: la aplicación cargará alrededor de 5000 (5k) objetos, no 5000k objetos. Ya he cargado estos muchos objetos en la memoria y Silverlight lo maneja bien. Estoy considerando usar alguna versión del patrón de proxy, pero el peso mosca no me gana mucho aquí. –

+0

De hecho, terminé usando un tipo de peso mosca usando frijoles en lugar de servir los ricos gráficos de objetos a Silverlight. –

1

Si he entendido bien, en realidad hay dos problemas aquí:

  1. Estado del sistema está representado por los datos procedentes de múltiples fuentes de datos. Como resultado, consultar el estado es costoso.
  2. La cantidad de datos que describe el estado del sistema es grande. Como resultado, consultar todos los datos que describen el estado es costoso.

Los patrones estándar para resolver estos problemas son introducir un nivel medio y usar deltas para actualizar el estado. P. ej .:

  1. Claramente, no desea que sus clientes de Silverlight hablen directamente con los sistemas de fondo. No solo eso podría no ser posible, también es muy ineficiente, ya que cada cliente puede solicitar la misma fuente de datos sobre su estado. Para evitar esta solución estándar es necesario introducir un nivel intermedio que agregue los datos procedentes de todas las fuentes de datos back-end, y también proporciona una interfaz común para los clientes. Como resultado, las fuentes de datos back-end se sondearán tan a menudo como sea necesario (se pueden configurar por cada fuente de datos en el nivel medio), y los clientes no tendrán que lidiar con detalles específicos de esas fuentes de datos respaldadas. Además, puede implementar la indexación de los datos en el nivel medio, en función de las consultas más comunes para los clientes.

  2. Suponiendo que cada registro tenga ID, el cliente solo debe solicitar deltas desde la última actualización. Uno de los muchos patrones es usar una marca de tiempo. P.ej. cuando el cliente se inicializa, solicita el estado del sistema y el nivel medio envía ese estado con la marca de tiempo. Cuando el cliente necesita actualizar ciertos registros, proporciona los ID en la solicitud y la marca de tiempo de la última actualización. Por lo tanto, el nivel intermedio solo enviará cambios desde la última marca de tiempo y solo para las ID solicitadas. Si el objeto tiene 15 propiedades, y solo 3 de ellas se cambiaron desde la última marca de tiempo, entonces la actualización contendrá solo los valores de esas 3 propiedades.

En cuanto a push vs. poll, push no es automáticamente la mejor solución. Realmente se trata de una cuestión de compensación entre la frecuencia con la que el cliente necesita actualizarse y la cantidad de tráfico entre el cliente/nivel medio. P.ej. si el cambio de estado es frecuente pero escaso (por ejemplo, afecta solo unas pocas propiedades a la vez) y no es necesario actualizar el estado del cliente de inmediato, el cliente puede preferir que se acumulen los cambios en lugar de recibir cada actualización, por lo que sería preferible realizar un sondeo.

+0

Acepto que hacer un seguimiento de los deltas en el nivel intermedio va a ser crítico para el rendimiento de esta aplicación. Tenemos un nivel medio muy similar a lo que describes en el punto 1, pero en su mayoría es apátrida. –

2

Me pregunto si podría reducir la cantidad de datos que van a la pantalla del cliente en primer lugar? De todos modos, no puedes ver 5.000 puntos de datos a la vez. Y si necesita desplazarse para buscar las cosas importantes, considere filtrar las cosas no importantes para empezar. Considere algunos diseños de IU (tablero de instrumentos y tipo de indicador) para que el usuario solo vea los puntos problemáticos. Luego pueden perforar y tomar medidas según sea necesario.

Sé que no puede revelar detalles y he hecho un montón de suposiciones y esta no es una respuesta técnica directa a su pregunta, pero quizás repensar el suministro de datos necesarios lo ayudaría a empujarlo en una dirección más eficiente para tanto el back-end como el front-end.

+0

La interfaz de usuario debe ser un tipo de interfaz de "Google Maps", por lo que definitivamente necesitamos todos los puntos de datos que se muestran. Usted hace un buen punto, y estoy pensando en cargar los datos de la pantalla al último o cargarlos de forma lenta. –

Cuestiones relacionadas