A persistência de sessão, também conhecida como sticky sessions (sessões fixas), é uma técnica de balanceamento de carga usada por proxies para garantir que todas as requisições de um cliente específico sejam roteadas de forma consistente para o mesmo servidor de backend durante toda a duração da sessão.
Esse mecanismo resolve o problema imposto por aplicações com estado em um ambiente com balanceamento de carga. Muitas aplicações web mantêm no servidor dados específicos da sessão (por exemplo, conteúdo do carrinho de compras, status de autenticação do usuário, configurações personalizadas). Sem persistência de sessão, uma requisição subsequente do cliente pode ser direcionada pelo balanceador de carga a um servidor de backend diferente. Se esse servidor não tiver os dados de sessão do cliente, o estado da sessão é perdido, o que gera erros, exige nova autenticação ou obriga o cliente a reiniciar a interação. As sticky sessions evitam isso "grudando" o cliente em um servidor específico assim que a conexão inicial é estabelecida.
Como funciona a persistência de sessão
Os proxies implementam a persistência de sessão por diversos métodos, basicamente identificando um cliente e depois mapeando esse cliente para um servidor de backend específico.
Métodos de identificação do cliente
IP Hash (hashing do IP de origem)
Esse método usa o endereço IP do cliente como chave para determinar o servidor de backend. O proxy calcula o hash do endereço IP do cliente e usa o valor resultante para selecionar um servidor do pool disponível. Isso garante que todas as requisições originadas do mesmo endereço IP sejam direcionadas ao mesmo servidor.
- Mecanismo:
hash(client_ip) % number_of_servers - Prós: simples de implementar, não exige cookie no lado do cliente nem modificação da aplicação.
- Contras:
- Desequilíbrio de carga: se muitos clientes compartilham o mesmo IP público (por exemplo, atrás de um gateway NAT ou de uma rede corporativa), esse único servidor pode ficar sobrecarregado.
- Falha do servidor: se o servidor atribuído falhar, a sessão do cliente é perdida e as requisições seguintes serão roteadas para um novo servidor (podendo perder a fixação se o cálculo do hash apontar para outro servidor ou se o proxy reavaliar a distribuição).
- IPs dinâmicos: clientes com endereços IP dinâmicos podem perder a sessão se o IP mudar no meio dela.
Persistência baseada em cookie
Este é um método amplamente usado e mais flexível. O proxy ou a aplicação insere um cookie no navegador do cliente. Esse cookie contém informações usadas pelo proxy para rotear as requisições subsequentes ao servidor de backend correto.
Cookies gerados pelo proxy
O próprio proxy injeta um cookie na resposta HTTP antes de enviá-la ao cliente. Esse cookie normalmente contém um identificador do servidor de backend que processou a requisição inicial. Nas requisições seguintes, o proxy lê esse cookie e direciona o cliente ao servidor identificado.
- Mecanismo: o proxy intercepta a resposta e adiciona o cabeçalho
Set-Cookie: PROXY_SESSION_ID=server_id. Nas requisições seguintes, o proxy lêCookie: PROXY_SESSION_ID=server_ide encaminha paraserver_id. - Prós: não exige modificação da aplicação, é transparente para ela.
- Contras:
- Falha do servidor: se o servidor identificado falhar, a sessão do cliente é perdida. O proxy precisa então rotear a requisição para um novo servidor e atualizar o cookie, ou o cliente recebe um erro.
- Gerenciamento de cookies: exige que os navegadores dos clientes aceitem e enviem cookies.
Cookies gerados pela aplicação
A própria aplicação de backend cria e gerencia um cookie de sessão (por exemplo, JSESSIONID em aplicações Java, PHPSESSID em PHP). O proxy é configurado para inspecionar esse cookie específico da aplicação e usar seu valor (ou parte dele) para determinar o servidor de backend de destino. O proxy pode calcular o hash do valor do cookie ou extrair um identificador de servidor embutido nele.
- Mecanismo: a aplicação define
Set-Cookie: APP_SESSION_ID=unique_session_id. O proxy lêCookie: APP_SESSION_ID=unique_session_ide usa esse valor para mapear um servidor. - Prós: aproveita o gerenciamento de sessão já existente na aplicação, sendo potencialmente mais robusto na identificação de sessões únicas.
- Contras: exige configurar o proxy para entender os formatos de cookie específicos da aplicação. A falha do servidor leva à perda da sessão.
Persistência baseada em cabeçalho
Menos comum do que IP hash ou métodos baseados em cookie, essa abordagem usa um cabeçalho HTTP personalizado para transportar informações de identificação da sessão ou do servidor. O cliente ou um proxy intermediário pode inserir esse cabeçalho.
- Mecanismo: o proxy lê
X-Server-ID: server_123ouX-Client-Session: abcdefe roteia de acordo. - Prós: pode ser útil em arquiteturas específicas de API gateway ou de microsserviços.
- Contras: exige a cooperação do cliente ou de um proxy upstream para injetar os cabeçalhos. Não é adequado para navegadores web comuns sem scripts no lado do cliente.
Comparação dos métodos de sticky session
| Recurso | IP Hash | Cookie gerado pelo proxy | Cookie gerado pela aplicação |
|---|---|---|---|
| Origem do ID do cliente | Endereço IP do cliente | Cookie injetado pelo proxy | Cookie gerado pela aplicação |
| Modificação da aplicação | Nenhuma | Nenhuma | Nenhuma (o proxy lê o cookie já existente) |
| Distribuição de carga | Pode ser desigual (NAT/proxies) | Geralmente boa | Geralmente boa |
| Falha do servidor | Sessão perdida, reroteia para novo servidor | Sessão perdida, reroteia para novo servidor | Sessão perdida, reroteia para novo servidor |
| Granularidade da persistência | Por endereço IP | Por sessão do navegador (expiração do cookie) | Por sessão da aplicação (expiração do cookie) |
| Requisito do cliente | Nenhum | Suportar cookies | Suportar cookies |
| Complexidade | Baixa | Média (gerenciamento de cookie pelo proxy) | Média (configuração do proxy para ler o cookie da aplicação) |
Por que a persistência de sessão é importante
- Suporte a aplicações com estado: essencial para aplicações que armazenam dados de sessão localmente no servidor (por exemplo, carrinhos de e-commerce, sessões de login, formulários de várias etapas).
- Experiência do usuário: evita perda de sessão, novos logins ou perda de progresso, resultando em uma experiência mais fluida.
- Simplicidade no design da aplicação: reduz a necessidade de soluções complexas de gerenciamento distribuído de sessão (por exemplo, armazenamentos externos como Redis ou Memcached), permitindo que as aplicações permaneçam mais simples.
Desvantagens e pontos de atenção
- Desequilíbrio de carga: a principal desvantagem. Se um servidor atende um número desproporcionalmente alto de clientes "fixados", ele pode ficar sobrecarregado enquanto outros servidores permanecem subutilizados. Isso pode anular os benefícios do balanceamento de carga.
- Impacto da falha de servidor: se um servidor com sessões fixas ativas falhar, todos os clientes atualmente "presos" a ele perderão os dados de sessão. Isso pode degradar a experiência ou interromper o serviço para esses clientes.
- Desafios de escalabilidade: pode complicar o escalonamento horizontal. Adicionar ou remover servidores de backend pode romper sticky sessions existentes, exigindo gestão cuidadosa durante as operações de escala.
- Consumo de recursos: manter o mapeamento de fixação (por exemplo, em uma tabela de consulta) consome recursos do proxy.
- Sobrecarga do gerenciamento de cookies: nos métodos baseados em cookie, há uma pequena sobrecarga para definir e ler cookies em cada requisição.
Exemplos de configuração
Nginx (open source)
O Nginx pode implementar sticky sessions com a diretiva ip_hash ou com métodos baseados em cookie mais avançados, via módulos comerciais ou módulos de terceiros como o nginx-sticky-module-ng.
IP Hash
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;
}
}
}
Neste exemplo, ip_hash; garante que as requisições do mesmo IP de cliente sejam roteadas de forma consistente para o mesmo servidor no grupo upstream backend.
Baseado em cookie (com o módulo sticky — normalmente Nginx Plus ou de terceiros)
Se estiver usando o Nginx Plus ou um módulo de terceiros compatível:
http {
upstream backend {
# Usando um cookie gerado pelo proxy chamado "route"
# O valor é um ID de rota atribuído pelo Nginx ao 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;
}
}
}
Aqui, sticky route $cookie_route; configura o Nginx para usar um cookie chamado route na persistência de sessão. O Nginx definirá esse cookie com um valor (A, B ou C) correspondente ao servidor de backend escolhido inicialmente.
Como alternativa, sticky learn pode ser usado para aprender cookies gerados pela aplicação:
http {
upstream backend {
# Aprende com o cookie JSESSIONID da aplicação
sticky learn
create=$upstream_cookie_JSESSIONID
lookup=$cookie_JSESSIONID
zone=client_sessions:1m; # Zona de memória compartilhada para os dados de sessão
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
}
Essa configuração tenta aprender o cookie JSESSIONID definido pela aplicação de backend. Se o cookie estiver presente, o Nginx usa seu valor para rotear as requisições seguintes ao servidor que o definiu inicialmente.
HAProxy
O HAProxy oferece recursos robustos de sticky session, com suporte tanto a métodos baseados em IP quanto a métodos baseados em cookie.
IP Hash (hashing do IP de origem)
frontend http_front
bind *:80
default_backend http_back
backend http_back
balance source # Usa o endereço IP do 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
A diretiva balance source instrui o HAProxy a usar o endereço IP de origem do cliente para o balanceamento de carga, fornecendo assim sticky sessions.
Cookie gerado pelo proxy
frontend http_front
bind *:80
default_backend http_back
backend http_back
balance roundrobin
cookie SERVERID insert indirect nocache # Insere um cookie chamado 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
Aqui, cookie SERVERID insert indirect nocache diz ao HAProxy para inserir um cookie chamado SERVERID na resposta ao cliente. Os valores cookie S1, cookie S2 etc., em cada linha de servidor, especificam o valor que o HAProxy deve usar para aquele servidor. O HAProxy então usa esse cookie para rotear as requisições seguintes. indirect significa que o cookie só é definido se o cliente ainda não tiver um, e nocache impede que proxies de cache armazenem respostas com o cabeçalho Set-Cookie.
Cookie gerado pela aplicação
frontend http_front
bind *:80
default_backend http_back
backend http_back
balance roundrobin
appsession JSESSIONID len 52 timeout 3h # Usa o 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
A diretiva appsession JSESSIONID len 52 timeout 3h configura o HAProxy para procurar um cookie chamado JSESSIONID (comum em aplicações Java). len 52 especifica o tamanho do ID de sessão a ser considerado, e timeout 3h define por quanto tempo o HAProxy lembrará o mapeamento sessão-servidor caso o cookie não esteja presente em uma requisição. Esse método exige que a aplicação defina o cookie JSESSIONID.
