返回介绍

9.6 竞品技术四瞥:性能优化

发布于 2024-08-17 23:46:11 字数 4003 浏览 0 评论 0 收藏 0

9.6.1 App自动选取最佳服务器的策略

我们经常看到App中会包含一个服务器列表文件,开发人员和测试人员可以随意切换到任意服务器进行开发测试工作。

这只是服务器列表文件的一种功用,是给开发和测试人员使用的,为此我们需要为App设计一个后门,由他们手动进行切换,相关内容请参见9.9.2章节。

服务器列表文件还有另一种作用,就是由App自己来决定选用哪个服务器作为MobileAPI服务器。

众所周知,App发起MobileAPI请求到接收到数据,这个过程所耗费的时间由3部分组成:从App到达服务器的时间,服务器处理的时间,从服务器到App的时间。其中,从App到达服务器的时间,加上从服务器到App的时间,我们称为来回走路时间。对于2G、3G、4G和WiFi用户,因为网络环境的不同,来回走路时间大相径庭。

于是我们会准备多台服务器,可能是放在全国各地,也可能是分别接入电信、移动或联通的专线。这些服务器有可能是配置相同的,也有可能是由若干高配和低配组成。我们把这些服务器的域名罗列在App的服务器列表文件中,如下所示:

<Servers>
  <Server key="s1" type="3G" url="http:// login1.company.com/">
  <Server key="s2" type="3G" url="http:// login2.company.com/">
  <Server key="s3" type="4G" url="http:// login3.company.com/">
  <Server key="s4" type="4G" url="http:// login4.company.com/">
  <Server key="s5" type="2G" url="http:// login5.company.com/">
  <Server key="s6" type="2G" url="http:// login6.company.com/">
  <Server key="s7" type="WiFi" url="http:// login7.company.com/">
  <Server key="s8" type="WiFi" url="http:// login8.company.com/">
</Servers>

接下来,我们会让MobileAPI提供一个接口服务A,该接口不需要任何入参,直接返回1这个结果。这样就确保了App从发起MobileAPI请求到接收到数据的时间,就是来回走路的时间。

在App第一次启动的时候,我会让App根据当前的网络情况,遍历服务器列表文件中的域名,访问这些域名下的接口服务A,计算出哪个域名的访问速度最快。同一个域名只访问一次,得不到准确的数据,一般而言,我会调用10次后取平均值,来作为参考标准。

当网络环境发生变化的时候,也要把上述这个操作执行一遍,测算出该网络环境下哪个域名的访问速度最快。为了避免频繁做这个事情,我会设置一个缓存,记录最后一次测算每种网络环境的时间,以确保1个小时之内不会测算2次。

一旦测算出当前网络环境下哪个域名的访问速度最快,那么接下来1个小时内,访问MobileAPI就会使用这个域名了。1个小时后,我们将在App后台线程再次发起测算工作,重新选择最佳的域名。

上述这种解决方案,能帮助用户选择最快的MobileAPI服务器,但是由此会导致另一种负面效果,App一厢情愿地认为网络环境好所对应的服务器访问速度也最快,于是这台服务器的CPU会迅速被占满,无法处理后续接踵而至的网络请求。所以,我们要将服务器的处理能力划分为优良中差四种级别,并在App发起测评请求(调用MobileAPI接口服务A)的时候把这个值返回给App,当达到中(CPU占用60%)这个级别时,即使网速很快,也不能采用这个域名对应的服务器。

9.6.2 使用TCP+Protobuf

当大多数公司还在纠结于如何能更好提高MobileAPI的性能时,已经有公司开始抛弃HTTP+JSON,开始走TCP+ProtoBuf的路线了。

TCP是长连接,ProtoBuf则是基于二进制的协议,可读性差但是体积小。这里我不讨论Protobuf协议中的required、optional或repeated关键字,也不讨论Android和iOS大小端对齐的问题。这些都属于App和服务器能使用Protobuf进行通信的第一步。

我只说三点,一是工具,二是架构,三是性能。

1.工具

我们需要做一个工具,能帮助开发人员把ProtoBuf协议自动转换为Android或iOS的实体类和相应的方法。使用该方法就可以发起一次ProtoBuf请求并获取到服务器返回的实体数据,这将极大地加速开发人员的工作效率。

2.架构

传统MobileAPI返回HTTP+JSON,当我们改为使用TCP+ProtoBuf的时候,之前的JSON仍然要维护,因为我们要给自己留一条后路,一旦服务器上的TCP+ProtoBuf扛不住了,要立刻能切换回HTTP+JSON。

那么问题就来了。难道我们要为App同时维护两套MobileAPI逻辑吗?当然不行,一种理想的设计方案如图9-11所示。

图9-11 新的MobileAPI架构设计

但是反观我们的MobileAPI代码,却不是这样的,你会发现业务逻辑和JSON绑定很紧,往往是从后台取到数据就立刻填充到JSON字段中了。我们需要重构,把取数据的业务逻辑和返回什么样的数据(JSON或ProtoBuf)剥离开,最好能拆分成3个项目,最差也应该是在一个项目中拆分为不同的目录。这样业务逻辑如果有变动,只需要修改一个地方,然后在JSON或ProtoBuf中追加字段。

生成器模式(Builder)这时候就能派上用场了,它能很好地弥合ProtoBuf和JSON这两种数据格式的差异性。

我们把业务逻辑、JSON生成器、ProtoBuf生成器框在一起后,下一步要面临的就是以HTTP还是TCP的协议返回给App数据了。HTTP协议由Header和Body两部分组成,都需要填充数据,其实我们也可以在TCP协议中定义Header和Body,把之前填充在HTTP的Header中的版本信息、Cookie传递过去。

策略模式(Strategy)可以用于指定使用Http协议还是TCP协议。

3.性能

TCP要解决的技术难点就在于,服务器上长连接数量多会导致服务器性能压力,如果解决不了,用起来还不如HTTP。

于是我们采取TCP长连接和短连接混合的模式。

TCP长连接就是每个App客户端都是作为一个连接,保存在服务器的长连接池中。但是这个池子中的长连接数量是有上限的,所以我们持续清理池子中长期不使用的长连接,比如说几分钟内不使用就关闭这个连接,大不了以后再连上来。

资源是有限的,对于日活几十万的App而言,我们要保证服务器至少能支撑这几十万个长连接。如果超过了这个池子的上限,那么我们就要使用短连接作为补充。短连接就是连接后完成一次调用就把连接关闭了。

服务器要根据当前长连接池的情况,来决定建立长连接还是短连接。如果TCP长连接和短连接都没有资源了,那就切换到HTTP,这其实也是一种短连接。

网络请求的场景不同,也会影响TCP长连接和短连接的选择。比如说xmpp聊天,就比较适合TCP长连接。用户的活跃度,也可以作为选择TCP长连接还是短连接的依据。活跃用户往往会长时间使用App,频繁发起网络请求,这时候要使用长连接。对于那些偶尔打开App随便点一点看一看的用户,可以先使用短连接。等用户发起网络请求的次数超过某个阈值时,就切换到长连接。

网络环境是影响App选择TCP长连接还是短连接的又一个因素。对于WiFi环境,网络请求普遍比2G、3G和4G要好。接下来的策略有两种:

·快的更快、慢的更慢,为使用WiFi的客户端建立长连接,而为2G、3G、4G网络环境下的客户端分配短连接。

·均衡策略,反正WiFi已经很快了,分配给它短连接不会有太大影响,而为了提高2G、3G、4G网络环境下的客户端访问速度,尽量为它们建立长连接。关于在2G、3G、4G网络环境使用TCP长连接是一个很热的话题,经常会出现网络不给力导致TCP连接频繁断开的情况,所以我们要做好随时可以把这部分用户切换到HTTP短连接的机制,以备突发情况的发生。

不得不说的是,WiFi不一定快过4G,甚至是3G和2G,所以上述策略有不准的情况。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文