La persistencia de sesión, también conocida como sesiones pegajosas (sticky sessions), es una técnica de balanceo de carga utilizada por los proxies para asegurar que todas las solicitudes de un cliente específico sean consistentemente dirigidas al mismo servidor backend durante la duración de su sesión.
Este mecanismo aborda el desafío que plantean las aplicaciones con estado en un entorno con balanceo de carga. Muchas aplicaciones web mantienen datos específicos de la sesión (por ejemplo, contenido del carrito de compras, estado de autenticación del usuario, configuraciones personalizadas) en el servidor. Sin la persistencia de sesión, una solicitud subsiguiente de un cliente podría ser dirigida a un servidor backend diferente por el balanceador de carga. Si ese servidor no contiene los datos de sesión del cliente, el estado de la sesión se pierde, lo que lleva a errores, requiere una nueva autenticación o fuerza al cliente a reiniciar su interacción. Las sesiones pegajosas evitan esto "pegando" un cliente a un servidor particular una vez que se establece una conexión inicial.
Cómo funciona la persistencia de sesión
Los proxies implementan la persistencia de sesión utilizando varios métodos, principalmente identificando a un cliente y luego mapeando ese cliente a un servidor backend específico.
Métodos de identificación de clientes
Hash de IP (Hashing de IP de origen)
Este método utiliza la dirección IP del cliente como clave para determinar el servidor backend. El proxy aplica un hash a la dirección IP del cliente y utiliza el valor resultante para seleccionar un servidor del grupo disponible. Esto asegura que todas las solicitudes que se originan desde la misma dirección IP sean dirigidas al mismo servidor.
- Mecanismo:
hash(client_ip) % number_of_servers - Pros: Sencillo de implementar, no requiere cookies del lado del cliente ni modificación de la aplicación.
- Contras:
- Desequilibrio de carga: Si muchos clientes comparten la misma IP pública (por ejemplo, detrás de una puerta de enlace NAT, red corporativa), ese único servidor puede sobrecargarse.
- Fallo del servidor: Si el servidor asignado falla, la sesión del cliente se pierde y las solicitudes subsiguientes se enrutarán a un nuevo servidor (potencialmente perdiendo la persistencia si el cálculo del hash apunta a un servidor diferente o el proxy reevalúa).
- IPs dinámicas: Los clientes con direcciones IP dinámicas pueden perder su sesión si su IP cambia a mitad de la sesión.
Persistencia basada en cookies
Este es un método ampliamente utilizado y más flexible. El proxy o la aplicación inserta una cookie en el navegador del cliente. Esta cookie contiene información utilizada por el proxy para enrutar las solicitudes subsiguientes al servidor backend correcto.
Cookies generadas por el proxy
El propio proxy inyecta una cookie en la respuesta HTTP antes de enviarla al cliente. Esta cookie suele contener un identificador para el servidor backend que procesó la solicitud inicial. En solicitudes subsiguientes, el proxy lee esta cookie y dirige al cliente al servidor identificado.
- Mecanismo: El proxy intercepta la respuesta, añade el encabezado
Set-Cookie: PROXY_SESSION_ID=server_id. En solicitudes subsiguientes, el proxy leeCookie: PROXY_SESSION_ID=server_idy lo reenvía aserver_id. - Pros: No requiere modificación de la aplicación, es transparente para la aplicación.
- Contras:
- Fallo del servidor: Si el servidor identificado falla, la sesión del cliente se pierde. El proxy debe entonces enrutar la solicitud a un nuevo servidor y actualizar la cookie, o el cliente experimenta un error.
- Gestión de cookies: Requiere que los navegadores del cliente acepten y envíen cookies.
Cookies generadas por la aplicación
La propia aplicación backend crea y gestiona una cookie de sesión (por ejemplo, JSESSIONID para aplicaciones Java, PHPSESSID para PHP). El proxy se configura para inspeccionar esta cookie de aplicación específica y usar su valor (o una parte de él) para determinar el servidor backend de destino. El proxy podría aplicar un hash al valor de la cookie o extraer un identificador de servidor incrustado en ella.
- Mecanismo: La aplicación establece
Set-Cookie: APP_SESSION_ID=unique_session_id. El proxy leeCookie: APP_SESSION_ID=unique_session_idy utiliza este valor para mapear a un servidor. - Pros: Aprovecha la gestión de sesiones existente de la aplicación, potencialmente más robusta en la identificación de sesiones únicas.
- Contras: Requiere configuración del proxy para entender los formatos de cookies específicos de la aplicación. El fallo del servidor conduce a la pérdida de la sesión.
Persistencia basada en encabezados
Menos común que los métodos basados en hash de IP o cookies, este enfoque utiliza un encabezado HTTP personalizado para llevar información de identificación de sesión o servidor. El cliente o un proxy intermedio podrían insertar este encabezado.
- Mecanismo: El proxy lee
X-Server-ID: server_123oX-Client-Session: abcdefy enruta en consecuencia. - Pros: Puede ser útil en arquitecturas específicas de pasarelas API o microservicios.
- Contras: Requiere la cooperación específica del cliente o del proxy ascendente para inyectar encabezados. No es adecuado para navegadores web estándar sin scripting del lado del cliente.
Comparación de métodos de sesiones pegajosas
| Característica | Hash de IP | Cookie generada por el proxy | Cookie generada por la aplicación |
|---|---|---|---|
| Fuente de ID de cliente | Dirección IP del cliente | Cookie inyectada por el proxy | Cookie generada por la aplicación |
| Modificación de la aplicación | Ninguna | Ninguna | Ninguna (el proxy lee la cookie de la aplicación existente) |
| Distribución de carga | Puede ser desigual (NAT/proxies) | Generalmente buena | Generalmente buena |
| Fallo del servidor | Sesión perdida, se redirige a un nuevo servidor | Sesión perdida, se redirige a un nuevo servidor | Sesión perdida, se redirige a un nuevo servidor |
| Granularidad de persistencia | Por dirección IP | Por sesión del navegador (caducidad de la cookie) | Por sesión de la aplicación (caducidad de la cookie) |
| Requisito del cliente | Ninguno | Soporta cookies | Soporta cookies |
| Complejidad | Baja | Media (gestión de cookies por el proxy) | Media (configuración del proxy para leer la cookie de la aplicación) |
Por qué es importante la persistencia de sesión
- Soporte de aplicaciones con estado: Esencial para aplicaciones que almacenan datos de sesión localmente en el servidor (por ejemplo, carritos de comercio electrónico, sesiones de inicio de sesión, formularios de varios pasos).
- Experiencia del usuario: Evita la pérdida de sesión, los re-inicios de sesión o la pérdida de progreso, lo que lleva a una experiencia de usuario más fluida.
- Simplicidad del diseño de la aplicación: Reduce la necesidad de soluciones complejas de gestión de sesiones distribuidas (por ejemplo, almacenes de sesiones externos como Redis o Memcached), permitiendo que las aplicaciones sigan siendo más simples.
Inconvenientes y consideraciones
- Desequilibrio de carga: El principal inconveniente. Si un servidor maneja un número desproporcionadamente alto de clientes "pegajosos", puede sobrecargarse mientras otros servidores permanecen subutilizados. Esto puede anular los beneficios del balanceo de carga.
- Impacto del fallo del servidor: Si un servidor con sesiones pegajosas activas falla, todos los clientes actualmente "pegados" a ese servidor perderán sus datos de sesión. Esto puede llevar a una experiencia de usuario degradada o a la interrupción del servicio para esos clientes.
- Desafíos de escalabilidad: Puede complicar la escalabilidad horizontal. Añadir o eliminar servidores backend puede interrumpir las sesiones pegajosas existentes, lo que requiere una gestión cuidadosa durante las operaciones de escalado.
- Consumo de recursos: Mantener el mapeo de persistencia (por ejemplo, en una tabla de búsqueda) consume recursos en el proxy.
- Sobrecarga de gestión de cookies: Para los métodos basados en cookies, hay una pequeña sobrecarga al establecer y leer cookies para cada solicitud.
Ejemplos de configuración
Nginx (código abierto)
Nginx puede implementar sesiones pegajosas utilizando la directiva ip_hash o métodos más avanzados basados en cookies con módulos comerciales o módulos de terceros como nginx-sticky-module-ng.
Hash de IP
http {
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
}
En este ejemplo, ip_hash; asegura que las solicitudes de la misma dirección IP del cliente se enruten consistentemente al mismo servidor en el grupo backend upstream.
Basado en cookies (usando el módulo sticky - típicamente Nginx Plus o de terceros)
Si se utiliza Nginx Plus o un módulo de terceros compatible:
http {
upstream backend {
# Usando una cookie generada por el proxy llamada "route"
# El valor es un ID de ruta asignado por Nginx al servidor.
sticky route $cookie_route;
server backend1.example.com route=A;
server backend2.example.com route=B;
server backend3.example.com route=C;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
}
Aquí, sticky route $cookie_route; configura Nginx para usar una cookie llamada route para la persistencia de sesión. Nginx establecerá esta cookie con un valor (A, B o C) correspondiente al servidor backend elegido inicialmente.
Alternativamente, sticky learn puede usarse para aprender cookies generadas por la aplicación:
http {
upstream backend {
# Aprender de la cookie JSESSIONID de la aplicación
sticky learn
create=$upstream_cookie_JSESSIONID
lookup=$cookie_JSESSIONID
zone=client_sessions:1m; # Zona de memoria compartida para datos de sesión
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
}
Esta configuración intenta aprender la cookie JSESSIONID establecida por la aplicación backend. Si la cookie está presente, Nginx usa su valor para enrutar las solicitudes subsiguientes al servidor que la estableció inicialmente.
HAProxy
HAProxy ofrece sólidas capacidades de sesiones pegajosas, soportando métodos basados tanto en IP como en cookies.
Hash de IP (Hashing de IP de origen)
frontend http_front
bind *:80
default_backend http_back
backend http_back
balance source # Usa la dirección IP del cliente
server backend1 192.168.1.10:80 check
server backend2 192.168.1.11:80 check
server backend3 192.168.1.12:80 check
La directiva balance source instruye a HAProxy a usar la dirección IP de origen del cliente para el balanceo de carga, proporcionando efectivamente sesiones pegajosas.
Cookie generada por el proxy
frontend http_front
bind *:80
default_backend http_back
backend http_back
balance roundrobin
cookie SERVERID insert indirect nocache # Inserta una cookie llamada SERVERID
server backend1 192.168.1.10:80 cookie S1 check
server backend2 192.168.1.11:80 cookie S2 check
server backend3 192.168.1.12:80 cookie S3 check
Aquí, cookie SERVERID insert indirect nocache le dice a HAProxy que inserte una cookie llamada SERVERID en la respuesta del cliente. Las cookie S1, cookie S2, etc., en cada línea de servidor especifican el valor que HAProxy debe usar para ese servidor. HAProxy usará entonces esta cookie para enrutar las solicitudes subsiguientes. indirect significa que la cookie solo se establece si el cliente aún no tiene una, y nocache evita que los proxies de caché almacenen en caché las respuestas con el encabezado Set-Cookie.
Cookie generada por la aplicación
frontend http_front
bind *:80
default_backend http_back
backend http_back
balance roundrobin
appsession JSESSIONID len 52 timeout 3h # Usa la cookie JSESSIONID
server backend1 192.168.1.10:80 check
server backend2 192.168.1.11:80 check
server backend3 192.168.1.12:80 check
La directiva appsession JSESSIONID len 52 timeout 3h configura HAProxy para buscar una cookie llamada JSESSIONID (común para aplicaciones Java). len 52 especifica la longitud del ID de sesión a considerar, y timeout 3h establece cuánto tiempo HAProxy recordará el mapeo de sesión a servidor si la cookie no está presente en una solicitud. Este método requiere que la aplicación establezca la cookie JSESSIONID.