2017 年 2 月

第 32 卷,第 2 期

移动 DevOps - 通过主动监控应用和服务来推动开发

作者 Kraig Brockschmidt | 2017 年 2 月

编写移动应用的理想环境需要满足两个条件,一是可以确切知道客户脑海中立即浮现的需求,二是为了满足这些需求而编写的代码可以立即传递给这些客户。简单来说,就是客户需求、开发和传递之间没有任何间隙。

完全不切实际,对吗? 如果你开发软件至少一个小时以上,便会发现现实与这样的幻想相去甚远。然而,每个开发者都可能遇到过这样的无缝循环,因为这正是你为自己编写软件时的切身体会。事实上,这可能就是你一开始被代码深深吸引的地方。你有了灵感,编写了一些代码,然后按下 F5。瞧! 奇妙的事情发生了,你可以随心所欲地控制、打造和探索应用,经常会弄到深夜。

接下来,你可能会开始为其他人编写软件,这就在此过程中引入了各种时间滞后。与按下 F5 相比,将代码更改传递给外部客户所需的时间才是真正得长,因此需要进行源代码管理、持续集成和持续交付来优化此过程,如本系列文章的前几期所述。这一点也适用于沟通(与为自己编写软件相比,在这种情况下,你既是客户,也是开发者),明确客户需求和客户体验十分困难,就像进入遥远星系一样困难!

因此,尽管你已竭尽全力提供应用和服务来满足客户需求,并试图防止向客户传递的内容出现缺陷,但实际上传递内容中仍会出现某些缺陷,而且一些客户需求也仍会得不到满足。这就是监控(图 1 所示发布管道的最后一个阶段)成为首要关注问题的原因所在。这样一来,重点就从传递转移到侦听上,即要注意对客户造成影响的缺陷和问题;同时还转移到学习上,即要在第一时间发现未满足的需求并验证版本创建涉及的所有假设。所侦听和学习的内容会反馈到发布管道的开端,以推动接下来的一系列代码更改。

监控对于了解应如何推动后续发布必不可少
图 1:监控对于了解应如何推动后续发布必不可少

简单来说,监控实现了各版本之间的循环,同时确保不断向客户提供有意义的价值。因此,不断验证性能十分有必要,这就是 DevOps 的全部含义所在。

借助 Microsoft DevOps 移动堆栈,可以使用 HockeyApp 监控移动应用,并使用 Application Insights 监控 Web 应用程序和服务。如我们所见,两种工具均提供多种方式来侦听软件的自然行为。

监控文化

在 Kraig 的上一篇文章 (msdn.com/magazine/mt791797) 中,他谈到可以将持续部署视为一种文化,因为若要实现这一水平的传递优化,就必须坚决执行代码评审和自动测试。这还意味着要坚决执行监控:

  • 由于没有哪一套测试是完美无缺的,一些缺陷仍会出现在生产版中,因此团队必须主动监控故障报告、遥测、负载失衡、评分、评价和客户直接反馈。这包括监控应用在每个受支持的平台上的性能,以及监控后端服务的运行状况。
  • 团队必须坚决执行问题会审和设置优先级,并将它们馈送给开发积压工作 (backlog),以便快速修正后续版本。

此外,监控对测试和过渡环境的重要性如同对生产环境一样。为了监控应用和收集遥测而编写的代码与其他任何代码一样容易出现 bug,必须在发布之前花时间进行调试和故障排除。同时,在测试和过渡环境中进行监控,可以让团队有机会测试故障处理和反馈流程。

例如,从应用和服务收集的自定义遥测通常用于判断客户使用情况以及是否达到特定的业务目标(请参阅 Kraig 在 bit.ly/2dZH5Vx 上的博文“Instrumenting Your App for Telemetry and Analytics”(检测应用以获取遥测和分析数据),以及他在 bit.ly/2d1p6fC 上的 Build 2014 演示文稿“Understanding Customer Patterns”(了解客户模式))。然而,遥测代码中的缺陷并不会影响客户。相反,遥测缺陷可以很容易地就使你收集的数据无效。优质数据代表一切,所以必须在测试和过渡环境中充分收集遥测数据,同时区分遥测数据与生产数据。当然,还必须仔细检查收集和表方面是否存在任何错误。

测试和过渡环境还有助于测试应用中的反馈机制。使用 HockeyApp 向发布前测试人员进行分发时,应建议测试人员通过应用本身提供反馈,因为这正是生产客户将采用的反馈方式。

然而,监控测试和过渡环境最重要的目的在于响应故障、客户反馈以及遥测揭示的问题。简而言之,监控既是侦听又是响应,因为响应可以证明你确实在侦听。响应还意味着确认收到反馈并将立即采取措施,方法为建立常规流程,将相应的优先处理问题馈送给积压工作 (backlog),以便开发者可以进行处理。

建立这样的流程不能留到事后才考虑,而应在首次发布前就开始着手,与安装生成服务器和发布管道同时。这样一来,可以在为了首次发布而进行测试和过渡环境准备时实施和提升此流程,因为一旦开始发布,就必须持续监控。

强大的监控流程甚至可以其他测试的形式在一定程度上弥补最初的劣势。创建非常出色的自动测试不仅需要时间,还需要一定的专业知识,鉴于发布计划的约束或合格候选发布的可用性,这极具挑战性。另一方面,监控不需要拥有太多的特定领域技能,建立团队来监控活动通常比编写一整套测试更为快速简单。通常情况下,早期采用者也很可能会容许缺陷出现,前提是他们相信你非常仔细地侦听并修复缺陷的话。借助良好的监控,可以向客户快速传递应用和服务,并开始收集有价值的遥测和反馈,未必要等到测试流程完成。

使用 HockeyApp 进行监控

移动应用(以及桌面应用)的特殊挑战是,它们安装在数百万设备和设备配置上,这些超出了你的控制范围。与 Web 服务相比,无法直接登录用户的移动设备并分析日志文件或附加调试程序。因此,需要使用另一个系统从这些设备检索故障和使用情况信息(当然会尊重隐私),然后将数据上载到中心服务以供分析。HockeyApp 便派上用场。

除了可以为发布前分发提供有价值的服务(如上次所述)外,HockeyApp 还有助于不断监控应用在整个生命周期内的每个版本。可以从首个原型入手,收集会话、事件、故障和反馈,然后继续从 beta 版本、候选发布以及最后的实际应用收集信息。持续监控可以提供流程每一步的宝贵数据,并能从早期阶段开始监控,方便你捕捉其他预发布测试流程未捕捉到的缺陷。因此,只要缺陷对实际客户造成影响,你就会注意到这些缺陷,这有助于确定修补程序在近期应用更新程序中的优先级。

从正在运行的应用获取信息表示使用 HockeySDK 检测应用。本机 SDK 适用于 Android、iOS、Windows和 macOS;其他 SDK 支持 Xamarin、Cordova、React Native 和 Unity 等跨平台技术。

我们将以 Xamarin 应用为例。首先,需要从 HockeyApp 获取与每个目标平台对应的唯一应用 ID。先在 hockeyapp.net 上创建免费帐户,然后单击主仪表板上的“新应用”。此时,你会收到上载应用包的邀请。也可以单击“改为手动创建应用”,直接输入详细信息。无论采用上述哪种方式,都会看到图 2 所示的页面(有关 MyDriving iOS 应用,请访问 aka.ms/iotsampleapp),左上角显示有应用 ID。

在 HockeyApp 门户上查找应用 ID
图 2:在 HockeyApp 门户上查找应用 ID

对于 Xamarin,在 Xamarin 解决方案中的每个项目内安装 HockeySDK.Xamarin NuGet 包,使用 HockeySDK.UWP 的 Windows 除外。然后,在启动过程中使用从门户获取的应用 ID 初始化 SDK。对于 iOS,将以下代码添加到 FinishedLaunching 方法 (AppDelegate.cs) 中,并用从门户获取的值替换 APP_ID_IOS:

using HockeyApp;
// ...
var manager = BITHockeyManager.SharedHockeyManager;
manager.Configure("APP_ID_IOS");
manager.StartManager();
manager.Authenticator.AuthenticateInstallation();

此代码能够为预发布内部版本(通过 HockeyApp 分发的版本)自动启用故障报告、用户和会话跟踪以及应用内更新功能。若要禁用这些功能,请在调用 StartManager 前设置 BITHockeyManager 类的属性。例如,以下代码可禁用应用内更新功能:

var manager = BITHockeyManager.SharedHockeyManager;
manager.Configure("APP_ID_IOS");
manager.DisableUpdateManager = true;
manager.StartManager();
manager.Authenticator.AuthenticateInstallation();

在 Android 中,再次使用应用 ID 将以下代码添加到 OnCreate (MainActivity.cs) 中,然后添加对 MetricsManager.Register 的调用,因为会话跟踪无法自动完成:

using HockeyApp.Android;
using HockeyApp.Android.Metrics;
CrashManager.Register(this, "APP_ID_ANDROID");
MetricsManager.Register(Application, "APP_ID_ANDROID");
UpdateManager.Register(this, "APP_ID_ANDROID");

对于使用 HockeySDK.UWP NuGet 包的 Windows,只需在应用构造函数中添加一行代码:

HockeyClient.Current.Configure("APP_ID_WINDOWS");

有关 HockeyApp API 的完整文档,请访问 support.hockeyapp.net/kb。对于 Xamarin.iOS 和 Xamarin.Android,请参阅 bit.ly/2elBqGp 中的“How to Integrate HockeyApp with Xamarin”(如何集成 HockeyApp 和 Xamarin)。对于 Windows,请参阅 bit.ly/2eiduXf 中的“HockeyApp for Applications on Windows”(适用于 Windows 上应用程序的 HockeyApp)。此外,还可以随时参考 MyDriving 应用代码。

初始化 SDK 后,我们将尝试在 iOS 上启用故障报告功能。最佳办法是在按钮处理程序中引发异常或使用 HockeySDK 提供的测试故障。在 iOS 中,示例代码如下:

crashButton.TouchUpInside += delegate {   
  var manager = BITHockeyManager.SharedHockeyManager;
  manager.CrashManager.GenerateTestCrash();
};

添加此代码(以及在 UI 中添加按钮)后,生成发布版本并将其部署到测试设备,在不进行调试的情况下运行应用,点击按钮触发故障,然后重新启动应用。应该会看到一个提示你提交故障报告的对话框。几秒钟后,HockeyApp 门户上便会显示相应的故障。门户上的故障报告只显示内存地址,因为发布内部版本不包含调试符号。但不要启用符号,因为这样一来,黑客就可以轻松反汇编你的应用。相反,Xamarin 项目的 bin 文件夹中包含 .dSYM (iOS) 和 .pdb(Windows 或 Android)文件,这些文件是调试符号的独立捆绑包。可以将这些符号文件上载到 HockeyApp(称为服务器端“符号化”),这样故障报告就可以显示完整的类、方法、文件名和行号了,如图 3 所示。

显示故障报告的完整符号信息的 HockeyApp 门户
图 3:显示故障报告的完整符号信息的 HockeyApp 门户

故障概览页显示故障发生频率、受影响的用户数,以及这些用户使用的操作系统版本和设备模型。可以将此类数据与应用概览页上显示的唯一用户数和会话数进行比较。尤其要注意无故障用户百分比指标,它可以准确衡量应用质量。

除了这些标准指标外,还可以添加自定义事件来深入了解客户的应用使用情况。例如,下面这行代码会记录用户何时开始播放视频:

HockeyApp.MetricsManager.TrackEvent("Video started");

由于将在 HockeyApp 门户中使用“视频开始播放”这一名称搜索事件,因此请务必为每个事件指定一个有意义的名称。此外,还请务必在有助于生成有意义的可操作数据的级别定义事件;再强调一次,有关常规指南,请参阅 bit.ly/2dZH5Vx 上的博文“Instrumenting Your App for Telemetry and Analytics”(检测应用以获取遥测和分析数据)。请注意,虽然 HockeyApp 限制为每个应用最多可以有 300 个唯一事件名称,但为每个事件名称记录的实例数不受限制。

若要将更多信息附加到事件,请使用如下属性:

HockeyApp.MetricsManager.TrackEvent(
  "Video Started",
  new Dictionary<string, string> { { "filename", "RickRoll.mp4" } },
  new Dictionary<string, double> { { "duration", 3.5 } }
);

虽然这些属性和度量在 HockeyApp 中不可见,但可以使用 Microsoft Application Insights 中的分析功能对其进行探索,如 bit.ly/2ekJwjD 所述。

另一种了解用户行为的方式是通过 HockeyApp 反馈功能直接与客户交互,这对于发布前和发布后的客户都很重要。

在发布前阶段发布新的测试版本时,所有测试人员都会收到一封电子邮件,并能直接回复电子邮件来报告问题和提供建议。HockeyApp 会分析这些回复,并在门户上为你进行收集。然后,对于发布前和发布后的客户,都可以使用 HockeyApp SDK 将反馈视图直接集成到应用中。下面展示了如何将 iOS 抖动事件用于此目的:

public override void MotionEnded(UIEventSubtype motion, UIEvent event)
{
  if (motion == UIEventSubtype.MotionShake)
  {
    var manager = BITHockeyManager.SharedHockeyManager;
    manager.FeedbackManager.ShowFeedbackComposeViewWithGeneratedScreenshot();
  }
}

HockeyApp FeedbackManager 自动捕获在有抖动手势时显示的视图的屏幕截图。然后会显示一个视图,以便用户可以在其中批注屏幕截图、附加更多屏幕截图,并提供文本消息来描述问题或建议,如图 4 所示。

在 iOS 上批注屏幕截图
图 4:在 iOS 上批注屏幕截图

提交反馈可方便用户和团队进行对话,只要团队回复,用户便会收到应用内通知,以便可以继续对话。这或许就是 HockeyApp 最宝贵的功能之一,方便你与客户直接联系,其他工具很难实现这一点。这样的直接对话是非常棒的具体详细数据来源,可有助于验证(或否定)你对从遥测事件中获取的更广泛数据的解释。两者都是非常有必要的补充做法。

与故障报告一样,用户反馈应最终在开发积压工作 (backlog) 中新建工作项,这样团队就可以在今后推出的版本中解决问题。这就实现了之前图 1 中显示的 DevOps 循环。实际上,可以将 HockeyApp 直接连接到积压工作 (backlog),方法为依次单击“管理应用”按钮和“Bug 跟踪器”,然后选择积压工作 (backlog) 工具(如 Visual Studio Team Services)。连接后,HockeyApp 会自动为每个故障组和反馈线程新建工作项。

假设你已建立流程定期对新工作项进行会审和设置优先级,可以在源代码中进行相应更改来快速响应故障和客户反馈。如果你还建立了自动发布管道(如本系列文章所述),这些更改会快速生成,并在经过测试后馈送到发布管理,以便可以快速传递给客户。完成发布后,持续监控揭示的故障报告应该会变少,客户满意度应该会提高,与业务息息相关的整体应用性能也应该会提升。

使用 Application Insights 监控 Web 服务

借助 Application Insights 这项服务,可以清楚地了解 Web 应用和服务的性能以及用户将它们用于哪些用途。一旦出现任何问题,此服务都会发出通知,并提供诊断数据和工具。此服务还可以分析和直观呈现与 HockeyApp 相关联的自定义事件的属性,如 bit.ly/2ekJwjD 所述。掌握了所有这些信息后,便可以有把握地规划未来开发工作并设置优先级。 

Application Insights 适用于在云和私有服务器中各种平台(包括 ASP.NET、J2EE 和 Node.js)上运行的 Web 应用。若要检测应用,请从“平台支持”页 (bit.ly/2eydqQU) 入手,选择语言/平台,然后按说明操作。只需执行几步简单的操作,就可以监控 Web 应用代码、网页中的客户端代码和其他任何后端服务,将所有组件(包括 HockeyApp)中的关键数据都汇总到仪表板上。

图 5 中一组典型的 Web 服务性能图表提供以下信息:

  • 版本注释(第一个图表): 蓝点标记了部署新版应用。在图 5 中,请注意服务器响应时间略有增加,这表明需要进行一些诊断来确定原因。
  • 向 Web 服务发出 HTTP 请求的速率(还是第一个图表): 细段将用户请求、测试请求和搜索引擎自动程序请求区分开来。单击后到达指定页面,按 URL、客户端位置和其他维度进行细分。
  • 所有请求的平均响应时间(第二个图表): 异常峰值似乎与一连串异常相关联。
  • 未捕获的异常和失败请求(第三个图表): 显示响应代码为 400 或更高的请求;单击后到达指定页面,查看各个故障和堆栈跟踪。
  • 无法调用依赖项(第四个图表): 显示通过 REST API 访问的数据库或外部组件。峰值表明,一些应用故障是由另一个组件中的故障造成的。
  • 可用性(第五个图表): Web 测试发送世界各地的综合请求来测试全球可用性。第一个间隙似乎与异常突然增多相关联,第二个间隙可能表明出现网络问题或需要执行服务器维护。

一组典型的 Web 服务 Application Insights 性能图表
图 5:一组典型的 Web 服务 Application Insights 性能图表

还可以生成图表了解其他各种指标,如用户数、会话数和网页浏览量;页面加载时间、浏览器异常和 AJAX 调用;CPU 的系统性能计数器、内存和其他资源使用情况;以及你自己编码的自定义指标。

你当然不想为了不遗漏故障而死盯图表,所以 Application Insights 可以发送详细的电子邮件通知,提醒你注意异常高的故障率、可用性下降或其他任何指标值,包括你自己编码的自定义指标。一些警报会自动配置,如智能故障检测。此警报会学习应用失败请求的正常模式,如果故障率突破常规,便会触发警报。无论如何,电子邮件都包含指向相应报告的链接,如图 6 所示。在报告中,可以单击各个指标图表后到达指定页面,并查看最近发生的事件,从而诊断问题。还可以在请求正在处理的同时,从请求日志进行导航,详细了解任何依赖项调用、异常或已发生的自定义遥测事件。

单击诊断报告后到达指定页面查看详细信息
图 6:单击诊断报告后到达指定页面查看详细信息

你希望在发现问题后立即将其馈送给开发积压工作 (backlog)。若为服务设置了自动发布管道,可以立即进行必要的代码更改,然后快速测试这些更改并将其部署到实际服务器中。

为了有助于此,Application Insights 可帮助你直接在详细视图中轻松创建 Visual Studio Team Services 工作项。只需查找“新建工作项 +”控件即可。有关配置此连接的说明,请访问 bit.ly/2eneoAD

还可以使用开发者分析工具插件(bit.ly/2enBwlg,此插件还适用于 Eclipse)直接在 Visual Studio 中使用 Application Insights(和 HockeyApp)提供的诊断数据。例如,在处理 Web 请求过程中调用的所有方法都在代码编辑器中进行了批注,标出了请求数和异常数。还有可检测实际 Web 应用的服务器端的选项,为你提供大部分遥测,而无需你访问代码。

借助记录功能,Application Insights 从最常用的记录框架(如 Log4J、Nlog、Log4Net 和 System.Diagnostics.Trace)捕获日志跟踪。这些事件可以与请求和其他遥测相关联,当然,无论是在后端代码中还是在客户端代码中,都可以添加提供诊断或使用情况信息的自定义事件和指标。例如,可以在服务中执行下列调用来定期监控内部缓冲区的长度,其中遥测为 Application Insights 对象:

telemetry.TrackMetric("Queue", queue.Length);

在 Application Insights 门户中,可以创建图标来显示此指标,如图 7 所示。

Application Insights 中的自定义指标图表
图 7:Application Insights 中的自定义指标图表

其他调用可用于统计业务或用户事件数,如赢得游戏或单击特定按钮。可以按你发送的其他任何详细信息来筛选和细分事件和指标。借助这些事件,可以深入了解用户将你的应用用于哪些用途以及应用的性能情况。

除了 Application Insights 提供的常规图表和搜索工具还想使用其他的,可以使用 Analytics,这是一个功能强大的查询语言,可适用于所有存储的遥测。图 8 中显示的查询可确定网站在一天内的使用次数,以及哪些国家/地区的用户数最多。

Application Insights 中的 Analytics 查询
图 8:Application Insights 中的 Analytics 查询

总结

我们由衷希望你对本系列文章,以及 Justin Raczak 关于 Xamarin Test Cloud 的文章(msdn.com/magazine/mt790199,介绍了移动应用和相关后端服务的 Microsoft DevOps 堆栈)感到满意。回顾图 1,我们介绍了发布管道的所有阶段,包括源存储库、生成、发布管理、分发和监控。同时,我们只做了肤浅的研究: 随着你不断提高生成和发布流程的复杂程度,还有更多有待探索,尤其是在考虑添加多级自动化测试时。图 1 中再次介绍了可以在发布管道中执行的不同类型测试,下面是一些入门链接:

  • 单元测试是测试各个代码单元(如方法)的过程。请参阅 bit.ly/2ekXt2v 上的“Getting Started with Unit Testing for Cross-Platform Mobile Apps”(跨平台移动应用的单元测试入门),这是 Kraig Brockschmidt 与 Jonathan Carter 一起教授的 Microsoft Virtual Academy 课程。
  • 集成测试也使用单元测试工具,但侧重于代码单元之间的交互(而不是单个单元)。集成测试经常使用实际服务器或数据库中的模拟数据,或只读的实际数据。强烈建议使用 Xamarin Test Cloud 等服务在实际设备上运行集成测试。
  • 对于 UI 测试,请参阅之前提到的 Justin 有关 Xamarin Test Cloud 的文章;对于 Apache Cordova 应用,请参阅 bit.ly/2dqTOkc 上有关 Visual Studio Tools for Apache Cordova 文档中的“UI Testing with Appium”(使用 Appium 进行 UI 测试)。
  • 安全或渗透测试意味着通过各种矢量在应用和服务上模拟攻击,这不能想当然。我们建议从 James Whittaker 的书籍“How to Break Software Security”(如何攻破软件)(amzn.to/2eCbpW4) 入手。这还是一个你可能会考虑聘请专业顾问的领域。
  • 使用 Visual Studio 本身提供的许多分析工具(有关信息,请参阅 bit.ly/2en62c3),以及 Xamarin Profiler (xamarin.com/profiler) 等专业工具可以获取性能诊断数据。
  • 负载或压力测试在各种条件下运行后端服务,以评估这些服务满足各种需求的情况。还可以评估服务根据需求进行缩放的情况,以便能够有效管理托管成本。有关详细信息,请查看 bit.ly/2ey6Dqe 上有关 Visual Studio Team Services 文档中的“Getting Started with Performance Testing”(性能测试入门)。
  • 本地化测试可验证应用的不同区域设置性能,这通常意味着直接执行 UI 测试来确保本地化资源和格式变体均正确无误。在世界各地聘请发布前测试人员也非常有效,因为他们可以指出技术和文化方面的问题。

至此,我们再次由衷希望你对本系列文章感到满意,并祝愿你的移动应用开发工作一切顺利!


Kraig Brockschmidt是 Microsoft 的高级内容开发者,主要负责移动应用的 DevOps。他是 Microsoft Press 出版的《Programming Windows Store Apps with HTML, CSS and JavaScript》(两个版本)和 kraigbrockschmidt.com 上的博客的作者。

Thomas Dohmke 是 HockeyApp 的联合创始人。Microsoft 于 2014 年年底收购 HockeyApp。Thomas 是 Microsoft 的组计划经理,负责推行产品愿景和管理 HockeyApp 和 Xamarin Test Cloud 计划经理团队。可以通过电子邮件地址 thdohmke@microsoft.com 或 Twitter (@ashtom) 与联系他。

Alan Cameron Wills 是 Microsoft 的高级内容开发者,负责编写 Application Insights。他在威尔士卡迪根工作和生活。

衷心感谢以下 Microsoft 技术专家对本文的审阅: Simina Pasat