Servicio de referencia de aplicaciones móviles

Ruslan Aromatov, desarrollador jefe, ICD



Buenas tardes, Khabrovites! Trabajo como desarrollador de backend en Moscow Credit Bank, y esta vez me gustaría hablar sobre cómo organizamos la entrega de contenido en tiempo de ejecución a nuestra aplicación móvil MKB Online. Este artículo puede ser útil para quienes se dedican al diseño y desarrollo de servidores frontales para aplicaciones móviles, en los que es necesario entregar constantemente una variedad de actualizaciones, ya sea documentos bancarios, puntos de geolocalización, iconos actualizados, etc., sin actualizar la aplicación en las tiendas. Aquellos que desarrollan aplicaciones móviles, tampoco les hará daño. El artículo no contiene ejemplos de código, solo algunas discusiones sobre el tema.

Antecedentes


Creo que cualquier desarrollador de aplicaciones móviles ha encontrado el problema de actualizar parte del contenido de su aplicación. Por ejemplo, cambie la cláusula del acuerdo de usuario, el icono o las coordenadas de la tienda de un cliente que se mudó de repente. Parece que podría ser más fácil? Reconstruimos la aplicación y la ponemos en la tienda. Los clientes están actualizados, todos están contentos.

Pero este esquema simple no funciona por una simple razón: no todos los clientes están actualizados. Y a juzgar por las estadísticas, hay muchos de esos clientes.

En el caso de una aplicación bancaria, la falta de entrega de información relevante puede costar tanto dinero como la insatisfacción del cliente. Por ejemplo, el primer día del mes siguiente, las tarifas de la tarjeta cambian, se incluyen nuevas reglas del programa de bonificación o se agregan nuevos tipos de beneficiarios. Y si el cliente inicia la aplicación exactamente a las 0 horas y 01 minutos, debería ver el contenido actualizado.

"¡Elemental!" - tu dices. - "Descarga esta información del servidor y estarás contento".

Y tendrás razón. Nosotros lo hacemos Eso es, no estamos de acuerdo .

Sin embargo, no todo es tan simple. Tenemos aplicaciones para iOS y Android. Cada plataforma tiene varias versiones diferentes que tienen diferentes funcionalidades y API.
Como resultado, puede suceder que necesitemos actualizar el archivo para una aplicación de Android con una versión de API superior a 27, pero no tocar iOS y versiones anteriores.

Resulta aún más interesante cuando, por ejemplo, necesitamos actualizar los íconos de los destinatarios de pagos o agregar nuevos artículos con nuevos íconos. Dibujamos cada instancia del icono en siete resoluciones diferentes para cada tipo específico de pantalla: para Android tenemos 4 de ellas (hdpi, xhdpi, xxhdpi, xxxhdpi) y 3 para iOS (1x, 2x, 3x). ¿Cuál debo enviar a una aplicación específica?

"Bueno, entonces envíe los parámetros de archivo que necesita una aplicación en particular".

¡Correctamente! Nadie sabe qué archivo necesita la aplicación, excepto la aplicación.
Sin embargo, esto no es todo. En las aplicaciones, hay bastantes archivos que están interconectados. Por ejemplo, las listas de beneficiarios (un archivo json) están asociadas con los detalles de los beneficiarios (otro archivo json). Y si recibimos el primer archivo y por alguna razón no podemos recibir el segundo, los clientes no podrán pagar el servicio. Y esto no es muy bueno, francamente.

El segundo caso: actualizamos todo el conjunto de iconos de destinatarios de pagos (y hay más de un centenar de ellos) al ingresar a la página de pago. Dependiendo de la velocidad de Internet, puede tomar de 10 segundos a varios minutos. ¿Cuál debería ser el comportamiento correcto de la página? Por ejemplo, simplemente puede mostrar la versión anterior de los íconos y descargar nuevos en segundo plano, luego guardar en caché y solo mostrar nuevos la próxima vez que el cliente visite la página. De alguna manera no realmente, ¿verdad?

Otra opción es reemplazar dinámicamente los íconos ya descargados por otros nuevos. No es muy bonita, ¿verdad? ¿Y si algún ícono no se descarga en absoluto? Luego veremos una hermosa serie de nuevos iconos con una pieza del diseño anterior en el medio.

Iconos de operación

"Luego descargue todo el conjunto de iconos en un archivo al iniciar la aplicación".

Buena idea. No realmente. Pero hay un matiz.

A menudo sucede que un diseñador vuelve a dibujar solo un par de cientos de iconos, y solo necesita reemplazarlos. Pesan 200 bytes, y todo el archivo tenemos 200 kilobytes. ¿Es que el cliente tendrá que volver a bombear lo que ya tiene?

Y aún no hemos calculado el costo de dicho trabajo en el servidor. Digamos que nos llegan 10.000 clientes por hora (este es el valor promedio, sucede más). El inicio de la aplicación inicia la actualización en segundo plano de los directorios.(sí, ahora sabes cómo lo llamamos). Si un cliente necesita actualizar 1 kilobyte, en una hora el servidor dará más de 10 megabytes. Peniques, ¿verdad? ¿Y si el kit de actualización pesa 1 megabyte? en este caso, tendremos que dar ya 10 gigabytes. En algún momento, llegamos a la conclusión de que el tráfico debe ser considerado.

Luego debe aprender a comprender qué archivos han cambiado y cuáles no, y descargar solo los necesarios.

Derecha. Pero, ¿cómo entender qué archivos han cambiado y cuáles no? Consideramos un hash para esto. Por lo tanto, un determinado caché de archivos aparece en la aplicación, que contiene un conjunto de archivos de referencia. Estos archivos se utilizan como recursos según sea necesario. Y en el lado del servidor, finalmente nacimos ...

Servicio de directorio


En general, este es un servicio web regular que envía archivos a través de http teniendo en cuenta todos los requisitos de la aplicación. Consiste en una serie de contenedores acoplables, dentro de los cuales una aplicación Java funciona con el servidor web de embarcadero a bordo. El backend es la base de datos Tarantool en el motor de vinilo (no había ninguna elección dolorosa, solo tenía todo el enlace para esta base de datos; puede leer sobre esto en mi artículo anterior Servicio de caché inteligente basado en ZeroMQ y Tarantool ) con replicación maestro-esclavo. Para gestionar archivos hay una interfaz web de servicio, también completamente autoescrita.



Los detalles de implementación técnica en el tema de este artículo no son particularmente significativos. Podría ser php + apache + mysql, C # + IIS + MSSQL o cualquier otro paquete, incluso sin una base de datos.

El siguiente diagrama muestra cómo funciona el servicio que llamamos Woodside. Los clientes móviles a través del equilibrador van a instancias de servicios web y, a su vez, obtienen los archivos necesarios de la base de datos.

Esquema de trabajo

Pero en este artículo solo hablaré sobre la estructura del sistema de referencia y cómo los usamos en las aplicaciones.

Archivos necesarios en las aplicaciones, los dividimos en 3 tipos diferentes.

  1. Archivos que siempre deben estar en la aplicación, e independientes del tipo de sistema operativo. Por ejemplo, este es un archivo pdf con un acuerdo de servicio bancario.
  2. -, , ( ) . , .
  3. , , . - , , . , .

Programa de afiliación

Los primeros 2 tipos de archivos en forma de archivos se colocan inmediatamente en el ensamblado de la aplicación; una versión nueva incluye de manera predeterminada el conjunto más nuevo de directorios. Caen en el sistema de actualización automática, que se ejecuta en segundo plano cuando se inicia la aplicación, y funciona de la siguiente manera.

1. El servicio de directorio recibe automáticamente parte de los datos de varios lugares: bases de datos, servicios relacionados, bolas de red: esta es una información bancaria general importante que otros departamentos actualizan. La otra parte son los directorios creados dentro de nuestro equipo a través de la interfaz web y que contienen archivos destinados solo a aplicaciones móviles.

2. De acuerdo con la programación (o mediante el botón), el servicio se ejecuta a través de todos los archivos de todos los directorios y, sobre la base, forma un conjunto de archivos de índice (dentro de json) tanto para los archivos del primer tipo (2 versiones para iOS y Android) como para los archivos de recursos del segundo tipo (7 versiones para cada tipo de pantalla).
Se ve algo como esto:

{
  "version": "43",
  "date": "04 Apr 2020 12:31:59",
  "os": "android",
  "screen": "any",
  "hashType": "md5",
  "ts": 1585992719,
  "files": [
    {
      "id": "WBRbDUlWhhhj",
      "name": "action-in-rhythm-of-life.json",
      "dir": "actions",
      "ts": 1544607853,
      "hash": "68c589c4fa8a44ded4d897c3d8b24e5c"
    },
    {
      "id": "o3K4mmPOOnxu",
      "name": "banks.json",
      "dir": "banks",
      "ts": 1583524710,
      "hash": "c136d7be420b31f65627f4200c646e0b"
    }
  ]
}

Los índices contienen información sobre todos los archivos de un tipo dado, sobre la base de los cuales se construye el mecanismo para actualizar directorios en las aplicaciones.

3. Aplicaciones al inicio, lo primero que descargan es indexar archivos en el directorio / new dentro de su caché de archivos. Y en el directorio / current tienen índices para el conjunto actual de archivos junto con los archivos mismos.

4. En función de los archivos de índice nuevos y antiguos (con la participación de todos los archivos actuales desde los que se considera el hash), se crean listas de archivos que deben actualizarse o eliminarse, y generalmente se establece la necesidad de actualización.

5. Después de eso, al directorio / newlas aplicaciones descargan los archivos necesarios desde el servidor a través de un enlace directo (la identificación del archivo en el índice es responsable de esto). En este caso, se tiene en cuenta la presencia y los hash de archivos que ya están en el directorio / new , ya que esto puede ser un currículum.

6. Tan pronto como se reciba el conjunto completo de archivos en el directorio / new , se verifican contra el archivo de índice (a veces sucede que los archivos no se descargaron por completo).

7. Si la verificación fue exitosa, todo el árbol de archivos se mueve con el reemplazo en el directorio / current . El archivo de índice nuevo se actualiza.

8. Si la verificación no tiene éxito, no se realizarán transferencias de archivos y la aplicación continuará utilizando el conjunto actual de directorios. La próxima vez que se inicie la aplicación, el mecanismo de actualización intentará solucionarlo. Si tenemos un bloqueo global al mover archivos, entonces nos vemos obligados a retroceder a la primera versión de los directorios que vinieron con el ensamblado. Hasta ahora no ha habido precedentes.

¿Pero por qué es tan difícil?

En realidad, no es muy difícil. Pero el hecho es que constantemente tenemos que experimentar y encontrar compromisos entre la cantidad de archivos constantemente actualizados y los tiempos de carga, entre ahorrar tráfico y velocidad. Se juega un papel importante en la elección de un tipo de archivo cuando se necesita exactamente en la aplicación. Supongamos que si el icono se muestra inmediatamente en la página principal después del inicio de sesión, la aplicación puede cargar dicho archivo en tiempo de ejecución inmediatamente, y no ponerlo en un mecanismo de actualización largo. Ahora el tamaño total del archivo con solo los archivos principales es de 12 megabytes, sin incluir recursos dependientes de la pantalla. Y dado que la actualización es esencialmente una operación atómica, debemos esperar hasta que termine. Esto puede llevar varios minutos en casos en los que la conexión es deficiente y hay muchos archivos nuevos.

Un punto importante es ahorrar tráfico. Hubo momentos en los que utilizamos por completo un canal de 100 megabits después de actualizaciones intensas. Tuve que ampliar a 300. Hasta ahora, suficiente. En promedio, las métricas muestran que generalmente los clientes descargan de 25 a 50 gigabytes por hora durante el día (esto se debe a que tenemos archivos bastante grandes que se actualizan diariamente). Todavía hay espacio para un mayor desarrollo en términos de economía, pero las empresas también están alerta: todo el tiempo están agregando varias cosas nuevas y hermosas.

En conclusión, puedo agregar que los propios servidores frontales también usan el servicio, que, al inicio, descargan los datos necesarios para procesar las solicitudes de los clientes.

¿Y cómo se entregan actualizaciones de contenido a las aplicaciones?

All Articles