Service de référence d'applications mobiles

Ruslan Aromatov, développeur en chef, ICD



Bonjour, Khabrovites! Je travaille en tant que développeur backend à la Banque de crédit de Moscou, et cette fois, je voudrais parler de la façon dont nous avons organisé la livraison du contenu d'exécution à notre application mobile MKB Online. Cet article peut être utile à ceux qui sont engagés dans la conception et le développement de serveurs frontaux pour applications mobiles, dans lesquels il est nécessaire de fournir en permanence une variété de mises à jour, que ce soit des documents bancaires, des points de géolocalisation, des icônes mises à jour, etc. sans mettre à jour l'application elle-même dans les magasins. Ceux qui développent des applications mobiles, ça ne fera pas de mal non plus. L'article ne contient pas d'exemples de code, seulement quelques discussions sur le sujet.

Contexte


Je pense que tout développeur d'applications mobiles a rencontré le problème de la mise à jour d'une partie du contenu de leur application. Par exemple, modifiez la clause d'accord utilisateur, l'icône ou les coordonnées du magasin d'un client qui a soudainement déménagé. Il semble que cela pourrait être plus facile? Nous reconstruisons l'application et la mettons dans le magasin. Les clients sont mis à jour, tout le monde est content.

Mais ce schéma simple ne fonctionne pas pour une raison simple - tous les clients ne sont pas mis à jour. Et à en juger par les statistiques, il y a beaucoup de ces clients.

Dans le cas d'une application bancaire, le défaut de fournir des informations pertinentes peut coûter à la fois de l'argent et l'insatisfaction des clients. Par exemple, le premier jour du mois suivant, les tarifs des cartes sont modifiés, de nouvelles règles du programme de bonus sont incluses ou de nouveaux types de destinataires de paiement sont ajoutés. Et si le client lance l'application à exactement 0 heure 01 minute, il devrait voir le contenu mis à jour.

"Élémentaire!" - vous dites. - "Téléchargez ces données depuis le serveur et vous serez content."

Et vous aurez raison. Nous le faisons. Voilà, nous ne sommes pas d'accord .

Cependant, tout n'est pas si simple. Nous avons des applications pour iOS et Android. Chaque plate-forme a plusieurs versions différentes qui ont des fonctionnalités et des API différentes.
En conséquence, il peut arriver que nous devions mettre à jour le fichier pour une application Android avec une version api supérieure à 27, mais pas toucher iOS et les versions antérieures.

Cela s'avère encore plus intéressant lorsque, par exemple, nous devons mettre à jour les icônes des destinataires des paiements ou ajouter de nouveaux éléments avec de nouvelles icônes. Nous dessinons chaque instance de l'icône dans sept résolutions différentes pour chaque type d'écran spécifique: pour Android, nous en avons 4 (hdpi, xhdpi, xxhdpi, xxxhdpi) et 3 pour iOS (1x, 2x, 3x). Lequel dois-je envoyer à une application spécifique?

"Eh bien, envoyez les paramètres de fichier nécessaires à une application particulière."

Correctement! Personne ne sait de quel fichier l'application a besoin, à l'exception de l'application.
Cependant, ce n'est pas tout. Dans les applications, plusieurs fichiers sont interconnectés. Par exemple, les listes de bénéficiaires (un fichier json) sont associées aux détails des bénéficiaires (un autre fichier json). Et si nous recevons le premier fichier et pour une raison quelconque, nous ne pouvons pas recevoir le second, les clients ne pourront pas payer pour le service. Et ce n'est pas très bon, franchement.

Le deuxième cas: nous mettons à jour l'ensemble des icônes des destinataires du paiement (et il y en a plus d'une centaine) lors de la saisie de la page de paiement. Selon la vitesse d'Internet, cela peut prendre de 10 secondes à plusieurs minutes. Quel devrait être le bon comportement de la page? Par exemple, vous pouvez simplement afficher la version précédente des icônes et en télécharger de nouvelles en arrière-plan, puis mettre en cache et n'afficher que les nouvelles la prochaine fois que le client visite la page. D'une certaine manière, pas vraiment, non?

Une autre option consiste à remplacer dynamiquement les icônes déjà téléchargées par de nouvelles. Pas trop joli, non? Et si une icône ne se télécharge pas du tout? Ensuite, nous verrons une belle série de nouvelles icônes avec un morceau de l'ancien design au milieu.

Icônes d'opération

"Ensuite, téléchargez l'ensemble des icônes dans une archive au démarrage de l'application."

Bonne idée. Pas vraiment. Mais il y a une nuance.

Il arrive souvent qu'un concepteur ne redessine que quelques centaines d'icônes et que vous n'ayez qu'à les remplacer. Ils pèsent 200 octets, et l'archive entière nous a 200 kilo-octets. Est-ce que le client devra re-pomper ce qu'il a déjà?

Et nous n'avons pas encore calculé le coût d'un tel travail sur le serveur. Disons que 10 000 clients par heure viennent chez nous (c'est la valeur moyenne, ça arrive plus). Le démarrage de l'application lance la mise à jour en arrière-plan des répertoires(oui, vous savez maintenant comment nous l'appelons). Si un client doit mettre à jour 1 kilo-octet, dans une heure, le serveur donnera plus de 10 mégaoctets. Pennies, non? Et si l'ensemble des mises à jour pèse 1 mégaoctet? dans ce cas, nous devrons déjà donner 10 gigaoctets. À un moment donné, nous arrivons à la conclusion que le trafic doit être pris en compte.

Ensuite, vous devez apprendre à comprendre quels fichiers ont changé et lesquels ne le sont pas, et télécharger uniquement les fichiers nécessaires.

Droite. Mais comment comprendre quels fichiers ont changé et lesquels ne l'ont pas été? Nous considérons un hachage pour cela. Ainsi, un certain cache de fichiers apparaît dans l'application, qui contient un ensemble de fichiers de référence. Ces fichiers sont utilisés comme ressources selon les besoins. Et côté serveur, nous sommes finalement nés ...

Service d'annuaire


En général, il s'agit d'un service Web régulier qui envoie des fichiers via http en tenant compte de toutes les exigences de l'application. Il se compose d'un certain nombre de conteneurs Docker, à l'intérieur desquels une application Java fonctionne avec le serveur Web de la jetée à bord. Le backend est la base de données Tarantool sur le moteur vinyle (il n'y avait pas de choix douloureux - il y avait juste toute la liaison pour cette base de données; vous pouvez en lire plus dans mon article précédent Service de cache intelligent basé sur ZeroMQ et Tarantool ) avec réplication maître-esclave. Pour gérer les fichiers, il existe une interface Web de service, également entièrement auto-écrite.



Les détails de mise en œuvre technique dans le sujet de cet article ne sont pas particulièrement significatifs. Il peut s'agir de php + apache + mysql, C # + IIS + MSSQL ou tout autre bundle, y compris sans base de données.

Le diagramme ci-dessous montre comment fonctionne le service que nous avons appelé Woodside. Les clients mobiles via l'équilibreur accèdent aux instances de services Web et ceux-ci, à leur tour, obtiennent les fichiers nécessaires de la base de données.

Schéma de travail

Mais dans cet article, je ne parlerai que de la structure du système de référence et de la façon dont nous les utilisons dans les applications.

Fichiers nécessaires dans les applications, nous nous divisons en 3 types différents.

  1. Fichiers qui doivent toujours être dans l'application et indépendants du type de système d'exploitation. Par exemple, il s'agit d'un fichier pdf avec un accord de service bancaire.
  2. -, , ( ) . , .
  3. , , . - , , . , .

Programme d'affiliation

Les 2 premiers types de fichiers sous forme d'archives sont immédiatement placés dans l'assembly d'application - une nouvelle version par défaut inclut le plus récent ensemble de répertoires. Ils tombent dans le système de mise à jour automatique, qui s'exécute en arrière-plan lorsque l'application démarre et fonctionne comme suit.

1. Le service d'annuaire reçoit automatiquement une partie des données de divers endroits: bases de données, services connexes, boules de réseau - ce sont des informations bancaires générales importantes qui sont mises à jour par d'autres services. L'autre partie est constituée de répertoires créés au sein de notre équipe via l'interface web et contenant des fichiers destinés uniquement aux applications mobiles.

2. Selon le planning (ou par le bouton), le service parcourt tous les fichiers de tous les répertoires et forme sur leur base un ensemble de fichiers d'index (à l'intérieur de json) aussi bien pour les fichiers du premier type (2 versions pour iOS et android) que pour les fichiers de ressources du second type (7 versions pour chaque type d'écran).
Cela ressemble à ceci:

{
  "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"
    }
  ]
}

Les index contiennent des informations sur tous les fichiers d'un type donné, sur la base desquels est construit le mécanisme de mise à jour des répertoires des applications.

3. Applications au démarrage, la première chose qu'elles téléchargent est les fichiers d'index dans le répertoire / new à l' intérieur de leur cache de fichiers. Et dans le répertoire / current , ils ont des index pour l'ensemble actuel de fichiers avec les fichiers eux-mêmes.

4. Sur la base des fichiers d'index nouveaux et anciens (avec la participation de tous les fichiers actuels à partir desquels le hachage est pris en compte), des listes de fichiers sont créées qui doivent être mises à jour ou supprimées, et la nécessité d'une mise à jour est généralement établie.

5. Après cela, dans le répertoire / newles applications téléchargent les fichiers nécessaires depuis le serveur via un lien direct (l'ID de fichier dans l'index en est responsable). Dans ce cas, la présence et les hachages de fichiers déjà dans le répertoire / new sont pris en compte , car cela peut être un CV.

6. Dès que l'ensemble des fichiers est reçu dans le répertoire / new , ils sont vérifiés par rapport au fichier d'index (il arrive parfois que les fichiers ne soient pas complètement téléchargés).

7. Si la vérification a réussi, l'arborescence de fichiers entière est déplacée avec le remplacement dans le répertoire / current . Un nouveau fichier d'index devient actuel.

8. Si la vérification échoue, les transferts de fichiers n'auront pas lieu et l'application continuera d'utiliser l'ensemble actuel de répertoires. Au prochain démarrage de l'application, le mécanisme de mise à jour tentera de la corriger. Si nous avons un crash global lors du déplacement de fichiers, nous sommes obligés de revenir à la toute première version des répertoires fournis avec l'assembly. Jusqu'à présent, il n'y a eu aucun précédent.

Mais pourquoi est-ce si difficile?

En réalité, pas très difficile. Mais le fait est que nous devons constamment expérimenter et trouver des compromis entre le nombre de fichiers constamment mis à jour et les temps de chargement, entre l'économie de trafic et la vitesse. Un rôle important dans le choix d'un type de fichier est joué lorsqu'il est exactement nécessaire dans l'application. Supposons que si l'icône doit être affichée immédiatement sur la page principale après la connexion, l'application peut alors charger un tel fichier au moment de l'exécution et ne pas le placer dans un long mécanisme de mise à jour. Maintenant, la taille totale de l'archive avec uniquement les fichiers principaux est de 12 mégaoctets, sans compter les ressources dépendantes de l'écran. Et comme la mise à jour est essentiellement une opération atomique, nous devons attendre qu'elle soit terminée. Cela peut prendre plusieurs minutes dans les cas où la connexion est mauvaise et où il y a beaucoup de nouveaux fichiers.

Un point important est la sauvegarde du trafic. Il y avait des moments où nous utilisions complètement un canal de 100 mégabits après des mises à jour épaisses. J'ai dû passer à 300. Jusqu'à présent, assez. En moyenne, les métriques montrent qu'en général les clients téléchargent de 25 à 50 gigaoctets par heure pendant la journée (c'est parce que nous avons des fichiers assez volumineux qui sont mis à jour quotidiennement). Il y a encore de la place pour un développement supplémentaire en termes d'économie, mais les entreprises sont également sur le qui-vive - tout le temps, elles ajoutent diverses nouvelles belles choses.

En conclusion, je peux ajouter que les serveurs frontaux eux-mêmes utilisent également le service qui, au démarrage, télécharge les données nécessaires au traitement des demandes des clients.

Et comment fournissez-vous des mises à jour de contenu aux applications?

All Articles