快速解决生产问题






4.81/5 (8投票s)
使用 PDB 文件,使用远程调试工具
引言
开发人员面临的最主要问题之一是生产环境发生问题。开发人员必须快速找到问题的根本原因,或者在开发环境中重现相同的问题以解决它。由于时间至关重要,延迟找到根本原因可能会给客户带来经济损失,或导致公司声誉受损。有几种方法可以高效且快速地解决生产环境中的问题。
调试问题的方法
- 通过日志查看调用堆栈
- 启用跟踪并检查跟踪输出
- 在开发环境中重现场景并使用 Visual Studio 进行调试
- 使用程序数据库 (PDB) 文件
- 远程调试
1. 通过日志查看调用堆栈
这是最常见的调试问题的方法,即获取用户的日志文件并检查其中的异常。如果异常已知且已用自定义消息处理,则很有用,但如果异常是未处理的,则很难找出异常是如何发生的。调用堆栈在此方法中很有用,但调用堆栈仍然提供方法级别的信息。方法级别的信息无法显示确切是哪一行导致了问题。要获取确切的行信息,我们需要将程序数据库 (PDB) 文件与应用程序一起使用。PDB 文件将在下面详细介绍。日志的另一个缺点是,我们无法在应用程序中进行大量日志记录,尤其是在日志写入输出文件的情况下。这会极大地降低应用程序的性能。因此,日志记录应保持有限,并按需进行。
2. 启用跟踪并检查跟踪输出
可以通过配置启用跟踪,然后重新运行应用程序以检查跟踪输出。如果禁用跟踪,程序将忽略 Trace
语句。因此,可以在代码中包含带有跟踪开关的 Trace
语句。但此方法仍然存在限制,因为它需要为每个逻辑代码编写,这维护起来有点麻烦。
3. 在开发 (Dev) 环境中重现场景并使用 Visual Studio 进行调试
由于一种常见的做法是仅在客户机上部署程序集(编译后的代码)和框架,因此很明显,客户机上没有应用程序代码或 Visual Studio IDE/调试器用于调试目的。因此,为了找到根本原因,开发人员需要设置开发环境并重现类似场景,并在开发人员的机器上进行调试。
这是找到问题根本原因的最可靠的方法,但存在严重限制。
- 开发和生产环境中的数据可能不相同,因此数据相关的问题难以重现。
- 这是一个耗时的工作,考虑到重现问题的紧迫性,在开发环境中设置可能很难,具体取决于应用程序运行所涉及的多个系统。
4. 使用程序数据库 (PDB) 文件
这是在客户机上调试问题的最简单方法。但 PDB 文件是什么?当应用程序编译时,我们通常会在 bin 文件夹中看到它们。即使它们不存在,程序也可以运行,那么它们携带了什么信息?
- PDB 文件:程序数据库文件也称为符号文件,包含代码的调试信息,例如:
- 全局变量
- 局部变量
- 函数名称及其入口点的地址
- 帧指针省略 (FPO) 记录
- 源行号 (参考 MSDN)
因此,可以更丰富地获取堆栈跟踪。当我们随 EXE/DLL 一起包含 PDB 文件并重现场景时,当前的堆栈跟踪还将提供错误发生的行号。这有助于我们确切地了解错误发生在哪里,然后进行纠正或提供修复。让我们通过一个例子来展示 PDB 文件的用法。
让我们创建一个名为“ProdProject
”的简单控制台项目和一个名为“DataLayer
”的类库。DataLayer
类库有一个名为 SaveIntoDatabase
的 DatabaseOperations
类。
DatabaseOperations.cs
namespace DataLayer
{
public class DatabaseOperations
{
public void SaveIntoDatabase(string Name,string MathsMarks,string ScienceMarks)
{
int Maths = Convert.ToInt32(MathsMarks);
int Science = Convert.ToInt32(ScienceMarks);
// Code to insert values into the database
}
}
}
Program.cs
namespace SymbolProject
{
class Program
{
static void Main(string[] args)
{
try
{
string[] arrValues = new string[3];
Console.Write("Name:");
string Name = Console.ReadLine();
Console.Write("Maths Marks:");
string MathsMarks = Console.ReadLine();
Console.Write("Science Marks:");
string ScienceMarks = Console.ReadLine();
DataLayer.DatabaseOperations dbOperation = new DataLayer.DatabaseOperations();
dbOperation.SaveIntoDatabase(Name, MathsMarks, ScienceMarks);
Console.Write("Data inserted successfully");
Console.ReadLine();
}
catch(Exception ex)
{
Console.WriteLine("Message:" + ex.Message +
Environment.NewLine + "StackTrace:" + ex.StackTrace);
Console.ReadLine();
}
}
}
}
在发布模式下构建应用程序之前,我们需要启用 PDB 文件的创建。
这可以通过在解决方案资源管理器中右键单击 DataLayer 项目 => 属性 => 生成 => 高级 => 调试信息 => 仅 PDB 来完成。
这里有 3 个选项
- 无 – 不会创建 pdb 文件
- 仅 PDB – 符号仅存储在 pdb 文件中
- 完整 – 符号将存储在 pdb 文件和程序集中
在 \bin\Release 中,您将看到创建了以下文件
- DataLayer.dll
- DataLayer.pdb
- ProdApplication.exe
现在您可以将 DataLayer.dll 和 ProdApplication.exe 部署到客户。
(没有 PDB 文件) 如果错误发生在客户机上,将看到以下输出
您会看到堆栈跟踪显示了发生错误的方法名称,但仍然不知道方法中的具体位置。即 DataLayer.DatabaseOperation.SaveIntoDatabase
。
现在,如果您在 EXE 位置提供了 PDB 文件 (DataLayer.pdb) 并在客户机上重新运行应用程序,您将看到以下输出
这里,它显示了方法名称,即 DataLayer.DatabaseOperation.SaveIntoDatabase
,并且还提到了错误发生的行号,即第 15 行。
如果您转到源代码并检查这一行,您将看到哪段代码有问题,并为此问题提供修复。
非常重要:PDB 文件是 DLL/EXE 的特定于版本的。它们包含链接到相应 DLL/EXE 的 GUID。因此,一个版本的 PDB 文件不能与另一个版本的 DLL/EXE 一起使用,即使代码没有改变。因此,一旦您在发布模式下创建了一个版本,您就需要将该 PDB 存储在某个存储库中,称为“符号服务器”。提供 PDB 作为发布版本是可选的。但提供它并没有多大风险,因为您的程序集和 EXE 已经包含了您的源代码。反编译您的可执行文件是可能的,并且可能需要类似的努力来处理 PDB 文件。总而言之,除非您的安装包有大小限制,否则问题不大,因为 PDB 文件会占用大量空间。
5. 远程调试
PDB 文件是开始调试的好方法,但如果您可以连接到客户机,则可以从您的机器上调试应用程序。远程调试的实现相当简单。您只需要做以下几件事
您需要在客户机上设置远程调试工具。
这些工具可以在 Microsoft 网站上找到,例如 https://www.microsoft.com/en-us/download/details.aspx?id=48155。URL 可能会更改,因此最好搜索“Remote Tools for Visual Studio 20XX”。
- 要安装远程调试工具,用户需要管理员权限。
- 安装并打开应用程序后,您将看到以下窗口。该窗口要求您配置远程调试以允许防火墙连接到此计算机。单击配置远程调试。
单击后,您将看到
“
METADOR
”是我的服务器主机名。4020
是托管此服务的端口号。 - 单击工具 => 选项 => 权限,如果两台计算机共享相同的活动目录,则设置用户,或选择“无身份验证”。
- 现在,在客户机上运行应用程序。不要继续操作,但在此之前,我们需要在 Visual Studio 调试器中附加此进程。
- 完成此操作后,您已在客户机上设置了远程调试器。现在是时候发现客户机并将您的 Visual Studio 调试器附加到那里运行的应用程序进程了。
- 为此,请使用您想要调试的应用程序代码打开 Visual Studio。转到调试 => 附加到进程。
- 选择传输为“远程(无身份验证)”[如果如步骤 3 中所述没有身份验证],然后单击查找。
它将搜索主机名显示的服务器/客户机。这里是“
METADOR
”,然后单击选择。 - 在进程窗口中选择应用程序,然后单击附加。现在进程已附加,您可以对代码设置调试点。现在可以从您的机器上逐步调试用户输入的输入。
- 附加进程后,您需要检查符号文件是否已正确加载。当您尝试设置断点时,您会看到以下错误,从而可以观察到这一点
要解决此问题,请转到调试 => 窗口 => 模块
您可以看到 ProdApplication.exe 和 DataLayer.dll 的符号未加载。如果符号未加载,则无法使用断点进行调试。
要解决此问题,您可以右键单击模块中的 DataLayer.dll 并选择加载符号选项。这将弹出一个对话框来搜索 pdb 文件。找到该版本的 PDB 文件并加载它。
如果为其创建了 ProdApplication.exe,也请对其执行类似操作。加载后,您将在模块中看到符号状态为“已加载符号”。
在客户机 (
METADOR
) 上:输入可以重现场景的值。在程序员机器上
按 F11。
这就是开发人员如何加快应用程序调试过程并提供快速响应。还有其他一些方法,例如分析应用程序内存转储并找出崩溃或内存泄漏的原因。但我将它们排除在本文的讨论范围之外,也许我可以在下一部分中介绍。
参考文献
以下参考文献非常全面且非常有用,如果您有时间,请务必阅读
- https://codeproject.org.cn/Articles/37456/How-To-Inspect-the-Content-of-a-Program-Database-P
- http://blogs.msdn.com/b/visualstudioalm/archive/2012/12/10/creating-ngen-pdbs-for-profiling-reports.aspx
- https://msdn.microsoft.com/en-IN/library/y7f5zaaa.aspx
- http://www.wintellect.com/devcenter/jrobbins/pdb-files-what-every-developer-must-know
- https://codeproject.org.cn/Articles/6084/Windows-Debuggers-Part-A-WinDbg-Tutorial