Capítulo 1. ¿Qué es la observabilidad?

Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com

En el sector del desarrollo de software, el tema de la observabilidad ha suscitado mucho interés y aparece con frecuencia en las listas de nuevos temas candentes. Pero, como ocurre inevitablemente cuando un tema candente despierta un gran interés de adopción, las ideas complejas se prestan a malentendidos si no se profundiza en los muchos matices que encierra una simple etiqueta temática. Este capítulo analiza los orígenes matemáticos del término "observabilidad" y examina cómo los profesionales del desarrollo de software lo adaptaron para describir las características de los sistemas de software de producción.

También veremos por qué es necesaria la adaptación de la observabilidad para su uso en sistemas de software de producción. Las prácticas tradicionales para depurar el estado interno de las aplicaciones de software se diseñaron para sistemas heredados que eran mucho más sencillos que los que solemos gestionar hoy en día. A medida que la arquitectura de los sistemas, las plataformas de infraestructura y las expectativas de los usuarios han ido evolucionando, las herramientas que utilizamos para razonar sobre esos componentes no lo han hecho. En general, las prácticas de depuración desarrolladas hace décadas con las incipientes herramientas de monitoreo siguen siendo las mismas que utilizan hoy muchos equipos de ingeniería, aunque los sistemas que gestionan sean infinitamente más complejos. Las herramientas de observabilidad nacieron por pura necesidad, cuando las herramientas y métodos de depuración tradicionales sencillamente no estaban a la altura de la tarea de encontrar rápidamente problemas profundamente ocultos y escurridizos.

Este capítulo te ayudará a entender qué significa "observabilidad", cómo determinar si un sistema de software es observable, por qué es necesaria la observabilidad y cómo se utiliza la observabilidad para encontrar problemas de formas que no son posibles con otros enfoques.

La definición matemática de la observabilidad

El término "observabilidad" fue acuñado por el ingeniero Rudolf E. Kálmán en 1960. Desde entonces ha crecido hasta significar muchas cosas diferentes en distintas comunidades. Exploremos el panorama antes de pasar a nuestra propia definición para los sistemas de software modernos.

En su artículo de 1960, Kálmán introdujo una caracterización que denominó observabilidad para describir los sistemas de control matemático.1 En teoría del control, la observabilidad se define como una medida de lo bien que pueden deducirse los estados internos de un sistema a partir del conocimiento de sus salidas externas.

Esta definición de observabilidad te haría estudiar la observabilidad y la controlabilidad como duales matemáticos, junto con sensores, ecuaciones de álgebra lineal y métodos formales. Esta definición tradicional de observabilidad es el reino de los ingenieros mecánicos y de quienes gestionan sistemas físicos con un estado final específico en mente.

Si buscas un libro de texto orientado a la ingeniería matemática y de procesos, has venido al lugar equivocado. Esos libros existen, sin duda, y cualquier ingeniero mecánico o de sistemas de control te informará (normalmente con pasión y detenimiento) de que la observabilidad tiene un significado formal en la terminología tradicional de la ingeniería de sistemas. Sin embargo, cuando ese mismo concepto se adapta para su uso con sistemas de software virtuales más escuetos, se abre una forma radicalmente distinta de interactuar y comprender el código que escribes.

Aplicación de la observabilidad a los sistemas de software

La definición de observabilidad de Kálmán puede aplicarse a los sistemas de software modernos. Al adaptar el concepto de observabilidad al software, también debemos estratificar consideraciones adicionales que son específicas del ámbito de la ingeniería de software. Para que una aplicación de software tenga observabilidad, debe poder hacer lo siguiente:

  • Comprende el funcionamiento interno de tu aplicación

  • Comprender cualquier estado del sistema en el que pueda haberse metido tu aplicación, incluso los nuevos que nunca has visto antes y no podrías haber predicho

  • Comprender el funcionamiento interno y el estado del sistema únicamente observando e interrogando con herramientas externas

  • Comprender el estado interno sin enviar nuevo código personalizado para manejarlo (porque eso implica que necesitabas conocimientos previos para explicarlo).

Una buena prueba de fuego para determinar si esas condiciones son ciertas es hacerte las siguientes preguntas:

  • ¿Puedes responder continuamente a preguntas abiertas sobre el funcionamiento interno de tus aplicaciones para explicar cualquier anomalía, sin llegar a callejones sin salida en la investigación (es decir, el problema podría estar en un determinado grupo de cosas, pero no puedes desglosarlo más para confirmarlo)?

  • ¿Puedes entender lo que un usuario concreto de tu programa puede estar experimentando en un momento dado?

  • ¿Puedes ver rápidamente cualquier sección transversal del rendimiento del sistema que te interese, desde las vistas agregadas de nivel superior, hasta las peticiones de usuario únicas y exactas que puedan estar contribuyendo a cualquier lentitud (y en cualquier punto intermedio)?

  • ¿Puedes comparar cualquier grupo arbitrario de solicitudes de usuarios de forma que te permita identificar correctamente qué atributos comparten comúnmente todos los usuarios que experimentan un comportamiento inesperado en tu aplicación?

  • Una vez que encuentres atributos sospechosos en una solicitud de usuario individual, ¿puedes buscar en todas las solicitudes de usuario para identificar patrones de comportamiento similares que confirmen o descarten tus sospechas?

  • ¿Puedes identificar qué usuario del sistema está generando la mayor carga (y, por tanto, ralentizando más el rendimiento de la aplicación), así como el 2º, 3º o 100º usuario que más carga genera?

  • ¿Puedes identificar cuáles de esos usuarios que generan más carga han empezado a afectar al rendimiento recientemente?

  • Si el 142º usuario más lento se queja de la velocidad de rendimiento, ¿puedes aislar sus peticiones para entender por qué exactamente las cosas van lentas para ese usuario concreto?

  • Si los usuarios se quejan de que se producen tiempos de espera, pero tus gráficos muestran que las peticiones del percentil 99, 99,9 e incluso 99,99 son rápidas, ¿puedes encontrar los tiempos de espera ocultos?

  • ¿Puedes responder a preguntas como las anteriores sin tener que prever primero que algún día tendrás que hacértelas (y, por tanto, establecer de antemano monitores específicos para agregar los datos necesarios)?

  • ¿Puedes responder a preguntas como éstas sobre tus aplicaciones aunque nunca antes hayas visto o depurado este problema concreto?

  • ¿Puedes obtener respuestas a preguntas como las anteriores con rapidez, de modo que puedas formular iterativamente una nueva pregunta, y otra, y otra, hasta llegar a la fuente correcta de problemas, sin perder el hilo (lo que normalmente significa obtener respuestas en cuestión de segundos en lugar de minutos)?

  • ¿Puedes responder a preguntas como las anteriores aunque esa cuestión concreta no haya ocurrido nunca antes?

  • ¿Los resultados de tus investigaciones de depuración te sorprenden a menudo revelando hallazgos nuevos, desconcertantes y extraños, o generalmente sólo encuentras los problemas que sospechabas que podrías encontrar?

  • ¿Puedes aislar rápidamente (en cuestión de minutos) cualquier fallo de tu sistema, por complejo, profundamente enterrado u oculto que esté en ?

Cumplir todos los criterios anteriores es un listón muy alto para muchas organizaciones de ingeniería de software. Si puedes superar ese listón, sin duda entenderás por qué la observabilidad se ha convertido en un tema tan popular entre los equipos de ingeniería de software.

En pocas palabras, nuestra definición de "observabilidad" para los sistemas de software es una medida de lo bien que puedes entender y explicar cualquier estado en el que pueda entrar tu sistema, por novedoso o extraño que sea. Debes ser capaz de depurar comparativamente ese estado extraño o novedoso en todas las dimensiones de los datos de estado del sistema, y combinaciones de dimensiones, en una investigación iterativa ad hoc, sin tener que definir o predecir esas necesidades de depuración de antemano. Si puedes comprender cualquier estado extraño o novedoso sin necesidad de enviar código nuevo, tienes observabilidad.

Creemos que adaptar de este modo el concepto tradicional de observabilidad para los sistemas de software es un enfoque único con matices adicionales que merece la pena explorar. Para los sistemas de software modernos, la observabilidad no tiene que ver con los tipos de datos o entradas, ni con ecuaciones matemáticas. Se trata de cómo las personas interactúan con sus sistemas complejos e intentan comprenderlos. Por tanto, la observabilidad requiere reconocer la interacción entre las personas y la tecnología para comprender cómo funcionan juntos esos sistemas complejos.

Si aceptas esa definición, surgen muchas preguntas adicionales que exigen respuestas:

  • ¿Cómo se reúnen esos datos y se reúnen para su inspección?

  • ¿Cuáles son los requisitos técnicos para el tratamiento de esos datos?

  • ¿Qué capacidades del equipo son necesarias para beneficiarse de esos datos?

Nos ocuparemos de estas cuestiones y de otras más a lo largo de este libro. Por ahora, pongamos algo más de contexto en la observabilidad aplicada al software.

La aplicación de la observabilidad a los sistemas de software tiene mucho en común con sus raíces en la teoría del control. Sin embargo, es mucho menos matemática y mucho más práctica. En parte, esto se debe a que la ingeniería de software es una disciplina mucho más joven y de evolución más rápida que su predecesora, la ingeniería mecánica, más madura. Los sistemas de software de producción están mucho menos sujetos a pruebas formales. Esa falta de rigor es, en parte, una traición de las cicatrices que, como industria, nos hemos ganado operando el código de software que escribimos en producción.

Como ingenieros que intentan comprender cómo salvar la distancia entre las prácticas teóricas codificadas en las pruebas clínicas y los impactos de lo que ocurre cuando nuestro código se ejecuta a escala, no fuimos en busca de un nuevo término, definición o funcionalidad para describir cómo llegamos hasta ahí. Fueron las circunstancias de la gestión de nuestros sistemas y equipos las que nos llevaron a evolucionar nuestras prácticas alejándonos de conceptos, como el monitoreo, que sencillamente ya no funcionaban. Como sector, tenemos que ir más allá de las lagunas actuales en herramientas y terminología para superar el dolor y el sufrimiento que nos infligen las interrupciones y la falta de soluciones más proactivas.

La observabilidad es la solución a esa laguna. Nuestros complejos sistemas de software de producción son un desastre por diversas razones tanto técnicas como sociales. Así que harán falta soluciones tanto sociales como técnicas para sacarnos de este agujero. La observabilidad por sí sola no es la solución completa a todos nuestros problemas de ingeniería de software. Pero te ayuda a ver claramente lo que ocurre en todos los rincones oscuros de tu software, donde de otro modo sueles dar tumbos en la oscuridad e intentar comprender las cosas.

Imagina que te levantas un sábado por la mañana con grandes planes para preparar un brunch para toda la familia. Tienes varios platos en mente, incluida una compleja receta de soufflé de queso, una lista de los alérgenos y sensibilidades alimentarias conocidos de todos, y un calendario apretado: la abuela tiene que llegar al aeropuerto a mediodía. Esto ya es de por sí un reto nada trivial. Ahora imagina que no encuentras tus gafas (y que eres tan miope como nosotros). Cuando se trata de resolver problemas prácticos y urgentes en ingeniería de software , la observabilidad es un buen punto de partida.

Caracterizaciones erróneas sobre la observabilidad del software

Antes de continuar, tenemos que abordar otra definición de "observabilidad", la que popularmente promueven los vendedores de herramientas de desarrollo de software como servicio (SaaS) en . Estos vendedores insisten en que "observabilidad" no tiene ningún significado especial, que es simplemente otro sinónimo de "telemetría", indistinguible de "monitoreo". Los defensores de esta definición relegan la observabilidad a ser otro término genérico para entender cómo funciona el software. Oirás a este contingente explicar la observabilidad como "tres pilares" de cosas que pueden venderte y que ya hacen hoy: métricas, registros y trazas.2

Es difícil decidir qué es peor de esta definición: su redundancia (¿para qué necesitamos exactamente otro sinónimo de "telemetría"?) o su confusión epistémica (¿por qué reunir una lista de un tipo de datos, un lío de cadenas antitipo de datos y una... forma de visualizar las cosas ordenadas por tiempo?) En cualquier caso, el fallo lógico de esta definición queda claro cuando te das cuenta de que sus defensores tienen un gran interés en venderte las herramientas y mentalidades construidas en torno a la recopilación y almacenamiento de datos en silos con su actual conjunto de herramientas de métricas, registro y seguimiento. Los defensores de esta definición dejan que sus modelos empresariales limiten su forma de pensar sobre las posibilidades futuras.

Para ser justos, nosotros -los autores de este libro- también somos vendedores en el espacio de la observabilidad. Sin embargo, este libro no se ha creado para venderte nuestras herramientas. Hemos escrito este libro para explicar cómo y por qué hemos adaptado el concepto original de observabilidad a la gestión de los sistemas de software modernos. Puedes aplicar los conceptos de este libro, independientemente de las herramientas que elijas, para practicar la construcción de sistemas de software de producción con observabilidad. La observabilidad no se consigue pegando herramientas dispares con marketing. No tienes que adoptar una herramienta específica para conseguir la observabilidad en tus sistemas de software. Más bien, creemos que la observabilidad requiere evolucionar la forma en que pensamos sobre la recopilación de los datos necesarios para depurar eficazmente. Creemos que, como industria, ha llegado el momento de evolucionar las prácticas que utilizamos para gestionar los sistemas de software modernos.

Por qué importa ahora la observabilidad

Ahora que estamos de acuerdo en lo que significa y lo que no significa la observabilidad de en el contexto de los sistemas de software modernos, hablemos de por qué es importante ahora este cambio de enfoque. En resumen, el enfoque tradicional de utilizar métricas y monitoreo del software para comprender lo que está haciendo se queda drásticamente corto. Este enfoque es fundamentalmente reactivo. Puede que haya servido bien a la industria en el pasado, pero los sistemas modernos exigen una metodología mejor.

Durante las dos o tres últimas décadas, el espacio entre el hardware y sus operadores humanos ha estado regulado por un conjunto de herramientas y convenciones que la mayoría llama "monitoreo". En general, los profesionales han heredado este conjunto de herramientas y convenciones y lo han aceptado como el mejor enfoque para comprender ese espacio virtual blando entre lo físico y su código. Y han aceptado este enfoque a pesar de saber que, en muchos casos, sus limitaciones inherentes les han tomado como rehenes hasta altas horas de la madrugada en muchas noches de insomnio para solucionar problemas. Aun así, siguen concediéndole sentimientos de confianza, y puede que incluso de afecto, porque ese captor es lo mejor que tienen.

Con el monitoreo, los desarrolladores de software no pueden ver completamente sus sistemas. Entrecierran los ojos ante los sistemas. Intentan, en vano, dimensionarlos y predecir todas las innumerables formas en que podrían fallar. Luego observan -monitorean- esos modos de fallo conocidos. Establecen umbrales de rendimiento y los declaran arbitrariamente "buenos" o "malos". Despliegan un pequeño ejército de robots para comprobar y volver a comprobar esos umbrales en su nombre. Recogen sus conclusiones en cuadros de mando. Luego se organizan en torno a esos robots en equipos, rotaciones y escaladas. Cuando esos robots les dicen que el rendimiento es malo, se alertan a sí mismos. Luego, con el tiempo, se ocupan de esos umbrales arbitrarios como jardineros: podando, ajustando y trasteando las señales ruidosas que crecen.

¿Es ésta realmente la mejor manera?

Durante décadas, así es como lo han hecho los desarrolladores y operadores. El monitoreo ha sido el enfoque de facto durante tanto tiempo que tienden a pensar que es la única forma de entender sus sistemas, en lugar de una única forma. El monitoreo es una práctica tan predeterminada que se ha vuelto casi invisible. Como industria, generalmente no nos preguntamos si debemos hacerlo, sino cómo.

La práctica del monitoreo se basa en muchas suposiciones tácitas sobre los sistemas (que detallaremos a continuación). Pero a medida que los sistemas siguen evolucionando -a medida que se hacen más abstractos y complejos, y que sus componentes subyacentes empiezan a importar cada vez menos- esas suposiciones se vuelven menos ciertas. A medida que los desarrolladores y operadores siguen adoptando enfoques modernos para la implementación de sistemas de software (dependencias SaaS, plataformas de orquestación de contenedores, sistemas distribuidos, etc.), las grietas en esas suposiciones se hacen más evidentes.

Por tanto, cada vez más gente se da de bruces contra el muro de las limitaciones inherentes y se da cuenta de que los enfoques de monitoreo sencillamente no sirven para el nuevo mundo moderno. Las prácticas tradicionales de monitoreo son catastróficamente ineficaces para comprender los sistemas. Los supuestos de la métrica y el monitoreo se están quedando cortos. Para entender por qué fracasan, ayuda examinar su historia y el contexto previsto.

¿Por qué no bastan las métricas y el monitoreo?

En 1988, mediante el Protocolo Simple de Gestión de Redes (SNMPv1, tal como se define en el RFC 1157), nació el sustrato fundacional del monitoreo: la métrica. Una métrica es un número único, al que se añaden opcionalmente etiquetas para agrupar y buscar esos números. Las métricas son, por su propia naturaleza, desechables y baratas. Tienen una huella de almacenamiento predecible. Son fáciles de agregar a lo largo de cubos de series temporales regulares. Y, así, la métrica se convirtió en la unidad base de una o dos generaciones de telemetría: los datos que recopilamos de puntos finales remotos para su transmisión automática a los sistemas de monitoreo.

En se han construido muchos aparatos sofisticados sobre la métrica: bases de datos de series temporales (TSDB), análisis estadísticos, bibliotecas de gráficos, tableros de mandos extravagantes, rotaciones de guardia, equipos de operaciones, políticas de escalada y una plétora de formas de digerir y responder a lo que te dice ese pequeño ejército de robots.

Pero existe un límite superior a la complejidad de los sistemas que puedes comprender con métricas y herramientas de monitoreo. Y una vez que cruzas ese límite, el cambio es brusco. Lo que funcionaba suficientemente bien el mes pasado, simplemente ya no funciona. Empiezas a recurrir a comandos de bajo nivel como strace, tcpdump, y cientos de sentencias print para responder a preguntas sobre cómo se comporta tu sistema a diario.

Es difícil calcular exactamente cuándo se alcanzará ese punto de inflexión. Con el tiempo, el gran número de estados posibles en los que puede entrar el sistema superará la capacidad de tu equipo para establecer patrones basados en fallos anteriores. Demasiados estados nuevos y novedosos necesitan ser comprendidos constantemente. Tu equipo ya no puede adivinar qué cuadros de mando deben crearse para mostrar los innumerables modos de fallo.

Las herramientas basadas en el monitoreo y las métricas se construyeron con ciertas suposiciones sobre tu arquitectura y organización, suposiciones que servían en la práctica como tope a la complejidad. Estas suposiciones suelen ser invisibles hasta que las superas, momento en el que dejan de estar ocultas y se convierten en la pesadilla de tu capacidad para comprender lo que ocurre. Algunas de estas suposiciones podrían ser las siguientes:

  • Tu aplicación es un monolito.

  • Hay un almacén de datos con estado ("la base de datos"), que tú ejecutas.

  • Hay disponibles muchas métricas de bajo nivel del sistema (por ejemplo, memoria residente, media de carga de la CPU).

  • La aplicación se ejecuta en contenedores, máquinas virtuales (VM) o metal desnudo, que tú controlas.

  • Las métricas del sistema y las métricas de instrumentación son la principal fuente de información para depurar el código.

  • Tienes un conjunto bastante estático y de larga duración de nodos, contenedores o hosts que monitorizar.

  • Los ingenieros examinan los sistemas en busca de problemas sólo después de que se produzcan.

  • Los cuadros de mando y la telemetría existen para atender las necesidades de los ingenieros de operaciones.

  • El monitoreo examina las aplicaciones "caja negra" de forma muy similar a las aplicaciones locales.

  • El objetivo del monitoreo es el tiempo de actividad y la prevención de fallos.

  • El examen de la correlación se produce en un número limitado (o pequeño) de dimensiones.

Si se comparan con la realidad de los sistemas modernos, queda claro que los enfoques de monitoreo tradicionales se quedan cortos en varios aspectos. La realidad de los sistemas modernos es la siguiente:

  • Tu aplicación tiene muchos servicios.

  • Existe la persistencia políglota (es decir, muchas bases de datos y sistemas de almacenamiento).

  • La infraestructura es extremadamente dinámica, con una capacidad que entra y sale de la existencia elásticamente.

  • Se gestionan muchos servicios lejanos y débilmente acoplados, muchos de los cuales no están directamente bajo tu control.

  • Los ingenieros comprueban activamente cómo se comportan los cambios en el código de producción, para detectar a tiempo los pequeños problemas, antes de que creen un impacto en el usuario.

  • La instrumentación automática es insuficiente para comprender lo que ocurre en los sistemas complejos.

  • Los ingenieros de software son propietarios de su propio código en producción y están incentivados para instrumentar proactivamente su código e inspeccionar el rendimiento de los nuevos cambios a medida que se implementan.

  • La fiabilidad se centra en cómo tolerar la degradación constante y continua, al tiempo que se crea resistencia a los fallos que afectan al usuario, utilizando conceptos como el presupuesto de errores, la calidad del servicio y la experiencia del usuario.

  • El examen de la correlación se realiza en un número prácticamente ilimitado de dimensiones.

El último punto es importante, porque describe la ruptura que se produce entre los límites del conocimiento correlacionado sobre el que cabe esperar razonablemente que piense un humano y la realidad de las arquitecturas de los sistemas modernos. Hay tantas dimensiones posibles implicadas en el descubrimiento de las correlaciones subyacentes a los problemas de rendimiento que ningún cerebro humano, y de hecho ningún esquema, puede contenerlas.

Con la observabilidad, la comparación de datos de alta dimensionalidad y alta cardinalidad se convierte en un componente crítico para poder descubrir problemas que, de otro modo, quedarían ocultos enterrados en arquitecturas de sistemas complejos.

Depuración con métricas frente a observabilidad

Más allá de ese punto de inflexión de la complejidad del sistema , ya no es posible encajar un modelo del sistema en tu caché mental. Para cuando intentes razonar sobre sus diversos componentes, es probable que tu modelo mental ya esté desfasado.

Como ingeniero, probablemente estés acostumbrado a depurar mediante la intuición. Para llegar al origen de un problema, es probable que te guíes por una corazonada o utilices un recuerdo fugaz de una avería del pasado para guiar tu investigación. Sin embargo, las habilidades que te sirvieron en el pasado ya no son aplicables en este mundo. El enfoque intuitivo sólo funciona mientras la mayoría de los problemas que encuentres sean variaciones de los mismos pocos temas predecibles que has encontrado en el pasado.3

Del mismo modo, el enfoque del monitoreo basado en métricas se basa en haber encontrado modos de fallo conocidos en el pasado. El monitoreo ayuda a detectar cuándo los sistemas están por encima o por debajo de umbrales predecibles que alguien ha considerado previamente una anomalía. Pero, ¿qué ocurre cuando ni siquiera sabes que ese tipo de anomalía es posible?

Históricamente, la mayoría de los problemas a los que se enfrentan los ingenieros de software han sido variantes de modos de fallo algo predecibles. Quizá no se sabía que tu software podía fallar de la forma en que lo hacía, pero si razonabas sobre la situación y sus componentes, descubrir un fallo o modo de fallo novedoso no requería un salto lógico. La mayoría de los desarrolladores de software rara vez se encuentran con saltos lógicos realmente impredecibles porque no han tenido que enfrentarse al tipo de complejidad que hace que esos saltos sean habituales (hasta ahora, la mayor parte de la complejidad para los desarrolladores se ha agrupado dentro de la aplicación monolítica).

Toda aplicación tiene una cantidad inherente de complejidad irreducible. La única cuestión es: ¿quién tendrá que enfrentarse a ella: el usuario, el desarrollador de la aplicación o el desarrollador de la plataforma?

Larry Tesler

Las arquitecturas modernas de sistemas distribuidos fallan notoriamente de formas novedosas que nadie es capaz de predecir y que nadie ha experimentado antes. Esto ocurre con tanta frecuencia que se ha acuñado todo un conjunto de afirmaciones sobre las falsas suposiciones que suelen hacer los programadores novatos en informática distribuida. Los sistemas distribuidos modernos también se ponen a disposición de los desarrolladores de aplicaciones como plataformas de infraestructura abstraídas. Como usuarios de esas plataformas, los desarrolladores de aplicaciones tienen que enfrentarse ahora a una cantidad inherente de complejidad irreducible que ha caído directamente sobre sus platos.

La complejidad, antes sumergida, de las subrutinas del código de la aplicación que interactuaban entre sí en el interior oculto de la memoria de acceso aleatorio de una máquina física, ha salido ahora a la superficie como peticiones de servicio entre hosts. Esa complejidad recién expuesta salta entonces a través de múltiples servicios, atravesando una red impredecible muchas veces en el transcurso de una sola función. Cuando las arquitecturas modernas empezaron a favorecer la descomposición de monolitos en microservicios, los ingenieros de software perdieron la capacidad de recorrer su código con los depuradores tradicionales. Mientras tanto, sus herramientas aún tienen que asimilar ese cambio sísmico.

En pocas palabras: hemos volado el monolito. Ahora cada petición tiene que saltar la red varias veces, y cada desarrollador de software necesita conocer mejor los sistemas y las operaciones sólo para realizar su trabajo diario.

Ejemplos de este cambio sísmico pueden verse en la tendencia a la contenedorización de , el auge de las plataformas de orquestación de contenedores, el cambio a los microservicios, el uso común de la persistencia políglota, la introducción de la malla de servicios, la popularidad de las instancias efímeras de autoescalado, la informática sin servidor, las funciones lambda y cualquier otra miríada de aplicaciones SaaS en el conjunto de herramientas típico de un desarrollador de software. Encadenar estas diversas herramientas en una arquitectura de sistema moderna significa que una solicitud puede realizar entre 20 y 30 saltos después de llegar al perímetro de las cosas que controlas (y probablemente lo multipliques por dos si la solicitud incluye consultas a bases de datos).

En los sistemas modernos nativos de la nube, lo más difícil de depurar ya no es entender cómo se ejecuta el código, sino encontrar en qué parte del sistema vive el código que causa el problema. Buena suerte mirando un panel de control o un mapa de servicios para ver qué nodo o servicio es lento, porque las peticiones distribuidas en estos sistemas a menudo vuelven sobre sí mismas. Encontrar cuellos de botella de rendimiento en estos sistemas es increíblemente difícil. Cuando algo va lento, todo va lento. Y lo que es aún más difícil, dado que los sistemas nativos de la nube suelen funcionar como plataformas, el código puede vivir en una parte del sistema que este equipo ni siquiera controla.

En el mundo moderno, la depuración con métricas requiere que conectes docenas de métricas desconectadas que se registraron en el transcurso de la ejecución de una solicitud concreta, en cualquier número de servicios o máquinas, para deducir lo que pudo ocurrir en los distintos saltos necesarios para su cumplimiento. La utilidad de esas docenas de indicios depende totalmente de si alguien fue capaz de predecir, con antelación, si esa medición estaba por encima o por debajo del umbral que significaba que esa acción contribuía a crear un modo de fallo anómalo desconocido que nunca antes se había producido.

Por el contrario, la depuración con observabilidad comienza con un sustrato muy diferente: un contexto profundo de lo que estaba ocurriendo cuando se produjo esta acción. Depurar con observabilidad consiste en preservar la mayor parte posible del contexto en torno a una solicitud determinada, de modo que puedas reconstruir el entorno y las circunstancias que desencadenaron el fallo que condujo a un modo de fallo novedoso. El monitoreo es para lo conocido-desconocido, pero la observabilidad es para lo desconocido-desconocido.

El papel de la cardinalidad

En el contexto de las bases de datos, la cardinalidad se refiere a la unicidad de los valores de datos contenidos en un conjunto. Una cardinalidad baja significa que una columna tiene muchos valores duplicados en su conjunto. Una cardinalidad alta significa que la columna contiene un gran porcentaje de valores completamente únicos. Una columna que contenga un valor único siempre tendrá la cardinalidad más baja posible. Una columna que contenga identificadores únicos siempre tendrá la cardinalidad más alta posible.

Por ejemplo, en una colección de cien millones de registros de usuarios, puedes suponer que cualquier identificador único universal (UUID) tendrá la cardinalidad más alta posible. Otro ejemplo de cardinalidad alta podría ser una firma de clave pública. El Nombre y los Apellidos tendrían una cardinalidad alta, aunque menor que los UUID, ya que algunos nombres se repiten. Un campo como Género tendría una cardinalidad baja si el esquema se hubiera escrito hace 50 años, pero dada la comprensión más reciente del género, quizá ya no. Un campo como Especie tendría la cardinalidad más baja posible, suponiendo que todos tus usuarios sean humanos.

La cardinalidad es importante para la observabilidad, porque la información de alta cardinalidad es casi siempre la más útil a la hora de identificar datos para depurar o comprender un sistema. Considera la utilidad de ordenar por campos como ID de usuario, ID de carrito de la compra, ID de solicitud o cualquier otra miríada de ID como instancias, contenedor, nombre de host, número de compilación, intervalos, etc. La mejor forma de localizar agujas individuales en un pajar es poder realizar consultas a partir de identificadores únicos. Siempre puedes reducir un valor de cardinalidad alta a algo de cardinalidad más baja (por ejemplo, agrupando los apellidos por prefijos), pero nunca puedes hacer lo contrario.

Por desgracia, los sistemas de herramientas basados en métricas sólo pueden tratar dimensiones de baja cardinalidad a cualquier escala razonable. Aunque sólo tengas cientos de hosts para comparar, con los sistemas basados en métricas no puedes utilizar el nombre del host como etiqueta identificativa sin llegar a los límites de tu espacio de claves de cardinalidad.

Estas limitaciones inherentes imponen restricciones involuntarias a las formas en que pueden interrogarse los datos. Al depurar con métricas, por cada pregunta que quieras hacer a tus datos, tienes que decidir -poradelantado, antes de que se produzca un fallo- sobre qué necesitas preguntar para que su valor pueda registrarse cuando se escriba esa métrica.

Esto tiene dos grandes implicaciones. En primer lugar, si en el transcurso de la investigación decides que hay que hacer una pregunta adicional para descubrir el origen de un problema potencial, eso no puede hacerse a posteriori. Primero debes ir a establecer las métricas que podrían responder a esa pregunta y esperar a que el problema vuelva a producirse. En segundo lugar, como responder a esa pregunta adicional requiere otro conjunto de métricas, la mayoría de los proveedores de herramientas basadas en métricas te cobrarán por registrar esos datos. Tu coste aumenta linealmente con cada nueva forma en que decidas interrogar a tus datos para encontrar problemas ocultos que no podrías haber previsto de antemano.

El papel de la dimensionalidad

Mientras que la cardinalidad se refiere a la unicidad de los valores dentro de tus datos, la dimensionalidad se refiere al número de claves dentro de esos datos. En los sistemas observables, los datos telemétricos se generan como un evento estructurado arbitrariamente amplio (ver Capítulo 8). Estos eventos se describen como "amplios" porque pueden y deben contener cientos o incluso miles de pares clave-valor (o dimensiones). Cuanto más amplio sea el evento, más rico será el contexto capturado cuando se produjo el evento y, por tanto, más podrás descubrir sobre lo ocurrido al depurarlo posteriormente.

Imagina que tienes un esquema de eventos que define seis dimensiones de alta cardinalidad por evento: time, app, host, user, endpoint, y status. Con esas seis dimensiones, puedes crear consultas que analicen cualquier combinación de dimensiones para sacar a la superficie patrones relevantes que puedan estar contribuyendo a las anomalías. Por ejemplo, podrías recuperar "todos los errores 502 que se produjeron en la última media hora para el host foo", o "todos los errores 403 generados por peticiones al endpoint /export realizadas por el usuario bar", o "todos los tiempos de espera que se produjeron con peticiones enviadas al endpoint /payments por la aplicación baz y de qué host procedían".

Con sólo seis dimensiones básicas, puedes examinar un conjunto útil de condiciones para determinar lo que podría estar ocurriendo en el sistema de tu aplicación. Ahora imagina que, en lugar de sólo seis dimensiones, pudieras examinar cientos o miles de dimensiones que contengan cualquier detalle, valor, contador o cadena que parezca que podría ser útil para tus propósitos de depuración en algún momento futuro. Por ejemplo, podrías incluir dimensiones que tuvieran este aspecto

app.api_key
app.batch
app.batch_num_data_sets
app.batch_total_data_points
app.dataset.id
app.dataset.name
app.dataset.partitions
app.dataset.slug
app.event_handler
app.raw_size_bytes
app.sample_rate
app.team.id
…
response.content_encoding
response.content_type
response.status_code
service_name
trace.span_id
trace.trace_id

Con muchas más dimensiones disponibles, puedes examinar los eventos para establecer correlaciones muy sofisticadas entre cualquier grupo de solicitudes de servicio (consulta el Capítulo 8). Cuanto más dimensionales sean tus datos, más probable será que puedas encontrar patrones ocultos o elusivos en el comportamiento de la aplicación. En los sistemas modernos, donde las permutaciones de fallos que pueden producirse son efectivamente ilimitadas, capturar sólo unas pocas dimensiones básicas en tus datos de telemetría es insuficiente.

Debes reunir detalles increíblemente ricos sobre todo lo que ocurre en la intersección de los usuarios, el código y tus sistemas. Los datos de alta dimensionalidad proporcionan un mayor contexto sobre cómo se desarrollan esas intersecciones. En capítulos posteriores, veremos cómo se analizan los datos de alta dimensionalidad (que a menudo contienen datos de alta cardinalidad) para revelar en dónde se producen los problemas que te preocupan en un sistema y por qué.

Depurar con observabilidad

En lugar de limitar la cardinalidad y la dimensionalidad de los datos telemétricos, las herramientas de observabilidad animan a los desarrolladores a recopilar telemetría enriquecida para cada posible evento que pueda ocurrir, transmitiendo el contexto completo de cualquier solicitud y almacenándolo para su posible uso en algún momento posterior. Las herramientas de observabilidad están diseñadas específicamente para consultar datos de alta cardinalidad y alta dimensionalidad.

Por lo tanto, para depurar, puedes interrogar a tus datos de eventos de cualquier número de formas arbitrarias. Con la observabilidad, investigas iterativamente las condiciones que te preocupan explorando tus datos para ver qué pueden revelar sobre el estado de tu sistema. Haces una pregunta que no necesitabas predecir de antemano para encontrar respuestas o pistas que te lleven a hacer la siguiente pregunta, y la siguiente, y la siguiente. Repites ese patrón una y otra vez hasta que encuentras la aguja en el proverbial pajar que buscas. Una función clave de los sistemas observables es la capacidad de explorar tu sistema de forma abierta.

La explorabilidad de un sistema se mide por lo bien que puedes formular cualquier pregunta e inspeccionar su correspondiente estado interno. Explorabilidad significa que puedes investigar iterativamente y, finalmente, comprender cualquier estado en el que se haya metido tu sistema -incluso si nunca antes has visto ese estado- sin necesidad de predecir de antemano cuáles podrían ser esos estados. De nuevo, la observabilidad significa que puedes comprender y explicar cualquier estado en el que pueda entrar tu sistema -por novedoso o extraño que sea- sin enviar nuevo código.

La razón por la que el monitoreo funcionó tan bien durante tanto tiempo es que los sistemas solían ser lo suficientemente sencillos como para que los ingenieros pudieran razonar sobre dónde exactamente debían buscar problemas y cómo podían presentarse esos problemas. Por ejemplo, es relativamente sencillo conectar los puntos de que cuando los sockets se llenan, la CPU se sobrecargaría, y la solución es añadir más capacidad escalando las instancias de nodos de la aplicación, o afinando tu base de datos, o así sucesivamente. En general, los ingenieros podían predecir por adelantado la mayoría de los posibles estados de fallo y descubrir el resto por las malas una vez que sus aplicaciones estuvieran funcionando en producción.

Sin embargo, el monitoreo crea un enfoque fundamentalmente reactivo de la gestión del sistema. Puedes detectar condiciones de fallo que preveías y sabías que debías comprobar. Si sabes que lo puedes esperar, lo compruebas. Para cada condición que no sepas buscar, tienes que verla primero, enfrentarte a la desagradable sorpresa, investigarla lo mejor que puedas, posiblemente llegar a un callejón sin salida que te obligue a ver esa misma condición varias veces antes de diagnosticarla correctamente, y entonces podrás desarrollar una comprobación para ella. En ese modelo, los ingenieros están perversamente incentivados a tener una fuerte aversión a las situaciones que podrían causar fallos impredecibles. Esta es en parte la razón por la que a algunos equipos les aterroriza la implementación de código nuevo (más sobre este tema más adelante).

Un sutil punto adicional: los problemas de hardware/infraestructura son simples comparados con los que genera tu código o tus usuarios. El cambio de "la mayoría de mis problemas son fallos de los componentes" a "la mayoría de mis preguntas tienen que ver con el comportamiento de los usuarios o con sutiles errores e interacciones del código" es la razón por la que incluso las personas con monolitos y arquitecturas más sencillas pueden perseguir el cambio de monitoreo a observabilidad.

La observabilidad es para los sistemas modernos

Un sistema de software de producción es observable en la medida en que puedes entender los nuevos estados internos del sistema sin tener que hacer conjeturas arbitrarias, predecir esos modos de fallo de antemano o enviar nuevo código para entender ese estado. De este modo, ampliamos el concepto de observabilidad de la teoría de control al campo de la ingeniería de software.

En su contexto de ingeniería de software, la observabilidad aporta ventajas a quienes trabajan con arquitecturas más tradicionales o sistemas monolíticos. Siempre es útil poder rastrear tu código y ver dónde se gasta el tiempo, o reproducir el comportamiento desde la perspectiva de un usuario. Sin duda, esta capacidad puede evitar que los equipos tengan que descubrir modos de fallo impredecibles en producción, sea cual sea tu arquitectura. Pero es con los sistemas distribuidos modernos cuando el bisturí y el reflector que ofrecen las herramientas de observabilidad se vuelven absolutamente innegociables.

En los sistemas distribuidos, la proporción entre los modos de fallo algo predecibles de y los modos de fallo novedosos y nunca vistos se inclina en gran medida hacia lo extraño e impredecible. Esos modos de fallo impredecibles ocurren con tanta frecuencia, y se repiten con tan poca frecuencia, que superan la capacidad de la mayoría de los equipos para configurar cuadros de mando de monitoreo lo suficientemente adecuados y relevantes como para mostrar fácilmente ese estado a los equipos de ingeniería responsables de garantizar el tiempo de actividad continuo, la fiabilidad y el rendimiento aceptable de sus aplicaciones de producción.

Escribimos este libro pensando en este tipo de sistemas modernos. Cualquier sistema formado por muchos componentes poco acoplados, de naturaleza dinámica y difícil de razonar es adecuado para aprovechar las ventajas de la observabilidad frente a los enfoques de gestión tradicionales. Si gestionas sistemas de software de producción que se ajustan a esa descripción, este libro describe lo que la observabilidad puede significar para ti, tu equipo, tus clientes y tu empresa. También nos centramos en los factores humanos necesarios para desarrollar una práctica de la observabilidad en áreas clave de tus procesos de ingeniería.

Conclusión

Aunque el término observabilidad se define desde hace décadas, su aplicación a los sistemas de software es una nueva adaptación que conlleva varias consideraciones y características nuevas. En comparación con sus primitivos homólogos más sencillos, los sistemas modernos han introducido tal complejidad adicional que los fallos son más difíciles que nunca de predecir, detectar y solucionar.

Para mitigar esa complejidad, ahora los equipos de ingeniería deben ser capaces de recopilar constantemente telemetría de formas flexibles que les permitan depurar los problemas sin necesidad de predecir primero cómo pueden producirse los fallos. La observabilidad permite a los ingenieros cortar y trocear esos datos telemétricos de formas flexibles que les permitan llegar a la raíz de cualquier problema que se produzca de maneras sin precedentes.

A menudo se dice erróneamente que la observabilidad se consigue cuando se tienen "tres pilares" de distintos tipos de datos telemétricos, por lo que no somos partidarios de ese modelo. Sin embargo, si debemos tener tres pilares de observabilidad, entonces lo que deben ser son herramientas que soporten una alta cardinalidad, alta dimensionalidad y explorabilidad. A continuación, examinaremos en qué se diferencia la observabilidad del enfoque tradicional de monitoreo de sistemas.

1 Rudolf E. Kálmán, "Sobre la teoría general de los sistemas de control", Actas de la IFAC Volúmenes 1, nº 1 (agosto de 1960): 491-502.

2 A veces estas afirmaciones incluyen lapsos de tiempo para significar "sucesos discretos de cambio" como cuarto pilar de un sinónimo genérico de "telemetría".

3 Para un análisis más profundo, consulta la entrada del blog de Pete Hodgson "Por qué la solución intuitiva de problemas ha dejado de funcionarte".

Get Ingeniería de la observabilidad now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.