移动应用参考服务

ICD首席开发人员Ruslan Aromatov,哈勃罗夫主义者,



下午好!我在Moscow Credit Bank担任后端开发人员,这次我想谈一谈我们如何组织将运行时内容交付到MKB Online移动应用程序。本文对于从事移动应用程序前端服务器设计和开发的人员很有用,在这些应用程序中,有必要不断交付各种更新,无论是银行文档,地理位置,更新的图标等,而无需在商店中更新应用程序本身。那些开发移动应用程序的人也不会受到伤害。本文不包含代码示例,仅包含有关该主题的一些讨论。

背景


我认为任何移动应用程序开发人员都遇到了更新其应用程序某些内容的问题。例如,更改用户协议条款,突然移动的客户的图标或商店的坐标。似乎会更容易?我们重建应用程序并将其放入商店。客户得到更新,每个人都很高兴。

但是,由于一个简单的原因,这种简单的方案不起作用-并非所有客户端都已更新。从统计数据来看,有很多这样的客户。

对于银行应用程序,无法提供相关信息可能会导致金钱和客户不满。例如,在下个月的第一天,更改卡费率,包括新的奖励计划规则,或添加新的付款接收者类型。并且,如果客户端在恰好0小时01分钟启动应用程序,则他应该看到更新的内容。

“初级!” - 你说。 -“从服务器下载此数据,您会很高兴的。”

你会是对的。我们这样做。就是这样,我们不同意

但是,并非都那么简单。我们有适用于iOS和Android的应用程序。每个平台都有几个具有不同功能和API的不同版本。
因此,可能需要为api版本高于27的android应用程序更新文件,而不是接触iOS和更早版本。

事实证明,例如,当我们需要更新付款接收者的图标或使用新图标添加新项目时,情况会更加有趣。我们为每种特定类型的屏幕以七个不同的分辨率绘制图标的每个实例:对于android,我们有4种(hdpi,xhdpi,xxhdpi,xxxhdpi),而对于iOS,则有3种(1x,2x,3x)。我应该发送哪一个到特定的应用程序?

“然后发送特定应用程序所需的文件参数。”

正确!除了应用程序外,没人知道应用程序需要哪个文件。
但是,这还不是全部。在应用程序中,有很多相互关联的文件。例如,收款人列表(一个json文件)与收款人的详细信息(另一个json文件)相关联。如果我们收到第一个文件,但由于某种原因无法收到第二个文件,那么客户将无法为该服务付费。坦白说,这不是很好。

第二种情况:进入付款页面时,我们会更新付款接收者的整个图标集(其中有一百多个)。根据Internet的速度,可能需要10秒钟到几分钟的时间。正确的页面行为应该是什么?例如,您可以简单地显示图标的先前版本,并在后台下载新图标,然后缓存并仅在客户端下次访问页面时显示新图标。不知道是不是真的对不对?

另一个选择是用新图标动态替换已经下载的图标。不太漂亮吧?如果某些图标根本无法下载?然后,我们将看到一系列精美的新图标,中间还有一块旧设计。

操作图标

“然后在应用程序启动时将整个图标集下载到一个存档中。”

不错的想法。不完全是。但是有细微差别。

通常,设计人员只重绘数百个图标,而您只需要替换它们即可。它们重200字节,整个档案库有200千字节。客户是否必须重新泵送他已经拥有的东西?

而且我们尚未计算服务器上此类工作的成本。假设每小时有10,000位客户来找我们(这是平均值,这种情况发生的次数更多)。应用程序启动启动目录的后台更新(是的,您现在知道我们称之为什么)。如果一个客户端需要更新1 KB,则服务器在一小时内将提供10 MB以上的字节。便士,对吗?如果更新集重1兆字节?在这种情况下,我们将不得不提供10 GB的空间。在某个时候,我们得出结论,应该考虑流量。

然后,您需要学习了解哪些文件已更改,哪些文件未更改,并仅下载必要的文件。

对。但是,如何了解哪些文件已更改,哪些文件未更改?我们为此考虑一个散列。因此,某个文件缓存将出现在应用程序中,其中包含一组参考文件。这些文件根据需要用作资源。在服务器端,我们最终诞生了……

目录服务


通常,这是一个常规的Web服务,考虑到应用程序的所有要求,该服务通过http发送文件。它由许多docker容器组成,在其中有一个Java应用程序与板上的码头Web服务器一起工作。后端是Vinyl引擎上的Tarantool数据库(没有痛苦的选择-该数据库只有整个绑定;您可以在我以前的文章基于ZeroMQ和Tarantool的智能缓存服务中了解到此信息),具有主从复制功能。为了管理文件,有一个服务网络界面,该界面也完全是自写的。



本文主题中的技术实现细节不是特别重要。它可能是php + apache + mysql,C#+ IIS + MSSQL或任何其他捆绑软件,包括根本没有数据库的情况。

下图显示了我们称为Woodside的服务的工作方式。通过平衡器的移动客户端转到Web服务的实例,这些实例又从数据库中获取必要的文件。

工作计划

但是在本文中,我只会讨论参考系统的结构,以及我们如何在应用程序中使用它们。

在应用程序中必需的文件,我们分为3种不同的类型。

  1. 必须始终位于应用程序中且与操作系统类型无关的文件。例如,这是带有银行服务协议的pdf文件。
  2. -, , ( ) . , .
  3. , , . - , , . , .

会员计划

归档形式的前两种文件会立即放入应用程序集中-默认情况下,新版本包括最新的目录集。它们属于自动更新系统,该系统在应用程序启动时在后台运行,其工作方式如下。

1.目录服务自动从不同地方接收部分数据:数据库,相关服务,网络球-这是一些重要的常规银行信息,其他部门会更新这些信息。另一部分是我们团队中通过Web界面创建的目录,其中包含仅用于移动应用程序的文件。

2.根据计划(或通过按钮),该服务遍历所有目录的所有文件,并在它们的基础上形成一组索引文件(在json内),用于第一类文件(iOS和android的两个版本)和第二类资源文件类型(每种类型的屏幕7种版本)。
看起来像这样:

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

索引包含有关给定类型的所有文件的信息,在此基础上构建了用于更新应用程序目录的机制。

3.在启动时,应用程序下载的第一件事是文件缓存内/ new目录中的索引文件。并且在/ current目录中,它们具有当前文件集的索引以及文件本身。

4.基于新旧索引文件(考虑了哈希的所有当前文件的参与),创建了需要更新或删除的文件列表,并且通常确定了更新需求。

5.之后,转到/新目录应用程序通过直接链接从服务器下载必要的文件(索引中的文件ID对此负责)。在这种情况下,考虑到/ new目录中已经存在的文件和哈希文件,因为这可以作为恢复。

6.在/ new目录中收到整个文件集后,将立即根据索引文件对它们进行检查(有时会发生文件未完全下载的情况)。

7.如果检查成功,整个文件树将被替换并替换到/ current目录中。新的索引文件成为当前文件。

8.如果验证失败,则将不会进行文件传输,并且应用程序将继续使用当前目录集。下次应用程序启动时,更新机制将尝试对其进行修复。如果在移动文件时发生全局崩溃,那么我们将不得不回滚到程序集随附的目录的第一个版本。到目前为止,尚无先例。

但是为什么这么困难?

实际上,不是很困难。但是事实是,我们必须不断进行试验,并在不断更新的文件数和加载时间之间,节省流量和速度之间找到折衷方案。在应用程序中确实需要选择文件类型时,它扮演着重要的角色。假设,如果图标应在登录后立即显示在主页上,则应用程序可以立即在运行时加载此类文件,而无需将其置于长更新机制中。现在,仅包含主文件的归档文件的总大小为12 MB,不包括与屏幕相关的资源。并且由于更新本质上是原子操作,因此我们必须等待直到更新结束。如果连接不良并且有许多新文件,则可能需要花费几分钟。

重要的是节省流量。有时,经过大量更新后,我们完全利用了100兆比特的通道。我必须扩展到300。到目前为止,足够了。平均而言,指标显示,通常,客户端在一天中每小时的下载速度为25到50 GB(这是因为我们有相当大的文件,每天都会更新)。就经济而言,仍有进一步发展的空间,但企业也时刻保持警惕-一直在增加各种新的美感。

总之,我可以添加前端服务器本身也使用该服务,该服务在启动时会下载处理客户端请求所需的数据。

以及如何向应用程序交付内容更新?

All Articles