如何在 Windows Server 2012 上使用 Active Directory 性能测试工具

大家好,我叫 Tom Ausburne,是一名 Active Directory 专业高级现场工程师。最近有位客户咨询微软是否具有任何执行 Active Directory“压力”测试的工具。下面通过一项简单搜索,带领大家了解这款工具。

Active Directory 性能测试工具 (ADTest.exe)
https://www.microsoft.com/en-us/download/details.aspx?id=15275

在进入系统需求部分之前,您一定会认为这款工具十分完美。

  • 支持的操作系统

Windows 2000 和 Windows Server 2003

支持的操作系统有点老,是吗?Windows Server 2003 R2 主流支持已于 2010 年 7 月 10 日截止,扩展支持也将于 2015 年 7 月 14 日到期。绝大部分公司已经入于过渡阶段。那么 Windows Server 2008、Windows Server 2008 R2、Windows Server 2012 和 Windows Server 2012 R2 呢?这些环境可以运行这款工具吗?

很感谢您的提问。ADTest 工具在较新版本的 Active Directory 上依然可以正常运行。该工具使用 LDAP,因此兼容性不是问题。十全十美,对吗?不要这么快下结论。没错,这款工具的确可以运行,但依据相关文档进行设置的过程却不那么简单。在搜索答案时,我偶然发现了这份白皮书,其中不仅对 ADTest 使用方法进行了讨论,而且还提供了适用于 64 位操作系统的重写配置文件。

64 位版本的 Windows Server 2003 的 Active Directory 性能
https://www.microsoft.com/en-us/download/details.aspx?id=4948

大家可以在这篇文章中发现本文介绍的部分内容,但本文的内容更加简洁明了,下面我们对测试过程进行介绍。我将会假设大家了解 Active Directory 的安装和配置方法,因此不会介绍这些步骤。下面我们来说明一下设置过程,以便大家使用 Server 2012 R2 AD-DS 开始测试这款新硬件。在测试中,我使用的是 Windows Server 2012 R2 以及 Windows 7 和 Windows 8 客户端。

在开始讨论之前,我还想请大家注意的是,微软不再支持这款工具。本文只是为了表明,大家仍然可以在我们发布的较新的操作系统上运行并使用这款工具。

我还想提醒大家的是,由于这款工具会对 Active Directory 做出更改,并会对域控制器产生负载,因此只应在测试环境下使用。无需再为接到大量技术支持呼叫而担忧(由于域控制器太过繁忙而无法登录产生的投诉)!既然已经完全澄清,下面我们就开始介绍。

服务器设置

1. 安装 Active Directory 域服务 (AD-DS)。

2. 设置 dSHeuristics 位,这样可保证将 userPassword 属性视作密码而不是字符串属性。

a. 单击 Start,单击 Run,键入 adsiedit.msc,然后单击 OK

b. 双击 Configuration, CN=Configuration, CN=Services, CN=WindowsNT, CN=Directory Service

c. 右键单击 CN=Directory Service,然后单击 Properties

d. 单击 dSHeuristics

e. 单击 Edit

f. 将第 9 位设置为 1。(例如,将该值更改为 000000001)。

g. 单击 OK

h. 单击 Apply

i. 单击 OK

3. 您需要在服务器允许的范围内增加用户连接数目。MaxUserPort 值可控制应用程序从系统请求任何可用用户端口时使用的最大端口号。

a. 启动 PowerShell(或者,您也可以使用 CMD 窗口,但确实需要习惯使用 PowerShell)。

b. 键入 netsh int ipv4 set dynamicport tcp start=1025 num=64511

您可能会问,“那么修改 TcpWindowSize 呢?”Windows Server 2012、Windows Server 2008 R2 和 Windows Server 2008 已经不再支持 Windows Server 2003 中的这个注册表关键字。

对于允许手动配置资源(如接收缓冲区和发送缓冲区)的网络适配器,应该增加分配的资源。某些网络适配器将接收缓冲区设置为较低容量以便节约内存,控制占用主机的内存的量。值较低会导致数据包丢失及性能降低。因此,对于接收密集型场景,我们建议您将接收缓冲区值设置为最大值。

除此之外,我们建议您将所有设置保留为默认值。该操作系统可以有效自我调整以实现最佳性能。

4. 创建一个 ADTest 用户。在示例中,我创建了一个名为 perftest 的用户。此帐户用于创建组织单元、用户和组,并对 Active Directory 运行压力测试。将此用户设置为 Domain Admins 的成员。默认情况下,x64Performance.ats 脚本中使用的密码为 ss-123456。如果使用其他密码(像我一样),那么请确保修改此文件。您可以在本文末尾查看 x64Performance.ats 文件的内容。

客户端设置

1. 您需要在允许的范围内增加用户连接数。MaxUserPort 值可控制应用程序从系统请求任何可用用户端口时使用的最大端口号。

a. 启动 PowerShell(或者,您也可以使用 CMD 窗口,但确实需要习惯使用 PowerShell)。

b. 键入 netsh int ipv4 set dynamicport tcp start=1025 num=64511

2. 在各客户端上安装 ADTest 工具。您可以在此处获取该工具:
Active Directory 性能测试工具 (ADTest.exe)
https://www.microsoft.com/en-us/download/details.aspx?id=15275
本文中的所有屏幕截图均假设安装位置为 c:\ADTest

3. 将 x64Performance.ats 文件复制到您在测试中使用的各个客户端,并将其置于 ADTest 安装文件夹。您可以在文本末尾获取该文件。

4. 将这些客户端加入域。确保您创建的 ADTest 用户是各台计算机上的本地管理员组的成员。

设置测试环境

在介绍环境设置之前,我想一些用户会问我们为什么不使用 PowerShell 进行全面创建。这个问题问得好。如果具有脚本或希望编写脚本,那么可以使用 PowerShell 创建组织单元、组和用户。您需要使用下文提供的相同名称进行创建,“或者”也可以修改配置文件以反映您创建的结构。我想说明的是,如果这款工具可以在几分钟内创建一切,为什么还要为自己创造这些额外的麻烦?因此,我只需使用这项内置功能。

下面开始操作。在域根目录创建一个名为 BaseOU 的组织单元。在其下创建一个名为 Groups 的组织单元。

 

用于自动创建组织单元结构、用户、组以及向组添加用户的命令相当简单直观。我发现,如果在各项命令中输入刚刚在前面创建的用户名和密码,所有操作会运行得更加顺畅。

要创建 10 个 3 层结构的组织单元,请使用以下命令:

adtest -r NewRoot -f x64Performance.ats -user perftest -password perftest -root 0 -t 10 -sf -e -o newroot.log

 

现在,我们需要添加一些用户。以下命令将向每个团队组织单元添加 1000 名用户。

adtest -r AddUser -f x64Performance.ats -user perftest -password perftest -root 0 -t 10 -sf -e -o adduser.log

我们需要添加一些全局安全组。以下命令将添加 20 个组。

adtest -r AddGlobalSecurityGroup -f x64Performance.ats -user perftest -password perftest -root 0 -t 1 -sf -e -o addgroups.log

最后,向这些安全组添加用户。您可以更改 GROUP=1,以反映您要添加用户的组。

adtest -r AddMembers -f x64Performance.ats -user perftest -password perftest -root 0 -t 1 -sf -e -set GROUP=1 -o addmembers1.log

我执行过多次相关设置,最终只创建了一个包含所有命令的 cmd 文件。您将会发现,我运行过多次 AddMembers 命令,以便将用户添加到不同的组。一旦掌握命令并使其按照您喜欢的方式运行,那么就可以利用这种有效方法快速进行设置。

运行测试

您已经完成全部设置,可以随时运行测试。您需要执行测试的每个客户端上运行此命令:

adtest -r %1 -f x64Performance.ats -user perftest -password perftest -root %2 -t %3 -sf -e

其中:

    • -r 用于指定测试 (%1) 的名称。例如,Search_Base_1Attr       或 update_1attr       都是可能的测试名称。
    • -f 用于指定自定义文件(提供的 x64Performance.ats       脚本),而不是默认 adTest.ats。
    • -user 和 –password 用于识别各台服务器上的管理员组成员。
    • -root 用于指定需要从管理单元结构中的哪个位置开始 (%2)。例如,0 从 ou_0000 开始。
    • -t 用于指定并发运行以生成负载的线程数 (%3)。通常情况下,此数值的范围为 1 到 3,为加快操作可设置为高达 5 或 6,如搜索和牢固绑定。
    • -sf 用于显示测试输出。
    • -e 用于加密指令。

针对每项测试相应地更改这些参数的值。下面是对运行 6 个线程的第一个组织单元执行 NTLM 登录测试的一个示例:

adtest -r NTLM_Logon -f x64Performance.ats -user perftest -password perftest -root 0 -t 6 -sf –e

以下两项测试通过一次性更新并搜索 10 项属性来加重 DC 负载:

adtest -r Update_10Attr -f x64Performance.ats -user perftest -password perftest -root 0 -t 6 -sf -e

adtest -r Search_Base_10Attr -f x64Performance.ats -user perftest -password perftest -root 0 -t 6 -sf -e

您可以通过查询 x64Performance.ats 文件获取可用测试列表。如果要使用此工具查看一些真实的测试结果,请查阅该文档(本文前面也曾引用)以查看 3,000,000 名用户的性能数据。只需记住,它使用的是 Windows Server 2003。

64 位版本的 Windows Server 2003 的 Active Directory 性能
https://www.microsoft.com/en-us/download/details.aspx?id=4948

您可以通过多种方式测量 Active Directory 和新服务器硬件的性能。其中一种方法是使用内置性能监视器。您可以启动 Active Directory Diagnostics,以便在设置和测试期间收集一些有用的信息。

这就产生了一个很好的想法。为生产网络设置性能数据基准一直以来都是一个不错的主意。这是获取相关信息的有效途径。只需在正常工作日(比方说周一上午 7:00 至 10:00)运行该工具,这样就能在运行不正常时进行信息比较。

我不是要偏离主题,但大家一定会发现这些信息非常有用。运行收集器设置后,可以在 Reports 下查看对应的结果。

疑难解答

如果遇到任何问题,可以向任何命令添加调试输出。只需添加 –d 5,然后再次运行该命令即可。

EX: adtest -r NTLM_Logon -f x64Performance.ats -user perftest -password perftest -root 0 -t 6 -sf –e –d 5

在本例中,我发现输出中显示以下错误

----------------------------------------

SYSTEM ERROR
Error: 1326
System Message: The user name or password is incorrect.
Extended Message: Logon Failed for User="u01_000713", Password="password123!",Domain="Hay-Buv"
----------------------------------------

返回查看 x64Performance.ats 文件,仔细研究刚刚运行的测试部分。

然后,查看创建这些用户时设置的密码。大写很重要!

在将密码更改为 Password123! 之后,一切运行正常。我在执行此设置期间遇到的大部分问题均已在调试中得到解决。

有时候,您会因为值设置问题而发生失败。例如,如果根总数 (%2) + 线程数 (%3) 大于最高编号组织单元,就会发生失败。在上面的示例中,如果根是 0,线程数是 11,则会返回错误,因为不存在组织单元 10。

如果大家像我一样,那么很可能会掠过设置说明直接进行测试,因为您已经无数次这样做。若是这样,则可能会遇到一些问题。

  • 如果再运行第一项命令时收到错误,并且随即启用调试,那么可能会看到以下信息:

LDAP ERROR -----------------------------

Host: ADTestSrv. Hay-Buv.local
Extended Message: 00000005: SecErr: DSID-031521E1, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0

-----------------------------------------------

这只是一个简单的例子。您忘记将测试用户添加为 Domain Admins 成员。

  • 现在,一切正常,只是没有创建任何用户。添加 –d 5(调试)命令,将会显示下列类型的错误:

LDAP ERROR -----------------------------

Host: ADTestSrv.Hay-Buv.local
Extended Message: 0000052D: SvcErr: DSID-031A129B, problem 5003 (WILL_NOT_PERFORM), data 0

----------------------------------------------

同样提供一种快速修复方法。您需要将 dSHeuristics 第 9 位的值设置为 1

没有那么难是吗?大多数时候,我们都能为大家出色地提供详尽说明,并且很多建议效果非常好。但是,我们当中的一些用户更倾向于查看“按顺序操作”列表,然后按部就班地完成操作。欢迎来到我的世界!或许我不得不开始多做一些工作,我们将此称为简要计算提示

X64Performance.ats

使用记事本,将以下代码粘贴到一个新文件中。将该文件另存为 x64Performance.ats,并置于 ADTest 安装文件夹中。

//---------------- DEFINES ------------------------//

// [ROOT] is specified on the command line (e.g. -r 32 for [ROOT] = 32)

//Number of users in an organization unit

#define $DefaultRange #(0-299999)

//Users are formatted u0001_0001

#define $Padding ######

#define $UserName u##([ROOT])_$Padding(*)

//Organization Unit Hierarchy

#define $Division ou##([ROOT])_division

#define $Unit ou##([ROOT])_unit

#define $Team ou##([ROOT])_team

#define $DivisionBranch ou=$Division,ou=BaseOU,[DOMAIN]

#define $UnitBranch ou=$Unit,ou=$Division,ou=BaseOU,[DOMAIN]

#define $TeamBranch ou=$Team,ou=$Unit,ou=$Division,ou=BaseOU,[DOMAIN]

#define $FQDN cn=$UserName,ou=$Team,ou=$Unit,ou=$Division,ou=BaseOU,[DOMAIN]

#define $BaseOU ou=BaseOU,[DOMAIN]

#define $GroupOU ou=Groups,ou=BaseOU,[DOMAIN]

//----------------- TESTS ------------------------//

//----------------- AUTHENTICATIONS -------------//

NTLM_Logon

{

TEST [LOGON]

LOOP RAND

RANGE $DefaultRange

DN $UserName

PWD ss-123456!T

OP LOGON32_LOGON_NETWORK

SCOPE LOGON32_PROVIDER_WINNT40

}

Kerberos_Logon

{

TEST [LOGON]

LOOP RAND

RANGE $DefaultRange

DN $UserName

PWD ss-123456!T

OP LOGON32_LOGON_INTERACTIVE

SCOPE LOGON32_PROVIDER_DEFAULT

}

//-------------------- BINDS --------------------------//

Fast_Bind

{

INIT FASTBIND_ON

TEST [BIND]

LOOP RAND

RANGE $DefaultRange

DN $FQDN

PWD ss-123456!T

}

Simple_Bind

{

TEST [BIND]

LOOP RAND

RANGE $DefaultRange

DN $FQDN

PWD ss-123456!T

}

//-------------------- UPDATES --------------------------//

Update_1Attr

{

TEST [MODIFY]

LOOP RAND

OP LDAP_MOD_REPLACE

RANGE $DefaultRange

DN $FQDN

ATTR homePhone:###(0-999)-###(0-999)-####(0-9999)

}

Update_10Attr

{

TEST [MODIFY]

LOOP RAND

OP LDAP_MOD_REPLACE

RANGE $DefaultRange

DN $FQDN

ATTR homePhone:###(0-999)-###(0-999)-####(0-9999)

ATTR pager:###(0-999)-###(0-999)-####(0-9999)

ATTR mobile:###(0-999)-###(0-999)-####(0-9999)

ATTR facsimileTelephoneNumber:###(0-999)-###(0-999)-####(0-9999)

ATTR ipPhone:###(0-999)-###(0-999)-####(0-9999)

ATTR company:Microsoft

ATTR title:Program Manager

ATTR postOfficeBox:101010

ATTR streetAddress:1 Microsoft Way

ATTR postalCode:98052

}

//-------------------- SEARCHES -----------------------//

Search_Base_1Attr

{

TEST [SEARCH]

LOOP RAND

RANGE $DefaultRange

DN $FQDN

FILTER (objectClass=*)

SCOPE LDAP_SCOPE_BASE

ATTR cn

}

Search_Base_10Attr

{

TEST [SEARCH]

LOOP RAND

RANGE $DefaultRange

DN $FQDN

FILTER (objectClass=*)

SCOPE LDAP_SCOPE_BASE

ATTR postalCode;postOfficeBox;preferredLanguage;roomnumber;streetAddress

ATTR homePhone;ipPhone;telephonenumber;title;wWWHomePage

}

Search_One_Level_1Attr

{

TEST [SEARCH]

LOOP RAND

RANGE $DefaultRange

DN $TeamBranch

FILTER (userPrincipalName=$UserName)

SCOPE LDAP_SCOPE_ONELEVEL

ATTR cn

}

Search_One_Level_10Attr

{

TEST [SEARCH]

LOOP RAND

RANGE $DefaultRange

DN $TeamBranch

FILTER (userPrincipalName=$UserName)

SCOPE LDAP_SCOPE_ONELEVEL

ATTR postalCode;postOfficeBox;preferredLanguage;roomnumber;streetAddress

ATTR homePhone;ipPhone;telephonenumber;title;wWWHomePage

}

Search_Subtree_1Attr

{

TEST [SEARCH]

LOOP RAND

RANGE $DefaultRange

DN $BaseOU

FILTER (userPrincipalName=$UserName)

SCOPE LDAP_SCOPE_SUBTREE

ATTR cn

}

Search_Subtree_10Attr

{

TEST [SEARCH]

LOOP RAND

RANGE $DefaultRange

DN $BaseOU

FILTER (userPrincipalName=$UserName)

SCOPE LDAP_SCOPE_SUBTREE

ATTR postalCode;postOfficeBox;preferredLanguage;roomnumber;streetAddress

ATTR homePhone;ipPhone;telephonenumber;title;wWWHomePage

}

Search_NonIndexed_1Attr

{

TEST [SEARCH]

LOOP RAND

RANGE $DefaultRange

DN $BaseOU

FILTER (department=Windows2003CapacityPlanning-####(*))

SCOPE LDAP_SCOPE_SUBTREE

ATTR cn

}

Search_NonIndexed_10Attr

{

TEST [SEARCH]

LOOP RAND

RANGE $DefaultRange

DN $BaseOU

FILTER (department=Windows2003CapacityPlanning-####(*))

SCOPE LDAP_SCOPE_SUBTREE

ATTR postalCode;postOfficeBox;preferredLanguage;roomnumber;streetAddress

ATTR homePhone;ipPhone;telephonenumber;title;wWWHomePage

}

//-------------------- SETUP --------------------------//

// Note: Order of these tests is not important but are processed more

// quickly at startup time if you define the inner tests first (e.g., AddDivision)

// and the outer tests second (e.g., NewRoot).

// Use NewRoot to run AddDivision, AddUnit and AddTeam all at once

AddDivision

{

TEST [ADD]

LOOP SEQ | ONCE

OP LDAP_MOD_ADD

DN $DivisionBranch

ATTR ObjectClass:organizationalUnit

ATTR name:$Division

ATTR instanceType:4

}

AddUnit

{

TEST [ADD]

LOOP SEQ | ONCE

OP LDAP_MOD_ADD

DN $UnitBranch

ATTR ObjectClass:organizationalUnit

ATTR name:$Unit

ATTR instanceType:4

}

AddTeam

{

TEST [ADD]

LOOP SEQ | ONCE

OP LDAP_MOD_ADD

DN $TeamBranch

ATTR ObjectClass:organizationalUnit

ATTR name:$Team

ATTR instanceType:4

}

// Typically run adtest -run newroot -root # where # is the root you want

NewRoot

{

RANGE #(1)

LOOP SEQ | ONCE

TEST AddDivision

TEST AddUnit

TEST AddTeam

}

AddUser

{

TEST [ADD]

LOOP SEQ | ONCE

OP LDAP_MOD_ADD

RANGE $DefaultRange

DN $FQDN

ATTR ObjectClass:user

ATTR userAccountControl:66048

ATTR cn:$UserName

ATTR SAMAccountName:$UserName

ATTR userPrincipalName:$UserName

ATTR aCSPolicyName:UnicodeString

ATTR adminCount:1

ATTR adminDescription:Uni

ATTR adminDisplayName:Uni

ATTR comment:Uni

ATTR company:Microsoft

ATTR CountryCode:8

ATTR department:Windows2003CapacityPlanning-$Padding(*)

ATTR description:Uni

ATTR desktopProfile:UnicodeString

ATTR destinationIndicator:PrintableString

ATTR displayName:$UserName

ATTR displayNamePrintable:UniP

ATTR division:Uni

ATTR employeeID:Uni

ATTR extensionName:23456

ATTR facsimileTelephoneNumber:425-555-1227

ATTR givenName:$UserName

ATTR groupPriority:UnicodeString

ATTR homeDirectory:UnicodeString

ATTR homeDrive:Uni

ATTR homePhone:425-555-1218

ATTR ipPhone:425-555-1217

ATTR initials:Uni

ATTR maxStorage:300000

ATTR mhsORAddress:Uni

ATTR mobile:425-555-1216

ATTR otherHomePhone:425-555-1215

ATTR otherIpPhone:Uni

ATTR otherMailbox:Uni

ATTR otherMobile:425-555-1213

ATTR otherPager:425-555-1214

ATTR otherTelephone:425-555-1220

ATTR pager:425-555-1219

ATTR personalTitle:PM

ATTR physicalDeliveryOfficeName:Uni

ATTR postalAddress:Uni

ATTR postalCode:Uni

ATTR postOfficeBox:Uni

ATTR preferredLanguage:English

ATTR roomnumber:1326

ATTR streetAddress:Uni

ATTR telephonenumber:425-555-1212

ATTR title:SDE

ATTR wWWHomePage:www.microsoft.com

ATTR userPassword:ss-123456!T

}

AddGlobalDistributionGroup

{

TEST [ADD]

LOOP SEQ | ONCE

OP LDAP_MOD_ADD

RANGE #(0-25)

DN cn=GrpAcc_$Padding(*),$GroupOU

ATTR ObjectClass:group

ATTR groupType:2

ATTR name:GrpAcc_$Padding(*)

ATTR sAMAccountName:GrpAcc_$Padding(*)

ATTR instanceType:4

}

AddGlobalSecurityGroup

{

TEST [ADD]

LOOP SEQ | ONCE

OP LDAP_MOD_ADD

RANGE #(26-50)

DN cn=GrpAcc_$Padding(*),$GroupOU

ATTR ObjectClass:group

ATTR groupType:2147483650

ATTR name:GrpAcc_$Padding(*)

ATTR sAMAccountName:GrpAcc_$Padding(*)

ATTR instanceType:4

}

AddMembers

{

TEST [MODIFY]

LOOP SEQ | ONCE

OP LDAP_MOD_ADD

RANGE $DefaultRange

DN cn=GrpAcc_$Padding([GROUP]),$GroupOU

ATTR member:$FQDN

}

-Tom Ausburne