使用 USNChanged 轮询更改
DirSync 控件功能强大且高效,但有两个重大限制:
- 仅适用于高特权应用程序:若要使用 DirSync 控件,应用程序必须在具有域控制器 SE_SYNC_AGENT_NAME 权限的帐户下运行。 很少有帐户具有很高的特权,因此普通用户无法运行使用 DirSync 控件的应用程序。
- 无子树范围:DirSync 控件返回命名上下文中发生的所有更改。 仅对命名上下文的小型子树中发生的更改感兴趣的应用程序必须经过许多不相关的更改,这对于应用程序和域控制器来说都是低效的。
还可以通过查询 uSNChanged 属性来获取 Active Directory 中的更改,从而避免 DirSync 控件的限制。 此替代方法并非优于 DirSync 控件,因为它涉及在发生任何属性更改时传输所有属性,并且它要求应用程序开发人员执行更多工作才能正确处理某些故障方案。 目前,这是编写某些更改跟踪应用程序的最佳方法。
当域控制器修改对象时,它将该对象的 uSNChanged 属性设置为大于该对象的 uSNChanged 属性先前值的值,并且大于该域控制器上保留的所有其他对象的 uSNChanged 属性的当前值。 因此,应用程序可以通过查找具有最大 uSNChanged 值的对象,在域控制器上查找最近更改的对象。 域控制器上最近更改的第二个对象将具有第二个最大的 uSNChanged 值,等等。
不会复制 uSNChanged 属性,因此在两个不同的域控制器上读取对象的 uSNChanged 属性通常会给出不同的值。
例如, uSNChanged 属性可用于跟踪子树 S 中的更改。首先,执行子树 S 的“完全同步”。假设 S 中任意对象的最大 uSNChanged 值是 U。定期查询子树 S 中的所有对象,其 uSNChanged 值大于 U。查询将返回自完全同步以来已更改的所有对象。将你设置为这些已更改对象中最大的 uSNChanged ,并且你已准备好再次轮询。
实现 uSNChanged 同步应用程序的微妙之处包括:
使用 rootDSE 的最高CommittedUSN 属性绑定 uSNChanged 筛选器。 也就是说,在启动完全同步之前,读取关联域控制器 的最高CommittedUSN 。 然后,使用分页结果执行完全同步查询 (,) 初始化数据库。 完成此操作后,在完全同步查询之前存储读取 的最高CommittedUSN 值;用作下一次同步的 uSNChanged 属性的下限。 稍后,若要执行增量同步,请重新读取 最高CommittedUSN rootDSE 属性。 然后使用分页结果查询相关对象,其 uSNChanged 大于从上一次同步保存的 uSNChanged 属性值的下限。 使用此信息更新数据库。 完成后,从增量同步查询之前读取的最高CommittedUSN 值更新 uSNChanged 属性的下限。 始终将 uSNChanged 属性值的下限存储在应用程序与域控制器内容同步的同一存储中。
遵循此过程,而不是基于所检索对象的 uSNChanged 值,避免使服务器重新复查更新的对象超出适用于应用程序的集。
由于 uSNChanged 是一个非复制属性,因此应用程序每次运行时都必须绑定到同一域控制器。 如果它无法绑定到该域控制器,则它必须等到它才能执行此操作,或者与某些新域控制器关联,并与该域控制器执行完全同步。 当应用程序关联到域控制器时,它会在稳定存储中记录该域控制器的 DNS 名称,这是与域控制器内容保持一致的存储。 然后,它使用存储的 DNS 名称绑定到同一域控制器进行后续同步。
应用程序必须检测它当前所属的域控制器何时已从备份还原,因为这可能会导致不一致。 当应用程序与域控制器关联时,它会缓存稳定存储中该域控制器的“调用 ID”,也就是说,它与域控制器内容保持一致。 域控制器的“调用 ID”是存储在域控制器服务对象的 调用ID 属性中的 GUID。 若要获取域控制器的服务对象的可分辨名称,请阅读 rootDSE 的 dsServiceName 属性。
请注意,从备份还原应用程序的稳定存储时,没有一致性问题,因为域控制器名称、调用 ID 和 uSNChanged 属性值的下限与与域控制器内容同步的数据一起存储。
查询服务器时使用分页(完整同步和增量同步)以避免同时检索大型结果集的可能性。 有关详细信息,请参阅 “指定其他搜索选项”。
执行基于索引的查询,以避免在使用分页结果时强制服务器存储大型中间结果。 有关详细信息,请参阅 索引属性。
通常,不要使用服务器端对搜索结果进行排序,这可以强制服务器存储和排序大型中间结果。 这同时适用于完整同步和增量同步。 有关详细信息,请参阅 “指定其他搜索选项”。
正常处理任何父条件。 应用程序可以在识别其父对象之前识别对象。 根据应用程序,这可能或可能不是问题。 应用程序始终可以从目录中读取父级的当前状态。
若要处理移动或删除的对象,请存储每个跟踪对象的 objectGUID 属性。 无论对象在整个林中移动的位置, 对象的 objectGUID 属性保持不变。
若要处理移动的对象,请执行定期完全同步或增加搜索范围,并在客户端端筛选出不感兴趣的更改。
若要处理已删除的对象,请定期执行完全同步,或者在执行增量同步时对已删除的对象执行单独的搜索。 查询已删除的对象时,检索已删除对象的 objectGUID ,以确定要从数据库中删除的对象。 有关详细信息,请参阅 检索已删除的对象。
请注意,搜索结果仅包括调用方有权根据) 各个对象的安全描述符和 DACL 读取 (的对象和属性。 有关详细信息,请参阅 安全性对查询的影响。
有关详细信息,以及显示 USNChanged 同步应用程序的基础知识的代码示例,请参阅 使用 USNChanged 检索更改的示例代码。