Hoy quería hablaros un poco de cómo funciona la replicación en Active Directory (AD). Habíamos visto en el artículo sobre los FSMO roles que los Domain Controllers funcionan en modo multi-master, es decir, que podemos hacer cambios como modificar un usuario o cambiar el grupo al que pertenece en cualquier Domain Controller (DC) y esta información será la misma en todos ellos, es decir, se replicará.
Sin embargo, a pesar de que la mayor parte de la información relativa a los usuarios, grupos u otros objetos es la misma en todos los DCs, encontrarás que hay algunas diferencias entre ellos, como por ejemplo el USN (Update Sequence Number) que es un número de 64 bits y que tiene que ver con el seguimiento que hace AD de la versión de ese objeto.
Nota: Alguna vez me han preguntado que pasaría si alcanzásemos el máximo valor posible del USN, pues, obviamente, tendríamos un problema ya que nuestro AD no podría continuar replicando y tendríamos quizás que reinstalar nuestro Forest. Lo cierto es que con 64 bits… haciendo 100 cambios por segundo tendríamos 5 billones de años aún por delante hasta llegar al máximo, así que, no es algo que nos deba preocupar de momento 🙂 .
AD necesita asegurarse de que cuando un objeto se cambie en un DC, se cambie en todos los demás. A este proceso le llamamos replicación.
¿Cómo funciona la replicación?
Nos podemos encontrar con dos escenarios diferentes, cuando tenemos a todos los DCs en el mismo Site: Replicación Intrasite; y cuando tenemos los DCs en diferentes Sites: Replicación Intersite.
Nota: Un Site es la forma que tenemos en AD de representar una ubicación física, por ejemplo una sucursal, delegación u oficina remota de la organización. Podemos configurar y ver los diferentes Sites de nuestra organización en la consola AD Sites and Services, en la imagen siguiente vemos el Site que se crea por defecto llamado Default-First-Site-Name, el cual en este ejemplo contiene un solo DC.

Replicación Intrasite:
En el siguiente ejemplo tenemos un escenario con 3 DCs ubicados en el Site A-Coruña, los cuales todos replican entre sí:

El sentido de las flechas indican que hay dos procesos de replicación distintos: en un sentido y en el otro (entrante y saliente), consiguiendo finalmente una replicación bidireccional entre todos los DCs. Desde AD Sites and Services:

Podemos comprobar que automáticamente se crean unos «conectores de replicación» entre los distintos DCs:

Con lo que vemos que la replicación tiene lugar entre pares de DCs:
DC1-DC2
DC2-DC3
DC3-DC1
¿Quién crea estos conectores? Pues hay un proceso en AD llamado Knowledge Consistency Checker (KCC) que se encarga de ello. Tiene como responsabilidad crear y mantener los conectores de replicación ante posibles cambios en la topología de nuestra organización. Hablaremos más adelante de ello.
Vamos a ver qué ocurre cuando hacemos un cambio en un DC, es decir, cómo ese cambio se replica a los demás DCs. Es importante resaltar que la replicación ocurre entre pares de DCs, es decir, entre 2 DCs en un solo sentido por cada transacción.
Cuando hacemos un cambio en un DC cualquiera, por ejemplo, si creamos un usuario en el DC1, este se guardará en la base de datos del DC1, y le será asignado un USN. Un USN no es más que un valor numérico que se asigna de forma secuencial, incrementándose en 1 con cada cambio. Son únicos para cada DC, es decir, no hay relación entre los USNs de distintos DCs y en ningún caso se decrementan o reutilizan (salvo cuando restauramos de un backup).
Cada par de DCs mantiene su propia conversación de replicación, la cual extrae información de dos tablas de valores: «High-Watermark Vector» y «Up-To-Dateness Vector».
El High-Watermark Vector (HWMV) es el valor USN más alto que un DC ha recibido desde un partner de replicación directo. Cada DC mantiene una tabla con estos valores.
El Up-To-Dateness Vector (UTDV) es el valor USN más alto que un DC ha recibido de otro DC cualquiera. Cada DC mantiene una tabla de Up-To-Dateness Vector de cada uno de los DCs que existen o han existido en el forest. Esta tabla también contiene una marca de tiempo (timestamp) de la última vez que el DC replicó satisfactoriamente con cada uno de esos DCs.
Vamos a verlo mejor con un ejemplo sencillo, tenemos 2 DCs: DC1 y DC2, crearemos un objeto en el DC1 que se replicará al DC2 (sentido de la replicación desde DC1 a DC2). El cambio que realizamos en el DC1 se considera un «Originating Write», mientras que el DC que recibirá dicho cambio se considera «Replicated Write».
En un momento dado, ó en intervalos de una hora si no ha tenido lugar ningún cambio antes, DC2 envía una solicitud a DC1 preguntando si hubo algún cambio (si hubiese algún cambio antes de este tiempo en DC1, éste notificaría a DC2 para que se iniciase la replicación). Como curiosidad, la replicación dentro de un mismo Site tarda 15 segundos en notificar un cambio, esto es así para que puedan producirse más cambios (objetos a replicar) dentro de una misma transacción, y si hubiera más de un partner de replicación los iría notificando con incrementos de 3 segundos a cada uno de esos partners. A efectos prácticos se considera que la replicación Intrasite es instantánea. En nuestro ejemplo sólo hay un partner que sería DC2.
Cuando DC2 hace la solicitud envía también la siguiente información (entre otras cosas):
– El USN del DC1 que almacena en su propio HWMV
– El USN del DC1 que almacena en su propio UTDV
Con esta información, DC1 comprueba que objetos necesita replicar al DC2. Para ello compara su USN más alto con el HWMV recibido del DC2. Cualquier objeto con un USN mayor que el HWMV necesita ser replicado. Estos objetos se replican al DC2 y reciben un USN en dicho DC2. El HWMV del DC2 para el DC1 se actualiza para reflejar el USN del DC1 que se ha recibido.
Si por ejemplo se hubiesen creado varios usuarios y estos se replicasen al DC2 en una misma transacción, el USN del DC2 se incrementaría también en 1 ya que sería una única transacción.
Se dice que la replicación de AD es «one-way pull replication» ya que el DC que necesita los cambios (DC2 en nuestro ejemplo) está en contacto con el partner de replicación (DC1). Es el DC de origen (DC1) el que selecciona los cambios que el DC de destino necesita (DC2). De esta forma se evita que circule información innecesaria por el proceso de replicación.
Esta sería la situación inicial (los USNs y valores de los vectores son ficticios) en donde los dos DCs tienen la misma información:
|
DC1 |
DC2 |
USN |
1000 |
2000 |
High-Watermark Vector |
2000 |
1000 |
Up-To-Dateness Vector |
2000 |
1000 |
Creamos un usuario en el DC1, con lo que se incrementa su USN en 1:
|
DC1 |
DC2 |
USN |
1001 |
2000 |
High-Watermark Vector |
2000 |
1000 |
Up-To-Dateness Vector |
2000 |
1000 |
Es en este punto, justo después de recibir la solicitud de cambios del DC2, donde DC1 comprueba los objetos a replicar al DC2, por lo que compara su USN (1001) con el HWMV recibido (1000), y al ser superior, el objeto con el USN 1001 se replica a DC2.
El USN en DC2 se incrementa al mismo tiempo que los valores de HWMV y UTDV se envían desde DC1 a DC2:
|
DC1 |
DC2 |
USN |
1001 |
2001 |
High-Watermark Vector |
2000 |
1001 |
Up-To-Dateness Vector |
2000 |
1001 |
Hasta aquí todo parece ir bien pero hay un problema: tenemos el objeto replicado en DC2 pero éste tiene un USN nuevo (2001) que además es mayor que el HWMV que almacena el DC1 (2000), por lo que siguiendo el funcionamiento anterior, tendría que replicarse a DC1, en donde se le daría un nuevo USN, que volvería a ser superior al HWMV que almacenaría el DC2 con lo que tendría que volver a replicarse, etc. Es decir, tendríamos un bucle infinito y nuestra replicación de AD colapsaría.
Para solventar este problema se utiliza el UTDV y los «replication metadata» de los objetos. Cuando el DC2 decide que cambios necesita enviar al DC1 mira el valor de UTDV y filtra cualquier objeto que tenga un «Originating USN» igual o inferior porque eso significaría que el DC1 ya contiene ese objeto actualizado.
Hay una serie de metadatos que se guardan con los objetos, por ejemplo el «Originating DSA» o el «Originating USN», los cuales se utilizan para comparar con el UTDV y filtrar del proceso de replicación objetos que el DC de destino ya contiene. El «Originating USN» como su propio nombre indica es el USN asignado por el DC en el cual se creó o actualizó el objeto.
Vamos a entenderlo mejor partiendo del ejemplo anterior. Ahora vamos a crear un nuevo usuario pero esta vez en DC2, por lo que su USN se incrementa en 1:
|
DC1 |
DC2 |
USN |
1001 |
2002 |
High-Watermark Vector |
2000 |
1001 |
Up-To-Dateness Vector |
2000 |
1001 |
DC2 notifica a DC1 que hay cambios por lo que DC1 envía la solicitud incluyendo su HWMV con un valor de 2000, DC2 compara su propio USN 2002 con el HWMV recibido por lo que todos los objetos con USNs superiores a 2000 serán replicados (en este caso el 2001 sería el usuario creado previamente en DC1 y el 2002 el nuevo usuario creado directamente en DC2). Sin embargo, como el DC2 almacena un UTDV del DC1 de 1001, va a filtrar todos los objetos con un «Originating USN» de 1001, es decir, el objeto con USN 2001 no se enviará, ya que su «Originating USN» tiene un valor de 1001, significando que fue creado en el DC1 y ya contiene todos los cambios actualizados para ese objeto.
Finalmente la tabla quedaría así después de replicar:
|
DC1 |
DC2 |
USN |
1002 |
2002 |
High-Watermark Vector |
2002 |
1001 |
Up-To-Dateness Vector |
2002 |
1001 |
No es fácil de entender por lo que te animo a que pienses mentalmente que ocurriría en este estado final si cualquiera de los dos DCs enviasen una solicitud de cambios (aún sin producirse ninguno).
Y si en vez de 2 DCs tenemos 3, como en la imagen que os puse al principio del artículo? Aquí se complican las cosas, pero básicamente sería lo mismo… Si creamos un usuario en el DC1, este se replicará directamente al DC2 y al DC3, recordando los pares:
DC1-DC2
DC3-DC1
DC2-DC3
Qué ocurrirá cuando DC2 intente replicar con DC3? Pues básicamente no replicará al usuario ya que DC3 ya lo tendrá como bien indicará su UTDV.
Si queréis hacer algunas pruebas en vuestros laboratorios os dejo estas pequeñas prácticas para que podáis ver algunos de los valores interesantes que intervienen en la ecuación:
Como encontrar el USN más alto de un DC:
El atributo «highestCommittedUSN» del objeto RootDSE contiene el USN más alto que se incrementará con cada transacción (original o replicada).
Lo podéis ver con el cmdlet «Get-ADRootDSE» o bien desde ADSI Edit:

Desde ADSI Edit:

En propiedades:

Ver los USN de un objeto:
Os animo a que hagáis la siguiente prueba: Teniendo un escenario con 2 DCs en el mismo Site, crear un usuario «test» en el primer DC y ver sus distintos USN y metadatos desde ambos DCs.
Desde Users and Computers (recordad siempre tener habilitado la vista avanzada):

En propiedades:

Aquí os encontraréis dos valores para el USN:
– uSNCreated: contiene el USN del objeto en el momento de la creación del mismo
– uSNChanged: contiene el USN del objeto en el momento de su último cambio
Fijaros además que tenéis los «timestamps» de ambos momentos, cuando se creó y cuando cambió por última vez. Los valores de USN en este caso son distintos por apenas 5 cambios (25638 -25633) pese a que yo no cambié nada de mi usuario «test».
Si queremos ver que cambios se han producido en mi usuario «test» podemos ver sus metadatos con el siguiente comando:
repadmin /showobjmeta [DC Name] [distinguished Name]

Podemos ver que el último cambio es en el atributo «userAccountControl» con un valor de 25638. Se comprueba también que algunos atributos siguen con su USN de creación 25633. Vemos también que el «Local USN» coincide con el «Originating USN» ya que el usuario ha sido creado en el DC1. Y también vemos el «Originating DSA» (DSA = Directory Service Agent) que identifica a la base de datos del DC en el cual se creó o modificó ese objeto o atributo. Este «Originating DSA» no es más que el «objectGUID» de la base de datos NTDS del DC1, lo podemos comprobar desde «Sites and Services»:

Si utilizamos Ldp:
1. Ejecuta ldp.exe
2. Selecciona Connection – Connect.
3. En «Server» indica el nombre del DC o dominio que contiene al objeto, en mi caso DC1.
4. Puerto 389 y click OK.
5. Ahora te vas al menú y seleccionas Connection – Bind.
6. Introduces credenciales (si es necesario) de un usuario que pueda ver el objeto y click OK.
7. Desde el menú, selecciona Browse – Replication – View Metadata.
8. En «Object DN» introduces el Distinguished Name del objeto en cuestión, en mi ejemplo «cn=test,cn=users,dc=itadmins,dc=es»
Verás un resultado similar al proporcionado por el comando anterior «repadmin /showobjmeta» en el cual puedes observar que el Originating DSA coincide con nuestro objectGUID de la base de datos NTDS del DC1:

Este GUID de la base de datos NTDS se establece en la promoción del propio DC y no cambia, sin embargo existe otro atributo llamado «invocationId» que se utiliza en el proceso de replicación y que normalmente coincide con el objectGUID como vemos en la siguiente imagen:

Sin embargo, este valor sí que puede cambiar bajo determinadas circunstancias como por ejemplo cuando se hace una restauración de un DC desde un Backup (en el cual se vuelve 0 para asegurarse de que recibe todos los cambios que se hayan producido desde que se hizo la copia de seguridad). Un problema común que nos solemos encontrar aquí es el del USN rollback.
Volviendo a los metadatos y ya para terminar… si lanzamos el mismo comando anterior pero esta vez en el DC2 veremos que los «Originating USN» coinciden con los de nuestro DC1 para todos los atributos que fueron creados en el DC1 excepto el «cn» que se crea en el DC2. Además vemos que nuestro DC2 lleva un USN local totalmente distinto al USN local de nuestro DC1 (recordamos que cada DC lleva su propio USN).

Como vemos, un objeto contiene múltiples atributos y cada uno tiene un USN. Con esto se consigue que por ejemplo cuando cambiamos la contraseña de un usuario sólo se repliquen los atributos necesarios para ello, dejando los demás sin replicar y con ello optimizando el rendimiento de la replicación.
Esto ha sido todo por hoy, llevaba bastante tiempo sin publicar debido al covid (espero que todos estén bien) y aunque creo que es un tema interesante, es a la vez complicado de entender. Por si fuera poco, aún hay más variables en la ecuación y tenemos que hablar entre otras cosas de la replicación Intersite o cómo comprobar que la replicación está funcionando correctamente, pero como es un tema extenso lo dejaremos para el próximo o próximos artículos.
Un saludo y cuídense! 🙂
Grande Maseda!
🙂
Muy buena explicación. Aunque es un poco complicado entender como bien dices, pienso que la mejor forma de entenderlo es plantearte el problema realmente, para luego ver la solución que ofrece cada objeto según las variables que tengan al momento de replicarse.
Gracias Freddy! Totalmente de acuerdo! Un saludo!