微软云服务器架构图,Azure PaaS - Cloud Service服务架构及快速调试

Azure PaaS - Cloud Service服务架构及快速调试

09/11/2014

17 minutes to read

In this article

开发Windows Azure云服务(Cloud Service)过程中,难免会出现一些代码异常或者部署失败,对于Azure开发者,有必要了解一下Azure云服务在云端的实际服务架构,并借此来调试和诊断Azure云服务,快速找出已有云服务中存在或隐藏的问题。本篇将覆盖以下两方面的内容:

1.了解Azure云服务的服务架构

2.了解云服务的快速调试方法

博主有幸在2013年的微软TechED会议(北京-上海) 上对本主题进行了讲解,本篇在之前的研究基础上,进行了部分更新。

1. 了解Azure云服务的服务架构

Microsoft Azure托管服务(Cloud Service)的启动和运行过程如图所示。

5826.111.png

„ RDFE:Azure平台对外统一接口。图中步骤1表示开发者发起操作请求到RDFE,如上传发布包、更新托管服务配置、管理证书等。操作可以通过Azure管理门户来完成,也可以通过Visual Studio、PowerShell等工具完成。FFE模块将外部请求转成内部命令,模块查找到目标计算机群,开始与集群总控通信。

„ Fabric Controller:集群总控,维护和监控数据中心的所有计算资源。集群总控寻找可用的计算资源(CPU、Memory等),并与相应的Host Agent进行通信,将发布包和配置文件等信息复制到目标宿主服务器。

„ Host Agent:存在于Host OS中,负责准备Guest OS,并与Guest OS通信(WaAppAgent),10分钟无信号即重启Guest OS。

„ WaAppAgent:安装、配置、更新WindowsAzureGuestAgent。

„ WindowsAzureGuestAgent:配置Guest OS,包括防火墙、本地缓存、发布包、执行账号等;与集群总控Fabric Controller保持心跳同步;启动WaHostBootstrapper。

„ WaHostBootstrapper:读取配置,执行启动任务和部署发布包,监测所有子进程并汇报StatusCheck结果。

„ IISConfigurator:适用于SDK 1.2以上的发布包部署(非HWC模式),负责安装IIS并清空IIS下默认的Application Pool,待Startup Task执行完后,IISConfigurator完成网站部署和配置等。

„ Startup Tasks:预启动任务,包括用户自定义的依赖任务和角色需要的预装服务,以三种模式运行。对于background模式的预启动任务,被启动之后,WaHostBootstrapper不等待其返回值直接进入下一个Startup Task或后续工作流。其他两种模式的预启动任务,WaHostBootstrapper需要等待其返回值,确认预启动任务正确执行后,进入下一个流程。

„ WaWorkerHost:Worker Role程序的宿主进程,所有Worker Role相关的DLL和EntryPoint代码运行于此。

„ WaWebHost:适用于SDK 1.2等HWC(Hostable Web Core)模式的发布包,该模式下网站服务直接运行在该宿主进程下,不依赖于IIS(Application Pool)。

„ WaIISHost:Full IIS模式下的Web Role的宿主进程,加载、执行RoleEntryPoint代码(e:\entrypoint)。

„ W3WP:IIS子进程,负责托管网站服务,即IIS中Application Pool对应的进程。

„Load Balancer:负载均衡,外部请求被均分到同一个Web(Worker)Role下的多个实例中。

值得一提的是,如之前的文章https://blogs.msdn.com/b/jianwu/archive/2014/08/15/azure-paas-3-azure-caching.aspx 中所提,云服务在实际运行过程中,可能会因为云平台的更新或者云服务本身的程序问题而Recycling,或者有可能因为用户的操作而重启或者重新镜像还原(reimage),故此,需要了解一下,这些活动对云服务的最终影响,如下:

虚机内部重启:

C: 不变

D: 不变

E: 不变

从管理门户上重启虚机:

C: 不变

D: 不变

E: 还原到原始部署状态

从管理门户是镜像还原(reimage):

C: 不变

D: 还原到原始部署状态

E: 还原到原始部署状态

更新部署(in-place upgrade):

C: 不变

D: 不变

E: 还原到原始部署状态

后端节点迁移:

C: 还原到原始部署状态

D: 还原到原始部署状态

E: 还原到原始部署状态

基于上述云服务活动中虚机上磁盘的变化,在设计云服务时,务必要注意:不要使用虚机上的磁盘作为永久存储,不要在虚机上手动安装部署环境提供永久使用。

参考出处:

2. 了解云服务的快速调试方法

a. 本地调试云服务

调试工具跟踪包括本地常见的工具:模拟客户端、进程分析工具等等

4810.111.png

启用IntelliTrace或者Profiling是跟踪云服务的一大特色:

3007.222.png

16123.333.png

使用Visual Studio Premium或者Ultimate即可查看已经部署的云服务中运行的IntelliTrace或者Profiling详细情况。(具体步骤是 View --> Server Explorer --> Windows Azure --> 目标云服务 -->  目标云服务虚机 --> 右键查看IntelliTrace或者Profiling)

2742.111.png

b. 远程调试云服务

通过配置远程连接(remote access),开发者可以登录到云服务虚机中进行服务调试和跟踪,主要包括以下两种方式:

1.)查看服务日志

鉴于上述对云服务启动架构的了解,开发者可以逐一检查各个模块的运行日志,找出云服务运行过程中的异常所在。具体的日志、输出等项目的查看路径和方法如下。

„ Windows Azure Event Logs:Azure运行时(Runtime)过程中的日志信息,包括OnStart、Startup Task、Crash等,如图所示。(打开方式:“Event Viewer”→“Applications and Services Logs”→“Windows Azure”。)7802.111.png

„ Application Event Logs:本地日志信息,同样适用于Azure调试。W3WP和Worker Role进程抛出的应用程序信息会集中于此。(打开方式:“Event Viewer”→“Windows Logs”→“Application”。)

„ App Agent Runtime Logs:存储在C:\Logs\AppAgentRuntime.log目录下,是WindowsAzureGuestAgent的输出日志,包括防火墙设置、角色状态变化等。

App Agent Heartbeat Logs:存储在C:\Logs\WaAppAgent.log目录下,是WindowsAzureGuestAgent的输出日志,包括心跳监测的结果。

Host Bootstrapper Logs:WaHostBootstrapper执行日志,对于SDK 2.1及以上的托管服务,该日志存储在C:\Resources目录下,SDK 2.1以下的存储在C:\Resources\Directory\ {DeploymentID}.{Rolename}.DiagnosticStore\WaHostBootstrapper.log目录下,其详细记录了WaHostBootstrapper启动各子进程的过程和后续跟踪,WaHostBootstrapper每次启动时重新创建新的日志文件。

IIS Logs:IIS网站的访问日志,记录实时流量处理的详细信息,存储在C:\Resources\ Directory\{DeploymentID}.{Rolename}.DiagnosticStore\LogFiles\Web中。

„ HTTP.SYS Logs:存储在D:\WIndows\System32\LogFiles\HTTPERR目录下,IIS未能处理的请求会在此记录,配合IIS Log能反映出所有进来的流量情况。

„ IIS Failed Request Log Files:IIS处理失败的流量请求信息,存储在C:\Resources\Directory\ {DeploymentID}.{Rolename}.DiagnosticStore\FailedReqLogFiles中。

„ Windows Azure Diagnostics Tables and Configuration:Windows Azure诊断(Diagnostics)和Performance Counters的监控输出,临时缓存在C:\Resources\Directory\{DeploymentID}. {Rolename}.DiagnosticStore\Monitor中。

„ Windows Azure Caching Log Files:若开启了Windows Azure Caching的日志功能(在默认情况下该功能是开启的),Caching服务的日志缓存在C:\Resources\Directory\ {DeploymentID}.{Rolename}.DiagnosticStore\AzureCaching中。

„ WaIISHost Logs:WaIISHost 进程的实时输出日志,存储在C:\Resources\Directory\{DeploymentID}.{Rolename}.DiagnosticStore\WaIISHost.log中。

„ IISConfigurator Logs:IISConfigurator进程的实时输出日志,存储在C:\Resources\ Directory\{DeploymentID}.{Rolename}.DiagnosticStore\IISConfigurator.log中。

„ Role Configuration Files:发布包的配置文件和定义文件,分别缓存在C:\Config\ {DeploymentID}.{DeploymentID.{Rolename}.{Version}.xml和E:\RoleModel.xml(或F:\ RoleModel.xml)中。

2.)配置Windows Azure Diagnostics诊断功能

如 https://blogs.msdn.com/b/jianwu/archive/2014/08/15/azure-paas-4.aspx 所述,在云服务中配置WAD(Windows Azure Diagnostics)可以实时将云服务虚机内部的实时信息(如应用程序日志、Windows事件日志、虚机CPU/内存使用率等)适时存储到Table Storage中,开发者可以通过分析Table Storage中永久存储的记录来分析云服务的运行质量和历史问题。

3.)在虚机上使用调试工具

1031.111.png

上述网页页面是一个示例,其中的很多按钮事件会导致后端代码错误,但由于代码中对有些错误做了封装处理,因此用户操作该网页时,有些错误能直接从页面上看到,有些错误看不出来,因此需要通过Windows 事件查看器、DebugView工具、ProcessExplorer、TaskManager(create dump)已经Windbg等工具来分析。

这个示例网页的主要代码如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Data;

using System.Data.SqlClient;

using System.IO;

using Microsoft.WindowsAzure.Storage;

using mjcomn;

using System.Diagnostics;

using System.Text;

namespace WebRole1

{

public partial class _Default : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

}

protected void Button1_Click(object sender, EventArgs e)

{

SqlDataReader sqldr = null;

SqlConnection cn = new SqlConnection("Server=tcp:a0yvwcchux.database.windows.net,1433;Database=mytestdb;User ID=testlogin@a0yvxxchux;Password=mypassword@test;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;");

SqlCommand cmd = new SqlCommand("select * from Persons", cn);

//try to connect and read data

Console.WriteLine("try to connect and read data...");

try

{

cmd.Connection.Open();

}

catch (Exception ex)

{

Console.WriteLine(ex.Message);

Console.Read();

}

Console.WriteLine("connected.");

//Console.Read();

sqldr = cmd.ExecuteReader(CommandBehavior.CloseConnection);

DataTable dt = new DataTable();

dt.Load(sqldr);

cmd.Connection.Close();

this.GridView1.DataSource = dt;

this.GridView1.DataBind();

}

运行效果如下,正常工作。

3857.111.png

protected void Button4_Click(object sender, EventArgs e)

{

SqlConnection cn = new SqlConnection("Server=tcp:a0yvwcchux.database.windows.net,1433;Database=mytestdb;User ID=testlogin@a0yxxchux;Password=mypassword@test;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;");

SqlCommand cmd = new SqlCommand("update Persons set City='China' where LastName='testor4'", cn);

cmd.Connection.Open();

cmd.ExecuteNonQuery();

cmd.Connection.Close();

}

操作数据库异常,该按钮背后的事件执行不成功,远程登录到虚机上,在Windows 事件查看器中可以找到问题的根源:数据库是只读的,因此写操作失败。

1258.222.png

protected void Button2_Click(object sender, EventArgs e)

{

//Azure存储帐号

var storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=portalvhds303zv6wrv9j9q;AccountKey=WNydsmystoragekey==");

var blobclient = storageAccount.CreateCloudBlobClient();

var container = blobclient.GetContainerReference("helloworldcontainer");

container.CreateIfNotExists();

var blob = container.GetBlockBlobReference("100");

try

{

MemoryStream stream = new MemoryStream();

blob.DownloadToStream(stream, null, null, null);

TextBox1.Text = System.Text.UTF8Encoding.UTF8.GetString(stream.ToArray());

}

catch (Exception ex)

{

System.Diagnostics.Trace.WriteLine(DateTime.Now.ToString() + " : " + ex.Message);

}

}

读取WAS操作异常,通过远程登录,开发者可以通过本地地址访问该页面,并点击该按钮重现问题。在页面返回的信息中,可以找到问题的原因:WAS访问权限不够。

3718.111.png

protected void Button3_Click(object sender, EventArgs e)

{

//Azure存储帐号

var storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=portalvhds303zv6wrv9j9q;AccountKey=WNydsi2FU6Gmystoragekey==");

var blobclient = storageAccount.CreateCloudBlobClient();

var container = blobclient.GetContainerReference("helloworldcontainer");

//container.CreateIfNotExists();

var blob = container.GetBlockBlobReference("100");

try

{

byte[] buffer = System.Text.Encoding.Default.GetBytes(this.TextBox1.Text);

blob.PutBlock(Convert.ToBase64String(System.BitConverter.GetBytes(100)), new MemoryStream(buffer, true), null);

List blocklist = new List();

blocklist.Add(Convert.ToBase64String(System.BitConverter.GetBytes(100)));

blob.PutBlockList(blocklist);

}

catch (StorageException ex)

{

System.Diagnostics.Trace.WriteLine(DateTime.Now.ToString() + " : " + ex.Message + "\r\n" + ex.StackTrace.ToString());

}

finally

{

this.TextBox1.Text = DateTime.Now.ToString() + " : Write data into WAS operation failed .";

}

}

本用例依然是操作WAS,但上述代码对程序异常进行了初步处理,导致异常返回的错误信息既不显示在返回页面上,也不返回在Windows事件查看器中。但是,开发者可以使用DebugView工具进行跟踪,实时捕捉到该异常,如图:

4532.333.png

6445.333.png

protected void Button5_Click(object sender, EventArgs e)

{

mjcomn.theApp app = new theApp();

app.WriteINI("KeyValues", "Date", DateTime.Now.ToString(), "./myout.ini");

this.TextBox1.Text = DateTime.Now.ToString() + " : succeeded using custom reference.";

}

访问本地文件测试,开发者可以以独占的方式使用目标文件(通过代码可以实现,如FileStream objFileStream = new FileStream(@"c:\a.txt", FileMode.Append, FileAccess.ReadWrite, FileShare.None); ),接下来点击该按钮时会导致访问异常access denied,此时使用Process Monitor工具可以查看到当前目标文件被哪个程序占用,从而找到该问题的根源。

7888.111.png

protected void Button6_Click(object sender, EventArgs e)

{

PerformanceCounter p = new PerformanceCounter("Processor", "% Processor Time", "_Total");

this.TextBox1.Text = p.NextValue().ToString();

float targetCPU = 85;

while (true)

{

if (p.NextValue() > targetCPU)

{

System.Threading.Thread.Sleep(2);

}

}

}

protected void Button7_Click(object sender, EventArgs e)

{

PerformanceCounter p = new PerformanceCounter("Memory", "Available Bytes");

float targetFreeMem = 100000000; //100MB

StringBuilder myStr = new StringBuilder("hello,World,this is test for Mem.");

while (true)

{

if (p.NextValue() > targetFreeMem)

{

myStr.Append(myStr.ToString());

}

else

{

System.Threading.Thread.Sleep(30000);

}

}

}

}

}

上面两处用例的目的是造成虚机的高CPU/Memory,使得虚机瞬间慢下来。对于此类问题,可以采用传统的分析工具Windbg来分析目标进程的转储文件(dump file),一个收集目标进程dump file的简单方法是,如下,在任务管理器中,选中CPU/Memory使用率最高的进程,选择属性中的创建转储文件(Create Dump File),即收集到了“问题”进程的转储文件。下图为样图,实际操作时,目标进程很有可能是w3wp.exe.

6866.111.png

对于产生的转储文件,分别使用上述提到的Windbg工具分析,可以得到以下线索,开发者可以依此来进一步修改代码。

0640.222.png

关于Dump文件分析及Windbg工具的使用,博主以后会尝试对该主题进行总结分享。开发者可以快速参考以下文章,快速学习:

关于上述用到的DebugView,Process Monitor,Windbg等工具,开发者可以直接在搜索引擎中下载,或者到以下链接进行下载:

4743.111.png