Como duplicar o tráfego TCP para um ou vários servidores remotos para fins de comparação?

30

Infraestrutura: servidores no Datacenter, SO - Debian Squeeze, servidor Web - Apache 2.2.16


Situação:

O servidor ativo é usado diariamente por nossos clientes, o que torna impossível testar ajustes e melhorias. Portanto, gostaríamos de duplicar o tráfego HTTP de entrada no servidor ativo para um ou vários servidores remotos em tempo real. O tráfego deve ser passado para o servidor da Web local (neste caso, Apache) E para o (s) servidor (es) remoto (s). Dessa forma, podemos ajustar as configurações e usar código diferente / atualizado no (s) servidor (es) remoto (s) para comparação e comparação com o servidor ativo atual. Atualmente, o servidor da web está ouvindo aprox. 60 portas adicionais além de 80 e 443, devido à estrutura do cliente.


Pergunta: Como essa duplicação em um ou vários servidores remotos pode ser implementada?

Já tentamos:

  • duplicador agnoster - isso exigiria uma sessão aberta por porta que não é aplicável. ( https://github.com/agnoster/duplicator )
  • proxy kklis - apenas encaminha o tráfego para o servidor remoto, mas não o transmite para o servidor lcoal. ( https://github.com/kklis/proxy )
  • iptables - O DNAT apenas encaminha o tráfego, mas não o transmite ao servidor da web local
  • iptables - o TEE duplica apenas para servidores na rede local -> os servidores não estão localizados na mesma rede devido à estrutura do datacenter
  • as alternativas sugeridas fornecidas para a pergunta "tráfego tcp duplicado com um proxy" no stackoverflow ( https://stackoverflow.com/questions/7247668/duplicate-tcp-traffic-with-a-proxy ) não tiveram êxito. Como mencionado, o TEE não funciona com servidores remotos fora da rede local. teeproxy não está mais disponível ( https://github.com/chrislusf/tee-proxy ) e não conseguimos encontrá-lo em outro lugar.
  • Adicionamos um segundo endereço IP (que está na mesma rede) e o atribuímos a eth0: 0 (o endereço IP primário é atribuído a eth0). Não foi possível combinar essa nova interface IP ou virtual eth0: 0 com a função ou rotas iptables TEE.
  • as alternativas sugeridas fornecidas para a pergunta "tráfego tcp de entrada duplicado no debian squeeze" ( tráfego TCP de entrada duplicado no debian squeeze ) não tiveram êxito. As sessões cat | nc (cat / tmp / prodpipe | nc 127.0.0.1 12345 e cat / tmp / testpipe | nc 127.0.0.1 23456) são interrompidas após cada solicitação / conexão por um cliente sem nenhum aviso ou log. Keepalive não mudou essa situação. Pacotes TCP não foram transportados para o sistema remoto.
  • Tentativas adicionais com diferentes opções de socat (HowTo: http://www.cyberciti.biz/faq/linux-unix-tcp-port-forwarding/ , https://stackoverflow.com/questions/9024227/duplicate-input- unix-stream-to-múltiplo-tcp-clients-using-socat ) e ferramentas semelhantes não tiveram êxito, porque a função TEE fornecida gravará apenas no FS.
  • Obviamente, pesquisar no Google e procurar esse "problema" ou configuração também não teve êxito.

Estamos ficando sem opções aqui.

Existe um método para desativar a imposição de "servidor na rede local" da função TEE ao usar IPTABLES?

Nosso objetivo pode ser alcançado com o uso diferente de IPTABLES ou rotas?

Você conhece uma ferramenta diferente para esse fim que foi testada e funciona para essas circunstâncias específicas?

Existe uma fonte diferente para tee-proxy (que atenderia perfeitamente aos nossos requisitos, AFAIK)?


Agradecemos antecipadamente por suas respostas.

----------

editar: 05.02.2014

aqui está o script python, que funcionaria da maneira que precisamos:

import socket  
import SimpleHTTPServer  
import SocketServer  
import sys, thread, time  

def main(config, errorlog):
    sys.stderr = file(errorlog, 'a')

    for settings in parse(config):
        thread.start_new_thread(server, settings)

    while True:
        time.sleep(60)

def parse(configline):
    settings = list()
    for line in file(configline):
        parts = line.split()
        settings.append((int(parts[0]), int(parts[1]), parts[2], int(parts[3])))
    return settings

def server(*settings):
    try:
        dock_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        dock_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        dock_socket.bind(('', settings[0]))

        dock_socket.listen(5)

        while True:
            client_socket = dock_socket.accept()[0]

            client_data = client_socket.recv(1024)
            sys.stderr.write("[OK] Data received:\n %s \n" % client_data)

            print "Forward data to local port: %s" % (settings[1])
            local_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            local_socket.connect(('', settings[1]))
            local_socket.sendall(client_data)

            print "Get response from local socket"
            client_response = local_socket.recv(1024)
            local_socket.close()

            print "Send response to client"
            client_socket.sendall(client_response)
            print "Close client socket"
            client_socket.close()

            print "Forward data to remote server: %s:%s" % (settings[2],settings[3])
            remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            remote_socket.connect((settings[2], settings[3]))
            remote_socket.sendall(client_data)       

            print "Close remote sockets"
            remote_socket.close()
    except:
        print "[ERROR]: ",
        print sys.exc_info()
        raise

if __name__ == '__main__':
    main('multiforwarder.config', 'error.log')

Os comentários para usar este script:
Esse script encaminha várias portas locais configuradas para outro servidor de soquete local e remoto.

Configuração:
adicione ao arquivo de configuração as linhas port-forward.config com o conteúdo da seguinte maneira:

As mensagens de erro são armazenadas no arquivo 'error.log'.

O script divide os parâmetros do arquivo de configuração:
Divida cada linha de configuração com espaços
0: porta local para escutar
1: porta local para encaminhar para
2: endereço IP remoto do servidor de destino
3: porta remota do servidor de destino
e configurações de retorno

Sise
fonte
Todo o tráfego é HTTP?
precisa saber é o seguinte
sim, todo o tráfego é HTTP.
Sise
1
btw. teeproxy está disponível aqui: github.com/chrislusf/teeproxy
Tombart
1
Outra possibilidade: github.com/ebowman/splitter, baseado em Scala / Netty.
Rich K.

Respostas:

11

É impossível. TCP é um protocolo statefull. O computador do usuário final está envolvido em todas as etapas da conexão e nunca responde a dois servidores separados tentando se comunicar com ele. Tudo o que você pode fazer é coletar todas as solicitações http no servidor da web ou em algum proxy e reproduzi-las. Mas isso não dará a simultaneidade exata ou condições de tráfego de um servidor ativo.

Kazimieras Aliulis
fonte
Duplicar o TCP é impossível - eu concordo com isso. Duplicar o tráfego da camada 7 não é. Você pode capturar as solicitações do cliente e reproduzi-las nos outros servidores. Uma solicitação simples por reprodução de sessão TCP deve ser bastante fácil. As conexões persistentes exigirão uma reflexão, na medida em que você calcula as solicitações adicionais do cliente.
Evan Anderson
@ Kazimieras Aliulis: não é necessário se comunicar com dois servidores separados. o cliente está se comunicando com o servidor principal = o servidor ativo. o servidor ativo está processando as solicitações do cliente e está respondendo ao cliente. além de processar e responder ao cliente, o servidor principal está duplicando as solicitações para o segundo servidor = servidor de teste. as respostas do segundo servidor para o servidor principal serão descartadas / ignoradas no servidor principal e não serão encaminhadas para o cliente.
achou
@Evan Anderson: duplicação no nível HTTP também foi nossa primeira idéia, mas, por exemplo, o proxy apache ou ferramentas ou módulos similares não permitem processar simultaneamente as solicitações localmente e duplicá-las em um host remoto. Se você tem alguma outra idéia, por favor, aconselhe-se! :) estamos preferindo a duplicação do que a gravação e a reprodução para obter resultados de comparação instantâneos.
Sise
1
@ Sise: você pode tentar escrever seu próprio proxy http, que passa o tráfego para dois servidores. Deve ser bem fácil fazer isso com o framework Twisted python twistedmatrix.com .
Kazimieras Aliulis
@ Kazimieras Aliulis: essa é definitivamente uma alternativa! Eu nunca ouvi falar disso. mas verificá-lo mostra que ele se encaixaria perfeitamente ao nosso propósito. Não consideramos python antes, mas atualmente estamos analisando a estrutura Twisted e as possibilidades com python geral. Vou relatar se conseguirmos!
Sise
20

Pelo que você descreve, o GOR parece atender às suas necessidades. https://github.com/buger/gor/ "Reprodução do tráfego HTTP em tempo real. Reproduz o tráfego da produção para os ambientes de preparação e desenvolvimento." ?

Arthur Lutz
fonte
2
Era exatamente isso que eu estava procurando, muito obrigado, você me salvou escrevendo exatamente isso, no Go! :-)
chmac
O nginx possui um módulo espelho. nginx.org/en/docs/http/ngx_http_mirror_module.html
Jimmy MG Lim
7

Teeproxy pode ser usado para replicar o tráfego. O uso é realmente simples:

./teeproxy -l :80 -a localhost:9000 -b localhost:9001
  • a servidor de produção
  • b servidor de teste

Quando você coloca um HAproxy (with roundrobin) antes do servidor da Web, pode redirecionar facilmente 50% do seu tráfego para o site de teste:

         /------------------> production
HAproxy /                 ^
        \                /
         \---- teeproxy -.....> test (responses ignored)
Tombart
fonte
4

O TCP, sendo um protocolo stateful, não é passível de simplesmente enviar cópias dos pacotes para outro host, como aponta @KazimierasAliulis.

Pegar os pacotes na camada de terminação TCP e retransmiti-los como um novo fluxo TCP é razoável. A ferramenta duplicadora à qual você vinculou se parece com a sua melhor aposta. Ele funciona como um proxy TCP, permitindo que a máquina de estado TCP opere corretamente. As respostas de suas máquinas de teste serão descartadas. Parece que se encaixa exatamente no que você deseja.

Não está claro para mim por que você descartou a ferramenta duplicadora como inaceitável. Você precisará executar várias instâncias da ferramenta, pois ela apenas escuta em uma única porta, mas, presumivelmente, você deseja retransmitir cada uma dessas portas de atendimento diferentes para portas diferentes no sistema back-end. Caso contrário, você poderá usar o iptables DNAT para direcionar todas as portas de escuta para uma única cópia de escuta da ferramenta duplicadora.

A menos que os aplicativos que você está testando sejam muito simples, espero que você tenha problemas com essa metodologia de teste relacionada ao tempo e ao estado interno do aplicativo. O que você quer fazer parece enganosamente simples - espero que você encontre muitos casos extremos.

Evan Anderson
fonte
sim, você está completamente certo, a ferramenta duplicadora agnoster atenderia aos nossos requisitos, exceto na situação de várias portas. Também o descarte das respostas da máquina de teste é preenchido. Para atingir nosso objetivo de simular a situação real / ativa com a maior precisão possível, não podemos agrupar todas as portas no servidor ativo em uma única porta na máquina de teste. Portas diferentes são usadas para dividir os dispositivos do cliente em diferentes clientes. Assim, temos que abrir 60 a 70 sessões dessa ferramenta duplicadora. Isso não é muito prático como você pode imaginar.
Sise
@ Sise - Os computadores são bons em fazer coisas tediosas. Eu acho que você poderia escrever um script para analisar suas configurações do Apache e cuspir as linhas de comando necessárias para executar de 60 a 70 instâncias da ferramenta duplicadora. Não consigo imaginar que a ferramenta duplicadora consome muitos recursos, mas, mesmo que fosse, você poderia executar essas instâncias de 60 a 70 em outra máquina e fazer alguns truques de rede para obter o tráfego por lá. Para mim, pelo menos, isso parece completamente prático e uma maneira bastante direta de lidar com isso.
Evan Anderson
1

Estou tentando fazer algo semelhante, no entanto, se você estiver simplesmente tentando simular a carga em um servidor, olharia algo como uma estrutura de teste de carga. Eu usei o locust.io no passado e funcionou muito bem para simular uma carga em um servidor. Isso deve permitir que você simule um grande número de clientes e que você brinque com a configuração do servidor sem precisar passar pelo doloroso processo de encaminhamento de tráfego para outro servidor.

snowbirdSkiBum
fonte
0

Quanto a "gostaríamos de duplicar o tráfego HTTP de entrada no servidor ativo para um ou vários servidores remotos em tempo real", há uma maneira não mencionada acima, que é configurar uma porta de espelho no comutador ao qual está conectado.

No caso dos switches Cisco Catalyst, isso é chamado de SPAN (mais informações aqui ). Em um ambiente Cisco, você pode até ter a porta espelhada em um switch diferente.

Mas o objetivo disso é a análise de tráfego, para que seja unidirecional - palavra-chave no texto citado no primeiro parágrafo acima: entrada . Não acho que essa porta permita qualquer tráfego de retorno e, se permitisse, como você lidaria com o tráfego de retorno duplicado? Isso provavelmente causará estragos na sua rede.

Então ... só queria adicionar uma possibilidade à sua lista, mas com a ressalva de que será realmente para tráfego unidirecional. Talvez você possa colocar um hub nessa porta espelhada e ter respostas duplicadas do servidor entregues por algum simulador de cliente local que capturaria sessões iniciadas e responderia, mas você duplicaria o tráfego de entrada no servidor duplicado ... provavelmente não é o que você quer.

James
fonte
nós pensamos sobre isso, eu li sobre a alternativa de usar o SPAN. Porém, como os servidores estão localizados em um data center de um fornecedor terceirizado, temos possibilidades limitadas quando se trata de alterações de hardware. Eu já solicitei conectar dois servidores em um segundo nic diretamente. Essa ação combinada com uma rede local para apenas esses 2 servidores me permitiria usar IPTABLES com TEE. Mas, para optar por essa alternativa, precisaríamos alterar os IPs externos dos servidores, que é um NoGo porque os dispositivos clientes estão configurados para se conectar ao IP definido.
Sise
0

Também escrevi um proxy reverso / balanceador de carga para uma finalidade semelhante com o Node.js (é apenas para diversão, não para produção pronta no momento).

https://github.com/losnir/ampel

É muito opinativo e atualmente suporta:

  • GET Usando a seleção round-robin (1: 1)
  • POSTUsando a divisão de pedidos. Não há conceito de "mestre" e "sombra" - o primeiro back-end que responde é aquele que atenderá à solicitação do cliente e, em seguida, todas as outras respostas serão descartadas.

Se alguém achar útil, eu posso melhorá-lo para ser mais flexível.

Losnir
fonte
O Node.js é uma escolha muito estranha de idioma para um aplicativo como este, que exigirá um desempenho muito alto. Não tenho certeza se isso estará pronto para produção.
Michael Hampton
Você está absolutamente certo. Isso não era para ter um alto desempenho - apenas fácil de escrever (para mim). Eu acho que depende da carga necessária. Eu era capaz de atingir um pouco mais de 1.000 rps em uma máquina de gama baixa (2 núcleos).
losnir 23/07/18
0

minha empresa tinha requisitos semelhantes: clonar um pacote e enviar para outro host (executamos simuladores de dados de mercado e precisávamos de uma solução temporária que escutasse um feed TCP de dados de mercado, ingerisse cada pacote, mas também enviasse um clone de cada pacote para outro simulador servidor)

esse binário funciona muito bem, é uma versão do TCP Duplicator, mas escrito em golang em vez de jscript, portanto, é muito mais rápido e funciona como anunciado,

https://github.com/mkevac/goduplicator

perfecto25
fonte
-1

existe uma ferramenta criada por um cara de uma empresa chinesa e talvez seja o que você precisa: https://github.com/session-replay-tools/tcpcopy

Musikoder
fonte
2
Olá e bem-vindo ao serverfault. Você pode fornecer uma resposta mais detalhada? O que o programa faz exatamente? Está escrito em C ...?
bgtvfr