使用 Azure) 生成 Real-World 云应用的监视和遥测 (

作者 :Rick Anderson,TomDykstra

下载修复项目下载电子书

使用 Azure 构建真实世界云应用 电子书基于 Scott Guthrie 开发的演示文稿。 本文介绍了 13 种模式和做法,可帮助你成功开发适用于云的 Web 应用。 有关电子书的信息,请参阅 第一章

许多人依靠客户来告知他们的应用程序何时关闭。 这在任何地方都不是最佳做法,尤其是在云中。 不能保证快速通知,当你收到通知时,你通常会得到关于所发生情况的最少或误导性数据。 借助良好的遥测和日志记录系统,你可以了解应用发生的情况,当出现问题时,你可以立即发现并获取有用的故障排除信息。

购买或租用遥测解决方案

注意

本文是在 Application Insights 发布之前编写的。 Application Insights 是 Azure 上遥测解决方案的首选方法。 有关详细信息,请参阅 为 ASP.NET 网站设置 Application Insights

云环境有一个伟大的事情是,购买或租用的方式真的很容易获得胜利。 遥测就是一个示例。 无需付出很多努力,就可以非常经济高效地启动并运行一个非常好的遥测系统。 有一些优秀的合作伙伴与 Azure 集成,其中一些合作伙伴具有免费层,因此,你可以一无所获地获取基本遥测数据。 以下是目前在 Azure 上可用的一些功能:

Microsoft System Center 还包括监视功能。

我们将快速演练如何设置 New Relic,以演示如何轻松使用遥测系统。

在 Azure 管理门户中,注册该服务。 单击“ 新建”,然后单击“ 应用商店”。 此时将显示 “选择加载项 ”对话框。 向下滚动并单击“ 新建 Relic”。

选择加载项

单击右箭头并选择所需的服务层级。 在本演示中,我们将使用免费层。

个性化加载项

单击向右箭头,确认“购买”,New Relic 现在在门户中显示为加载项。

查看购买

管理门户中的 New Relic 加载项

单击“ 连接信息”,并复制许可证密钥。

连接信息

转到门户中 Web 应用的“ 配置 ”选项卡,将 “性能监视 ”设置为 “加载项”,并将 “选择加载项 ”下拉列表设置为 “新建 Relic”。 然后单击“保存” 。

“配置”选项卡中的“新建 Relic”

在 Visual Studio 中,在应用中安装 New Relic NuGet 包。

“配置”选项卡中的开发人员分析

将应用部署到 Azure 并开始使用它。 创建一些 Fix It 任务,为 New Relic 提供一些要监视的活动。

然后返回到门户的“加载项”选项卡中的“新建 Relic”页,然后单击“管理”。 门户会将你发送到 New Relic 管理门户,使用单一登录进行身份验证,因此无需再次输入凭据。 “概述”页提供了各种性能统计信息。 (单击图像可查看概述页完整大小。)

“新建 Relic 监视”选项卡

下面只是可以看到的一些统计信息:

  • 一天中不同时间的平均响应时间。

    响应时间

  • 吞吐量速率 () 一天中的不同时间每分钟请求数。

    吞吐量

  • 处理不同 HTTP 请求所用的服务器 CPU 时间。

    Web 事务时间

  • 在应用程序代码的不同部分花费的 CPU 时间:

    跟踪详细信息

  • 历史性能统计信息。

    历史性能

  • 对外部服务(如 Blob 服务)的调用,以及有关服务的可靠性和响应速度的统计信息。

    外部服务

    外部服务2

    外部服务

  • 有关世界何处或美国 Web 应用流量来自何处的信息。

    地理位置

还可以设置报表和事件。 例如,你可以说,每当开始看到错误时,都会发送电子邮件,提醒支持人员注意该问题。

报表

New Relic 只是遥测系统的一个示例:也可以从其他服务获取所有这些内容。 云的美妙在于,无需编写任何代码,只需花费极少或无需花费任何费用,你就能突然获得有关应用程序使用方式以及客户实际体验的更多信息。

日志以获取见解

遥测包是很好的第一步,但你仍必须检测自己的代码。 遥测服务会在出现问题时告知你,并告知客户所经历的情况,但可能不会让你深入了解代码中发生的情况。

你不希望远程连接到生产服务器来查看应用正在执行的操作。 当你拥有一台服务器时,这可能可行,但当你已扩展到数百台服务器,而你不知道需要远程访问哪些服务器时呢? 日志记录应提供足够的信息,无需远程连接到生产服务器来分析和调试问题。 应记录足够的信息,以便仅通过日志隔离问题。

登录生产

许多人仅在出现问题并想要调试时才在生产环境中启用跟踪。 这可能会导致你意识到问题的时间和获取有关该问题的有用故障排除信息之间的大量延迟。 获取的信息对于间歇性错误可能无济于事。

在存储成本低的云环境中,我们建议始终在生产环境中保留日志记录。 这样,当错误发生时,你已经记录了这些错误,并且你拥有的历史数据可以帮助你分析随时间推移或在不同时间定期发生的问题。 可以自动执行清除过程来删除旧日志,但你可能会发现设置此类进程比保留日志更昂贵。

与故障排除时间和金钱相比,日志记录的额外费用是微不足道的,在出现问题时,可以通过提供所需的所有信息来节省成本。 然后,当有人告诉你,他们昨晚8:00左右有一个随机错误,但他们不记得错误,你可以很容易地找出问题是什么。

每月不到 4 美元,可以保留 50 GB 的日志,只要记住一件事,日志记录的性能影响就微不足道 - 为了避免性能瓶颈,请确保日志记录库是异步的。

区分通知日志和需要操作的日志

日志旨在通知 (我希望你了解一些) 或 ACT (我希望你) 做一些事情。 请注意,仅针对真正需要人员或自动化进程采取措施的问题编写 ACT 日志。 过多的 ACT 日志会产生干扰,需要太多的工作来筛选所有内容才能找到真正的问题。 如果 ACT 日志自动触发某些操作(例如向支持人员发送电子邮件),请避免让成千上万的此类操作由单个问题触发。

在 .NET System.Diagnostics 跟踪中,可以为日志分配“错误”、“警告”、“信息”和“调试/详细”级别。 可以通过保留 ACT 日志的错误级别并使用较低级别的 INFORM 日志来区分 ACT 日志和 INFORM 日志。

日志记录级别

在运行时配置日志记录级别

尽管在生产环境中始终启用日志记录是值得的,但另一个最佳做法是实现日志记录框架,使你可以在运行时调整正在记录的详细信息级别,而无需重新部署或重启应用程序。 例如,使用 中的 System.Diagnostics 跟踪工具时,可以创建错误、警告、信息和调试/详细日志。 建议始终在生产环境中记录错误、警告和信息日志,并且希望能够动态添加调试/详细日志记录,以便逐个进行故障排除。

Azure 应用服务 中的Web 应用内置支持将日志写入System.Diagnostics文件系统、表存储或 Blob 存储。 可以为每个存储目标选择不同的日志记录级别,并且可以在不重启应用程序的情况下动态更改日志记录级别。 通过 Blob 存储支持,可以更轻松地在应用程序日志上运行 HDInsight 分析作业,因为 HDInsight 知道如何直接使用 Blob 存储。

记录异常

不要只是 例外。日志记录代码中的 ToString () 。 这遗漏了上下文信息。 如果出现 SQL 错误,则会遗漏 SQL 错误号。 对于所有异常,包括上下文信息、异常本身和内部异常,以确保提供故障排除所需的一切。 例如,上下文信息可能包括服务器名称、事务标识符和用户名 (但不包括密码或任何机密!) 。

如果依赖每个开发人员执行异常日志记录的正确操作,则其中一些开发人员不会这样做。 若要确保每次都以正确的方式完成,请直接在记录器接口中生成异常处理:将异常对象本身传递给记录器类,并在记录器类中正确记录异常数据。

记录对服务的调用

强烈建议在每次应用调用服务时写入日志,无论是数据库、REST API 还是任何外部服务。 日志中不仅包括成功或失败的指示,还包括每个请求花费的时间。 在云环境中,你经常会看到与速度缓慢而不是完全中断相关的问题。 通常需要 10 毫秒的内容可能会突然开始花费一秒钟。 当有人告诉你你的应用速度缓慢时,你希望能够查看 New Relic 或你拥有的任何遥测服务并验证其体验,然后你希望能够查看自己的日志,以深入了解其速度缓慢的原因。

使用 ILogger 接口

建议在创建生产应用程序时创建一个简单的 ILogger 接口,并在其中保留一些方法。 这样,以后就可以轻松更改日志记录实现,不必遍历所有代码即可执行此操作。 我们可以在整个 Fix It 应用中使用 System.Diagnostics.Trace 类,但我们会在实现 ILogger 的日志记录类的封面下使用它,并在整个应用中进行 ILogger 方法调用。

这样,如果想要使日志记录更丰富,则可以将 替换为 System.Diagnostics.Trace 所需的任何日志记录机制。 例如,随着应用的增长,你可能会决定要使用更全面的日志记录包,例如 NLog企业库日志记录应用程序块。 (Log4Net 是另一种常用的日志记录框架,但它不执行异步日志记录。)

使用 NLog 等框架的一个可能原因是便于将日志记录输出划分为单独的大容量和高价值数据存储。 这有助于高效存储不需要对其执行快速查询的大量 INFORM 数据,同时保持对 ACT 数据的快速访问。

语义日志记录

有关可生成更多有用诊断信息的相对较新的日志记录方法,请参阅 企业库语义日志记录应用程序块 (SLAB) 。 SLAB 使用 适用于 Windows 的事件跟踪 (ETW) 和 .NET 4.5 中的 EventSource 支持,使你能够创建更具结构化和可查询的日志。 为记录的每种类型的事件定义不同的方法,使你能够自定义所写的信息。 例如,若要记录SQL 数据库错误,可以调用 方法LogSQLDatabaseError。 对于此类异常,你知道一个关键信息是错误号,因此可以在方法签名中包含错误号参数,并将错误号记录为所写日志记录中的单独字段。 由于数字位于单独的字段中,因此,与将错误号连接成消息字符串相比,可以更轻松、可靠地获取基于 SQL 错误号的报告。

在“修复问题”应用中登录

ILogger 接口

下面是 Fix It 应用中的 ILogger 接口。

public interface ILogger
{
    void Information(string message);
    void Information(string fmt, params object[] vars);
    void Information(Exception exception, string fmt, params object[] vars);

    void Warning(string message);
    void Warning(string fmt, params object[] vars);
    void Warning(Exception exception, string fmt, params object[] vars);

    void Error(string message);
    void Error(string fmt, params object[] vars);
    void Error(Exception exception, string fmt, params object[] vars);

    void TraceApi(string componentName, string method, TimeSpan timespan);
    void TraceApi(string componentName, string method, TimeSpan timespan, string properties);
    void TraceApi(string componentName, string method, TimeSpan timespan, string fmt, params object[] vars);
}

通过这些方法,可以在 System.Diagnostics 支持的相同四个级别编写日志。 TraceApi 方法用于记录外部服务调用以及有关延迟的信息。 还可以为调试/详细级别添加一组方法。

ILogger 接口的记录器实现

接口的实现非常简单。 它基本上只是调用标准 System.Diagnostics 方法。 以下代码片段显示了所有三种 Information 方法以及另外一种。

public class Logger : ILogger
{
    public void Information(string message)
    {
        Trace.TraceInformation(message);
    }

    public void Information(string fmt, params object[] vars)
    {
        Trace.TraceInformation(fmt, vars);
    }

    public void Information(Exception exception, string fmt, params object[] vars)
    {
        var msg = String.Format(fmt, vars);
        Trace.TraceInformation(string.Format(fmt, vars) + ";Exception Details={0}", exception.ToString());
    }

    public void Warning(string message)
    {
        Trace.TraceWarning(message);
    }

    public void Error(string message)
    {
        Trace.TraceError(message);
    }

    public void TraceApi(string componentName, string method, TimeSpan timespan, string properties)
    {
        string message = String.Concat("component:", componentName, ";method:", method, ";timespan:", timespan.ToString(), ";properties:", properties);
        Trace.TraceInformation(message);
    }
}

调用 ILogger 方法

每次 Fix It 应用中的代码捕获异常时,它都会调用 ILogger 方法来记录异常详细信息。 每次调用数据库、Blob 服务或 REST API 时,它都会在调用前启动秒表,在服务返回时停止秒表,并记录已用时间以及有关成功或失败的信息。

请注意,日志消息包含类名和方法名称。 最好是确保日志消息标识应用程序代码的哪个部分编写它们。

public class FixItTaskRepository : IFixItTaskRepository
{
    private MyFixItContext db = new MyFixItContext();
    private ILogger log = null;

    public FixItTaskRepository(ILogger logger)
    {
        log = logger;
    }

    public async Task<FixItTask> FindTaskByIdAsync(int id)
    {
        FixItTask fixItTask = null;
        Stopwatch timespan = Stopwatch.StartNew();

        try
        {
            fixItTask = await db.FixItTasks.FindAsync(id);
            
            timespan.Stop();
            log.TraceApi("SQL Database", "FixItTaskRepository.FindTaskByIdAsync", timespan.Elapsed, "id={0}", id);
        }
        catch(Exception e)
        {
            log.Error(e, "Error in FixItTaskRepository.FindTaskByIdAsynx(id={0})", id);
        }

        return fixItTask;
    }

因此,现在,每次 Fix It 应用调用 SQL 数据库时,你都可以看到调用、调用它的方法,以及它花费的时间。

日志中的SQL 数据库查询

显示“编辑实体属性”的屏幕截图,以及成功更新所需的每个属性的外观以及花费的时间。

如果浏览日志,可以看到数据库调用所花费的时间是可变的。 此信息可能很有用:因为应用会记录所有这些内容,你可以分析数据库服务随时间推移的执行方式的历史趋势。 例如,服务可能大部分时间都很快,但请求可能会失败,或者响应可能会在一天中的特定时间变慢。

可以对 Blob 服务执行相同的操作 - 每次应用上传新文件时,都会有一个日志,并且可以看到上传每个文件所花费的确切时间。

Blob 上传日志

每次调用服务时,只需编写几行额外的代码,现在每当有人说他们遇到问题时,你都可以确切地知道问题是什么,是否是错误,或者即使它只是运行缓慢。 你可以查明问题的根源,而无需远程连接到服务器,或者在错误发生后打开日志记录,并希望重新创建它。

Fix It 应用中的依赖关系注入

你可能想知道上面所示的示例中的存储库构造函数如何获取记录器接口实现:

public class FixItTaskRepository : IFixItTaskRepository
{
    private MyFixItContext db = new MyFixItContext();
    private ILogger log = null;

    public FixItTaskRepository(ILogger logger)
    {
        log = logger;
    }

为了将接口连接到实现,应用使用 依赖项注入 (DI) AutoFac。 DI 使你能够在整个代码的许多位置使用基于接口的对象,并且只需在一个位置指定实例化接口时使用的实现。 这使更改实现变得更容易:例如,你可能希望将 System.Diagnostics 记录器替换为 NLog 记录器。 或者,对于自动测试,可能需要替换模拟版本的记录器。

Fix It 应用程序在所有存储库和所有控制器中使用 DI。 控制器类的构造函数获取 ITaskRepository 接口的方式与存储库获取记录器接口的方式相同:

public class DashboardController : Controller
{
    private IFixItTaskRepository fixItRepository = null;

    public DashboardController(IFixItTaskRepository repository)
    {
        fixItRepository = repository;
    }

该应用使用 AutoFac DI 库自动为这些构造函数提供 TaskRepositoryLogger 实例。

public class DependenciesConfig
{
    public static void RegisterDependencies()
    {
        var builder = new ContainerBuilder();

        builder.RegisterControllers(typeof(MvcApplication).Assembly);
        builder.RegisterType<Logger>().As<ILogger>().SingleInstance();

        builder.RegisterType<FixItTaskRepository>().As<IFixItTaskRepository>();
        builder.RegisterType<PhotoService>().As<IPhotoService>().SingleInstance();
        builder.RegisterType<FixItQueueManager>().As<IFixItQueueManager>();

        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }
}

此代码基本上说,在构造函数需要 ILogger 接口的任何地方,传入 Logger 类的实例,每当它需要 IFixItTaskRepository 接口时,都会传入 FixItTaskRepository 类的实例。

AutoFac 是可以使用的众多依赖项注入框架之一。 另一个受欢迎的是 Unity,Microsoft 模式和实践推荐和支持它。

Azure 中的内置日志记录支持

Azure 支持在 Azure 应用服务 中对Web 应用进行以下类型的日志记录:

  • System.Diagnostics 跟踪 (无需重启站点) 即可打开和关闭并动态设置级别。
  • Windows 事件。
  • IIS 日志 (HTTP/FREB) 。

Azure 在 云服务 中支持以下类型的日志记录:

  • System.Diagnostics 跟踪。
  • 性能计数器。
  • Windows 事件。
  • IIS 日志 (HTTP/FREB) 。
  • 自定义目录监视。

Fix It 应用使用 System.Diagnostics 跟踪。 若要在 Web 应用中启用 System.Diagnostics 日志记录,只需在门户中翻转开关或调用 REST API。 在门户中,单击站点的“ 配置 ”选项卡,然后向下滚动以查看 “应用程序诊断 ”部分。 可以打开或关闭日志记录,然后选择所需的日志记录级别。 可以让 Azure 将日志写入文件系统或存储帐户。

“配置”选项卡中的应用诊断和站点诊断

在 Azure 中启用日志记录后,可以在创建日志时在 Visual Studio 输出窗口中看到这些日志。

流式处理日志菜单

流式处理日志菜单2

还可以将日志写入存储帐户,并使用任何可访问 Azure 存储表服务的工具(例如 Visual Studio 中的服务器资源管理器Azure 存储资源管理器)查看日志。

服务器资源管理器中的日志

总结

实现现成的遥测系统、在自己的代码中检测日志记录并在 Azure 中配置日志记录非常简单。 如果遇到生产问题,遥测系统和自定义日志的组合将有助于在问题成为客户的主要问题之前快速解决问题。

在下一章中,我们将介绍如何处理暂时性错误,使其不会成为必须调查的生产问题。

资源

有关详细信息,请参阅以下资源。

主要有关遥测的文档:

主要有关日志记录的文档:

主要有关故障排除的文档:

视频:

  • FailSafe:生成可缩放、可复原云服务。 由乌尔里希·霍曼、马克·莫库里和马克·西姆斯组成的九部分系列。 以非常易于访问且有趣的方式呈现高级概念和体系结构原则,其中从 Microsoft 客户咨询团队 (CAT) 实际客户的体验中得出的故事。 第 4 集和第 9 集与监视和遥测有关。 第 9 集包括监视服务 MetricsHub、AppDynamics、New Relic 和 PagerDuty 的概述。
  • 构建大型:从 Azure 客户那里吸取的教训 - 第 II 部分。 马克·西姆斯谈到设计故障和检测一切。 类似于故障安全系列,但会介绍更多操作方法详细信息。

代码示例: