Conceptos esenciales de diseño de sistemas

  1. Sistema de Nombres de Dominio (DNS)

El DNS es esencial para la infraestructura de internet, ya que convierte nombres de dominio fáciles de recordar en direcciones IP, como si fuera una guía telefónica. Esto permite a los usuarios acceder a servicios web al escribir nombres como www.google.com, en lugar de números como "192.0.2.1".

Cuando ingresas un dominio en tu navegador, el DNS localiza su dirección IP asociada a través de varias etapas: un solucionador recursivo consulta al servidor raíz, al servidor TLD (de nivel superior) y, finalmente, al servidor autorizado. Una vez obtenida la IP, tu navegador se conecta al servidor y carga el contenido solicitado.

  1. Balanceador de carga

Un balanceador de carga es una herramienta fundamental, ya sea como hardware o software, que distribuye el tráfico entrante entre varios servidores para asegurar un uso eficiente de los recursos, mantener una baja latencia y garantizar una alta disponibilidad. Este componente es crucial en sistemas modernos, especialmente para gestionar incrementos repentinos de tráfico, escalar aplicaciones y distribuir de manera uniforme las solicitudes entre servidores activos.

El balanceador utiliza distintos algoritmos para asignar tráfico de manera efectiva:

  • Round Robin: Reparte las solicitudes de forma cíclica entre los servidores disponibles, garantizando una distribución equitativa de la carga.

  • Menor número de conexiones: Dirige las solicitudes al servidor con menos conexiones activas en ese momento, optimizando el rendimiento y balanceando la carga.

  • Hash de IP: Asocia a cada cliente con un servidor específico basado en su dirección IP, asegurando persistencia en las sesiones y continuidad en la experiencia del usuario.

Además de optimizar la gestión de tráfico, los balanceadores aportan resiliencia al sistema, redirigiendo solicitudes a otros servidores si uno falla. Esto no solo refuerza la estabilidad, sino que también asegura que las aplicaciones se mantengan accesibles y funcionales incluso bajo condiciones adversas. Es una pieza imprescindible para cualquier infraestructura que busque escalar de manera eficiente y ofrecer un alto rendimiento.

Balanceador de Carga

  1. Puerta de enlace API

Una API Gateway es un componente esencial en sistemas modernos, actuando como intermediario entre los clientes externos y los servicios internos, como microservicios o APIs del backend. Este elemento resulta indispensable en arquitecturas contemporáneas, especialmente en las basadas en microservicios, ya que facilita la comunicación y centraliza el acceso a múltiples servicios desde un único punto de entrada.

Las responsabilidades clave de una API Gateway incluyen:

  • Enrutamiento de solicitudes: Direccionar las peticiones entrantes hacia el microservicio o backend adecuado conforme a reglas preestablecidas.

  • Autenticación y autorización: Garantizar que solo usuarios o aplicaciones autorizadas accedan a los servicios, verificando credenciales como tokens o claves API.

  • Control de velocidad: Prevenir sobrecarga o abuso aplicando límites a la frecuencia de las solicitudes según políticas definidas.

  • Caché: Reducir la latencia y aliviar la carga del backend almacenando temporalmente respuestas comunes para entregarlas directamente a los clientes.

  • Transformación de datos: Ajustar formatos de solicitudes y respuestas, modificando encabezados o parámetros según sea necesario para asegurar compatibilidad entre clientes y servicios.

Incorporar una API Gateway es un paso estratégico para arquitecturas de microservicios, aportando eficiencia, seguridad y capacidad de manejo de tráfico. Es una solución clave para simplificar la gestión de servicios distribuidos.

  1. CDN (Red de Distribución de Contenido)

Una CDN es una red de servidores distribuidos geográficamente que almacena y entrega contenido web, como imágenes, videos, estilos o scripts, desde ubicaciones más cercanas al usuario final. Su objetivo principal es optimizar el rendimiento, garantizar la rapidez y proporcionar fiabilidad, sin importar la distancia entre el usuario y el servidor de origen.

¿Cómo funciona una CDN?

  • Cuando un usuario solicita contenido, la petición se redirige al servidor más cercano, conocido como servidor de borde.

  • Si el contenido solicitado está almacenado en caché en este servidor, se entrega directamente al usuario, reduciendo la latencia y mejorando la experiencia al acortar la distancia que los datos deben recorrer.

  • Si no está en la caché, el servidor perimetral obtiene el contenido del servidor de origen o de otro nodo cercano, lo almacena en caché para futuras solicitudes y lo envía al usuario.

  • Para garantizar que el contenido sea actualizado, la CDN sincroniza periódicamente los datos con el servidor de origen, asegurando la entrega de información actualizada.

Al reducir la latencia, distribuir el tráfico y mejorar la disponibilidad, las CDN son herramientas esenciales en sistemas modernos que priorizan el rendimiento y la experiencia del usuario.

CDN

  1. Proxy directo vs. Proxy inverso

Un proxy directo, también conocido como servidor proxy, se coloca entre los dispositivos cliente y el internet. Actúa como intermediario, reenviando las solicitudes de los clientes hacia los recursos en línea y devolviendo las respuestas desde los servidores remotos. Por ejemplo, cuando un cliente intenta acceder a un sitio web, la solicitud pasa primero por el proxy directo, que se conecta al servidor de destino en nombre del cliente y entrega la respuesta solicitada.

En contraste, un proxy inverso se posiciona frente a uno o varios servidores web, funcionando como puente entre estos servidores y los usuarios externos. Cuando un cliente realiza una solicitud, esta es interceptada inicialmente por el proxy inverso, que la redirige al servidor correspondiente. Una vez procesada la solicitud, el proxy inverso toma la respuesta del servidor y la envía de vuelta al cliente.

Mientras un proxy directo actúa para proteger y gestionar el acceso del cliente hacia internet, un proxy inverso centraliza y optimiza el acceso de los clientes hacia los servidores backend, ofreciendo beneficios como seguridad, balanceo de carga y almacenamiento en caché.

  1. Almacenamiento en caché: esencial en el diseño de sistemas

La caché es una solución de almacenamiento rápido que actúa como intermediario entre una aplicación y su fuente de datos original, como bases de datos, sistemas de archivos o servicios remotos. Al solicitar datos, primero se verifica la caché; si los datos están disponibles, se entregan directamente, acelerando las respuestas. Si no están presentes, se obtienen de la fuente original, se guardan en la caché para futuras consultas y luego se devuelven a la aplicación.

En sistemas distribuidos, la caché puede implementarse en distintos niveles: cliente, DNS, CDN, balanceadores de carga, pasarelas de API, servidores o bases de datos, optimizando el rendimiento y reduciendo la carga en las fuentes de datos principales. Este enfoque es clave para mejorar la experiencia del usuario y garantizar la eficiencia en aplicaciones modernas.

Cache

  1. Particionado de datos

En el contexto de bases de datos, el particionado es una estrategia utilizada para mejorar el rendimiento y la escalabilidad al dividir los datos en partes más manejables.

  • Particionado horizontal (también conocido como fragmentación): Consiste en distribuir las filas de una tabla en varias tablas más pequeñas, que luego se almacenan en diferentes servidores o instancias de bases de datos. Este enfoque es ideal para distribuir la carga de trabajo, reduciendo la congestión en un solo servidor y mejorando la velocidad de acceso en sistemas de gran escala.

  • Particionado vertical: Implica dividir las columnas de una tabla en distintas tablas independientes. Se utiliza para reducir la cantidad de columnas en una tabla, optimizando las consultas que acceden únicamente a un subconjunto específico de datos. Esto resulta eficiente cuando las consultas no requieren trabajar con toda la información almacenada en la tabla original.

Ambos métodos son esenciales en sistemas distribuidos para manejar grandes volúmenes de datos, mejorar la capacidad de respuesta y garantizar una arquitectura más eficiente.

Particionado de datos

  1. Replicación de bases de datos: clave para la fiabilidad en sistemas modernos

La replicación de bases de datos consiste en mantener múltiples copias de una base de datos en diferentes servidores o ubicaciones, asegurando redundancia, disponibilidad y resistencia ante fallos. Este enfoque es esencial para garantizar que los sistemas continúen operativos incluso en casos de errores de hardware o interrupciones inesperadas.

En una arquitectura replicada, un servidor principal (o maestro) administra las operaciones de escritura, mientras que las réplicas (o secundarias) sincronizan los datos, garantizando su actualización constante. Entre los beneficios destacados de esta estrategia se encuentran:

  • Rendimiento optimizado: Las consultas de lectura pueden distribuirse entre las réplicas, reduciendo la carga del servidor principal y acelerando los tiempos de respuesta.

  • Alta disponibilidad: Ante una falla del servidor principal, las réplicas aseguran un acceso continuo a los datos, minimizando interrupciones en los servicios.

  • Resiliencia de datos: Mantener copias en múltiples ubicaciones protege contra la pérdida de información debido a desastres o fallos críticos.

  • Distribución de carga: Las réplicas pueden gestionar solicitudes de lectura, equilibrando el tráfico y mejorando la eficiencia del sistema.

Este método resulta indispensable para sistemas que buscan combinar fiabilidad con escalabilidad en entornos distribuidos.

  1. Sistemas de mensajería distribuida: comunicación eficiente en sistemas escalables

Los sistemas de mensajería distribuida ofrecen una forma confiable, escalable y resistente a fallos para el intercambio de mensajes entre distintos componentes, aplicaciones o servicios, incluso si están ubicados en diferentes regiones geográficas. Estos sistemas desacoplan a los emisores de los receptores, permitiendo que ambos funcionen y evolucionen de manera independiente, lo que los convierte en un elemento esencial en sistemas complejos.

Son especialmente útiles en arquitecturas modernas como los microservicios y en entornos de computación distribuida, donde la comunicación eficiente es crucial para el rendimiento general. Tecnologías populares que implementan este paradigma incluyen Apache Kafka y RabbitMQ, las cuales manejan grandes volúmenes de datos mientras garantizan baja latencia y alta disponibilidad.

Este enfoque resulta indispensable para escalar sistemas y mantenerlos funcionales bajo cargas elevadas o condiciones críticas.

  1. Microservicios: Diseño modular para sistemas modernos

Los microservicios adoptan una arquitectura en la que las aplicaciones se estructuran como un conjunto de servicios pequeños, autónomos y poco acoplados. Cada microservicio aborda una función específica dentro del sistema y se conecta con otros a través de API bien definidas. A diferencia de la arquitectura monolítica tradicional, en la que todo está integrado como una única unidad, los microservicios dividen las aplicaciones en módulos independientes, mejorando su flexibilidad y escalabilidad.

Características clave:

  • Responsabilidad única: Cada servicio aborda una función o dominio bien definido, facilitando su desarrollo, mantenimiento y comprensión.

  • Independencia: Los microservicios pueden implementarse y escalarse de forma individual, permitiendo que los equipos trabajen en paralelo sin afectar al sistema completo.

  • Descentralización: Cada servicio administra sus propios datos y lógica de negocio, fomentando la autonomía y la separación de responsabilidades.

  • Comunicación ligera: Los servicios se conectan a través de protocolos eficientes como HTTP/REST, gRPC o sistemas de mensajería, facilitando la integración y actualización modular.

  • Resiliencia: Si un servicio falla, el sistema en su conjunto sigue operativo, aumentando la tolerancia a fallos.

Esta arquitectura aporta flexibilidad y eficiencia, siendo ideal para sistemas que requieren adaptarse rápidamente a nuevas necesidades y entornos cambiantes.

  1. Bases de datos NoSQL: la alternativa flexible a lo relacional

Las bases de datos NoSQL, conocidas como "No solo SQL", son sistemas no relacionales diseñados para gestionar datos no estructurados o semiestructurados. Ofrecen una solución más adaptable y escalable en comparación con las bases de datos relacionales tradicionales, especialmente para aplicaciones modernas que requieren manejar grandes volúmenes de información, análisis en tiempo real o procesamiento de big data.

Clasificaciones principales:

  • Basadas en documentos: Utilizan estructuras similares a JSON o BSON, permitiendo datos heterogéneos y flexibles. Ejemplos: MongoDB, Couchbase.

  • Claves-valor: Almacenan pares clave-valor, ideales para operaciones rápidas de lectura y escritura, y altamente escalables. Ejemplos: Redis, Amazon DynamoDB.

  • Familias de columnas: Organizan los datos en columnas relacionadas, siendo eficientes para cargas de trabajo intensivas en escritura. Ejemplos: Apache Cassandra, HBase.

  • Grafos: Diseñadas para datos con relaciones complejas, como redes sociales o sistemas de recomendación. Usan nodos y aristas para modelar dichas conexiones. Ejemplos: Neo4j, Amazon Neptune.

Gracias a su capacidad para adaptarse a necesidades específicas y escalas masivas, las bases de datos NoSQL han transformado la forma en que se almacenan y gestionan los datos en sistemas modernos.

Tipos de bases de datos NoSQL

  1. Índice de base de datos: optimización de consultas

Un índice en una base de datos es una estructura de datos diseñada para acelerar las consultas al proporcionar un acceso más eficiente a la información. Similar a un índice en un libro, permite localizar rápidamente datos específicos sin tener que recorrer fila por fila en una tabla. Esto reduce significativamente los tiempos de recuperación de datos y optimiza el rendimiento del sistema.

Los índices suelen crearse sobre una o más columnas de una tabla. El índice de árbol B es el más común, estructurando los datos de manera jerárquica para permitir búsquedas, inserciones y eliminaciones rápidas. Otros tipos de índices incluyen:

  • Mapas de bits: Útiles para columnas con valores categóricos o booleanos.

  • Hash: Eficientes para búsquedas exactas basadas en claves específicas.

Aunque los índices son herramientas valiosas, tienen algunas limitaciones:

  • Espacio adicional: Requieren almacenamiento extra para las estructuras de datos adicionales.

  • Impacto en escrituras: Operaciones como inserciones, actualizaciones o eliminaciones pueden ralentizarse debido a la necesidad de mantener los índices actualizados.

Equilibrar los beneficios de rendimiento con estos costos es clave al diseñar sistemas basados en bases de datos.

Índice de base de datos

  1. Sistemas de archivos distribuidos: almacenamiento eficiente en arquitecturas modernas

Los sistemas de archivos distribuidos están diseñados para gestionar archivos y directorios a través de múltiples servidores, nodos o máquinas conectados en red. Estos sistemas permiten a los usuarios y aplicaciones trabajar con los archivos como si estuvieran almacenados localmente, aunque estén distribuidos físicamente en ubicaciones remotas.

Son especialmente útiles en entornos de computación distribuidos o de gran escala, ofreciendo beneficios clave como:

  • Tolerancia a fallos: Mantienen la operatividad del sistema incluso frente a interrupciones en servidores individuales.

  • Alta disponibilidad: Garantizan acceso continuo a los datos al distribuir copias entre diferentes nodos.

  • Rendimiento optimizado: Mejoran la velocidad y eficiencia al proporcionar acceso paralelo y descentralizado.

Estos sistemas son esenciales en aplicaciones que requieren manejo de datos masivo, fiabilidad y escalabilidad. Ejemplos destacados incluyen Hadoop Distributed File System (HDFS) y Google File System (GFS), los cuales han transformado la manera en que se gestionan datos en arquitecturas avanzadas.

  1. Sistemas de notificación: manteniendo a los usuarios conectados en tiempo real

Los sistemas de notificación son esenciales en el diseño de sistemas modernos, proporcionando actualizaciones en tiempo real a los usuarios mediante diversos canales como correos electrónicos, notificaciones push y mensajes de texto.

Estos sistemas permiten mantener a los usuarios informados sobre eventos importantes, como actualizaciones de estado, alertas críticas o recordatorios personalizados. Además, pueden integrarse con arquitecturas distribuidas para garantizar que las notificaciones lleguen rápidamente y de manera confiable, incluso bajo cargas elevadas.

Tecnologías como Firebase Cloud Messaging (FCM) y Amazon SNS son ejemplos populares que ofrecen soluciones escalables para implementar este tipo de sistemas en aplicaciones contemporáneas, mejorando significativamente la experiencia del usuario.Búsqueda de texto completo: recuperación eficiente de datos en el diseño de sistemas

La búsqueda de texto completo permite a los usuarios buscar palabras o frases específicas en una aplicación o sitio web. Al recibir una consulta, la aplicación o el sitio web ofrece los resultados más relevantes. Para lograr esto de forma rápida y eficaz, la búsqueda de texto completo utiliza un índice invertido, una estructura de datos que asocia palabras o frases con los documentos donde se encuentran. Elastic Search es un ejemplo de estos sistemas.

  1. Búsqueda de texto completo: Recuperación avanzada para sistemas eficientes

La búsqueda de texto completo es una funcionalidad crucial en aplicaciones y sitios web, ya que permite a los usuarios localizar palabras o frases específicas de manera precisa. Esta técnica no solo proporciona resultados relevantes, sino que también lo hace con rapidez y eficacia, mejorando significativamente la experiencia del usuario.

¿Cómo funciona? El componente central de la búsqueda de texto completo es el índice invertido, una estructura de datos que relaciona palabras o frases con los documentos en los que aparecen. Este índice actúa como un mapa que permite localizar rápidamente los datos solicitados sin necesidad de realizar búsquedas exhaustivas en todo el contenido.

Ejemplo práctico: Plataformas como Elastic Search aprovechan esta técnica para ofrecer capacidades de búsqueda altamente escalables y rápidas, lo que las hace ideales para aplicaciones que manejan grandes volúmenes de datos. Elastic Search crea y gestiona índices invertidos, permitiendo búsquedas complejas, desde coincidencias exactas hasta búsquedas difusas o por relevancia.

Implementar búsqueda de texto completo es clave para sistemas modernos que priorizan rendimiento y accesibilidad.

  1. Servicios de coordinación distribuida: clave para la gestión de sistemas complejos

Los servicios de coordinación distribuida desempeñan un papel fundamental en entornos donde aplicaciones, servicios o nodos trabajan de manera distribuida. Estos sistemas aseguran sincronización fiable, eficiencia operativa y tolerancia a fallos, siendo esenciales para mantener la consistencia de datos y gestionar la interacción entre componentes en arquitecturas complejas.

Funciones destacadas de estos servicios:

  • Sincronización distribuida: Coordinan las acciones entre múltiples nodos para evitar conflictos y garantizar flujos de trabajo organizados.

  • Gestión de configuración: Supervisan y actualizan configuraciones compartidas, facilitando cambios sin interrupciones en los sistemas.

  • Consistencia: Garantizan que todos los nodos o servicios involucrados trabajen con la misma información, evitando discrepancias que puedan comprometer el sistema.

En entornos como microservicios, clústeres de bases de datos o computación distribuida, estos servicios son invaluables. Herramientas como Apache ZooKeeper, etcd y Consul destacan por ofrecer soluciones robustas para implementar coordinación distribuida, mejorando tanto la escalabilidad como la fiabilidad.

  1. Heartbeat: Monitoreo de disponibilidad en sistemas distribuidos

En arquitecturas distribuidas, los datos y tareas se dividen entre diferentes servidores, lo que requiere un monitoreo constante para identificar cuáles están activos y disponibles. Esto es fundamental para asegurar el enrutamiento eficaz de solicitudes hacia el servidor adecuado y gestionar posibles fallos sin interrumpir el sistema.

El mecanismo de latidos (heartbeat) permite a cada servidor confirmar periódicamente que sigue funcionando. Los servidores envían mensajes de latido a un servidor de monitoreo central o a otros nodos, indicando que están activos. Este proceso permite:

  • Detección temprana de fallos: Si un servidor no envía latidos dentro de un tiempo límite, se asume que ha fallado, y se inician acciones correctivas.

  • Continuidad del sistema: Los datos y tareas del servidor inactivo se transfieren a otros operativos, manteniendo la estabilidad del entorno.

En configuraciones centralizadas, todos los servidores reportan al servidor principal. En configuraciones descentralizadas, seleccionan aleatoriamente otros nodos para enviar latidos. Así, los sistemas distribuidos logran eficiencia, tolerancia a fallos y disponibilidad constante.

  1. Suma de comprobación: asegurando la integridad de datos en sistemas distribuidos

En sistemas distribuidos, es posible que los datos transferidos entre nodos lleguen corruptos debido a errores en el almacenamiento, la red o el software. Para abordar este desafío y garantizar que los clientes no reciban información dañada, se utiliza el concepto de suma de comprobación.

La suma de comprobación se genera mediante una función hash criptográfica, como MD5, SHA-1, SHA-256 o SHA-512. Estas funciones convierten los datos de entrada en cadenas únicas de longitud fija (compuestas de números y letras) que representan el estado original de los datos.

Proceso:

  • Cuando los datos son almacenados, se calcula su suma de comprobación utilizando una función hash y se guarda junto con ellos.

  • Al recuperar los datos, el cliente calcula nuevamente la suma de comprobación y la compara con la original almacenada.

  • Si ambas coinciden, se confirma que los datos están íntegros. Si no coinciden, se asume que los datos están corruptos, y el cliente puede optar por recuperarlos desde otra réplica o fuente confiable.

Este método asegura que los sistemas distribuidos sean capaces de detectar corrupción de datos oportunamente, manteniendo la fiabilidad y consistencia en su funcionamiento.

Conclusión: Implementando los principios del diseño de sistemas

Comprender y dominar estos 18 conceptos clave en el diseño de sistemas es un paso crucial para crear aplicaciones robustas y escalables. Conceptos como la resolución de DNS, el balanceo de carga y el uso de almacenamiento en caché sientan las bases para sistemas resilientes y de alto rendimiento. Estas prácticas no solo mejoran el diseño técnico, sino que también te posicionan para abordar con confianza las entrevistas de diseño de sistemas.

Al utilizar la plantilla maestra para estructurar tus respuestas y profundizar en debates sobre componentes críticos como la partición de datos o la coordinación distribuida, estarás mejor preparado para manejar preguntas desafiantes. Además, mantenerte actualizado sobre temas avanzados te ayudará a destacar en un campo competitivo como la arquitectura de software moderna.

Aquí hay una lista de preguntas comunes en entrevistas de diseño de sistemas que puedes explorar para afianzar tus habilidades:

  • Diseña un servicio de intercambio de archivos como Google Drive o Dropbox.

  • Diseña una plataforma de transmisión de video.

  • Diseña un servicio de acortamiento de URL.

  • Diseña un rastreador web.

  • Diseña un sistema como Uber.

  • Diseña un servicio de mensajería como Facebook Messenger.

  • Diseña el motor de búsqueda de Twitter.

  • Diseña una plataforma como Instagram.

Explorar y practicar estas preguntas te ayudará a poner en práctica los conceptos aprendidos mientras te mantienes a la vanguardia en el diseño de sistemas modernos.

0
Subscribe to my newsletter

Read articles from Cristian F. Martin directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Cristian F. Martin
Cristian F. Martin

Desarrollador apasionado por convertir bugs en funcionalidades (y café en productividad). Especialista en sistemas distribuidos, microservicios y todo lo que hace que la tecnología funcione… o finja que lo hace. Amante del código limpio, aunque mi historial de commits podría decir otra cosa. Siempre aprendiendo, siempre depurando, y ocasionalmente negociando con mi teclado para que coopere.