Come duplicare il traffico TCP verso uno o più server remoti a scopo di benchmarking?


30

Infrastruttura: Server in Datacenter, SO - Debian Squeeze, Webserver - Apache 2.2.16


Situazione:

Il server live viene utilizzato quotidianamente dai nostri clienti, il che rende impossibile testare regolazioni e miglioramenti. Pertanto vorremmo duplicare il traffico HTTP in ingresso sul server live su uno o più server remoti in tempo reale. Il traffico deve essere passato al Webserver locale (in questo caso Apache) E ai server remoti. In questo modo possiamo regolare le configurazioni e utilizzare un codice diverso / aggiornato sui server remoti per l'analisi comparativa e il confronto con l'attuale server live. Attualmente il server web sta ascoltando circa. 60 porte aggiuntive oltre a 80 e 443, a causa della struttura del client.


Domanda: come può essere implementata questa duplicazione su uno o più server remoti?

Abbiamo già provato:

  • duplicatore di agnoster: ciò richiederebbe una sessione aperta per porta che non è applicabile. ( https://github.com/agnoster/duplicator )
  • proxy kklis - inoltra solo il traffico al server remoto, ma non lo passa al server web lcoal. ( https://github.com/kklis/proxy )
  • iptables - DNAT inoltra solo il traffico, ma non lo passa al server web locale
  • iptables - TEE duplica solo i server nella rete locale -> i server non si trovano nella stessa rete a causa della struttura del datacenter
  • le alternative suggerite fornite per la domanda "traffico tcp duplicato con un proxy" su stackoverflow ( /programming/7247668/duplicate-tcp-traffic-with-a-proxy ) non hanno avuto esito positivo. Come accennato, TEE non funziona con server remoti al di fuori della rete locale. teeproxy non è più disponibile ( https://github.com/chrislusf/tee-proxy ) e non siamo riusciti a trovarlo altrove.
  • Abbiamo aggiunto un secondo indirizzo IP (che si trova nella stessa rete) e l'abbiamo assegnato a eth0: 0 (l'indirizzo IP primario è assegnato a eth0). Nessun successo con la combinazione di questo nuovo IP o interfaccia virtuale eth0: 0 con la funzione o i percorsi TEE di iptables.
  • le alternative suggerite fornite per la domanda "duplicare il traffico tcp in entrata su Debian Squeeze" ( duplicare il traffico TCP in entrata su Debian Squeeze ) non hanno avuto successo. Le sessioni cat | nc (cat / tmp / prodpipe | nc 127.0.0.1 12345 e cat / tmp / testpipe | nc 127.0.0.1 23456) vengono interrotte dopo ogni richiesta / connessione da parte di un client senza preavviso o registro. Keepalive non ha cambiato questa situazione. I pacchetti TCP non sono stati trasportati sul sistema remoto.
  • Ulteriori tentativi con diverse opzioni di socat (HowTo: http://www.cyberciti.biz/faq/linux-unix-tcp-port-forwarding/ , /programming/9024227/duplicate-input- unix-stream-to-multiple-tcp-client-using-socat ) e strumenti simili non hanno avuto successo, perché la funzione TEE fornita scriverà solo in FS.
  • Naturalmente, anche cercare su Google questo "problema" o impostazione non ha avuto successo.

Stiamo esaurendo le opzioni qui.

Esiste un metodo per disabilitare l'applicazione del "server nella rete locale" della funzione TEE quando si utilizza IPTABLES?

Il nostro obiettivo può essere raggiunto con un diverso utilizzo di IPTABLES o Route?

Conosci uno strumento diverso per questo scopo che è stato testato e funziona in queste circostanze specifiche?

Esiste una fonte diversa per tee-proxy (che si adatterebbe perfettamente ai nostri requisiti, AFAIK)?


Grazie in anticipo per le tue risposte.

----------

modifica: 05.02.2014

ecco lo script Python, che funzionerebbe nel modo in cui ne abbiamo bisogno:

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')

I commenti per utilizzare questo script:
Questo script inoltra un numero di porte locali configurate a un altro server socket locale e remoto.

Configurazione:
aggiungere al file di configurazione le righe port-forward.config con i contenuti come segue:

I messaggi di errore sono memorizzati nel file "error.log".

Lo script divide i parametri del file di configurazione:
Dividi ogni riga di configurazione con spazi
0: porta locale per ascoltare
1: porta locale per inoltrare a
2: indirizzo IP remoto del server di destinazione
3: porta remota del server di destinazione
e impostazioni di ritorno


Tutto il traffico è HTTP?
collo lungo,

sì, tutto il traffico è HTTP.
Seduta il

1
btw. teeproxy è disponibile qui: github.com/chrislusf/teeproxy
Tombart

1
Un'altra possibilità: github.com/ebowman/splitter Scala / Netty-based.
Rich K.

Risposte:


11

È impossibile. TCP è protocollo statefull. Il computer dell'utente finale è coinvolto in ogni fase della connessione e non risponderà mai a due server separati che provano a comunicare con esso. Tutto quello che puoi fare è raccogliere tutte le richieste http sul server web o alcuni proxy e riprodurle. Ma ciò non fornirà la concorrenza esatta o le condizioni del traffico di un server live.


La duplicazione del TCP è impossibile-- Sono d'accordo con quello. La duplicazione del traffico di livello 7 non lo è. È possibile acquisire le richieste dal client e riprodurle sugli altri server. La semplice riproduzione di 1 richiesta per sessione TCP dovrebbe essere piuttosto semplice. Le connessioni persistenti richiedono alcune considerazioni in merito al tempo impiegato per le richieste aggiuntive del cliente.
Evan Anderson,

@Kazimieras Aliulis: non è necessario comunicare con due server separati. il client sta comunicando con il server primario = il server live. il server live sta elaborando le richieste del client e sta rispondendo al client. oltre a elaborare e rispondere al client, il server primario sta duplicando le richieste al secondo server = server di prova. le risposte dal secondo server al server primario verranno scartate / ignorate sul server primario e non verranno inoltrate al client.
Seduta il

@Evan Anderson: anche la duplicazione a livello HTTP è stata la nostra prima idea, ma ad esempio il proxy apache o strumenti o moduli simili non consentono di elaborare simultaneamente le richieste localmente e duplicarle su un host remoto. se hai qualche altra idea, per favore consiglio! :) preferiamo la duplicazione rispetto alla registrazione e alla riproduzione per ottenere risultati di confronto istantanei.
Seduta il

1
@Sise: potresti provare a scrivere il tuo proxy http, che trasmette il traffico a due server. Dovrebbe essere abbastanza facile da fare con Python Twisted framework twistedmatrix.com .
Kazimieras Aliulis,

@Kazimieras Aliulis: questa è sicuramente un'alternativa! non ne ho mai sentito parlare. ma verificarlo mostra che si adatterebbe perfettamente al nostro scopo. Non avevamo mai considerato Python prima, ma attualmente stiamo esaminando il framework Twisted e le possibilità anche con Python generale. Riferirò se avremo successo!
Seduta il


7

Teeproxy potrebbe essere utilizzato per replicare il traffico. L'utilizzo è davvero semplice:

./teeproxy -l :80 -a localhost:9000 -b localhost:9001
  • a server di produzione
  • b server di test

Quando metti un HAproxy (con roundrobin) davanti al tuo server web puoi facilmente reindirizzare il 50% del tuo traffico al sito di test:

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

4

TCP, essendo un protocollo con stato, non è suscettibile di eseguire semplicemente il brillamento di copie dei pacchetti su un altro host, come sottolinea @KazimierasAliulis.

Raccogliere i pacchetti a livello di terminazione TCP e inoltrarli come nuovo flusso TCP è ragionevole. Lo strumento duplicatore a cui sei collegato sembra la tua scommessa migliore. Funziona come un proxy TCP, consentendo alla macchina a stati TCP di funzionare correttamente. Le risposte dalle tue macchine di prova verranno semplicemente scartate. Sembra che si adatti perfettamente a quello che vuoi esattamente.

Non mi è chiaro perché tu abbia cancellato lo strumento duplicatore come inaccettabile. Dovrai eseguire più istanze dello strumento poiché è in ascolto solo su una singola porta ma, presumibilmente, vuoi inoltrare ciascuna di queste diverse porte di ascolto a porte diverse sul sistema back-end. In caso contrario, è possibile utilizzare iptables DNAT per indirizzare tutte le porte di ascolto a una singola copia di ascolto dello strumento duplicatore.

A meno che le applicazioni che stai testando non siano sporche, mi aspetto che tu abbia problemi con questa metodologia di test relativa ai tempi e allo stato interno dell'applicazione. Quello che vuoi fare sembra ingannevolmente semplice: mi aspetto che troverai molti casi limite.


sì, hai perfettamente ragione, lo strumento duplicatore agnoster si adatterebbe ai nostri requisiti tranne che per la situazione multiporta. Anche lo scarto delle risposte della macchina di prova è pieno. Per raggiungere il nostro obiettivo di simulare la situazione reale / live nel modo più accurato possibile, non possiamo raggruppare tutte le porte sul server live su un'unica porta sulla macchina di prova. Porte diverse vengono utilizzate per dividere i dispositivi client in clienti diversi. Quindi, dobbiamo aprire 60-70 sessioni di questo strumento duplicatore. Questo non è molto pratico come puoi immaginare.
Seduta il

@Sise - I computer sono bravi a fare cose noiose. Penso che potresti scrivere uno script per analizzare le configurazioni di Apache e sputare le righe di comando necessarie per eseguire 60 - 70 istanze dello strumento duplicatore. Non riesco a immaginare che lo strumento duplicatore richieda molte risorse ma, anche se lo fosse, potresti eseguire quelle 60 - 70 istanze su un'altra macchina e fare qualche trucco di rete per ottenere il traffico laggiù. Per me, almeno, sembra del tutto pratico e un modo abbastanza semplice per gestirlo.
Evan Anderson,

1

Sto cercando di fare qualcosa di simile, tuttavia, se stai semplicemente cercando di simulare il carico su un server, guarderei qualcosa come un framework di test del carico. Ho usato locust.io in passato e ha funzionato molto bene per simulare un carico su un server. Ciò dovrebbe consentire di simulare un gran numero di client e di giocare con la configurazione del server senza dover passare attraverso il doloroso processo di inoltro del traffico a un altro server.


0

Per quanto riguarda "vorremmo duplicare il traffico HTTP in ingresso sul server live su uno o più server remoti in tempo reale", c'è un modo non menzionato sopra, che sta configurando una porta mirror sullo switch a cui è connessa.

Nel caso degli switch Cisco Catalyst, questo si chiama SPAN (maggiori informazioni qui ). In un ambiente Cisco puoi persino avere la porta speculare su uno switch diverso.

Ma lo scopo di questo è per l'analisi del traffico, quindi sarà unidirezionale - parola chiave nel testo citato nel primo paragrafo sopra: in entrata . Non credo che la porta consentirà alcun traffico di ritorno e, in caso affermativo, come gestiresti il ​​traffico di ritorno duplicato? Questo probabilmente causerà il caos con la tua rete.

Quindi ... volevo solo aggiungere una possibilità al tuo elenco, ma con l'avvertenza che sarà davvero per il traffico a senso unico. Forse puoi mettere un hub su quella porta mirror e avere risposte duplicate del server fornite da alcuni simulatori client locali che raccolgono sessioni avviate e rispondono, ma poi duplicheresti il ​​traffico in entrata sul tuo server duplicato ... probabilmente non quello che volere.


ci abbiamo pensato, ho letto dell'alternativa all'utilizzo di SPAN. Tuttavia, poiché i server si trovano in un data center di un fornitore di terze parti, abbiamo possibilità limitate quando si tratta di modifiche hardware. Ho già richiesto di collegare 2 server su un secondo nic direttamente. Questa azione combinata con una rete locale solo per questi 2 server mi permetterebbe di usare IPTABLES con TEE. Ma per scegliere questa alternativa dovremmo cambiare gli IP esterni dei server, che è un NoGo perché i dispositivi client sono configurati per connettersi all'IP impostato.
Seduta il

0

Ho anche scritto un proxy inverso / bilanciamento del carico per uno scopo simile con Node.js (è solo per divertimento, non pronto per la produzione al momento).

https://github.com/losnir/ampel

È molto supponente e attualmente supporta:

  • GET Utilizzo della selezione round robin (1: 1)
  • POSTUtilizzo della suddivisione della richiesta. Non esiste un concetto di "master" e "shadow": il primo back-end che risponde è quello che servirà la richiesta del client e quindi tutte le altre risposte verranno scartate.

Se qualcuno lo trova utile, posso migliorarlo per renderlo più flessibile.


Node.js è una scelta di linguaggio molto strana per un'applicazione come questa che richiederà prestazioni molto elevate. Non sono sicuro che questo sarà mai pronto per la produzione.
Michael Hampton

Hai assolutamente ragione. Questo non voleva essere altamente performante - solo facile da scrivere (per me). Penso che dipenda dal carico richiesto. Sono stato in grado di raggiungere un po 'più di 1.000 giri su una macchina di fascia bassa (2 core).
losnir,

0

la mia azienda aveva requisiti simili, per clonare un pacchetto e inviarlo a un altro host (eseguiamo simulatori di dati di mercato e avevamo bisogno di una soluzione temporanea in grado di ascoltare un feed TCP di dati di mercato, ingerire ogni pacchetto ma anche inviare un clone di ciascun pacchetto a un altro simulatore server)

questo binario funziona molto bene, è una versione di TCP Duplicator ma scritta in Golang invece che in jscript, quindi è più veloce e funziona come pubblicizzato,

https://github.com/mkevac/goduplicator


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.