下载本文的PDF版本 PDF

提升移动网络速度

移动性能问题?修复后端,而不仅仅是客户端。


Kate Matsudaira


移动客户端一直在兴起,并且只会持续增长。这意味着,如果您通过互联网为客户端提供服务,则不能忽视移动设备上的客户体验。

关于移动性能的文章有很多信息丰富,关于通用API设计的文章也同样多,但是您会发现很少有文章讨论优化移动客户端后端系统所需的设计考虑因素。无论您拥有应用程序、移动网站还是两者兼而有之,这些客户端都可能正在使用来自您后端系统的API。

当然,优化应用程序在移动设备上的性能至关重要,但是软件工程师可以做很多工作来确保远程为移动客户端可靠且高效地提供数据和应用程序资源。

移动设备的特殊性

移动设备有什么特别之处?如果您回到过去使用互联网,您会注意到大多数网站感觉都比较慢。现在的技术已经发展到客户端可以有效地使用和协商低带宽通道的程度。但是,移动客户端不具备台式机的计算能力、存储空间和高带宽连接,因此需要对移动设备进行稍微不同的考虑。

以下是在构建基于移动设备的应用程序时需要考虑的一些特殊因素

屏幕尺寸有限。用于数据和图像的空间更少。

同时连接数较少。这一点很重要,因为与可以运行许多并发异步请求的Web浏览器不同,移动浏览器在任何给定时刻每个域的连接数都有限。

网络速度较慢。网络性能受到不良信号接收和多次蜂窝网络切换的严重影响(即使某些客户端使用Wi-Fi,某些网络也可能拥塞,并且如果用户更改蜂窝塔,则可能需要额外的查找)。

处理能力较慢。大量的客户端计算、3D图形渲染和大量JavaScript使用会严重影响性能。

缓存较小。移动客户端通常受内存限制,因此最好不要过度依赖缓存内容来提高性能。

“特殊”浏览器。在许多方面,移动浏览器生态系统让人想起几年前碎片化的桌面浏览器场景,移动供应商生产的版本存在致命的缺陷和不兼容性。

尽管有很多方法可以解决这些独特的障碍,但本文重点介绍可以从API或后端服务方面做些什么来提高移动客户端的性能(或用户对此的感知)。本文分为两部分

• 最大程度地减少网络连接和数据传输的需求——高效的媒体处理、有效的缓存以及采用连接较少且面向数据的更长操作。

• 通过网络发送“正确”的数据——设计API以仅返回所需/请求的数据,并针对各种类型的移动设备进行优化。

尽管本文重点关注移动设备,但许多经验和想法也可以应用于其他API客户端形式。

最大程度地减少网络连接和数据传输

毫无疑问,减少渲染网页所需的HTTP请求数量是提高移动性能的最佳方法之一。有很多方法可以做到这一点,但是确切的方法可能取决于您的数据和应用程序的架构。

在大多数情况下,您都希望最大程度地减少通过网络发送的信息量。在服务器上渲染具有其优势(例如,当服务器发回整个HTML页面时),因为它比在客户端上执行渲染需要更少的计算和处理资源。当然,这种方法的缺点是,服务器端渲染的代码越多,该代码就越有可能在客户端浏览器中出现显示问题(而处理浏览器兼容性很少有趣)。尽管如此,可以在客户端上完成的工作越多,通过网络的行程就越少。毕竟,这就是“应用程序”变得如此流行的原因——如果您可以在带有网络的Web浏览器中完成所有操作,那么这将是一个移动网站世界。

最大程度地减少图像请求

在标准浏览器中,为页面上的每个图像发出单个请求可以提高速度,并允许您利用每个图像的缓存。浏览器能够快速并行地执行每个请求,因此发出许多请求不会造成很大的性能损失(并且利用缓存优势甚至可以提高性能)。但是,这种方法可能会对移动设备造成致命打击。

移动设备上的每个数据请求都可能需要更多的开销,这可能会为每个请求增加明显的延迟。因此,最大程度地减少图像请求可以减少请求数量,并在某些情况下减少需要发送的数据量(这也有助于提高移动性能)。

以下是一些需要考虑的策略

使用图像精灵。使用图像精灵可以减少需要从服务器下载的单个图像的数量,但是精灵可能难以维护,并且在某些情况下(例如,在产品搜索结果中显示许多产品的缩略图图像时)难以生成。

使用CSS代替图像。尽可能避免使用图像,而使用CSS(层叠样式表)渲染阴影渐变和其他效果可以减少需要传输和下载的字节数。

支持响应式图像。向正确的设备交付正确的图像的一种流行方法是使用响应式图像。Apple通过加载常规图像,然后使用JavaScript将它们替换为高分辨率图像来实现此目的。7 其他几种方法3 来解决此问题,但是这个问题远未解决12

在这些情况下,您应确保服务器端支持和API能够支持同一图像的不同版本,而确切的方法将取决于客户端的方法。例如,使用API执行此操作的一种简便方法是支持少量图像尺寸作为请求的参数,如下所示

请求

http://yourdomain.net/api/objects.json?objectIds=18369542&imageSize=IMG_140x140

响应


objects: [
     { product: {
       id: "18369542",
       title: "立式冷冻柜",
       brand: "Frigidaire",
       imageURL: "https://yourdomain.net/140x140/18369542-140x140.jpg",
     } }
     { product: {
       id: "14958145",
       title: "索尼 Bravia 32英寸液晶电视",
       brand: "Sony",
       imageURL: "https://yourdomain.net/140x140/14958145-140x140.jpg",
     } }
]

这些是我在最后一个项目中使用的尺寸选项

{'IMG_ORIGINAL'|'IMG_70x70'|'IMG_80x80'|'IMG_85x85'|'IMG_90x90'|'IMG_100x100'|'IMG_140x140'|'IMG_160x160'|'IMG_170x170'|'IMG_180x180'|'IMG_200x200'|'IMG_312x312'}

为了使API保持简单,请使此参数成为可选参数,并发送回默认大小。要选择默认大小,请选择最小尺寸(以处理诸如响应式图像之类的情况)或您网站上最常用的尺寸。

使用数据URI内联图像以最大程度地减少额外的请求。精灵的替代方法是使用数据URI(统一资源标识符)将图像内嵌在HTML本身中。这使图像成为整个页面的一部分,虽然URI编码的图像在字节方面可能更大,但它们可以通过gzip压缩更好地压缩,这有助于最大程度地减少传输额外数据的影响。

如果使用URI,请确保

• 在将图像编码为URI有效负载之前,将其大小调整为适当的大小。

• Gzip响应(以利用压缩)。

• 请注意,URI编码的图像是页面CSS的一部分。因此,单个图像的缓存更加困难,因此,如果有充分的理由在本地缓存图像(例如,在多个页面上频繁重复使用),请不要使用此方法。

利用localStorage和缓存

由于移动网络可能很慢,因此HTML,CSS和图像可以存储在localStorage中,以加快移动体验。(有一个关于Bing使用localStorage改进移动设备以将HTML文档的大小从大约200 KB减小到大约30 KB的绝佳案例研究11

从本地存储中提取数据可能会对性能产生负面影响,13但是这种影响通常远小于跨网络产生的延迟。除了localStorage之外,某些应用程序还在使用HTML5中的其他功能6例如appCache1 以提高性能和启动时间。

可以在服务器上利用的一种优化是了解设备上的内容。通过将CSS和JavaScript直接嵌入到单个Web请求中,然后在客户端上存储对这些文件的引用,可以跟踪已下载并驻留在缓存中的内容。然后,下次客户端向服务器发出请求时,它可以通过cookie将对其缓存文件的引用传递给服务器。然后,服务器只需要通过网络发送新文件,这可以防止客户端再次下载这些资产。

这种利用本地缓存的技巧可以节省大量时间。(有关如何直接嵌入然后引用这些文件以及有关该主题的更多阅读资源的更多详细信息,请参见Mark Pilgrim的Dive into HTML58

预取和缓存数据

提高感知性能的一种好方法是预取将在整个移动体验中使用的数据,以便可以直接在设备上加载数据而无需其他请求——例如,分页结果、热门查询和用户数据。考虑这些用例并将它们纳入您的API设计中,将使您能够创建旨在在用户与之交互之前预取和缓存数据的API,从而提高感知响应速度。

如果您的客户端是应用程序,则对于更新之间不太可能更改的数据(例如类别或主导航),请考虑将数据随应用程序一起发布,这样它就永远不需要跨网络传输。

如果您想变得复杂,请将数据随应用程序一起发布,但也创建一个版本控制和过期方案;这样,应用程序可以在后台ping服务器,并且仅当设备上的版本过时时才更新数据。

理想情况下,您希望在客户端需要时传输数据,并在有利时预加载数据(即,当网络或其他所需资源未在使用时)。因此,如果最终用户不查看图像或内容,请不要发送它(这对于响应式网站尤为重要,因为有些网站只是“隐藏”元素)。设计您的API使其具有灵活性,并支持向客户端发送较小的有效负载。

预取图像的一个很好的用例是图像结果库,例如电子商务网站上的产品列表。在这些情况下,值得下载上一个和下一个图像,以加快交互和浏览速度。但是,请注意不要过度,并且不要预取太远;否则,您最终可能会请求用户可能看不到的数据。

使用非阻塞I/O

通过客户端优化,开发人员知道要提防阻塞JavaScript执行,14这可能会对性能感知产生重大影响。对于API而言,这一点更为重要。如果存在较长的API调用,例如可能依赖于第三方并且可能超时的API调用,则将此调用实现为非阻塞(甚至长时间等待)非常重要,而是选择轮询或触发模型

轮询API(基于拉取的模型)。客户端发出请求,然后定期检查该请求的结果,如果需要,则定期退避。

触发API(基于推送的模型)。调用发出请求,然后侦听来自服务器的响应。服务器配备了回调,因此它可以触发事件,让调用者知道结果可用。

触发API通常更难实现,因为移动客户端上的连接不可靠。因此,在大多数情况下,轮询是更好的选择。

例如,在Decide.com的移动应用程序中,4 每个产品页面都会显示用户位置附近商店的可用性和价格。由于第三方提供这些结果,因此开发人员不希望本地定价花费与合作伙伴的API向客户端交付结果的时间一样长。为了解决这个问题,Decide.com创建了自己的包装器API,该API允许用户为任何产品查询(一组API支持以各种方式检索产品数据)传递一个标志,该标志将向服务器发出信号,以检索该产品的本地价格。这些价格将存储在服务器的缓存中。然后,如果用户需要该产品的本地定价,则这些价格将更有可能在缓存中,并且不会产生来自第三方合作伙伴的更长等待时间。

此方法很像客户端上的预取,而是改为在服务器端使用API和数据完成。以下是显示其工作原理的示例请求

产品请求

http://example.com/api/products.json?productId=18369542&local=true

响应

{"product": {
   "id": "18369542",
   "title": "立式冷冻柜",
   "brand": "Frigidaire"
}}

价格请求

http://example.com/api/prices.json?productId=18369542

如图1所示,此调用首先在缓存中查找,如果缓存不包含该产品的价格,则它将调用第三方API并等待。

通常,您要确保API快速返回且不阻止等待结果,因为移动客户端的连接数有限。在服务器端某些组件明显比其他组件慢的情况下,可能值得将API分解为单独的调用,以典型响应时间作为因素。这样,客户端可以从初始快速响应调用开始渲染页面,同时等待较慢的调用。目标是最大程度地减少屏幕上的文本渲染时间。

您应避免冗余API,并且在网络状况较慢的情况下,避免过多的API调用非常重要。一个好的经验法则是让渲染页面所需的所有数据都在单个API调用中返回。

避免重定向并最大程度地减少DNS查找

对于请求而言,重定向会损害性能,尤其是在它们跨域并需要DNS查找时。

例如,许多站点使用客户端重定向来处理其移动站点。例如,当移动客户端转到主站点URL(例如,http://katemats.com)时,它会将客户端重定向到移动站点(http://m.katemats.com)。当站点建立在不同的技术堆栈上时,这种情况尤其常见。以下是此工作原理的示例

1. 用户在Google上搜索“yahoo”,然后单击结果中的第一个链接。

2. Google使用其自己的跟踪URL捕获点击,然后将手机重定向到http://www.yahoo.com[重定向]。

3. Google的重定向响应通过蜂窝塔,然后返回到手机。

4. 然后对www.yahoo.com进行DNS查找。

5. 从DNS查找获得的IP通过蜂窝塔发送回手机。

6. 当手机访问http://www.yahoo.com时,它被识别为移动客户端,并被重定向到http://m.yahoo.com[重定向]。

7. 然后,手机必须对该子域(http://m.yahoo.com)执行另一个DNS查找。

8. 从DNS查找获得的IP通过蜂窝塔发送回手机。

9. 生成的HTML和资产最终通过蜂窝塔发送回手机。

10. 移动站点页面上的一些图像通过CDN(内容交付网络)提供,引用了另一个域http://l2.yimg.com。

11. 然后,手机必须对该子域http://l2.yimg.com执行另一个DNS查找。

12. 从DNS查找获得的IP通过蜂窝塔发送回手机。

13. 图像被渲染,完成页面。

从此示例中可以明显看出,这些请求涉及大量开销。可以通过在服务器端使用重定向(通过服务器路由并在客户端上将DNS查找和重定向保持在最低限度)或使用响应式技术来避免这些开销。2如果DNS查找不可避免,请尝试对已知域使用DNS预取以节省时间。

使用HTTP流水线和SPDY

另一种有用的技术是HTTP流水线,它允许组合多个请求。但是,如果要实现优化转换层,我将选择SPDY,它本质上优化了HTTP请求,使其效率更高。SPDY在Amazon的Kindle浏览器、Twitter和Google等地方越来越受欢迎。

发送“正确”的数据

根据客户端的不同,体验可能需要不同的文件、CSS、JavaScript甚至不同数量的结果。以支持不同排列和结果和文件版本的方式创建API,为创建出色的客户端体验提供了最大的灵活性。

使用limit和offset获取结果

与常规API一样,使用以下项获取结果limitoffset允许客户端请求对客户端用例有意义的数据范围(因此,移动设备的结果更少)。limitoffset符号比(例如,start和next)更常见,在大多数数据库中都得到很好的理解,因此易于构建在

/products?limit=25&offset=75

您应选择适合最低或最高公分母的默认值,具体取决于哪些客户端对您的业务更重要:如果移动客户端是您的最大用户,则选择较小的值;如果用户可能在其台式机上,例如B2B网站或服务,则选择较大的值。

支持部分响应和部分更新

设计API以允许客户端仅请求他们需要的信息。这意味着API应支持一组字段,而不是每次都返回完整的资源表示形式。通过避免客户端收集和解析不必要的数据,您可以简化请求并提高性能。

部分更新允许客户端对他们写入API的数据执行相同的操作(从而避免了需要指定资源分类中的所有元素)。

Google通过在逗号分隔列表中添加可选字段来支持部分响应,如下所示

http://www.google.com/calendar/feeds/[email protected]/private/full?fields=entry(title,gd:when)

对于每个调用,指定entry表示调用者仅请求一组部分字段。

避免或最大程度地减少Cookie

每次客户端向域发送请求时,它都会包含来自该域的所有cookie——即使是重复的条目或无关的值。这意味着保持cookie小是降低有效负载和提高性能的另一种方法。除非必要,否则不要使用或要求cookie。从无cookie域提供不需要权限的静态内容,例如来自静态域或CDN的图像。(Google开发者网站提供了一些关于cookie和性能的最佳实践。5

为API建立设备配置文件

考虑到台式机、平板电脑和移动电话上许多不同的屏幕尺寸和分辨率,建立您计划支持的一组配置文件很有帮助。对于每个配置文件,您可以交付不同的图像、数据和文件,以使其适合每种设备;您可以使用客户端上的媒体查询来执行此操作。10

如果每个配置文件都针对设备量身定制,那么它就有机会提供更好的用户体验。但是,每个配置文件支持的每个不同功能和场景都使其更难以维护(因为设备在不断变化和发展)。因此,最明智的方法是仅支持您的特定业务绝对需要的配置文件数量。(mobiForge网站提供了有关在不同设备上创建出色体验的一些权衡和选项的更多信息。9

对于大多数应用程序,三个配置文件就足够了

• 移动电话——较小的图像,启用触摸功能,低带宽。

• 平板电脑——为较低带宽设计,启用触摸功能,每个请求的数据更多的大图像。

• 台式机——为台式机浏览器或具有高分辨率和Wi-Fi的平板电脑设计的大型高分辨率图像。

选择正确的配置文件可以由客户端处理,这意味着在服务器端,API只需要支持此配置即可。您应设计API以将这些配置文件作为输入或参数,并根据发出请求的设备发送不同的信息。根据应用程序的不同,这可能意味着发送较小的图像、更少的结果或内联CSS和JavaScript。

例如,如果您的API之一向客户端返回搜索结果,则每个配置文件的行为可能会有所不同,如下所示

/products?limit=25&offset=0

这将使用默认配置文件(台式机)并提供标准页面,为每个图像发出请求,以便可以从缓存中加载后续产品视图。

/products?profile=mobile&limit=10&offset=0

这将返回10个产品结果,并使用编码为URI的低分辨率图像以及相同的HTTP请求。

/products?profile=tablet&limit=20&offset=0

这将返回20个产品结果,并使用编码为URI的较大尺寸的低分辨率图像以及相同的HTTP请求。

您甚至可以为功能手机等设备创建特殊的配置文件。与智能手机不同,功能手机只能按页面缓存文件,因此最好为这些客户端的每个请求发送CSS和JavaScript。使用配置文件是在服务器端支持该功能的简便方法。

当每个配置文件的服务器响应差异很大时,应使用配置文件而不是部分响应——例如,如果响应在一个案例中具有内联URI图像和紧凑布局,而在另一种情况下则没有。当然,可以使用“部分响应”来指定配置文件,尽管通常部分响应用于指定标准架构的一部分(或部分)(例如,较大分类的子集),而不是整套不同的数据、格式等。

结论

有很多方法可以使Web更快,包括移动设备。本文旨在为API开发人员提供有用的参考,这些开发人员正在设计支持移动客户端的后端系统——并为此最终实现和保持积极的移动应用程序用户体验。

参考文献

1. Bidelman, E. 2011. A beginner's guide to using the application cache. HTML5 Rocks; http://www.html5rocks.com/en/tutorials/appcache/beginner/.

2. Breheny, R., Jung, E., Zürrer, M. 2012. Responsive design—harnessing the power of media queries. Google Webmaster Central Blog; http://googlewebmastercentral.blogspot.com/2012/04/responsive-design-harnessing-power-of.html.

3. Coyier, C. 2012. Which responsive images solution should you use? CS-tricks; https://css-tricks.cn/which-responsive-images-solution-should-you-use/.

4. Decide.com. https://www.decide.com/.

5. Google Developers. 2012. Make the Web faster; https://developers.google.com/speed/docs/best-practices/request.

6. Graham, A. 2010. Google APIs + HTML5 = a new era of mobile apps. Google code; http://googlecode.blogspot.com/2010/04/google-apis-html5-new-era-of-mobile.html.

7. Grigsby, J. 2012. How Apple.com will serve retina images to new iPads. Cloud Four Blog; http://blog.cloudfour.com/how-apple-com-will-serve-retina-images-to-new-ipads/.

8. Pilgrim, M. 2011. The past, present and future of local storage for Web applications. In Dive into HTML5; http://diveintohtml5.info/storage.html.

9. Rieger, B. 2009. Effective design for multiple screen sizes. mobiForge; http://mobiforge.com/designing/story/effective-design-multiple-screen-sizes.

10. Smus, B. 2012. A nonresponsive approach to building cross-device Webapps; http://www.html5rocks.com/en/mobile/cross-device/.

11. Souders, S. 2011. Storager case study: Bing, Google; http://www.stevesouders.com/blog/2011/03/28/storager-case-study-bing-google/.

12. W3C Responsive Images Community Group; http://www.w3.org/community/respimg/.

13. Zakas, N. C. 2011. localStorage read performance. Performance Calendar; http://calendar.perfplanet.com/2011/localstorage-read-performance/.

14. Zakas, N. C. 2010. What is a nonblocking script? NCZonline; http://www.nczonline.net/blog/2010/08/10/what-is-a-non-blocking-script/.

喜欢它,讨厌它?请告诉我们

[email protected]

Kate Matsudaira 是一位经验丰富的软件工程师,在过去的七年中,她作为架构师或首席技术官沉浸在创业世界中。在此之前,她曾在亚马逊和微软担任软件工程师和技术主管/经理。她对移动设备充满热情,并且在构建大型分布式Web系统、大数据、云计算和工程领导力方面拥有丰富的经验。她在 http://katemats.com 上维护一个博客。

© 2013 1542-7730/13/0100 $10.00

acmqueue

最初发表于Queue vol. 11, no. 1
数字图书馆 中评论本文





更多相关文章

Shylaja Nukala, Vivek Rau - 为什么SRE文档很重要
SRE(站点可靠性工程)是一种工作职能、一种思维方式以及一套工程方法,用于使Web产品和服务可靠地运行。SRE在软件开发和系统工程的交叉点上运作,以解决运营问题并设计解决方案,以可扩展、可靠且高效地设计、构建和运行大规模分布式系统。成熟的SRE团队可能具有与许多SRE功能相关的明确定义的文档主体。


Taylor Savage - 组件化Web
在当今的软件工程中,没有比Web开发更艰巨的任务了。Web应用程序的典型规范可能如下:该应用程序必须跨各种浏览器工作。它必须以60 fps的速度运行动画。它必须立即响应触摸。它必须符合一组特定的设计原则和规范。它必须在几乎所有可以想象的屏幕尺寸上工作,从电视和30英寸显示器到移动电话和手表表面。它必须在长期内得到良好的工程设计和可维护性。


Arie van Deursen - 超越页面对象:使用状态对象测试Web应用程序
Web应用程序的端到端测试通常涉及通过Selenium WebDriver之类的框架与Web页面进行棘手的交互。隐藏此类Web页面复杂性的推荐方法是使用页面对象,但是首先要回答一些问题:在测试Web应用程序时,应创建哪些页面对象?您应该在页面对象中包含哪些操作?给定您的页面对象,您应该指定哪些测试场景?


Rich Harris - 消除准入障碍
一场战争正在Web开发世界中进行。一方面是工具制造者和工具用户的先锋,他们以破坏糟糕的旧观念(在这种环境中,“旧”是指在Hacker News上首次亮相超过一个月的任何事物)和关于转译器等的热烈辩论而蓬勃发展。





© 保留所有权利。

© . All rights reserved.