Azure PaaS - Cloud Service服务架构及快速调试
开发Windows Azure云服务(Cloud Service)过程中,难免会出现一些代码异常或者部署失败,对于Azure开发者,有必要了解一下Azure云服务在云端的实际服务架构,并借此来调试和诊断Azure云服务,快速找出已有云服务中存在或隐藏的问题。本篇将覆盖以下两方面的内容:
1.了解Azure云服务的服务架构
2.了解云服务的快速调试方法
博主有幸在2013年的微软TechED会议(北京-上海) 上对本主题进行了讲解,本篇在之前的研究基础上,进行了部分更新。
1. 了解Azure云服务的服务架构
Microsoft Azure托管服务(Cloud Service)的启动和运行过程如图所示。
- „ 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: 还原到原始部署状态
基于上述云服务活动中虚机上磁盘的变化,在设计云服务时,务必要注意:不要使用虚机上的磁盘作为永久存储,不要在虚机上手动安装部署环境提供永久使用。
参考出处:
https://blogs.msdn.com/b/kwill/archive/2011/05/05/windows-azure-role-architecture.aspx
https://msdn.microsoft.com/en-us/library/azure/hh472157.aspx
2. 了解云服务的快速调试方法
a. 本地调试云服务
调试工具跟踪包括本地常见的工具:模拟客户端、进程分析工具等等
启用IntelliTrace或者Profiling是跟踪云服务的一大特色:
使用Visual Studio Premium或者Ultimate即可查看已经部署的云服务中运行的IntelliTrace或者Profiling详细情况。(具体步骤是 View --> Server Explorer --> Windows Azure --> 目标云服务 --> 目标云服务虚机 --> 右键查看IntelliTrace或者Profiling)
b. 远程调试云服务
通过配置远程连接(remote access),开发者可以登录到云服务虚机中进行服务调试和跟踪,主要包括以下两种方式:
1.)查看服务日志
鉴于上述对云服务启动架构的了解,开发者可以逐一检查各个模块的运行日志,找出云服务运行过程中的异常所在。具体的日志、输出等项目的查看路径和方法如下。
- „ Windows Azure Event Logs:Azure运行时(Runtime)过程中的日志信息,包括OnStart、Startup Task、Crash等,如图所示。(打开方式:“Event Viewer”→“Applications and Services Logs”→“Windows Azure”。)
- „ 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.)在虚机上使用调试工具
上述网页页面是一个示例,其中的很多按钮事件会导致后端代码错误,但由于代码中对有些错误做了封装处理,因此用户操作该网页时,有些错误能直接从页面上看到,有些错误看不出来,因此需要通过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();
}
运行效果如下,正常工作。
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 事件查看器中可以找到问题的根源:数据库是只读的,因此写操作失败。
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访问权限不够。
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<string> blocklist = new List<string>();
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工具进行跟踪,实时捕捉到该异常,如图:
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工具可以查看到当前目标文件被哪个程序占用,从而找到该问题的根源。
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.<EOM>");
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.
对于产生的转储文件,分别使用上述提到的Windbg工具分析,可以得到以下线索,开发者可以依此来进一步修改代码。
关于Dump文件分析及Windbg工具的使用,博主以后会尝试对该主题进行总结分享。开发者可以快速参考以下文章,快速学习:
https://www.cnblogs.com/yuanxiaoping_21cn_com/archive/2012/09/21/2697520.html
https://blogs.msdn.com/b/kaevans/archive/2011/04/11/intro-to-windbg-for-net-developers.aspx
关于上述用到的DebugView,Process Monitor,Windbg等工具,开发者可以直接在搜索引擎中下载,或者到以下链接进行下载:
https://blogs.msdn.com/b/azure-cn/archive/2013/12/06/debugging-tools-shared-in-teched-2013.aspx