65.9K
CodeProject 正在变化。 阅读更多。
Home

监控多层 Windows Azure 应用程序的性能

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2014 年 1 月 16 日

CPOL

9分钟阅读

viewsIcon

16181

关于如何在云基础架构中托管的多层应用程序进行故障排除的技巧。

引言

AppDynamics 是一款应用程序性能管理解决方案,可帮助解决分布式或多层应用程序面临的一些最大挑战:应用程序监控、故障排除和性能分析。我在 Microsoft 担任了很长时间的现场工程师,深知其中的一些挑战。通常,您会来到客户现场,发现问题是由于数据库中缺少索引导致一切运行缓慢。有时,您可能会注意到网络中的挑战正在减缓整个应用程序套件。在其他情况下,简单的代码更改可能会引入严重的性能问题,当应用程序是分布式的且您不知道从何处着手时,找到源头可能是一项艰巨的挑战。

Windows Azure 上的云应用程序通常是多层应用程序

Windows Azure 可以轻松编写云托管的应用程序。根据设计,这些应用程序往往高度分布式,具有多个层。对性能不佳进行故障排除意味着确切地知道哪个节点或层出现了故障。分布式应用程序没有单一的故障点。从操作系统、中间件、第三方产品、硬件、网络配置到您自己的软件逻辑,这里的每一样事物以及每个层上的每个节点都可能是可疑的。每个节点通常执行自己的 I/O,拥有自己的以太网卡,并包含各种运行的进程和线程。

随着应用程序复杂性的增长,寻找缓慢的部分变得越来越困难。这不仅仅是查看操作系统或 Web 服务器的日志文件。只有当工程师预先考虑了记录错误状况时,日志记录才有用。

云计算通常会为您的应用程序增加一层抽象。首先,您无法物理访问硬件。这限制了您与架构特定部分的物理交互。它也限制了您对所有移动部分的理解——您需要自己创建图表。许多基于云的应用程序利用第三方服务,例如身份验证或缓存。在故障排除时,这些部分经常被忽略,因为它们不是应用程序代码库的重要组成部分。

应用程序性能管理 (APM) 通过查看您基于云的应用程序的内部工作原理来解决问题。这些工具可以看到执行的代码、应用程序的入口和出口调用、跨多个应用程序组件流动的事务。

需要高层视角

真正需要的是整个应用程序的视觉概览。应用程序流图可帮助您了解分布式应用程序的所有依赖关系。能够深入了解连接点和各个节点至关重要。通常会有受影响的客户,因此快速解决至关重要。对所有移动部分进行鸟瞰图是高效故障排除和更快解决生产问题的关键。

预见问题

更好的方法是实际预见问题在其发生之前。也就是说,目标应该从被动监控方法转向更主动的监控方法。这意味着在性能问题变得严重之前立即找到并修复它们。一个很好的起点是构建应用程序流图,它显示应用程序中的所有部分以及数据如何在这些部分之间传输。它还意味着构建一个在特定负载阈值下的预期性能基线,然后随时间监控性能。这包括测量浏览器响应时间,这最终是客户评估您基于云的应用程序性能的方式。如果未达到性能目标,网络管理员、开发人员和业务利益相关者能够及早获得一些数据和事实并避免未来出现问题非常重要。当基线条件发生偏差时,AppDynamics 可以设置警报。

一个例子 - 3 层(Web 前端、服务总线、后台进程/工作进程)

我开始做的就是通过一个 Azure 实验室。我想测试的实验室是这个

该实验室演示了队列、发布/订阅

该实验室的目的是设置一个利用 Windows Azure 服务总线队列的多层应用程序。正如大多数架构师所知,队列使得构建解耦的应用程序成为可能。队列非常强大,因为它们允许客户端应用程序以极快的速度提交消息,其速度可能超过后端服务器的处理能力。随着队列大小的增加,可以添加更多 Windows Azure 工作进程来增加规模,从而及时处理消息。这也是发布/订阅模式的核心构建块。

3 层图

图 1 的工作原理很简单。客户端应用程序连接到 Web 角色并发送消息。Web 角色接收这些消息,然后将它们放入队列,队列作为 Windows Azure 服务总线应用程序运行。工作角色可以被视为后台进程。它检查服务总线中的队列并从中读取消息。如果队列开始变得太大,那么我们需要扩展工作角色以处理放入服务总线队列的消息量。

注意: Web 角色既可以作为其他应用程序的代理。它还包含一个网页前端。这意味着在此示例中,Web 角色实际上是两个层。

图 1 - 多层应用程序的概念图

瓶颈在哪里?

从上图可以看出,Web 角色可以充当希望向工作角色提交消息的客户端应用程序的代理。但是,如果此应用程序开始性能不佳,则故障排除可能具有挑战性。识别性能瓶颈可能很棘手。例如,这可能发生在 Web 角色将消息提交到服务总线时。或者,可能是由于提交的消息的吞吐量和大小,工作角色无法足够快地从服务总线读取。此外,设想一个数据库涉及其中,进一步模糊了应用程序异常行为的确切来源。

理想世界

在理想的世界里,开发人员可以将他们的应用程序发布到云端,并在一个 Web 门户的图表中将每个层视为一个节点。没错,这正是 AppDynamics 所做的。 

AppDynamics 自动提供有用的图表

请注意,AppDynamics 提供的视图(图 2)几乎与概念图相同。这一切的优点是,它由 AppDynamics 在您发布应用程序时自动完成。随着您的应用程序的增长或扩展,AppDynamics 会为您维护该图表。AppDynamics 还允许您自动捕获用于未来诊断的基准。

图 2 中的视图是在 AppDynamics 门户中可以看到的。这不是开发人员或架构师构建的图表。这是 AppDynamics 使用 AppDynamics 的代理和框架元素自动构建的图表。当您部署 Azure 项目时,此 MSI 会执行:dotNetAgentSetup64.msi

图 2 - AppDynamics 视图 - 自动生成

查看一些代码

这是 Visual Studio 2013 中的解决方案。请注意,该解决方案与图 1 和图 2 非常相似。这是理想的场景——开发人员可以从概念、性能监控到 Visual Studio 项目布局进行概念性思考。

图 3 - Visual Studio 项目

理解代码

在整个解决方案中有三个项目。Msftazuretut 是解决方案中的主项目,用于部署和整体配置。如前所述,Web 角色有两种用法。第一种用法是作为客户端应用程序,将消息提交到队列。第二种用法是它可以作为其他客户端应用程序的前端。毕竟,它是一个 MVC Web API 风格的应用程序。第三部分是工作角色,它基本上是一个后台进程,从队列读取消息,异步处理 Web 角色放入队列的消息。

图 4 - Visual Studio 2013 解决方案

更详细的逻辑

这里的逻辑非常简单。

Web 角色代码 - 控制器

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Mvc; 
using FrontendWebRole.Models; 
using Microsoft.ServiceBus.Messaging; 
using Microsoft.ServiceBus; 

namespace FrontendWebRole.Controllers 
{ 
    // The controller for the web role. 
    // It has 2 capabilities. First, it presents an entry 
    // form for an order (Customer and Product Numbers) 
    // Once the form is submitted, the second capability 
    // comes into play - to place the submitted order as 
    // a message into a service bus queue. 
    public class HomeController : Controller 
    { 
        public ActionResult Index() 
        { 
            // Simply redirect to Submit, since Submit will serve as the 
            // front page of this application 
            return RedirectToAction("Submit"); 
        } 

        public ActionResult About() 
        { 
            return View(); 
        } 

        // GET: /Home/Submit 
        public ActionResult Submit() 
        { 
            // Connect to the service bus queue 
            var namespaceManager = QueueConnector.CreateNamespaceManager(); 


            // Get the queue, and obtain the message count. 
            var queue = namespaceManager.GetQueue(QueueConnector.QueueName); 
            ViewBag.MessageCount = queue.MessageCount; 

            return View(); 
        } 

        // POST: /Home/Submit 
        // Controler method for handling submissions from the submission 
        // form. 
        [HttpPost] 
        // Attribute to help prevent cross-site scripting attacks and 
        // cross-site request forgery. 
        [ValidateAntiForgeryToken] 
        public ActionResult Submit(OnlineOrder order) 
        { 
            if (ModelState.IsValid) 
            { 
                // Create a message based on the order submitted by the form. 
                // This will include a customer number and a product number. 
                var message = new BrokeredMessage(order); 


                // Submit the order. This adds the order to the 
                // service bus queue. 
                QueueConnector.OrdersQueueClient.Send(message); 
                return RedirectToAction("Submit"); 
            } 
            else 
            { 
                return View(order); 
            } 
        } 
    } 
}
图 5 - Web 角色

工作角色代码

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.Net; 
using System.Threading; 
using Microsoft.ServiceBus; 
using Microsoft.ServiceBus.Messaging; 
using Microsoft.WindowsAzure; 
using Microsoft.WindowsAzure.ServiceRuntime; 
using FrontendWebRole.Models; 

namespace OrderProcessingRole 
{ 
    // Worker role is responsible for reading message 
    // put into the service bus queue by the web role. 
    public class WorkerRole : RoleEntryPoint 
    { 
        // The name of the queue. It is the same queue used 
        // by the web role. 
        const string QueueName = "OrdersQueue"; 
        bool onStopCalled = false; 

        // The Client is an object used to read from the 
        // service bus queue. 
        QueueClient Client; 

        // The Run() method can be thought of as a never ending background 
        // process that reads messages from the service bus queue. 
        public override void Run() 
        { 
            Trace.WriteLine("Starting processing of messages"); 

            // Loop forever until onStopCalled is set. 
            while (true) 
            { 
                try 
                { 
                    // If OnStop has been called, return to do a graceful shutdown. 
                    if (onStopCalled == true) 
                    { 
                        System.Diagnostics.Debug.WriteLine("onStopCalled WorkerRole"); 
                        return; 
                    } 

                    // Read the messsage (if exists) from the service bus queue. 
                    BrokeredMessage receivedMessage = Client.Receive(); 

                    // Process the message 
                    System.Diagnostics.Debug.WriteLine("Processing Service Bus message: " + 
                                     receivedMessage.SequenceNumber.ToString()); 

                    // Load the message into the OnlineOrder object. 
                    OnlineOrder order = receivedMessage.GetBody<OnlineOrder>(); 

                    // For debugging purposes, display the order sent in by the web role. 
                    Debug.WriteLine(order.Customer + ": " + order.Product, "ProcessingMessage"); 
                    receivedMessage.Complete(); 
                } 
                catch 
                { 
                    // Handle any message processing specific exceptions here 
                } 
            } 

            //CompletedEvent.WaitOne(); 
        } 

        public override bool OnStart() 
        { 
            // Set the maximum number of concurrent connections 
            ServicePointManager.DefaultConnectionLimit = 12; 

            // Get the connection string to setup the connection. 
            string connectionString = 
                    CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString"); 
            var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString); 

            // Create queue, if doesn't exist. 
            if (!namespaceManager.QueueExists(QueueName)) 
            { 
                namespaceManager.CreateQueue(QueueName); 
            } 

            // Create a client object to be used by Run() method to 
            // read messges. 
            Client = QueueClient.CreateFromConnectionString(connectionString, QueueName); 
            return base.OnStart(); 
        } 

        public override void OnStop() 
        { 
            // Cleanup and close. 
            Client.Close(); 
            onStopCalled = true; 
            base.OnStop(); 
        } 
    } 
}
图 6 - 工作角色

简单的性能监控 6 步

完成 Azure 教程后,您可以准备解决方案以利用应用程序性能管理。

只有六个简单的步骤。它们在此处有完整的文档记录

步骤 1 注册一个 AppDynamics 帐户。
第二步 下载 AppDynamics 的 .NET 代理。
步骤 3 将代理添加到 Web 角色或工作角色。您必须将代理添加到每个 Web 和工作角色。
步骤 4 以 startup.cmd 文本文件的形式添加一些启动命令。这意味着将一些样板代码复制到 startup.cmd 中。这也意味着进入 ServiceDefinition.csdef 文件并指明您刚刚添加的 startup.cmd 文件在启动时执行。
步骤 5 发布您的应用程序。
步骤 6 监控性能。使用浏览器访问您在欢迎电子邮件和 AppDynamics 帐户主页上提供的 URL 的 AppDynamics 控制器。

结论

多层应用程序出了名的难以进行故障排除,尤其是在云基础架构中托管时。当出现中断或性能下降时,很难确定问题的根本原因或位置。更难的是在问题严重影响最终用户之前预见问题。设置警报和监控代理需要简单快捷。此外,随着应用程序复杂性的增长,系统动态发现应用程序层并映射事务流非常重要,重点关注实时请求延迟、有效负载检查、响应时间、错误率和事务分组。总之,AppDynamics 在业务事务级别以及更低级别的基础架构组件性能方面提供了全面的、多维度的视图。它可以快速轻松地查找慢速事务、内存泄漏、慢速数据库查询、线程争用等。 在此处开始您的免费试用

© . All rights reserved.