Menú
Está libre
registro
hogar  /  Navegantes/ El lado del servidor de las aplicaciones cómo funciona. Desarrollo de aplicaciones móviles: sincronización de servidores

El lado del servidor de las aplicaciones cómo funciona. Desarrollo de aplicaciones móviles: sincronización de servidores

El desarrollo del lado del servidor de una aplicación cliente-servidor comienza con el diseño de la arquitectura. Mucho depende de la arquitectura: desde la extensibilidad de la aplicación hasta su rendimiento y facilidad de soporte / mantenimiento.

En primer lugar, debe determinar cómo se colocarán los datos en el servidor y cómo se procesarán las solicitudes provenientes del cliente. También debe pensar en la organización del almacenamiento en caché de datos del servidor.

Es necesario determinar los protocolos de intercambio de datos y los formatos de transferencia de datos.

API (interfaz de programación de aplicaciones) es una interfaz de programación de aplicaciones. En un lenguaje más comprensible, este es un conjunto de solicitudes al servidor, que este último comprende y puede dar la respuesta correcta. La API define la funcionalidad de la lógica del lado del servidor, mientras que la API le permite abstraerse de cómo se implementa exactamente esa funcionalidad. En otras palabras, la API es una parte necesaria de la infraestructura general de cliente / servidor.

Compare JSON y XML. Proporcione un ejemplo de protocolos según el tipo de aplicación.

Multihilo

Uno de los aspectos clave de la programación moderna es el multiproceso. Con la ayuda del subproceso múltiple, podemos asignar varios subprocesos en una aplicación que realizará varias tareas al mismo tiempo.

El subproceso múltiple es una propiedad de una plataforma (por ejemplo, un sistema operativo, una máquina virtual, etc.) o una aplicación en la que un proceso generado en un sistema operativo puede constar de varios subprocesos que se ejecutan "en paralelo", es decir, sin un orden a tiempo.

La esencia del subproceso múltiple es casi multitarea al nivel de un proceso ejecutable, es decir, todos los subprocesos se ejecutan en el espacio de direcciones del proceso. Además, todos los subprocesos de un proceso no solo tienen un espacio de direcciones común, sino también descriptores de archivo comunes. Un proceso en ejecución tiene al menos un hilo (principal).

El multiproceso (como doctrina de programación) no debe confundirse con la multitarea o el multiprocesamiento, a pesar de que los sistemas operativos que implementan la multitarea tienden a implementar también el multiproceso.

Las ventajas del subproceso múltiple en la programación incluyen las siguientes:

Simplificación del programa en algunos casos debido al uso de un espacio de direcciones común.

Menos tiempo dedicado a la creación de corrientes en relación con el proceso.

Incrementar la productividad del proceso debido a la paralelización de los cálculos del procesador y las operaciones de E / S.

Fluir(threаd) es una unidad administrada de código ejecutable. En un entorno multitarea basado en subprocesos, todos los procesos en ejecución deben tener un subproceso principal, pero puede haber más. Esto significa que se pueden realizar varias tareas de forma asincrónica en un programa. Por ejemplo, editar texto en un editor de texto mientras se imprime, ya que estas dos tareas se realizan en diferentes hilos.

En un procesador convencional, el control de flujo lo maneja el sistema operativo. Un hilo se ejecuta hasta que expira una interrupción de hardware, una llamada al sistema o el tiempo asignado por el sistema operativo. Después de eso, el procesador cambia al código del sistema operativo, que guarda el estado del subproceso (su contexto) o cambia al estado de otro subproceso, al que también se le asigna tiempo para la ejecución. Con este tipo de subprocesos múltiples, una gran cantidad de ciclos de procesador se gastan en el código del sistema operativo que cambia de contexto. Si el soporte de subprocesos se implementa en el hardware, entonces el propio procesador podrá cambiar entre subprocesos e, idealmente, ejecutar varios subprocesos simultáneamente para cada ciclo de reloj.

- Multihilo temporal (un hilo)

- Múltiples subprocesos simultáneos (múltiples subprocesos al mismo tiempo)

El subproceso múltiple, como un modelo de ejecución de código y programación generalizado, permite que se ejecuten varios subprocesos dentro de un solo proceso. Estos hilos de ejecución comparten los recursos del proceso, pero también pueden ejecutarse de forma independiente. El modelo de programación multiproceso proporciona a los desarrolladores una abstracción conveniente para la ejecución en paralelo. Sin embargo, quizás la aplicación más interesante de la tecnología es cuando se aplica a un solo proceso, lo que permite su ejecución en paralelo en un sistema multiprocesador.

Esta ventaja de un programa multiproceso permite que se ejecute más rápido en sistemas informáticos que tienen múltiples procesadores, un procesador con múltiples núcleos o en un grupo de máquinas, porque los subprocesos de ejecución del programa se prestan naturalmente a la ejecución verdaderamente paralela de procesos. En este caso, el programador debe tener mucho cuidado para evitar condiciones de carrera y otros comportamientos poco intuitivos. Para manipular correctamente los datos, los hilos de ejecución deben pasar con frecuencia por el procedimiento de encuentro para procesar los datos en el orden correcto. Los subprocesos de ejecución también pueden necesitar mutex (que a menudo se implementan mediante semáforos) para evitar que los datos compartidos se modifiquen o lean al mismo tiempo durante el proceso de actualización. El uso descuidado de estas primitivas puede conducir a un callejón sin salida.

Otro uso del subproceso múltiple, aplicable incluso para sistemas monoprocesador, es la capacidad de una aplicación para responder a la entrada. En los programas de un solo subproceso, si el subproceso principal está bloqueado por una tarea de ejecución prolongada, se puede congelar toda la aplicación. Al mover esas tareas que consumen mucho tiempo a un subproceso de trabajo que se ejecuta en paralelo con el subproceso principal, es posible que las aplicaciones continúen respondiendo a la entrada del usuario mientras las tareas se ejecutan en segundo plano. Por otro lado, en la mayoría de los casos, el multiproceso no es la única forma de preservar la sensibilidad de un programa. Lo mismo se puede lograr mediante E / S asíncronas o señales en UNIX.

En total, hay dos tipos de multitarea: basado en procesos y basado en streams... La diferencia entre la multitarea basada en procesos y en subprocesos se reduce a lo siguiente: la multitarea basada en procesos está organizada para la ejecución paralela de programas, y la multitarea basada en subprocesos es para la ejecución paralela de partes separadas del mismo programa.

En total, se distinguen dos tipos de corrientes:

Subprocesos en primer plano o en primer plano. De forma predeterminada, cada hilo creado a través del método Thread.Start () se convierte automáticamente en el hilo de primer plano. Estos tipos de subprocesos brindan protección a la aplicación actual contra la terminación. El CLR no detendrá la aplicación hasta que hayan finalizado todos los subprocesos en primer plano.

Hilos de fondo Este tipo de subproceso también se denomina subproceso daemon y CLR lo interpreta como rutas de ejecución extensibles que pueden ignorarse en cualquier momento. Por lo tanto, si se terminan todos los subprocesos en primer plano, todos los subprocesos en segundo plano se destruyen automáticamente cuando se descarga el dominio de la aplicación. Para crear subprocesos en segundo plano, establezca la propiedad IsBackground en true.

Indique los estados de los subprocesos: en ejecución, suspendidos, en ejecución, pero en espera de algo.

Problema de sincronización de subprocesos y recursos compartidos.

Interacción de hilos

En un entorno multiproceso, a menudo surgen problemas relacionados con el uso de los mismos datos o dispositivos mediante la ejecución de subprocesos en paralelo. Para resolver tales problemas, se utilizan métodos de interacción de subprocesos como mutex, semáforos, secciones críticas y eventos.

Mutex Es un objeto de sincronización que se establece en un estado de señalización especial cuando no está ocupado con ningún hilo. Solo un hilo posee este objeto en un momento dado, de ahí el nombre de dichos objetos (del inglés, acceso mutuamente excluyente): se excluye el acceso simultáneo a un recurso compartido. Después de que se toman todas las acciones necesarias, se libera el mutex, dando a otros subprocesos acceso al recurso compartido. El objeto puede admitir la captura recursiva por segunda vez por el mismo hilo, incrementando el contador sin bloquear el hilo y luego requiriendo múltiples desasignaciones. Esta es, por ejemplo, la sección crítica en Win32. Sin embargo, hay algunas implementaciones que no admiten esto y hacen que el hilo se bloquee al intentar una captura recursiva. Este es FAST_MUTEX en el kernel de Windows.

Semáforos son recursos disponibles que pueden ser adquiridos por varios subprocesos al mismo tiempo hasta que el grupo de recursos esté vacío. Luego, los subprocesos adicionales deben esperar hasta que la cantidad requerida de recursos esté disponible nuevamente. Los semáforos son muy eficientes porque permiten el acceso simultáneo a los recursos.

Desarrollos... Objeto que almacena 1 bit de información "señalizado o no", sobre el que se definen las operaciones "señalizar", "resetear a no señalizado" y "esperar". Esperar un evento señalado es la ausencia de una operación con continuación inmediata de la ejecución del hilo. Esperar un evento no seleccionado hace que el subproceso se suspenda hasta que otro subproceso (o la segunda fase del controlador de interrupciones en el kernel del sistema operativo) señale el evento. Es posible esperar varios eventos en los modos "cualquiera" o "todos". También es posible crear un evento que se restablezca automáticamente a un estado no señalado después de que se despierte el primer y único subproceso en espera (dicho objeto se utiliza como base para la implementación del objeto "sección crítica"). Se utilizan activamente en MS Windows, tanto en modo usuario como en modo kernel. Hay un objeto similar en el kernel de Linux llamado kwait_queue.

Secciones críticas proporcionan una sincronización similar a los mutex, excepto que los objetos que representan secciones críticas están disponibles dentro del mismo proceso. Los eventos, mutex y semáforos también se pueden usar en una aplicación de proceso único; sin embargo, las implementaciones de la sección crítica en algunos sistemas operativos (como Windows NT) proporcionan un mecanismo de sincronización mutuamente excluyente más rápido y más eficiente: las operaciones de obtención y liberación en el La sección crítica está optimizada para el caso de un solo hilo (sin contención) con el fin de evitar cualquier llamada al sistema que conduzca al kernel del sistema operativo. Al igual que los mutex, un objeto que representa una sección crítica solo puede ser utilizado por un hilo a la vez, lo que los hace extremadamente útiles para delimitar el acceso a los recursos compartidos.

Variables condicionales(condvars). Son similares a los eventos, pero no son objetos que ocupan memoria - solo se usa la dirección de una variable, el concepto de "contenido de una variable" no existe, la dirección de un objeto arbitrario se puede usar como variable condicional . A diferencia de los eventos, establecer una variable de condición en un estado señalado no tiene consecuencias si actualmente no hay subprocesos esperando en la variable. Establecer un evento en un caso similar implica almacenar el estado "señalado" dentro del evento mismo, después de lo cual los siguientes subprocesos que deseen esperar el evento continúan ejecutándose inmediatamente sin detenerse. Para hacer un uso completo de dicho objeto, también es necesario liberar el mutex y esperar la variable condicional atómicamente. Se utilizan ampliamente en sistemas operativos similares a UNIX. Las discusiones sobre las ventajas y desventajas de los eventos y las variables de condición son una parte notable de las discusiones sobre las ventajas y desventajas de Windows y UNIX.

Puerto de terminación de E / S(Puerto de finalización de E / S, IOCP). El objeto "cola" implementado en el kernel del sistema operativo y accesible a través de llamadas al sistema con las operaciones "poner la estructura en la cola de la cola" y "tomar la siguiente estructura de la cabeza de la cola" - la última llamada detiene la ejecución de el hilo si la cola está vacía, y hasta que otro hilo no haga la llamada a "poner". La característica más importante de IOCP es que las estructuras se pueden colocar en él no solo mediante una llamada explícita al sistema desde el modo de usuario, sino también implícitamente dentro del kernel del sistema operativo como resultado de una operación de E / S asíncrona completada en uno de los descriptores de archivo. Para lograr este efecto, debe utilizar la llamada al sistema "vincular descriptor de archivo a IOCP". En este caso, la estructura colocada en la cola contiene el código de error de la operación de E / S y también, si esta operación tiene éxito, el número de bytes de entrada o salida reales. La implementación del puerto de finalización también limita la cantidad de subprocesos que se ejecutan en un solo procesador / núcleo después de que una estructura se pone en cola. El objeto es específico de MS Windows y permite procesar solicitudes de conexión entrantes y fragmentos de datos en el software del servidor en una arquitectura en la que el número de subprocesos puede ser menor que el número de clientes (no es necesario crear un subproceso separado con consumo de recursos para cada nuevo cliente).

Pool de hilos

Cuéntanos sobre el grupo de subprocesos

Gran parte de lo moderno aplicaciones para plataformas móviles(iOS, Android, etc.) funciona en conjunto con un servidor. Una aplicación con datos desactualizados pierde su utilidad. Por lo tanto, es importante asegurarse de que los datos del servidor al dispositivo se mantengan actualizados. Esto se aplica a las aplicaciones sin conexión que deberían funcionar sin Internet. Para aplicaciones completamente en línea que no funcionan (o son inútiles) sin Internet (por ejemplo, Foursquare, Facebook), hay especificidades que están más allá del alcance de este artículo.

Usando el ejemplo de una de nuestras aplicaciones fuera de línea, le diré qué enfoques usamos para sincronizar datos. En las primeras versiones hemos desarrollado algoritmos simples y, en el futuro, con experiencia, los mejoramos. En el artículo se presenta una secuencia similar, desde prácticas obvias simples hasta prácticas más complejas.

Cabe aclarar que el artículo trata sobre la transferencia de datos solo en una dirección: del servidor al dispositivo. Aquí el servidor es la fuente de datos.

Disposiciones generales para todos los enfoques

Como ejemplo, consideraremos transferir un directorio de platos ("platos") al dispositivo. Asumiremos que el dispositivo solicita la url “/ service /lates / update”, el intercambio se realiza a través del protocolo http en formato JSON ( www.json.org). El servidor tiene una tabla "platos" con los siguientes campos: id (identificador de registro), nombre (nombre del plato), actualizado (en el momento en que se actualizó el plato, es mejor hacer soporte de zona horaria de inmediato, "AAAA-MM -DDThh: mm: ssTZD ”, por ejemplo,“ 1997-07-16T19: 20: 30 + 01: 00 ”), is_deleted (signo de registro eliminado).

Comentario sobre la presencia del último campo. Por defecto, su valor es 0. En una aplicación donde las entidades están sincronizadas entre el cliente y el servidor, no se recomienda borrar físicamente los datos del servidor (para evitar errores). Por lo tanto, is_deleted = 1 se establece para platos eliminados. Cuando una entidad con is_deleted = 1 llega al dispositivo, se elimina del dispositivo.

Con cualquier enfoque, que se considerará a continuación, el servidor devuelve una matriz de objetos a los dispositivos JSON (puede estar vacío):

[
(identificación: , nombre: , actualizado: , esta borrado: },…
]

Ejemplo de respuesta del servidor:

[
(id: 5625, nombre: "Bread", actualizado: "2013-01-06 06:23:12", isDeleted: 0),
(id: 23, nombre: "Sémola cocida", actualizado: "2013-02-01 14:44:21", isDeleted: 0), (

nombre: "sopa de pescado",

actualizado: "2013-08-02 07:05:19",

Principios de actualización de datos en un dispositivo.

  1. Si un elemento que está en el dispositivo vino y isDeleted = 0, entonces se actualiza
  2. Si ha llegado un elemento que no está en el dispositivo, y isDeleted = 0, entonces se agrega
  3. Si un elemento que está en el dispositivo vino y es Eliminado = 1, entonces se elimina.
  4. Si ha llegado un elemento que no está en el dispositivo y está eliminado = 1, no se hace nada

Enfoque 1: todo está siempre sincronizado

Este es el método más sencillo. El dispositivo solicita una lista de platos del servidor y el servidor envía la lista completa. Cada vez que viene la lista completa. Sin clasificar.

Solicitud de ejemplo: nulo o "()"

Ventajas:

  • la lógica en el servidor es simple: siempre damos todo
  • la lógica del dispositivo es simple: siempre sobrescribimos todo

Desventajas:

  • si solicita la lista con frecuencia (cada 10 minutos), habrá mucho tráfico de Internet
  • si rara vez solicita la lista (una vez al día), se violará la relevancia de los datos

Área de aplicación:

  • para aplicaciones de poco tráfico
  • transmisión de datos que cambian muy raramente (lista de ciudades, categorías)
  • transferencia de la configuración de la aplicación
  • al comienzo del proyecto para el primer prototipo de una aplicación móvil

Enfoque 2: sincronizar solo lo actualizado

El dispositivo solicita una lista de platos, actualizada de la sincronización anterior. La lista viene ordenada por "actualizado" en orden ascendente (opcional, pero conveniente). El dispositivo almacena el valor "actualizado" para el plato enviado más recientemente y, en la siguiente solicitud, lo envía al servidor en el parámetro "lastUpdated". El servidor envía una lista de platos que son más nuevos que "lastUpdated" (actualizado> lastUpdated). En la primera solicitud al servidor "lastUpdated" = nulo.

Solicitud de ejemplo: (lastUpdated: "2013-01-01 00:00:00")

En el diagrama: "last_updated" es el valor que se almacena en el dispositivo. Por lo general, se crea una tabla separada en el dispositivo para almacenar estos valores "last_updated" para cada entidad (plato, ciudad, organización, etc.)

Este enfoque es adecuado para sincronizar listas lineales simples donde las reglas de llegada son las mismas para todos los dispositivos. Para una sincronización más selectiva, consulte "Método 5: Sincronizar con el conocimiento de lo que ya está en el dispositivo".

Este enfoque generalmente cubre la mayoría de las necesidades. Solo llegan nuevos datos al dispositivo, puede sincronizar al menos cada minuto; el tráfico será pequeño. Sin embargo, existen problemas asociados con las limitaciones de los dispositivos móviles. Estos son memoria y procesador.

Método 3: sincronizar en lotes

Los dispositivos móviles tienen poca RAM. Si hay 3000 platos en el directorio, entonces analizar una cadena json grande desde el servidor en objetos en el dispositivo puede causar una falta de memoria. En este caso, la aplicación se bloqueará o no guardará estos 3000 platos. Pero incluso si el dispositivo pudo digerir dicha cadena, entonces el rendimiento de la aplicación en los momentos de sincronización en segundo plano será bajo (la interfaz se retrasa, no se desplaza suavemente, etc.) Por lo tanto, es necesario solicitar la lista en porciones más pequeñas.

Para ello, el dispositivo pasa un parámetro más ("cantidad"), que determina el tamaño de la porción. La lista debe enviarse ordenada por el campo "actualizado" en orden ascendente. El dispositivo, similar al enfoque anterior, recuerda el valor "actualizado" de la última entidad enviada y lo pasa al campo "lastUpdated". Si el servidor ha enviado exactamente el mismo número de entidades, entonces el dispositivo continúa sincronizando y vuelve a realizar una solicitud, pero con el "lastUpdated" actualizado. Si el servidor ha enviado menos entidades, esto significa que no tiene más datos nuevos y finaliza la sincronización.

En el diagrama: "last_updated" y "amount" son los valores que se almacenan en aplicación movil... "Last_item": la última entidad (plato) enviada desde el servidor. Es más nuevo que este valor que se solicitará la siguiente lista.

Solicitud de ejemplo: (lastUpdated: "2013-01-01 00:00:00", cantidad: 100)

Ventajas:

  • El dispositivo recibe todos los datos que puede procesar a la vez. El tamaño de la porción se determina mediante pruebas prácticas. Las entidades simples se pueden sincronizar 1000 a la vez. Pero también sucede que entidades con una gran cantidad de campos y lógica de procesamiento de almacenamiento compleja se sincronizan normalmente no más de 5 piezas.

Desventajas:

  • Si hay 250 platos con la misma actualización, entonces con cantidad = 100, los últimos 150 no se enviarán a los dispositivos. Esta situación es bastante real y se describe en el siguiente enfoque.

Método 4: sincronización correcta de los lotes

En el enfoque anterior, es posible que si la tabla contiene 250 platos con el mismo "actualizado" (por ejemplo, "2013-01-10 12:34:56") y el tamaño de la porción es 100, entonces solo los primeros 100 Vendrán registros. Los 150 restantes se recortarán (actualizado> último actualizado). ¿Por qué va a pasar esto? Cuando se soliciten los primeros 100 registros, lastUpdated se establecerá en "2013-01-10 12:34:56" y la siguiente solicitud tendrá la condición (actualizado> "2013-01-10 12:34:56"). Incluso suavizar la condición (actualizado> = “2013-01-10 12:34:56”) no ayudará, porque el dispositivo solicitará sin cesar los primeros 100 registros.

La situación con el mismo "actualizado" no es tan rara. Por ejemplo, al importar datos de un archivo de texto, el campo "actualizado" se estableció en AHORA (). Puede llevar menos de un segundo importar un archivo con miles de líneas. También puede suceder que todo el directorio tenga el mismo "actualizado".

Para solucionar este problema, debe utilizar algún campo de plato que sea único al menos en un momento ("actualizado"). El campo "id" es único en toda la tabla, por lo que debería utilizarlo adicionalmente en la sincronización.

Entonces, la implementación de este enfoque se ve así. El servidor devuelve la lista ordenada por "actualizado" e "id", y los dispositivos solicitan datos utilizando "lastUpdated" y el nuevo parámetro "lastId". En el servidor, la condición de selección es más complicada: ((actualizado> lastUpdated) O (actualizado = lastUpdated e id> lastId)).

En el diagrama: “last_updated”, “last_id” y “amount” son los valores que se almacenan en la aplicación móvil. "Last_item": la última entidad (plato) enviada desde el servidor. Es más nuevo que este valor que se solicitará la siguiente lista.

Método 5: sincronizar con el conocimiento de lo que ya está en el dispositivo

Los enfoques anteriores no tienen en cuenta el hecho de que el servidor no sabe realmente con qué éxito se guardaron los datos en el dispositivo. El dispositivo simplemente no pudo guardar algunos de los datos debido a errores inexplicables. Por lo tanto, sería bueno recibir la confirmación del dispositivo de que todos (o no todos) los platos se han conservado.

Además, el usuario de la aplicación puede configurar la aplicación de tal forma que solo necesite una parte de los datos. Por ejemplo, un usuario desea sincronizar platos de solo 2 ciudades de cada 10. Esto no se puede lograr utilizando las sincronizaciones descritas anteriormente.

La idea detrás del enfoque es la siguiente. El servidor almacena (en una tabla separada "lista_de_elementos_almacenados") información sobre qué platos hay en el dispositivo. Podría ser simplemente una lista de pares "id - actualizados". Esta tabla contiene todas las listas de pares de platos "id - actualizados" para todos los dispositivos.

El dispositivo envía información sobre los platos disponibles en el dispositivo (la lista de pares "id - actualizados") al servidor junto con una solicitud de sincronización. Cuando se le solicita, el servidor verifica qué platos deberían estar en el dispositivo y cuáles están ahora. Luego, la diferencia se envía al dispositivo.

¿Cómo determina el servidor qué platos deben estar en el dispositivo? En el caso más simple, el servidor realiza una solicitud que devolverá una lista de pares "id - actualizados" de todos los platos (por ejemplo, SELECT id, actualizado FROM platos). En el diagrama, esto se hace mediante el método "WhatShouldBeOnDeviceMethod ()". Esta es la desventaja del enfoque: el servidor tiene que calcular (a veces haciendo consultas SQL pesadas) lo que debería estar en el dispositivo.

¿Cómo determina el servidor qué platos hay en el dispositivo? Realiza una consulta a la tabla "stored_item_list" para este dispositivo y obtiene una lista de pares "id - actualizado".

Al analizar estas dos listas, el servidor decide qué se debe enviar al dispositivo y qué se debe eliminar. En el diagrama, esto es "delta_item_list". Por lo tanto, la solicitud no contiene "lastUpdated" y "lastId", su tarea es realizada por los pares "id - updated".

¿Cómo sabe el servidor sobre los platos disponibles en el dispositivo? En la solicitud al servidor, se agrega un nuevo parámetro "elementos", que contiene una lista de la identificación de platos que se enviaron al dispositivo en la última sincronización ("device_last_stored_item_list"). Por supuesto, puede enviar una lista de la identificación de todos los platos que hay en el dispositivo, y no complicar el algoritmo. Pero si hay 3000 platos en el dispositivo y todos se envían cada vez, los costos de tráfico serán muy altos. En la gran mayoría de las sincronizaciones, el parámetro "elementos" estará vacío.

El servidor debe actualizar constantemente la "lista_de_elementos_almacenados" con los datos que provienen del dispositivo en el parámetro "elementos".

Debe implementar un mecanismo para borrar los datos del servidor en la lista de elementos almacenados. Por ejemplo, después de reinstalar una aplicación en un dispositivo, el servidor asumirá que el dispositivo aún está actualizado. Por lo tanto, al instalar la aplicación, el dispositivo debe informar de alguna manera al servidor para que borre la lista de elementos almacenados para este dispositivo. En nuestra aplicación, enviamos un parámetro adicional "clearCache" = 1 en este caso.

Conclusión

Una tabla resumen de las características de estos enfoques:

Un acercamiento Volumen de tráfico(5 - grande) Intensidad laboral del desarrollo(5 - alto) Uso de memoria del dispositivo(5 - alto) Exactitud de los datos en el dispositivo.(5 - alto) Puede seleccionar un dispositivo específico
1 Todo esta siempre sincronizado 5 1 5 5 No
2 Solo el actualizado 1 2 5 3 No
3 Sincronización por lotes 1 3 1 3 No
4 Correcta sincronización en lotes 1 3 1 3 No
5 Sincronización con el conocimiento de lo que ya está en el dispositivo. 2 5 2 5

La “exactitud de los datos en el dispositivo” es la probabilidad de que el dispositivo contenga todos los datos enviados por el servidor. En el caso de los enfoques n. ° 1 y n. ° 5, existe un 100% de certeza de que el dispositivo tiene todos los datos que necesita. En otros casos, no existe tal garantía. Esto no significa que no se puedan utilizar otros enfoques. Es solo que si se pierde parte de los datos en el dispositivo, entonces no será posible arreglarlo desde el servidor (y más aún averiguarlo en el lado del servidor).

Quizás, ante la presencia de tarifas ilimitadas de Internet y wifi gratuito, el problema de limitar el tráfico generado por una aplicación móvil sea menos relevante. Pero si bien tiene que recurrir a todo tipo de trucos, idee enfoques más inteligentes que puedan reducir los costos de red y aumentar el rendimiento de las aplicaciones. No siempre funciona. A veces es “cuanto más simple, mejor”, según la situación. Con suerte, a partir de este artículo, puede elegir un enfoque que sea útil.

Sorprendentemente, hay pocas descripciones de la sincronización del servidor en Internet y dispositivos móviles... Además, hay muchas aplicaciones que funcionan de acuerdo con este esquema. Para los interesados, un par de enlaces.

Sin conexión en el pasado, estar en línea hoy es imprescindible. Al menos para el mundo empresarial moderno. Presentaciones de productos y servicios de marca, pedidos y entregas en línea, mantenimiento de una base de clientes, comunicación con los clientes y mucho más: todo esto es simplemente imposible sin una presencia en Internet. Si necesita una aplicación, debe tener tanto Front-end (interfaz web) como Back-End (back-end de su aplicación). Y si desea poder editar el contenido de su aplicación sin la participación de los desarrolladores, necesita un buen panel de administración.

Mientras que el Front-end en el espacio de la aplicación móvil se construye utilizando tecnologías como X-Code y Java, el Back-end, donde se almacenará la base de datos y toda la lógica de la aplicación, requiere conocimientos profesionales de un lenguaje de programación del lado del servidor. Un buen ejemplo es PHP, que posiblemente sea el lenguaje de programación más popular utilizado para casi cualquier desarrollo del lado del servidor. Este es el líder indiscutible.

PHP tiene muchos usos: sitios web estáticos y dinámicos + sistemas de gestión de contenido personalizados, redes sociales, sistemas CRM especializados, software de comercio electrónico y más. Por supuesto, hay piezas de servidor y paneles de control gratuitos o baratos. Sin embargo, en muchos casos no brindan el nivel requerido de conveniencia, personalización y capacidad de actualización.

Nuestros programadores trabajan con tecnologías para implementar una amplia gama de soluciones para diferentes objetivos, necesidades y requisitos comerciales. Analizamos los requisitos del sistema para cada proyecto de forma individual y utilizamos varios software de servidor especializados para un rendimiento óptimo de su aplicación móvil.

Si está buscando un equipo que pueda llevarlo a la solución más inteligente y rentable para crear una aplicación desde cero, o reconstruir una existente para una experiencia de usuario perfecta, no necesita buscar más. Appsmob está listo para ayudarlo a encontrar la mejor solución para usted.

La desventaja de los clientes móviles es el servidor.

Los requisitos adicionales dependen de las características específicas de la aplicación:
escalabilidad del servidor: para SaaS, aplicaciones sociales, donde, idealmente, se espera un gran flujo de visitantes, esta condición es obligatoria. Para aplicaciones comerciales donde existen restricciones en el número de usuarios o se predice el número, esta propiedad no es necesaria;
interactividad: varias aplicaciones deben estar provistas de un mecanismo de notificación: para informar a la aplicación (usuario) sobre la ocurrencia de ciertos eventos, envíe un mensaje al usuario. Esta propiedad debe ser poseída, por ejemplo, por un sistema de cambio o un despachador automático de taxis.
API abierta: se supone que los desarrolladores externos pueden utilizar la funcionalidad del sistema a través de un protocolo documentado. Después de todo, un cliente puede ser una aplicación de servidor externo o móvil.
otros requerimientos ...

Mando
Idealmente, la composición del equipo del proyecto para el desarrollo del sistema puede ser la siguiente:
director de proyecto: gestiona, controla el proyecto, interactúa directamente con el cliente;
desarrollador de aplicaciones de servidor: desarrolla un servidor de lógica empresarial, una base de datos, un protocolo de red;
desarrollador de aplicaciones de administrador: desarrolla una aplicación web, una interfaz de usuario para configurar y administrar una aplicación de servidor;
desarrollador de aplicaciones cliente para Android;
desarrollador de aplicaciones de cliente iOS;
desarrollador de aplicaciones cliente para ...
tester: prueba la aplicación de administración y las aplicaciones de cliente.

El lector atento notará que si escribe una aplicación del lado del servidor con una interfaz gráfica, por ejemplo, en HTML5, puede ahorrar dinero. En este caso, no se requiere el desarrollo de aplicaciones cliente; la interfaz de usuario la proporciona el navegador. Este artículo no trata este caso, se trata del desarrollo de aplicaciones "nativas" (nativas) para dispositivos móviles.

He trabajado en un equipo con una plantilla completa, pero seré realista: los recursos humanos y el presupuesto no siempre permiten formar un equipo así. Y, a veces, los roles deben combinarse: administrador de proyectos + desarrollador de aplicaciones de servidor, desarrollador de aplicaciones de cliente + tester.

Tecnologías, herramientas, bibliotecas
Para desarrollar un servidor para clientes móviles, suelo utilizar la siguiente pila de tecnologías "gratuitas":
Apache Tomcat: contenedor de servlets;
MySQL - DBMS;
Subversion es un sistema de control de versiones;
Maven: un marco para automatizar la construcción de proyectos;
JUnit - proporcionará;
Apache Log4j: biblioteca de registro;
Jenkins: sistema de integración continua;
Hibernate - ORM (ajustes, configuración en propiedades, archivos xml y anotaciones);
hibernate-generic-dao: implementación de DAO de Google, implementa métodos básicos para trabajar con datos de bases de datos, simplifica la implementación de métodos de filtrado y clasificación;
- implementación de autenticación y autorización (seguridad), contenedor de servicios y beans (configuración en archivos xml y en anotaciones), también utilizamos al crear pruebas.

Dependiendo de las características específicas del sistema y los requisitos del mismo, utilizo una de las 2 opciones para implementar el protocolo de intercambio de datos.
Cuando se requiere multiplataforma, velocidad, simplicidad, eficiencia, escalabilidad, API abierta, opto por Jersey, una implementación de servicios web RESTful. Esta biblioteca le permite utilizar la serialización de datos JSON y / o XML. La configuración de REST se realiza mediante anotaciones. Para el intercambio con dispositivos móviles se tomó el formato JSON debido a que tiene una implementación más sencilla del lado del cliente (por eso no usamos servicios Web “clásicos”), se genera menos tráfico. Jersey le permite sintonizar el "look" JSON más apropiado.
De lo contrario, si necesita multiplataforma, alto rendimiento, simplicidad, eficiencia, interactividad, entonces tomo
Apache MINA es un marco para crear aplicaciones de red,
Google protobuf es una biblioteca de codificación y decodificación de datos estructurados. La estructura de los datos está determinada por los archivos de cabecera * .proto, el compilador genera clases Java a partir de ellos (también existe la posibilidad de generación para otros lenguajes de programación: C ++, Objective-C, etc., que proporciona la multiplataforma propiedad);
java.util.concurrent: usamos el paquete estándar.
Esta opción se puede escalar, pero debe establecerse en la etapa de diseño a nivel de arquitectura, teniendo en cuenta la lógica empresarial.

Consideremos un problema hipotético utilizando el ejemplo de la elección de tecnologías para un servicio SaaS real: "Subasta de servicios" Auknem ", que permite a las personas realizar un pedido para la ejecución de los servicios u obras requeridos, y las organizaciones, a su vez. , déjeles sus propuestas. Tomamos todos los requisitos básicos por defecto. Debido a que el registro en este sistema es gratuito y gratuito, definitivamente es necesario agregarles escalabilidad. ¿Y la interactividad? Sería genial informar a los contratistas (ejecutantes) sobre la creación de nuevos pedidos e informar a los clientes sobre las propuestas recibidas en el mismo momento en la aplicación, y no solo por correo electrónico. En base a esto, tomamos para la implementación de Apache MINA, Google protobuf. Observamos la siguiente propiedad: API abierta. El servicio está disponible públicamente, así que supongamos que los desarrolladores externos podrían estar interesados ​​en integrarse con él. ¡Espera un minuto! No es tan simple. El protocolo basado en Apache MINA depende bastante de la implementación y la integración sin conocer los matices es de ninguna manera transparente. En tal situación, tendrá que sopesar qué factor es más importante y tomar una decisión.

Conclusión
Me interesaría saber qué tecnologías, bibliotecas utilizó al desarrollar un servidor para dispositivos móviles o sistemas similares. Todo cambia, nada dura para siempre, en cada nivel existen alternativas con sus propias ventajas y desventajas: MySQL -

RESPALDO

¿Por qué necesita copias de seguridad en una plataforma móvil?

Los expertos saben lo poco fiables que son las aplicaciones móviles en 1C: pueden producirse errores en cualquier momento, por lo que la base de usuarios simplemente colapsará. Al mismo tiempo, nos enfrentamos a la falta de fiabilidad de los propios dispositivos: pueden romperse, perderse, pueden ser robados y los usuarios quieren conservar sus datos. Y hasta la versión 8.3.9 no teníamos un mecanismo de plataforma para guardar una copia de seguridad.

Dado que los usuarios no tenían anteriormente un botón para "guardar una copia", los desarrolladores de la aplicación Boss tuvieron que hacer sus propias copias de seguridad. ¿Cómo lo hicimos?

Guardamos los datos de la base de datos en forma de XML.

Es aconsejable ofrecer al usuario varias opciones para almacenar copias; en primer lugar, es conveniente para los clientes, pueden elegir la mejor opción para ellos: subir a la nube, enviar a su correo, guardar en el dispositivo.

Por lo tanto, los desarrolladores se aseguran adicionalmente. Si algo salió mal y el mecanismo para crear copias en Google Drive o Yandex Drive se rompió repentinamente, siempre puede decirle al usuario que el desarrollador está lidiando con un error, pero por ahora puede guardar los datos de una manera alternativa. Y los usuarios están satisfechos porque pueden estar seguros de sus datos.

Necesariamente necesidad de centrarse en los servicios en la nube, porque si el dispositivo se pierde o se rompe, y el usuario guarda una copia en el mismo dispositivo, los datos se perderán.

También nosotros asegúrese de recordarle al usuario la necesidad de crear copias de seguridad.

¿Cómo guardar copias si cambia la configuración?

Cuando hablamos de una solución masiva, de una aplicación en constante cambio, evolución y refinamiento, se debe tener en cuenta el comportamiento del cliente. Es posible que el usuario desee restaurar una copia de seguridad guardada en una versión anterior de la aplicación, que no tenía detalles. Y luego surge la tarea: leer los datos, luego completar los datos de acuerdo con la lógica de actualización de la versión anterior de la aplicación. ¿Cómo hacerlo? Además de los datos, guarda la propia estructura de datos para que luego sepas cómo leerla.

Hay varias opciones para almacenar esta estructura de datos, incluida la posibilidad de almacenarla en la propia configuración. Es decir, cada vez que se lanza una nueva versión, mantenga la estructura de metadatos de la versión anterior en un diseño en la configuración.

No olvides que en una aplicación móvil la configuración no debería crecer así, deberíamos valorar el lugar en ella, deberíamos hacerlo lo más compacto posible. Pero la aplicación se está desarrollando, habrá muchos diseños de este tipo y, con el tiempo, serán cada vez más numerosos.

Por lo tanto, en el caso de una aplicación móvil, es preferible otra forma: guardar la estructura de metadatos directamente en el archivo de datos... En la salida, obtenemos un archivo de este tipo, donde primero almacenamos algunos datos auxiliares: la versión de configuración, el esquema de configuración, los límites de secuencia, y luego escribimos los datos del usuario en formato XML. Además, en la sección "Datos auxiliares" del archivo, también puede almacenar otros datos importantes que, por alguna razón, no se pudieron escribir en XML.

Tomamos el esquema de datos que hemos guardado en el archivo y, sobre esta base, construimos el paquete XDTO para leer el archivo. Creamos un objeto similar en la base de datos, lo completamos, realizamos el procesamiento de recarga al actualizar y guardamos el objeto ya terminado en la base de datos.

A continuación, en la imagen, puede ver una pista sobre cómo escribir maravillosamente el modelo XDTO de estas configuraciones. La empresa que lanzó la aplicación Boss experimentó con esto, encontró varias formas, pero se decidió por esta opción para registrar el esquema de metadatos. Cuando abre el archivo de datos, puede ver el XML estructurado habitual, legible, que enumera todos los metadatos de la aplicación.

// Escribe el esquema de configuración ModelXDTO = FactoryXDTO.ExportModelsXDTO ("http://v8.1c.ru/8.1/data/enterprise/current-config"); XDTO Factory.WriteXML (UploadFile, modelo XDTO); // Leyendo el esquema de configuración Model XDTO = Factory XDTO. Read XML (Read XML, Factory XDTO. Type ("http://v8.1c.ru/8.1/xdto", "Model")); UnloadFactory = Nuevo XDTOFactory (XDTOModel);

Para proteger al usuario, es imperativo volver a preguntarle si necesita restaurar la copia de seguridad. Tal vez solo estaba experimentando y haciendo clic en todos los botones de la aplicación :) Y ahora se pueden perder los datos actuales. Por lo tanto, al realizar acciones potencialmente "peligrosas", siempre especificamos si realmente quiere esto y cómo debe hacerse. El usuario debe estar al tanto de sus acciones.

Debe haber un mecanismo para crear copias de seguridad cuando hablamos de una solución autónoma, cuando el usuario tiene todos los datos almacenados exclusivamente en un dispositivo móvil: el usuario puede perder su dispositivo y luego los datos se perderán. Y, al parecer, si la aplicación no funciona de forma autónoma, sino que está conectada a un servidor central, entonces el usuario no debería tener ese problema, porque si se pierde el dispositivo, se conectará al servidor, recibirá todos sus datos. desde el servidor de nuevo, y todo estará bien.

Sin embargo, los usuarios no siempre utilizan las copias de seguridad de la forma que esperamos :) Muy a menudo las utilizan simplemente para "revertir" los datos. Este es realmente un comportamiento muy extraño, pero los usuarios de aplicaciones móviles son demasiado perezosos para descubrir dónde podrían cometer un error al ingresar datos, y simplemente revierten los datos y vuelven a ingresar los datos del día actual. Después de analizar las estadísticas de trabajar con la aplicación Boss, nos dimos cuenta de que esta es una práctica normal y que este comportamiento de usuario es más común de lo que esperábamos.

Y si está utilizando la sincronización con otros dispositivos, debe manejarla. Aquí hay varias soluciones:

  • romper la conexión con el servidor, especificando que los datos que contiene permanecerán como estaban y la copia se restaurará solo en el dispositivo del usuario;
  • Es mejor que el usuario le permita restaurar una copia de una vez en todos los dispositivos, habiendo prescrito previamente dichos mecanismos.

Aquí hay una cosa más. Hasta ahora, guardamos las copias de seguridad nosotros mismos, controlamos todo el proceso, capturamos las acciones del usuario directamente en el código cuando presionó el botón "guardar una copia". Todo esto se puede procesar más tarde. En la plataforma 8.3.9, fue posible guardar copias de seguridad exactamente por medio de la plataforma. Y el usuario hace esto sin nuestro conocimiento. Si se utiliza la sincronización con una base de datos central, entonces se debe manejar tal escenario. De alguna manera debemos averiguar en nuestro servidor que el usuario ha restaurado una copia previamente guardada y debemos darle algún tipo de solución. No podemos permitirnos que los datos no estén sincronizados.

INTERCAMBIO

Cuando hablamos de una solución privada en una plataforma móvil, solemos tener un cliente que, por ejemplo, quiere utilizar una plataforma móvil para sus agentes de ventas, y para que intercambien datos con una base de datos central. Aquí todo es simple: una base de datos, varios dispositivos, enciende el servidor, establece la comunicación con él. Entonces, el problema del intercambio entre dispositivos es fácil de resolver.

Pero si hablamos de una aplicación masiva, donde hay muchas bases de datos, cada una de las cuales tiene un número muy grande de usuarios, la situación se complica. Los usuarios han descargado la aplicación del mercado y quieren sincronizar entre sí. Por ejemplo, un esposo descargó una aplicación para la contabilidad de las finanzas personales y ahora quiere que su esposa también se conecte y que trabajen juntos en la misma aplicación. Hay muchos usuarios, la aplicación se está desarrollando, creciendo y se necesita una gran cantidad de bases de datos. ¿Cómo organizar todo esto? Los usuarios no se comunicarán personalmente con los desarrolladores para crear una base de datos separada para ellos y habilitar la sincronización. Quieren presionar un botón y hacerlo funcionar de inmediato. En el mismo momento.

¿Cómo proceder? Aquí es donde el mecanismo de intercambio de datos viene al rescate. Le permite organizar una sola base de datos, donde hay una configuración común, pero al mismo tiempo, se almacena un número ilimitado de bases de usuarios dentro de una base de datos común.

La mejor parte es que puede agregar usuarios de forma dinámica, programática, sin nuestra participación. En realidad, los usuarios simplemente hacen clic en el botón "registrarse en el servidor" y todo sucede por sí solo: se crea una base de datos personal para él en el servidor y puede comenzar a trabajar en ella inmediatamente.

¿Cómo hacerlo? La primera y más sencilla solución es escribir su propia base de servidor con este mecanismo. Cuando nuestra empresa comenzó a hacer la aplicación Boss e intercambia información en ella, en la primera versión hicimos precisamente eso: escribimos una base de datos de servidor con un mecanismo de intercambio de datos. Todo funcionó, especialmente porque no había nada complicado: el separador de bases es un accesorio común.

Pero luego nos dimos cuenta de que estábamos reinventando la rueda :) De hecho, hay una solución ya hecha, y ya ha tenido en cuenta los puntos en los que ni siquiera habíamos pensado todavía. Esto es 1C: fresco.

La escalabilidad del servicio está pensada aquí: qué hacer cuando habrá muchos datos y bases de datos, cómo crecer con todo esto. Hay un punto sobre la creación de copias de seguridad de áreas de datos: es decir, no solo hacemos copias de seguridad de una base de datos común, hacemos copias de un usuario específico. Además, el mecanismo es tal que las copias se hacen solo cuando son realmente necesarias. Si un usuario no ha ingresado a la base de datos durante una semana, entonces no hacemos copias de él, porque nada ha cambiado allí. Otra característica nueva es que el servicio implementa un mecanismo para reducir la carga en el servidor, lo cual es muy importante cuando tienes muchas bases de datos.

En general, Fresh para nosotros es algo nuevo e interesante. Poco a poco estamos tratando de resolverlo, pero en su mayor parte estamos contentos con su trabajo.

Transferencia de datos. Cómo implementarlo para el intercambio entre dispositivos

La plataforma proporciona dos mecanismos: servicios SOAP y http. Hay matices de cómo acceder a estos servicios cuando está involucrado el mecanismo de intercambio de datos. En particular, debe agregar parámetros que indiquen el número específico del área a la que está accediendo, porque la plataforma no puede determinar a qué base de datos acceder mediante el nombre de usuario. Además, un mismo usuario puede trabajar con varias bases de datos dentro de una sola base de datos (ver imagen).

En cuanto a los servicios, la aplicación Boss implementa el intercambio instantáneo: un usuario ingresa datos y el otro los recibe. Los usuarios de aplicaciones móviles están acostumbrados al hecho de que todo sucede instantáneamente, por eso pensamos en qué servicio es mejor usar: SOAP o http. La velocidad de conexión jugó un papel clave. En http, la velocidad de conexión es mucho mayor, y cuando nos conectamos a través de SOAP, obtenemos una descripción del servicio, que es pesado y tarda mucho en cargar. La plataforma tiene una forma de almacenar una descripción de un servicio, pero debido a los parámetros que agregamos dinámicamente, no podemos usar referencias WS. Además, acceder a los servicios http es más conveniente y flexible en nuestra experiencia.

Entonces, nuestro objetivo es implementar el intercambio en tiempo real. Es decir, tratamos de que el usuario no tenga que ir a algún lugar, hacer clic en un botón, pensar en la relevancia de sus datos, si debe actualizarlos ... Los datos siempre deben ser relevantes para los usuarios. Están tan acostumbrados a trabajar en mensajería instantánea: uno envió los datos y el otro los recibió de inmediato. Todo sucede instantáneamente. Lo mismo se aplica a las aplicaciones relacionadas con el negocio: un vendedor ha realizado una venta, el otro debe ver inmediatamente la situación actual sin tomar ninguna medida.

Por lo tanto, la aplicación Boss utiliza trabajos en segundo plano para intercambios. Después de que cada dato se escribe en la base de datos, se inicia un trabajo en segundo plano, que inicia el intercambio. La primera parte es enviar datos al servidor. Entonces, otros dispositivos necesitan saber que hay nuevos datos. Para ello utilizamos notificaciones PUSH. Este esquema ya está funcionando y funciona lo suficientemente rápido.

Pero lo queríamos aún más rápido, porque trabajamos en tiempo real y normalmente tenemos pocos datos. Tenemos XML pequeño, pero al mismo tiempo enviamos un mensaje con estos datos desde el primer dispositivo al servidor, el servidor envía PUSH a otro dispositivo, y luego el segundo dispositivo, luego de recibir PUSH, inicia un intercambio de su lado, se dirige al servidor y solicita datos, recibe estos datos y luego envía una respuesta de que se han recibido los datos. Esto es mucho tiempo, pero los datos en sí eran muy pequeños.

Pensamos en cómo se puede acelerar este proceso.

Para hacer esto, descubrimos qué contiene PUSH, cómo se puede usar. Resultó que PUSH contiene campos como datos y texto. La documentación de iOS y Android contiene restricciones sobre el tamaño de los mensajes PUSH, pero esto no nos pareció suficiente y queríamos resolverlo empíricamente. Y comprobamos que la suma de caracteres válidos es 981 caracteres para iOS y 3832 caracteres para Android. En el último caso, es muy posible utilizar la restricción; uno o varios objetos base pueden apiñarse en tal volumen. Y luego los desarrolladores de la empresa cambiaron un poco el esquema. Cuando no hay muchos datos, los enviamos desde un dispositivo, los recibimos en el servidor, los empaquetamos en PUSH allí y los enviamos directamente a otro dispositivo en él. El esquema se hizo más corto y el intercambio comenzó a ocurrir aún más rápido :)

Un punto importante de usar PUSH es no molestar a los usuarios.

Es muy fácil deshacerse de esta situación: simplemente no envíe muchos mensajes PUSH al usuario :) Si está trabajando en la aplicación ahora, puede enviar muchos mensajes. Cuando la plataforma está en ejecución, el usuario no ve PUSH, todo sucede automáticamente para él. Pero cuando se cierra la aplicación, el cliente tiene muchos mensajes sin leer. Por lo tanto, en ningún caso se debe enviar el siguiente PUSH hasta que se reciba una respuesta del dispositivo de que la aplicación está en ejecución, activa y ya se ha procesado el PUSH anterior.

Otro matiz del intercambio es el trabajo a través de la web. Necesitamos aprovechar al máximo la asincronía. No puede trabajar como de costumbre: escriba el código, llame a la función, espere a que se ejecute, obtenga la respuesta, y todo está bien. Si trabaja a través de la web, aún enfrentará ciertas limitaciones, por ejemplo, Internet inestable, tiempos de espera activados al realizar operaciones a largo plazo. Por tanto, es necesario pensar en la arquitectura de antemano.

Veamos un ejemplo de registro de un dispositivo, lo que sucede en una aplicación cuando un usuario quiere registrarse. Mantiene registros durante un tiempo, ingresó muchos datos, pero luego quiere que el vendedor también trabaje con esta base de datos. El usuario hace clic en el botón "registrarse". Al principio todo fue muy simple: tomaron sus datos, los registraron en el servidor y, por favor, puedes trabajar y conectar usuarios. Pero luego nos encontramos con una situación en la que para algunos usuarios, las bases de datos en el dispositivo en el momento del registro ya habían crecido enormemente. Y este esquema ya no funcionó, ya que mientras se registraba toda la base de datos en el servidor, se activaba el tiempo de espera de la conexión o simplemente se cortaba Internet. Por lo tanto, reemplazamos una llamada sincrónica con muchas llamadas cortas. Ahora los datos se comparten en lugar de transmitirse todos a la vez. No esperamos de ninguna manera a que el servidor procese y registre los datos. Enviamos datos, recibimos una respuesta de que se recibieron los datos, cerramos la conexión. Periódicamente, debe sondear el servidor, qué está sucediendo allí y cómo, y mientras tanto, se está ejecutando un trabajo en segundo plano en el servidor, que registra los datos recibidos. De esta manera recibimos muchas llamadas al servidor, pero tenemos la garantía de que todo saldrá bien. Y ni los tiempos de espera ni la inestabilidad de Internet te impedirán subir todos los datos al servidor.

ACTUALIZACIONES

Intercambio entre dispositivos con diferentes versiones de la aplicación

Ya que estamos hablando de una aplicación masiva que se lanza a los mercados, debemos tener en cuenta algunas de las características del proceso de actualización e intercambio de datos.

Si ha lanzado una aplicación para una empresa y decidió actualizarla, por lo general, solo da un comando para que todos los empleados instalen la nueva aplicación juntos. Esto no se puede hacer con usuarios que descargaron la aplicación del mercado. No puedes decirles qué hacer en absoluto. Por ejemplo, están trabajando en una aplicación y no quieren actualizarla ni ahora ni nunca. No tienen actualización automática, por lo que es una situación bastante común cuando se conectan varios dispositivos a la base central, y todos son de diferentes versiones. Otro motivo de este fenómeno es el tiempo de publicación en los mercados: es diferente para iOS y Android. A menudo implementamos cosas clave, por ejemplo, arreglamos errores críticos, y no queremos esperar hasta que iOS verifique la nueva versión durante dos semanas, queremos al menos solo para Android, pero lanzamos la actualización ahora mismo.

No tenemos derecho a controlar a los usuarios. Si quieren, se actualizan, y si no, no hacen nada. La imagen muestra la proporción de instalaciones de la aplicación Boss por versiones en GooglePlay, así como las estadísticas de nuestro servidor: la proporción real de versiones de la aplicación que están instaladas en dispositivos que han intercambiado datos con el servidor durante la última semana. Aquí tienes un set para trabajar. Estas son versiones diferentes y metadatos diferentes. Y necesitamos organizar un intercambio normal al mismo tiempo :)

Los desarrolladores se enfrentan a las siguientes tareas:

  • Todo esto debe funcionar. Los usuarios no deberían sentirse incómodos por haber olvidado actualizar. No deberían notarlo en absoluto. Actualizado - es mejor, muy bien.
  • Debemos garantizar la seguridad de los datos. Por ejemplo, un usuario tiene un directorio y nuevos accesorios, mientras que otro aún no lo tiene. Además, si un usuario que no tiene nuevos detalles cambia algo en su dispositivo, los datos de otros dispositivos no deben perderse.
  • Necesitamos asegurarnos de que los datos se actualicen cuando actualizamos a una nueva versión. Cuando el usuario decide que está listo para actualizar, automáticamente debería tener toda la información nueva que no tenía solo porque tenía una versión anterior.

¿Cómo lo hicimos?

1. Usamos 2 planes de intercambio en el servidor. El primero es para compartir entre dispositivos y el segundo es para actualizaciones. Por ejemplo, enviamos un manual a un usuario, pero no tiene unidades de medida, es decir, datos incompletos. Debemos recordar esto. Y cuando esté actualizado, debemos enviarle toda la información que no tenía. Para eso sirve el segundo plan de intercambio.

2. Para escribir y leer objetos utilizamos el mismo mecanismo que se utiliza para las copias de seguridad, es decir, guardamos la versión de los metadatos. En este caso, estamos trabajando con el servidor y podemos permitirnos agregar todo lo que queramos directamente a la configuración, por lo que simplemente agregamos esquemas de metadatos a la configuración en forma de diseños a medida que se desarrolla la aplicación.

Cómo monitorear errores masivos durante el intercambio y en el servidor

Primero, debe controlar la disponibilidad del servidor en sí. Esto les sucede a los servidores: caen. No inventamos nada especial para monitorear, simplemente encontramos un bot en el telegrama que grita si algo anda mal. Cada minuto verifica el rendimiento del servidor, y si el servidor de repente no está disponible, comienza a gritar, los administradores lo ven y abren el servidor.

También recopilamos el registro de errores del registro. Tampoco nada sobrenatural: solo recopilamos un registro de errores cada tres horas, los enviamos por correo y los revisamos periódicamente. Esto ayuda a ver problemas comunes y algunos tipos de situaciones excepcionales. No es difícil leer su correo, rastrear y corregir errores rápidamente. Pero esto le permite identificar y resolver rápidamente problemas que pueden crecer con el crecimiento de las bases de datos.

Otro punto importante: asegúrese de darle al usuario la oportunidad de "quejarse". Mejora nuestro estado ante sus ojos y nos salva. Hay usuarios, como los llamamos, "histéricos" que, al más mínimo error, comienzan a enviarnos un montón de mensajes por correo de que nada funciona, la base de datos no carga, todo está terriblemente mal. Pero a veces realmente nos salvan, porque a veces encuentran errores que otros milagrosamente no han encontrado, errores graves.

El usuario no puede asustarse. No mensajes de miedo, nada más. Necesitan explicar todo bellamente y ofrecerse a quejarse. Y prometemos solucionarlo todo. Entonces los usuarios están contentos, porque ven que están atendidos e inmediatamente creen que los ayudarán :)

Este artículo fue escrito en base a los resultados del informe leído en la conferencia INFOSTART EVENT 2016 DEVELOPER. Se pueden leer más artículos.

En 2020, invitamos a todos a participar en 7 encuentros regionales, así como en el INFOSTART EVENT 2020 de aniversario en Moscú.