General

Stressting LDAP for fun and profit

Hace casi dos años, el grupo de Software Libre de PDVSA, la petrolera estatal venezolana, estaba indeciso sobre la utilización de OpenLDAP como solución de directorio compatible con LDAPv3 que les permitiera sustituir parcial o totalmente Microsoft Active Directory. Ellos/as me plantearon su mayor duda: ¿qué tan robusto es OpenLDAP en entoos empresariales?

Yo ya había utilizado OpenLDAP extensivamente en entoos empresariales, incluso en convivencia con Microsoft Active Directory cuando trabajé en el Centro de Cómputo de EDELCA, la principal empresa eléctrica en Venezuela. Ese setup ahora está utilizando 389 (antes Fedora Directory Server) para sincronizar claves con MSAD para más de 17 mil personas y centenares de miles de objetos, y a pesar de que lo había visto funcionar bajo cargas muy inusuales, y usábamos clusters con distribución geográfica, yo también tenía la duda de los números.

Decidí probar esto en varios frentes. El primero, generar LDIFs muy grandes, y averiguar cuánto representarían en disco una vez almacenados en Berkeley DB, suponiendo que se fuera a utilizar ese popular backend para OpenLDAP. Esto nos daría una idea, exceptuando índices y optimizaciones, de los requerimientos en memoria de un producto como OpenLDAP en escenarios muy grandes. El segundo frente estaba limitado a las pruebas de tiempo de respuesta de la aplicación ante escenarios de búsqueda.

La razón por la que pruebo búsquedas es porque esta es la aplicación más común de un directorio LDAP. Mis pruebas fueron locales usando TCP/IP porque, aparte de contaminar los tiempos, en mi experiencia los tiempos de respuesta de un directorio LDAP, cuando está networked, se diluyen en los tiempos de procesamiento de la aplicación; en EDELCA preparé un informe que estudiaba la razón de un problema con GNOME Evolution en el cual el autocompletado tardaba varios segundos en responder, aunque en trazas de red se evidenciaba que el directorio LDAP había respondido en milisegundos (un bug en la aplicación) Imagine otro escenario: en la firma y la comprobación de firma de una infraestructura de llave pública dependiente de LDAP, ¿será el tiempo de respuesta de LDAP determinante cuando estamos potencialmente sobrecargando al cliente calculando hashes para la firma de un documento?

Por esto, el tiempo de respuesta local vs. networked no sería un indicativo de la experiencia del usuario final con el directorio, en parte el motivo de la preocupación del cliente. Además hay proxys en LDAP (montamos uno en PDVSA CRP, junto con Penrose como integrador de directorios, o como lo llaman en el mercado, un virtual directory) y estrategias de infraestructura para atacar esto de manera estructural.

Como no quería pasar seis meses de mi vida diseñando experimentos y ya que supuse que nadie iba a estar demasiado interesado en los resultados, dejé de lado algunos escenarios de borde y preparé un par de scripts, en Perl como es natural, para escribir LDIFs muy rápido y para consultar LDAPs muy rápido. Utilicé threads en Perl para su implementación (quería consultar en paralelo), aunque estoy prácticamente convencido por Luis Muñoz, Alejandro Imass y Eesto Heández-Novich de no repetir el uso de threads jamás.

De allí nació un pedestrian LDAP tester, que luego extendí a un stresster de MTAs a través de SMTP y a uno de procesos de autenticación en aplicaciones Web utilizando WWW::Mechanize. Esto es porque el proyecto con PDVSA involucraba las tres cosas: implementamos un cluster de Zimbra Collaboration Suite Community y 389 (FDS) utilizando Debian GNU/Linux en ocho servidores con Xen y NFSv3 para un poco más de 25 mil cuentas, a la fecha 18 meses en producción. Voy a subir los otros scripts pronto, pero vamos con los findings de LDAP, de mi nota informal de Julio 2008:

Cargar 200 mil registros (un LDIF de 66 MB.) en la base de datos tiene una representación en BDB de unos 928 MB. Asumamos que requeriríamos, worst case scenario ese espacio en memoria, sin índices ni los registros de replicación. Cargar esos 200 mil registros en OpenLDAP (slapadd) se toma entre 135 y 180 minutos aproximadamente. Afortunadamente la carga se hace sólo una vez. Indizar la base de datos (slapindex) es relativamente rápido y el tiempo se mantiene igual con 1 mil o 200 mil registros. Esto es lógico y bueno.

Hice una búsqueda similar a una consulta de una libreta de direcciones popular. Esa búsqueda generó 15 mil resultados (el número de resultados se puede restringir en OpenLDAP, pero a efectos de la prueba lo desactivé) — en mis pruebas, 100 clientes consultando paralelamente por TCP/IP y obteniendo los 15 mil resultados, sin limitar los atributos más allá de las ACLs se tomó:

real    0m12.048suser    0m10.413ssys     0m0.768s

Lo cual es más que aceptable. Ahora bien, el uso en memoria RAM del servicio está en los 640 MB. de memoria virtual y casi 200 MB. en memoria residente. Esto representa el 15% de la memoria del servidor que utilicé, un HP Integrity descontinuado para 2008, que tiene 2 GB. de RAM. Al introducir índices, estos se cargan en memoria, así como el número de objetos que se quiere tener en caché (yo coloqué 50 mil) por lo que habría que pensar en al menos unos 4 GB. de RAM para un volumen así.

Creando índices para los atributos cn, sn, givenName y mail, y ajustando un poco los parámetros de configuración de BerkeleyDB (tabulado del FAQ-O-Matic) la indización se toma un tiempo bastante mayor, para un tiempo de respuesta con la misma búsqueda no mucho menor:

real    0m10.540suser    0m8.593ssys     0m0.480s

Por lo que, en general, optimizar poco los índices tendría mucho impacto en las cargas y poco impacto en las búsquedas: si vas a indizar, indiza todo lo que quieras y puedas. Lo otro crítico de optimizar es el DBCONFIG; para 2008, y gracias en parte al oscurantismo de Oracle, era más arte que ciencia. El FAQ-O-Matic de OpenLDAP, como siempre, da la mejor información, ver los artículos 1072, 1075, 42, 738 y 893.

Now for the goodies, hay tres scripts que publiqué en mi carpeta de CPAN. El primero genera LDIFs, de forma muy básica, entradas tipo libreta de direcciones (plt-ldif-generator); el segundo hace las consultas con threads (plt-bambam) y el tercero es una muestra del patrón de uso del tester (plt-usage-patte), en shell script.

Necesita un Perl razonablemente modeo, compilado con soporte para threads, la librería de Threads de Perl y el módulo Net::LDAP. Un aptitude install libthreads-perl libnet-ldap-perl es suficiente. El primer script también espera que usted provea un root.ldif (el nombre se puede cambiar en el código) con la entrada base del directorio (dc=foo,dc=bar; por ejemplo) y un model.ldif que tenga la entrada modelo con tags que el script sustituirá (obvio, puede usar un LDIF prehecho), algo como:

dn: cn=#CN#,dc=foo,dc=barobjectClass: topobjectClass: inetorgpersonuid: #USER#cn: #CN#sn: #SN#givenName: #FN#

Importante: como ya dije antes, algunos casos de uso están fuera de la prueba que realicé, en la mayoría de los casos porque no impactan la prueba
sensiblemente (por ejemplo, autenticar las conexiones usando credenciales, cifrado con TLS/SSL y otros, no sería un problema grave) aunque sí podría nombrar algunos elementos que influyen en el performance cuando se lleva OpenLDAP a la práctica en escenarios distintos al trivial, como por ejemplo el uso de muchos schemas y de atributos divergentes en las entradas del directorio, sobrecargar el servicio con temas administrativos como largas ACLs dinámicas y sobre todo altos niveles de verbosidad y overlays de terceros. Afortunadamente, ninguno de estos es un must para un setup grande de LDAP. El código de mis scripts también debe tener bugs y está terriblemente documentado, pero le cumple el propósito perfectamente.

Standard

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s