MCM: Indexing para las masas
Esta es una traduccion manual del articulo original publicado en el blog ASKPFEPLAT, durante las siguientes semanas estaremos publicando traducciones de los articulos mas populares del blog, como siempre se aceptan y agradecen las sugerencias y comentarios.
Que tal, mi nombre es Adrián Corona, Soy un PFE transaccional en Microsoft y estoy muy entusiasmado puesto que este es mi primer post en un blog, es un poco extenso así que espero que no estés limitado en tu plan de datos.
En esta ocasión estaré aportando a las series de post del programa MCM (Microsoft Certified Master) con un tópico que no es muy popular como replicación de Directorio Activo (DA) sin embargo es utilizado a diario – Índices!
Nota: solo cubriré información respecto a Windows 2003 en adelante, imagino que ya actualizaste tu infraestructura cierto?
Nota 2: Esta información también aplica para Active Directory Light-weight Services (ADLDS) o Active Directory Application Mode (ADAM).
Imagina que recibiste una llamada del departamento de desarrollo de software diciendo que los usuarios se están quejando del tiempo de respuesta de una aplicación critica (están cansados de ver esto: ), esta aplicación está altamente integrada con DA pero no se sabe cómo funciona exactamente, probablemente porque la aplicación “ya estaba aquí mucho antes que todos los miembros actuales de TI y nadie tiene documentación” (cualquier parecido con la realidad es mera coincidencia); entonces, tomas tu teclado, inicias sesión en tu controlador de dominio de confianza y abres Performance monitor.
Sin pensarlo dos veces, disparas una captura con el Active directory Data collector set (disponible solo en Windows 2008+)
|
Ya que tienes eso listo, le pides al usuario que abra su aplicación y haga pruebas:
Después de un rato de captura de datos, obtienes tu resultado:
Interesante, veamos de que se trata:
Mmmh! Creo que esto tiene que ver con una consulta, más abajo haces clic en Active Directory – Search para ver más información:
Después de analizar estos resultados, volteas a ver a tu programador y orgullosamente dices… Tu problema es que estas haciendo una búsqueda medial, corrígela! Y vuelves a trabajar, entonces él te recuerda que no hay documentación y no hay nada que se pueda hacer desde el código de la aplicación y te pregunta si tú puedes ayudarlo.
Tu respuesta es… Exacto! Índices!
Si el programador puede hacer cambios a tu aplicación, te recomiendo que intentes hacer la optimización del lado del cliente primero (detalles más adelante) |
Indización, en términos de bases de datos, es crear una estructura de datos o una lista “pre-compilada” de resultados posibles con el fin de obtenerlos mucho más rápido cuando una consulta es ejecutada en una tabla. En esencia esto quiere decir que hará más rápidas las operaciones de búsqueda en atributos específicos.
No quiero saturarte con mucha información, hablare de clases, atributos y opciones en otra publicación. Con la idea de que te quedes con ganas de más J.
Directorio Activo, como mi colega David Gregory explico en su publicación anterior, es una base de datos. Cuando un servidor es promovido a controlador de dominio, la base de datos es creada y muchas estructuras de datos son creadas también. Algunos atributos importantes son indexados por defecto para mejorar el rendimiento de consultas (LDAP u otras).
Más abajo encontraras una tabla con algunos de los atributos indexados por defecto en la base de datos de DA, (si te interesa ver la lista complete la puedes ver en este artículo.
Name |
Syntax |
Description |
common-Name |
Unicode String |
Common-Name |
display-Name |
Unicode String |
Display-Name |
given-Name |
Unicode String |
Given-Name |
group-Type |
Integer |
Group-Type |
lDAP-Display-Name |
Unicode String |
LDAP-Display-Name |
location |
Unicode String |
Location |
Unicode String |
E-mail-Addresses |
|
name |
Unicode string |
RDN |
object-Guid |
Octet string |
Object-Guid |
object-Sid |
SID |
Object-Sid |
organizational-Unit-Name |
Unicode string |
Organizational-Unit-Name |
sAM-Account-Name |
Unicode string |
SAM-Account-Name |
service-Principal-Name |
Unicode string |
Service-Principal-Name |
sID-History |
SID |
SID-History |
surname |
Unicode string |
Surname |
user-Account-Control |
Integer |
User-Account-Control |
user-Principal-Name |
Unicode string |
User-Principal-Name |
Algunos atributos en esta lista también son parte de la lista parcial de atributos o PAS por sus siglas en Ingles y también son configuradas para resolución de nombres ambigua o ANR por sus siglas en ingles las cuales explicare más adelante. Los atributos en la ANR y PAS son aquellos utilizados frecuentemente para identificar a los objetos más comunes como el nombre, apellido,etc.
Una de las áreas más frecuentes en DA son consultas. Las consultas son ejecutadas hacia la base de datos miles de veces por día (o por segundo en algunos casos). Las consultas son utilizadas para muchas operaciones como autenticación, requerimientos de aplicaciones específicas, políticas de grupo, libreta de direcciones de Outlook y prácticamente cualquier aplicación que utilice DA.
Por qué me habría de interesar?
El desempeño de tu aplicación puede ser afectado severamente cuando las respuestas a una consulta son muy lentas.
Asumiendo que mi aplicación está tratando de obtener objetos dentro de DA con un criterio especifico, por ejemplo, si la aplicación no puede encontrar el valor exacto del campo descripción, la aplicación podría intentar buscar con asteriscos ( esto se conoce como una búsqueda medial, en la cual múltiples valores antes y después de la cadena de caracteres pueden existir):
Description=*test*
Probemos esto con mi herramienta favorita: ldp.exe
Si no tienes ldp instalado necesitas agregar las herramientas administrativas (RAST) para servicios de directorio, las instrucciones para instalarlo están aquí para Windows 7 o Windows 8.
- Inicia el asistente para agregar roles desde el administrador de servidores.
- Abre “Remote Server Administration Tools” y selecciona las herramientas que quieras instalar en tu equipo. Si seleccionas la primera opción todas las herramientas administrativas serán instaladas
Nota: ldp se instala automáticamente cuando agregas los servicios de directorio y/o promueves un Nuevo controlador de dominio.
Abre ldp y haz una conexión a tu DC en el Puerto de catálogo global (3268), no olvides autenticarte.
Si quieres ver información detallada acerca de los resultados de alguna consulta, selecciona Options-> Controls, y selecciona Search Stats desde la sección Load Predefined:
Ahora, construimos una consulta especificando el filtro (description=*test*). Dejamos en blanco el campo Base DN, lo cual causara que la búsqueda se genera en la raíz del directorio:
Para que esto funcione hay que modificar las opciones de búsqueda con los siguientes parámetros:
Al seleccionar el tipo de llamada Extended, estoy especificando que junto a mi consulta quiero que se haga una operación extendida. Esto causa que se adjunte un identificador de objeto (OID) a la consulta. En este caso, el identificador Search Stats ya ha sido especificado como se observa arriba. Si no seleccionas Extended en las opciones de búsqueda, los controles que especifiquemos serán ignorados. Este es el resultado cuando ejecuto mi consulta:
Analicemos la información adicional que fue desplegada:
Call time: Es el tiempo que tomo en ejecutarse la consulta. Es el tiempo que el procesador tomo convertido a milisegundos, si el servidor se llegara a congelar haciendo algo más al mismo tiempo que la consulta, el resultado puede variar.
*Entries returned: El número de objetos encontrados.
*Entries visited: Entradas de la base de datos que fueron “tocadas” por la consulta. Si la proporción entre objetos visitados y encontrados es muy grande, esta es nuestra primera pista de que nuestra consulta es ineficiente. Para realizar consultas más eficientes, existen estrategias como reducir el rango de búsqueda (buscar en un contenedor en lugar del dominio entero), buscar un atributo diferente o dejar de usar asteriscos. (Revisa la optimización de cuentas más abajo).
Used filter: El filtro que utilice en mi consulta.
Used indexes: Indica los índices que fueron utilizados ( o creados) por el DC para ejecutar la consulta.
*Pages referenced: Referencia al número de páginas que el DC tuvo que utilizar para obtener resultados.
*Pages read from disk: De todas las pagina referenciadas, cuantas vinieron de disco.
*Pages Pre-read from Disk: De todas las pagina referenciadas, cuantas vinieron de cache.
*Clean pages modified: Este contador me dice cuántas paginas “limpias” (paginas no modificadas en memoria) modifico el DC para darme resultados.
*Dirty pages modified: Este contador me da el número de “paginas sucias” que fueron modificadas por el DC mientras procesaba la búsqueda, en otras palabras una página “doblemente ensuciada”
*Log record generated: Este número se refiere a las páginas que fueron modificadas después de leer desde disco y puestas en memoria.
*Log record bytes generated: Tamaño en bytes de los archivos de log creados por esta consulta.
*Para que estos controles funcionen correctamente en 2008, R2 y 2012, necesitas el permiso SeDebugPrivilege (Debug Programs) en la cuenta que utilices para ejecutar LDP, este permiso se configura en la política de seguridad de la Default domain controllers Policy, por default, Los miembros del grupo Administrators tienen ese privilegio.
Puedes validar que tengas los permisos con el siguiente comando: “whoami /priv”
Si no lo tienes, puedes agregarlo modificando la Default domain controllers GPO
Busca Computer Configuration \ Windows settings \ Security Settings \ Local Policies \ User Rights Assignment \ Debug Programs y agrega al grupo o usuario que desees a la lista.
Optimización de consultas del lado del cliente.
Manteniendo el miso filtro del lado del cliente, asumiendo que solamente me interesan los resultados de un solo dominio. Si repito la misma consulta pero apuntando al Puerto 389 (LDAP) en vez del default 3268 (Global Catalog) y especificar la partición de dominio en la sección Base DN. Mantén todas las demás configuraciones como las tenias.
Con este cambio los contadores call time, pages referenced y entries visited mostraron una reducción de aproximadamente 20%. Es importante mencionar que el número de páginas leídas puede variar en consultas subsecuentes por que pueden ser almacenadas temporalmente desde consultas previas.
Ahora que sabemos todo esto, veamos cómo podemos mejorar la eficiencia modificando nuestros parámetros de consulta. Por ejemplo, modificando el Base DN a una OU especifica donde se encuentren los objetos que nos interesan, también cambiar el Scope desde Subtree a One Level. Por último, no me devuelvas todos los atributos solo el atributo “name”:
Podemos ver que aplicando estos cambios básicos , el call time y pages referenced fueron reducidos dramáticamente. Al seleccionar one level reducimos el número de entradas visitadas y al especificar un atributo especifico limitamos los datos devueltos, con esto vemos una reducción del 61% en el tiempo de llamada y un 13% en las páginas referidas.
Optimización del lado del server (Índices)
Si la optimización del lado del cliente no es suficiente o necesitamos ejecutar una búsqueda especifica que pueda ser acelerada por un índice (por ejemplo búsquedas Mediales) podemos ejecutar optimización del lado del servidor creando índices. Existen 3 tipos de índices:
Índice de atributo (Attribute Index): el índice será creado para un atributo en específico. La estructura de datos del índice contiene todos los valores del atributo a traves de la base de datos. Por lo tanto un atributo puede tomar mucho tiempo en ser generado.
Índice en contenedor (Containerized Index (PDNT)): Indiza el valor del atributo relativo al nombre del contenedor. (una OU es un ejemplo de contenedor). Debido a que el índice es basado en el contenedor, su tamaño será más pequeño y probablemente más fácil.
Índice Ordenado (Tuple Index): este índice esta optimizado para búsquedas mediales, en los cuales los índices son creados con variaciones del valor. Nuestro filtro *test* es una búsqueda medial, debido a que buscamos la cadena “test” dentro del resultado complete. Nota: este índice es válido solamente cuando la cadena a buscar es mayor que 3 caracteres. Índices ordenados son los más grandes pero dado que contienen una gran cantidad de resultados, pueden optimizar las consultas dramáticamente.
ANR: Ambiguous Name resolution. Este no es un índice pero es una herramienta de búsqueda muy importante. Si agregamos un atributo a la “lista” de atributos ANR, las búsquedas que requieran ANR harán una evaluación del valor deseado contra los atributos definidos como ANR. Uno de los consumidores más grandes de ANR es Exchange, si! Todas las consultas que se hacen a la lista global (GAL) utilizan ANR. Si quieres saber que atributos están seleccionados como ANR puedes consultar la partición de Schema por todos los atributos que tengan el atributo searchflags con alguno de los siguientes valores:
(|(searchflags=4)(searchflags=5)(searchflags=6)(searchflags=7)(searchflags=12)(searchflags=13)(searchflags=14)(searchflags=15)(searchflags=20)(searchflags=21)(searchflags=22)(searchflags=23)(searchflags=28)(searchflags=29)(searchflags=30)(searchflags=31)(searchflags=36)(searchflags=37)(searchflags=38)(searchflags=39)(searchflags=44)(searchflags=45)(searchflags=46)(searchflags=47)(searchflags=52)(searchflags=53)(searchflags=54)(searchflags=55)(searchflags=60)(searchflags=61)(searchflags=62)(searchflags=63))
Así es como se ve:
Getting 17 entries:
Dn: CN=Display-Name,CN=Schema,CN=Configuration,DC=temores,DC=org
name: Display-Name;
Dn: CN=E-mail-Addresses,CN=Schema,CN=Configuration,DC=temores,DC=org
name: E-mail-Addresses;
Dn: CN=Given-Name,CN=Schema,CN=Configuration,DC=temores,DC=org
name: Given-Name;
Dn: CN=Legacy-Exchange-DN,CN=Schema,CN=Configuration,DC=temores,DC=org
name: Legacy-Exchange-DN;
Dn: CN=ms-DS-Additional-Sam-Account-Name,CN=Schema,CN=Configuration,DC=temores,DC=org
name: ms-DS-Additional-Sam-Account-Name;
Dn: CN=ms-DS-Phonetic-Company-Name,CN=Schema,CN=Configuration,DC=temores,DC=org
name: ms-DS-Phonetic-Company-Name;
Dn: CN=ms-DS-Phonetic-Department,CN=Schema,CN=Configuration,DC=temores,DC=org
name: ms-DS-Phonetic-Department;
Dn: CN=ms-DS-Phonetic-Display-Name,CN=Schema,CN=Configuration,DC=temores,DC=org
name: ms-DS-Phonetic-Display-Name;
Dn: CN=ms-DS-Phonetic-First-Name,CN=Schema,CN=Configuration,DC=temores,DC=org
name: ms-DS-Phonetic-First-Name;
Dn: CN=ms-DS-Phonetic-Last-Name,CN=Schema,CN=Configuration,DC=temores,DC=org
name: ms-DS-Phonetic-Last-Name;
Dn: CN=ms-Exch-Mail-Nickname,CN=Schema,CN=Configuration,DC=temores,DC=org
name: ms-Exch-Mail-Nickname;
Dn: CN=ms-Exch-Resource-Search-Properties,CN=Schema,CN=Configuration,DC=temores,DC=org
name: ms-Exch-Resource-Search-Properties;
Dn: CN=Physical-Delivery-Office-Name,CN=Schema,CN=Configuration,DC=temores,DC=org
name: Physical-Delivery-Office-Name;
Dn: CN=Proxy-Addresses,CN=Schema,CN=Configuration,DC=temores,DC=org
name: Proxy-Addresses;
Dn: CN=RDN,CN=Schema,CN=Configuration,DC=temores,DC=org
name: RDN;
Dn: CN=SAM-Account-Name,CN=Schema,CN=Configuration,DC=temores,DC=org
name: SAM-Account-Name;
Dn: CN=Surname,CN=Schema,CN=Configuration,DC=temores,DC=org
name: Surname;
Hay otros tipos de índices que solo especifican “pistas” o “hints” para crear el índice:
Subtree Index: Este tipo de índice prepara al DC para crear una “Vista Virtual” o VLV; una VLV no es un índice, más bien es una operación LDAP que habilita al cliente para solicitar un numero especifico de resultados antes y después del valor solicitado. Al ejecutar una VLV podrás ver una que una interfaz gráfica es generada dinámicamente con un conjunto pequeño de resultados y el usuario puede “Buscar” con diferentes métodos (scrolling, PAGE UP/DOWN, etc.). Esta es una operación que consume muchos recursos de Active directory y debería de ser evitada lo mas posible. Sin embargo es posible reducir un poco la carga de trabajo creándole un índice al atributo. (Exchange 2010 requiere que VLV este habilitado para ciertas operaciones) https://technet.microsoft.com/en-us/library/dd638130.aspx)
Qué clase de brujería es esta?
Para habilitar o deshabilitar índices hay que modificar el atributo searchflags en la definición del atributo que se quiera habilitar (en el esquema). El tributo searchflags es representado por un “signed integer “, esto quiere decir que soporta un rango desde negativo 2,147,483,648 hasta positive 2,147,483,647 (intenta poner cualquier valor dentro de ese rango y observa que sucede); sin embargo es más sencillo si lo tratamos como un arreglo de 9 bits en el cual cada bit tiene diferente propósito cuando se enciende
Show me the Money….
De vuelta a nuestra búsqueda de ejemplo. Como podríamos utilizar índices para optimizar búsquedas realizadas hacia el atributo descripción? En más detalle, asumamos que estamos ejecutando búsquedas mediales (description=*test*) en vez de una búsqueda de cadena inicial (description=test*). En este caso necesitamos un índice que sea optimizado para ambos casos: búsquedas mediales y a nivel de atributo.
Utilizando la información que discutimos antes, y los valores en la tabla anterior, necesitamos un índice Tuple (32) y un índice de atributo (1), entonces el valor que tenemos que especificar es 33 (32 + 1)
Es necesario establecer este valor en el atributo “description” en el esquema. Puedes usar la consola te Schema Management MMC, pero solo podrás configurar índices de atributo o contenedor desde ahí.
Recordatorio: Es necesario tener credenciales de Schema admin y conectarte al schema master con la consola, de otro modo, probablemente te topes con este amistoso mensaje:
Mmmh… intentemos con ADSIedit entonces, conéctate a la partición de Schema. Para hacerlo expande la partición de configuración y ve hacia Partitions, ahí encuentra Enterprise Schema dale clic derecho – Nueva conexión:
Ahora que todos los requisitos se cumplieron, ejecuta ADSI Edit y conéctate a la partición de esquema, busca el objeto que desees indizar (en esta caso el atributo descripción). Edita el objeto y busca el atributo searchflags. Configura el valor 33 (decimal) o 21 en Hex. Algo que me gusta de ADSIedit es que traduce el número que hayas puesto al valor que será establecido:
Una vez aceptado, AD creara el índice, puedes confirmar que haya sido creado en el event viewer en Directory services, anota el nombre del índice y el error -1404 JET_errIndexNotFound, No Such Index el cual
es esperado.
Ahora hay que esperar por confirmación de que el índice ha sido completado con el evento 1137, dependiendo de la cantidad de datos que se tengan que indizar esto puede llevar segundos hasta horas.
Debido a que este índice es creado en DCs, este cambio tiene que ser replicado y entonces los otros controladores regeneraran el índice en su momento, entonces el tiempo total para considerar in índice totalmente complete depende en la topología de AD, mi recomendación es monitoreo de los eventos mencionados.
Veamos como nuestro Nuevo índice afecta nuestra consulta. Si yo ejecuto la consulta optimizada anteriormente veo que el nuevo índice es utilizado:
En donde dice Used Indexes notaras que un nuevo índice fue usado con 3 piezas de información:
- Nombre del índice.
- Número aproximado de registros.
- Tipo de índice:
o N es Normal;
o P es contenido;
o I es Intersección Index (cuando se usa más de 1 índice crea un índice temporal)
o T es Tuple Index.
Si observas cuidadosamente, el número de entradas visitadas se redujo al menos 90% comparado contra la ejecución previa (16449), veras que el número de entradas visitadas contra regresadas es muy similar lo que indica una consulta mucho muy eficiente, el tiempo de llamada fue reducido en un 25%.
Cuál es el truco?
“Con grandes índices vienen grandes responsabilidades” tu base de datos de AD crecerá proporcionalmente al número de índices y al tipo de información que contengan. Afortunadamente hay modos para saber el tamaño de los índices: usando NTDSUTIL; es necesario detener los servicios de AD (ntds) si utilizas 2008 R2, si tus DCs usan 2003 necesitas reiniciar en modo DSRM (https://technet.microsoft.com/en-us/library/cc816897(v=WS.10).aspx)
Hay que seguir los siguientes pasos:
C:\Windows\system32>ntdsutil
ntdsutil: activate instance ntds
Active instance set to "ntds".
ntdsutil: files
file maintenance: Space Usage
Esto te dará una vista de tu base de datos como la siguiente:
La columna owned muestra el número de páginas que ocupa el índice, la implementación de ESENT hecha en AD utiliza páginas de 8KB de tamaño entonces, nuestro nuevo índice consume la colosal suma de 1208 kb en disco (8kb * 151 owned pages).
Es importante mencionar que estos índices consumirán recursos de los controladores de dominio cuando sean invocados como el resto de la base de datos de AD. Si los datos en los atributos indizados cambia rápidamente, el desempeño de tu DC tendrá un impacto, no puedo decir exactamente cuánto porque está basado en muchas variables, sin embargo, recomiendo 2 cosas:
1. Monitorea el uso de tus índices modificando la llave de registro “9 Internal processing”
2. Prueba la eficiencia de tu consulta modificando la llave de registro “15 Field Engineering
”
Ambas llaves se pueden encontrar en: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics
Si quieres instrucciones de como modificar estas llaves de registro ve a: (https://support.microsoft.com/kb/314980)
Resultados
Resumiendo aquí podemos ver las mejoras en este ejercicio:
Conclusión
Los Índices están hechos pare utilizarse y hacer nuestras vidas mas fáciles, pero antes de empezar a crearlos desmedidamente, hay que tener cuidado, ya discutimos el impacto que puede tener un índice en los recursos del DC, además muchos problemas de lentitud en ad pueden ser resueltos agregando más recursos a los servidores, agregando más DCs o solo reparando una aplicación mal escrita. No trato de desanimarte, más bien trato de que pienses en el costo-beneficio que tendrás al crear nuevos índices.
Recuerda: análisis y prueba! Solo así podrás entender el impacto real que tus DCs tendrás.
Si llegaste hasta aquí, gracias…. XD
Adrián “Solo quiero una” Corona
Technorati Tags: Active Directory,MCM,efficient,indexing,slow,queries,database,AD,indices,consultas