Active Directory 复制原理
为了结合以下示例进行说明,我们将只讨论站点内复制。基本上,站点内复制旨在将更改快速复制到同一站点的 DC 内,然后使用更改通知来执行。在站点内复制的情况下,DC1 将通知 DC2 有需要复制的更改,然后 DC2 从 DC1 中拉出这些更改。同样,当 DC2 有任何更改时,它也会通知 DC1,然后 DC1 从 DC2 中拉出这些更改。您可以看到,所有的 Active Directory 复制都通过“拉”操作而不是“推”操作进行。
因为 Active Directory 可扩展至几十万甚至数百万个对象,所以有必要将 Active Directory 数据库划分为多个部分(称为命名上下文)。每个域控制器可在 Active Directory 数据库的本地副本中存储至少三个 NC。
架构 NC 此 NC 将被复制到林中的其他各个域控制器中。它包含有关 Active Directory 架构的信息,该信息又定义了 Active Directory 内不同的对象类和属性。
配置 NC 此 NC 也会被复制到林中的其他各个 DC 中,它包含林范围内有关 Active Directory 的物理布局的配置信息,以及有关显示标识符和林范围内 Active Directory 配额的信息。
域 NC 此 NC 将被复制到单个 Active Directory 域中的其他各个 DC 中。正是此 NC 中包含最常访问的 Active Directory 数据:实际用户、组、计算机以及其他驻留在特定 Active Directory 域中的对象。
为了更好地优化复制通信量,将单独复制每个命名上下文,以使更改不频繁的 NC(如架构 NC)不占用域 NC(更改很可能更加频繁)所需的网络带宽。
由于可从任何 Active Directory DC 进行目录更改,因此 Active Directory 复制需要跟踪两种类型的写入操作。一种类型是原始写入,在直接对特定 DC 执行特定更改时进行的写入。例如,如果您连接到 DC1 并更改用户的密码,此更改便被视为 DC1 上的原始写入。Active Directory 还必须跟踪复制的写入,正如您能想像到的,这表示会将特定更改从其他域控制器中复制过来。被视为 DC1 上的原始写入的更改在被复制到 DC2、DC3 以及域范围内的其他任何 DC 中后,便被视为复制的写入。
Active Directory 域控制器通过使用复制元数据管理目录更改的传输。这表示 Active Directory 除了将已更改的实际数据从一个 DC 传输到另一个 DC(对 John Smith 的描述更改为“人力资源主管”),还会传递关于该更改的其他信息(如更改源自的 DC、进行更改的时间以及其他关键信息)以使域控制器以最高效的方式管理复制。
我们要讨论的第一个复制元数据项目是更新序列号 (USN)。每个域控制器都维护特定于该域控制器的 USN。每当从该 DC 对 Active Directory 进行更改,USN 都会增加 1。因此如果某 DC 的 USN 在上午 11:00 时为 1000,而在上午 11:30 时为 1005,您就会知道已在该 DC 上对 Active Directory 数据库进行了 5 次更改。事实上,进行什么样的更改对 USN 来说并不重要 ― 您可以修改 5 个不同的对象、创建 5 个对象、删除 5 个对象或前述操作的任意组合,该 DC 的 USN 都会增加 5。此外,USN 仅是特定域控制器的内部项目,与其他 DC 相比较时没有任何参考价值。域中的某个 DC 可能在上午 11:30 时进行更改,并指定 USN 为 1051;而相同域的另一个 DC 可能在同一时刻进行更改,并指定 USN 为 5084。尽管两个 DC 对于几乎同时进行的更改很明显具有完全不同的 USN,但这与如何复制这些更改并不相关;就不同变更之间的比较来说,某个 DC 的更新序列号对其他任何 DC 而言都毫无意义。
但这并不是增加 DC 的 USN 的唯一方式。请记住,对 Active Directory 数据库的更改可包括原始写入或复制的写入。两种类型的写入操作都可增加域控制器上的更新序列号,这意味着每当从其他 DC 复制了更改时,该序列号都会增加。现在,很明显可以看出,每个 DC 都需要一种方法来跟踪已复制的更改,否则每个 DC 在每次复制时都会通过缆线发送整个 Active Directory 数据库。为避免发生这种情况,每个 Active Directory 域控制器都为其他用于进行复制的域控制器维持一个称为高水准矢量 (HWMV) 的值。每个 DC 都将此高水准矢量与远程 DC 的全局唯一标识符 (GUID) 相关联,以防止在远程域控制器被重命名或从目录中删除后产生混淆。
我们从一个简单的示例开始,假设您在 contoso.com 域中配置了两个域控制器 dc1.contoso.com 和 dc2.contoso.com。因为 contoso.com 域中只有两个 DC,所以 DC1 和 DC2 只能彼此复制。(请注意这只是一个简化的示例,并不能完全说明 Active Directory 复制的所有细节。随着讲述的深入,我们会添加更多详细信息。)
我们再假设 DC1 的当前 USN 为 3000,DC2 的当前 USN 为 4500,在开始我们的示例时两个 DC 对彼此而言都已处于最新状态:
步骤 1:DC1 和 DC2 对彼此而言均处于最新状态。DC1 对于 DC2 的高水准矢量为 4500,DC2 对于 DC1 的高水准矢量为 3000
管理员在 DC1 上创建了一个新对象,DC1 的 USN 增加到了 3001,如图 2 所示。请注意 DC1 针对 DC2 的 HWMV 没有更改,因为 DC1 尚未通知 DC2 自己有正等待中的更改
DC1 通知 DC2 自己有可用更改。随后 DC2 启动对 DC1 的复制来请求任何可用的更新。作为此请求的一部分,DC2 将向 DC1 发送其针对 DC1 存储的高水准矢量,如图 3 所示。
步骤 4:DC1 向 DC2 发送与 USN 3001 相对应的更改,即在步骤 2 中在 DC1 上创建的对象。DC2 将自己的 USN 更新为 4501 并将针对 DC1 的 HWMV 更新为 3001,如图 4 所示。
图 4 更改和更新 (单击该图像获得较小视图)
到目前为止都没有问题吧?但现在问题就来了。DC2 有一个需要复制的更改。如果原来进行的只是 USN 和高水准矢量的更改,那么现在 DC2 要联系 DC1 以将 DC1 刚才复制到 DC2 的相同更改复制回 DC1,这将形成一个无穷的复制循环,并会不断占据越来越多的带宽。为防止此种情况,我们需要再多用几个矢量来解决难题,第一个是最新矢量(UTD 矢量或 UTDV)。
UTDV 是另一个用于强化抑制的复制元数据,即其目的是防止相同的更改通过网络一再重复被复制而耗费带宽。每个 DC 针对其他每个 DC 维护一个 UTDV 表,其中存储相关命名上下文的副本。对于域 NC,域中的各个 DC 针对该域中的每个 DC 维护一个 UTDV;对于配置和架构 NC,则针对林中的每个 DC 维护一个 UTDV。该 UTDV 表不仅会跟踪每个 DC 从其复制合作伙伴接收的最大 USN,还会跟踪从复制给定 NC 的各个 DC 中接收的最大 USN 值。为此,每个复制的更改还需要包括以下信息:
要复制更改的 DC 的 GUID。这个要复制的更改可以是原始写入或复制的写入。
要从中复制更改的 DC 的 USN。同样,此更改既可以来自原始写入,也可以来自复制的写入。
引起更改的 DC 的 GUID。如果此 GUID 与复制更改 DC 的 GUID 相同,表明它是原始写入。否则,UTDV 表就起作用了。
引起更改的 DC 的 USN。同样,如果此 USN 与复制更改的 DC 的 USN 相同,就表明这是原始写入。否则,它就不是 UTDV 表。
为了更好的说明此过程,我们添加第三方域控制器 (DC3) 增加示例的复杂性。在本示例中,DC1、DC2 和 DC3 是相互的复制伙伴;DC1 与 DC2 和 DC3 互相复制,DC2 与 DC1 和 DC3 互相复制,DC3 与 DC1 和 DC2 互相复制:
步骤 1:DC1、DC2 和 DC3 对彼此而言都处于最新状态。
步骤 2:DC3 通过重置 jsmith 用户帐户的密码执行单个原始写入。DC3 通知 DC1 和 DC2 自己有可用更改。DC1 和 DC2 从 DC3 拉出原始写入,然后更新各自针对 DC3 的 HWMV 和 UTDV 表,如图 5 所示。
图 5 更新 HWMV 和 UTDV 表 (单击该图像获得较小视图)
步骤 4:当 DC2 通知 DC3 自己有可用更改时以及当 DC1 以类似方式通知 DC2 和 DC3 时,便会发生相同的传播抑制情况。这三个 DC 将更新各自针对自已的复制伙伴的 HWMV 条目,如图 8 所示,但因为实际数据已在步骤 2 中传送到各个 DC,所以不会再度通过缆线传输。
多主机环境中的冲突解决方案
到目前为止,我们的示例依然存于一个完美的世界中,每次只有一个管理员对 DC 进行更改,从不会出现冲突情况。我们知道这在现实世界中很罕见。既然对 Active Directory 对象的更新可以来自域中的任何域控制器,那么,如果两个管理员从两个不同域控制器执行的更新相互冲突时会发生什么情况?Active Directory 环境中可能发生三种类型的冲突,它们使用不同的冲突解决方案方法。
冲突的属性变更 . 如果两名管理员用相互冲突的方式更新相同的对象,便会发生此类型的冲突:一名管理员将用户描述设置为“市场”,另外一名管理员在另一 DC 上将用户描述设置为“销售和市场”。
创建冲突的新对象 . 如果两个管理员同时使用相同的名称创建对象,例如,两个名为 jsmith 的用户,便会发生此类型的冲突。
将对象移动到删除的容器 . 这种类型的冲突较为少见,如果管理员在容器内(例如,OU)创建或移动对象,与此同时另一名管理员在另一 DC 上删除了该容器,便会发生此类型的冲突。
为了解决前两种类型的冲突,下面介绍另外两个主要用于冲突解决方案的复制源数据。为对象中每个单独的属性分配 versionID 值,初次创建对象时,该值的起始值为 1。只要一修改任意 DC 中的某个属性,versionID 就会增加 1。因此如果特定用户的描述属性已从默认值(空白或 <未设置>)更新为“市场部”,则描述属性的 versionID 会变成 2。如果稍后该描述修订为“销售和市场部”,则描述属性的 versionID 会变成 3,依此类推。此 VersionID 与我们之前介绍的其他元数据一起包含在每个复制项目中。
此 versionID 也可用于进一步减少复制通信量。例如,如果 DC2 上的管理员已对某个属性进行多次更改(可能该管理员几次键入错误更改),使 DC2 具有与 versionIDs 2、3、 4、和 5 对应的原始写入,在此情况下 DC2 将仅复制与最后一个版本 versionID 5 相对应的写入。由于早期更改难逃被覆盖的命运,因此这样可便捷地减少不必要的带宽占用。
对 Active Directory 所做的每个更改中还包含冲突解决方案使用的第二个附加元数据,这是一个时间戳,属于复制元数据的一部分,指示修改是何时进行的。
也可将时间戳属性用作检测 Active Directory 复制运行情况的主动措施。如果 DC 使用相对较新的时间戳未发现特定 DC 中有任何更改,就会开始生成错误消息指示相关 DC 中可能存在问题。
那么,如何在冲突解决方案中使用这两个属性?我们来依次检查每种冲突类型。