DevSecOps

25 fev, 2013

Como fazer um proxy no Apache

Publicidade

Existe uma grande variedade de formas de implementar recursos de proxy para servidores web. Como o Apache é o servidor web mais popular, vamos tentar implementar o proxy nele. Todo mundo que o conhece bem sabe, provavelmente, que o Apache implementa a capacidade de proxy para AJP13, FTP, CONNECT, HTTP/1.x.

A escolha do servidor proxy reverso depende totalmente do que está realmente tentando ser escondido por trás dele. Cada mecanismo de proxy possui suas próprias vantagens e gargalos. Apenas para o Apache existem várias formas de ocultar os servidores de aplicação (mod_proxy, mod_passenger, mod_wsgi, mod_jk). Enquanto mod_passenger e mod_wsgi são bons para os servidores Ruby e Python, respectivamente, eles estão um pouco fora da ideia de proxy. Neste artigo, vou falar sobre mod_proxy e mod_jk.

Como fazer

Agora vamos pensar no que temos e no que queremos colocar no proxy. O caso mais comum é colocar um pool de servidores Tomcat por trás do Apache. Os servidores Tomcat ouvem, por padrão, 8080 para HTTP e 8009 para AJP. Agora, queremos fazer o Apache ouvir na porta 80 por novas requisições HTTP e na 443 para requisições HTTPS. As pessoas que configuraram Tomcat para SSL, sem dúvida, concordam comigo que o SSL no Tomcat é bastante irritante, por isso é melhor implementar SSL no lado do Apache em vez de jogar com os keystores do Tomcat.

Ok, agora temos dois servidores Tomcat em dois servidores diferentes com nosso aplicativo instalado, e ambos estão na 8080 e na 8009 o HTTP/AJP respectivamente. E um Apache em um terceiro que vai fazer HTTP em 80, HTTPS em 443 para nós e processar as solicitações para fazer downstream nos servidores Tomcat.

Situação 1 com mod_proxy e mod_proxy_http:

imagem 1

 

OK, aqui está o que isso significa:

O usuário abre http://www.yourdomain.com em seu navegador

  1. A solicitação vem ao Apache
  2. O Apache faz um proxy neles via HTTP para fazer downstream no Tomcat para a porta 8080
  3. Tomcat envia a resposta ao Apache via HTTP
  4. O Apache fornece o conteúdo para o navegador do usuário

Bem, então quais são os prós e contras desta situação? Vamos fornecer algumas tabelas de comparação abaixo, mas em geral:

Prós:

  1. Fácil e rápido de configurar
  2. Funciona para todos os servidores de aplicação de downstream

Contras:

  1. Não temos sessões persistentes: se um usuário faz o login no Tomcat1 e envia outro pedido, é mais provável que vá para Tomcat2 e que o usuário receba um erro de sessão expirada.
  2. mod_proxy não suporta a detecção de falhas, por isso vai continuar a enviar pedidos para downstream o Tomcat mesmo que ele não esteja ativo.
  3. Alguns aplicativos Java apresentam um comportamento imprevisível quando estão sob um ambiente de proxy. (Pela minha experiência, as barras de progresso dos servidores Atlassian Bamboo e Fisheye estagnaram em várias
    páginas, mas isso foi corrigido, movendo para JK. Eu ouvi sobre outros problemas estranhos também.).

Agora vamos ver a Situação 2, na qual usamos JK para os servidores downstream:

imagem 2

 

Um exemplo da vida real

À primeira vista, podemos ver que nada foi mudado, mas isso é apenas à primeira vista. A diferença principal é que agora o Apache está se comunicando com os Tomcats via AJP 13 e não com o protocolo HTTP. Assim, o processo de abertura do site é o seguinte:

  1. O usuário abre http://www.yourdomain.com em seu navegador
  2. A solicitação vem ao Apache
  3. O Apache faz um proxy neles via AJP 13 para downstream o Tomcat para a porta 8009
  4. O Tomcat envia a resposta ao Apache via AJP
  5. O Apache recebe AJP e entrega o conteúdo para os usuários do navegador via HTTP

Parece que existe uma pequena sobrecarga com o fato de alternar entre HTTP e AJP, mas há benefícios também. Vamos ver os lados bons e ruins do balanceamento de JK:

Prós:

  1. Depois de alguns poucos ajustes, podemos ter sessions sticky apenas adicionando sticky_session=True no Apache e jvmRoute=”NODENAME” nos lados do Tomcat. Depois disso, os usuários que estão logados no  Tomcat1 nunca serão derrubados para Tomcat2 até Tomcat1 estar ativo. (Na verdade, você pode usar Membase ou Memcached como armazenamento de sessão, assim os usuários nunca irão perder sua sessão até ela que expire normalmente)
  2. Temos detecção de falha do node, por isso, se o Tomcat1 falhar, o Apache não enviará solicitações a ele até que detecte que ele está de volta.
  3. A configuração do JK é muito mais avançada do que mod_proxy e permite muitos ajustes, o que resultará em um melhor desempenho e tornará o ambiente de trabalho tal como você precisa que seja.
  4. JK tem uma ferramenta de administração web que te permite encerrar, suspender e jogar com o fator LB em tempo real.

Contras:

  1. Até agora eu só achei uma coisa ruim: é um pouco mais difícil de configurar, o que exigiu algumas habilidades de administrador.

Neste momento, você pode estar se perguntando: “Por que eu preciso disso? Eu tenho um servidor Tomcat único e está funcionando bem”. Na verdade, você precisa para construir uma rede que pode lidar com sua carga atual, ser escalonável e não vai afetar o comportamento normal de seus sites. A partir desse ponto de vista, a escolha da solução de proxy reverso é bastante razoável.

Aqui está um exemplo real de uma das nossas arquiteturas do servidor do cliente, que eu acho que é uma boa:

imagem 3

 

Em geral, o processo é o seguinte:

  1. Usuário faz a solicitação DNS, recebe o endereço IP de um dos servidores do Varnish e o servidor de conteúdo estático (NGINX).
  2. O NGINX fornece conteúdo diretamente.
  3. Varnish faz o cache de qualquer coisa que precise ser armazenada em cache e envia downstream de solicitação para um dos Apaches.
  4. O Apache obtém JSESSIONID e encaminha a solicitação via JK para o servidor Tomcat necessário ou faz o equilíbrio se o usuário não tiver cookie.
  5. Os servidores Tomcat mantêm as sessões na RAM local e copiam em cluster Membase (então, mesmo se um Tomcat falhar, outro pode recuperar sua sessão do Membase). Membase está agrupado memcache, por isso é tolerante a falhas por natureza.
  6. Tomcat precisa da lógica de aplicação, (recupera informações do banco de dados Hadoop/HBase etc.) e responde ao Apache.
  7. Apache envia a resposta de volta ao Varnish.
  8. Varnish atualiza cache se necessário e entrega ao cliente.

Esse é um cenário real de trabalho e que provou ser tolerante a falhas e extremamente rápido.

Eu sei que depois de ler este artigo um monte de gente vai perguntar: “Por que o Apache é necessário já que o Varnish pode fazer session stickiness etc.?”

Mas a ideia aqui é usar o melhor software possível para cada papel específico. Software que tem redundância real e que seja aprovada, que tenha camadas razoáveis ​​de arquitetura que podem nos ajudar a detectar problemas e a corrigi-los fácil e rapidamente. Além disso, se tivermos em mente que o cliente utiliza não só HTTP, mas também HTTPS, eu não conheço outro servidor que tenha trabalhado com o SSL tão bem quanto o Apache. Mesmo se não tivermos o SSL inicialmente, vamos tê-lo em breve, e eu não acredito que qualquer projeto web possa ir longe sem SSL.

A seguir está uma pequena comparação entre JK e mod_proxy, para que você possa ver mais de perto o que são essas ferramentas.

Características mod_proxy Peso mod_jk Peso

Load balancing

Básico 5 Avançado 10
Detecção de falha do Node mod_proxy_balancer  precisa estar presente no servidor 7 Avançado 10
Backend SSL suportado (mod_ssl requerido) 5 não suportado 0
Session stickiness não suportado 0 Suportado via JVM Route 10
Protocolos HTTP, HTTPS 10 AJP 13 8
Desativando o Node
Manual precisa recarregar o Apache

3

Online via web admin 10
Interface admin Web Não está presente 0 Avançado com suporte para RO e RW 10
Grandes pacotes AJP 8K 5 Maior que 8K 10
Compatibilidade com outros servidores app. Funciona com todos servidores de aplicação HTTP 10 Compatível com AJP (Tomcat, Glassfish etc.) 5
Configuração Compatível com o arquivo de configuração Apache Httpd 10 Precisa separar o arquivo JK Workers no formato .properties 8
Resumo 55 81

 

 

 

 

 

 

 

 

 

 

 

Então agora vamos fazer alguns testes de estresse em ambos mod_jk e mod_proxy. O esquema de instalação é como o descrito acima (um balanceador de carregamento, dois servidores de aplicação). Em ambos os hosts do servidor Apache, o software de monitoramento do Monitis.com está instalado, e ele irá verificar a saúde dos servidores em tempo real.

Nós usamos instâncias médias do Amazon EC2 para este teste. Aqui estão os resultados de teste de carregamento, tanto no modo gráfico como texto simples.

O monitoramento é implementado usando monitores M3 Monitis.

Dois monitores foram usados​​:

  • apache_monitor – utilizado para verificação da saúde do servidor Apache.
  • http_load monitor – usado para verificar a diferença de tempo de carregamento durante o benchmarking do Apache.

Os monitores mencionados fornecem informações úteis que ajudam a encontrar relações entre várias métricas.

mod_proxy:

O gráfico abaixo mostra o status do worker do Apache enquanto ocupado (linha superior) e inativo (linha inferior), enquanto faz o benchmarking usando o balanceadormod_proxy.

imagem 4

Este gráfico mostra os processos de trabalho ocupados e ociosos no servidor web Apache, para que possamos ver que, de 150 processos habilitados, quase todos estão ocupados durante o teste de estresse.imagem 5

 

Tempo de carregamento de conteúdo Http (tempo de conexão, tempo de transferência, tempo total)

A seguir, estão dados fornecidos pelo siege depois de fazer benchmark 7 vezes (usando mod_proxy), cada vez aumentando o número de usuários simultâneos por 100:

 

Concurrent conns. Trans Tempo Elap Trans de dados Tempo de Resp Taxa de Trans Rendimento Concurrent Falhas
100 112173 359.18 206 0.32 312.30 0.57 99.93 0
200 181578 360.01 333 0.40 504.37 0.92 199.72 3
300 179025 360.00 329 0.60 497.29 0.91 299.37 5
400 177681 360.00 326 0.81 493.56 0.91 397.44 40
500 166401 359.99 305 1.07 462.24 0.85 494.52 130
600 160853 359.99 295 1.31 446.83 0.82 584.32 444

 

mod_jk:

O gráfico abaixo representa o worker do Apache ocupado (linha superior) e o status ocioso (linha inferior) enquanto é feito benchmark usando mod_jk.

imagem 6

 

Este gráfico mostra os processos de trabalho ocupados e ociosos no servidor web Apache, para que possamos ver que, de 150 processos habilitados, quase todos estão ocupados durante o teste de estresse.

imagem 7

 

Tempo de carregamento de conteúdo Http (tempo de conexão, tempo de transferência, tempo total)

A seguir, estão os dados fornecidos pelo siege depois fazer 7 benchmarks (usando mod_jk), cada vez aumentando o número de usuários simultâneos para 100:

 OLHAR TRADUÇÃO DOS TERMOS DA TABELA

Conns.concomitante Trans Tempo de Elap Trans de dados Tempo de Resp Tempo de Trans Taxa de Transf Concomitante Fracassado
100 106919 359.60 198 0.34 297.33 0.55 99.93 0
200 186123 360.01 345 0.39 516.99 0.96 199.76 0
300 183017 360.00 339 0.59 508.38 0.94 299.29 8
400 179891 360.00 333 0.80 499.70 0.93 397.34 49
500 169284 359.99 313 1.05 470.25 0.87 494.55 124
600 182954 359.99 339 1.16 508.22 0.94 590.32 258

 

Conclusão

Ambos os módulos mencionados, mod_proxy e mod_jk, são usados ​​como balanceadores para servidores de aplicação de back-end, como Tomcat e GlassFish. Quais são as características mais importantes de load balancing? Eu supus de início a detecção de falhas no primeiro node e a facilidade de estabilidade de sessão e configuração de balanceamento de carregamento, sem a necessidade de quaisquer outras ferramentas extras ou pacotes. Não se esqueça do desempenho, também.

Então, o que temos? As tabelas resultantes mostram que, quando o balanceamento de carregamento avançado ou a detecção de falha do node é necessária, é preferível o mod_jk. No entanto, ele não pode proporcionar a flexibilidade tal como o mod_proxy faz ao configurar (a configuração do mod_proxy é tão fácil quanto a configuração do Apache e não há necessidade de separar arquivos como workers.properties), nem para as necessidades da compatibilidade com servidores, exceto compatibilidade AJP.

Agora um pouco de desempenho. Enquanto a contagem de usuários simultâneos não é muito alta (no nosso caso, 400), o comportamento dos dois servidores é semelhante, e parece que o mod_proxy é capaz de oferecer um desempenho melhor, mas as coisas mudaram quando o número de usuários simultâneos aumentou.

Dê uma olhada nesta tabela:

Usuários simultâneos Solicitações falhas (tempo de 10 segundos)
mod_jk 590.32 258
mod_proxy 584.32 444

Como você vê, com um número quase igual de conexões, o mod_proxy falha em 59% das vezes.

Se você tem um projeto pequeno, ou precisa esconder vários servidores de aplicação (Tomcat+Rails+Django), e se você precisa de uma solução SSL fácil e configurável, e o carregamento do seu servidor não é pesado, então use mod_proxy.

Mas se a sua meta é fazer o losd balancing de servidores de aplicação do Java, então o JK é definitivamente a melhor solução.

***

Texto original da equipe Monitis, liderada por Hovhannes Avoyan, disponível em http://blog.monitis.com/index.php/2012/10/25/how-to-proxyfy-apache/