在网络服务领域,DNS服务器扮演着至关重要的角色。随着技术的发展,DNS服务器也在不断地更新迭代,以满足日益增长的性能需求。本文将介绍一种用于测试多线程DNS服务器性能的工具,并比较不同版本的BIND服务器的性能差异。
通常,不同版本的DNS服务器之间的差异主要在于安全修复。例如,BIND的每个版本发布都包含了一些错误修复。这使得IT管理人员在升级时面临挑战,因为他们通常信任现有的防火墙机制和安全特性,或者不愿意处理新的配置。他们的观点在某种程度上是正确的,因为BIND版本之间的差异确实只在于错误修复。例如,许多DNS服务器仍在使用BIND 4.9版本,并且没有升级的计划。
BIND社区一直面临这个问题,因为他们必须为每个发布的BIND版本发布文档,每次发布新的安全修复时都是如此,更不用说他们必须在所有6个主要版本上修复安全漏洞。
自从BIND 9版本发布以来,认为情况发生了巨大的变化。从这个版本开始,BIND支持多线程,这意味着不再有排队的问题。在之前的版本中,如果同时发送了十几个数据包,它会将它们排队并逐个回答。但在BIND 9中,它内置了多线程。
在IUT想要更新DNS服务器,因为它们已经非常老旧,所以决定在FreeBSD上使用BIND。但实际上不知道该使用哪个版本,因为最受欢迎的版本是8,而最新的版本是9。
有一篇文章提到了版本9是一个多线程DNS服务器,所以想要测试性能提升。在一台双核服务器上进行的测试显示,旧版本的前几个数据包回答得更快,但当达到第10个或第12个数据包时,多线程DNS服务器的回答速度远远超过了旧版本。
尽管代码行数发生了很大变化,但已经非常流行的DNS测试器有一个非常整洁和高效的方式来测试DNS服务器。唯一的问题是它一次发送一个数据包,因此给服务器一些时间来处理每一个数据包。
认为这并不能真正测试新的多线程DNS服务器的能力。所以重写了它,使其使用线程。创建了一个线程池,并更改了一些函数,以便它们可以并行运行。这使得程序非常消耗内存,但谈论的是20MB的RAM,对于这样一个程序来说仍然是很多,但需要为每个线程复制远程主机列表和一些变量,如时间等。
例如,创建了一个名为dnscheck的函数,它像以前一样执行所有操作,只是处理它自己的远程主机,并向其发送数据包并等待回答。当然,它必须有自己的名称、时间和等的副本。
如所见,它只接受一个对象。实际上它拥有一切,因为传递了一个为此目的创建的类作为它的变量。但它必须是这样的,因为对于多线程来说,它必须是一个委托函数,才能同时运行多次。
还创建了一个虚拟委托函数。它所做的就是将对象传递给dnscheck:
private delegate void _dnscheck(object me);
private void dnscheck(object me) {}
在这里,为每个线程创建了一个委托函数的对象,并将函数作为其参数。然后初始化了一个名为me的类,它包含了所需的信息,然后将它传递给委托函数的对象:
for (i = 0; i < URLNamescount; i++)
{
_dnscheck ddnscheck = new _dnscheck(dnscheck);
me = new mine(URLNames, URLNamescount, DNSAddress1, DNSAddress2, i);
ThreadPool.QueueUserWorkItem(new WaitCallback(ddnscheck), me);
}
在状态框中显示异常时遇到了一些麻烦。因为在.NET中,通常不能在当前线程中访问在其他线程中创建的对象。函数必须是委托,并且还需要询问该对象是否需要调用:
private delegate void _StatusBoxPrint(object obj);
private void StatusBoxPrint(object obj)
{
string LogText = (string)obj;
StatusBox.Items.Add(DateTime.Now + "\n" + LogText);
StatusBox.TopIndex = StatusBox.Items.Count - 1;
if (StatusBox.Items.Count > 5000)
{
StatusBox.Items.RemoveAt(0);
}
StatusBox.Update();
}
并且在异常处理代码中添加了以下行:
StatusBox.Invoke(status, e.Message);
对于ResultView,它是一个listview对象,有一些严重的儿童问题(它让不得不以艰难的方式学习这些线程技巧,因为程序在第一次启动时产生了57个异常!):
if (ResultView.InvokeRequired)
{
changeListViewItems my = new changeListViewItems(_changeListViewItems);
ResultView.Invoke(my, mi);
}
这里changeListViewItems是一个委托函数,它接收一个对象,然后将其传递给。
真的很喜欢体验一些多线程应用程序,确实做到了,这非常有趣,处理这么多线程。这实际上是一个简单的任务:必须创建一个委托函数,并为每个线程创建一个实例。还需要使函数只接受一个对象,因为它通常传递一个对象。
还了解到,如果想在它创建的线程之外的线程中使用在另一个线程中创建的对象,必须调用该对象的类的对象的invoke函数,它简单地让访问该对象,正如上面提到的。