Jak zduplikować ruch TCP do jednego lub wielu zdalnych serwerów w celach testowych?

30

Infrastruktura: serwery w centrum danych, OS - Debian Squeeze, Webserver - Apache 2.2.16


Sytuacja:

Serwer na żywo jest używany przez naszych klientów każdego dnia, co uniemożliwia testowanie poprawek i ulepszeń. Dlatego chcielibyśmy powielić przychodzący ruch HTTP na serwerze na żywo do jednego lub wielu serwerów zdalnych w czasie rzeczywistym. Ruch musi zostać przekazany do lokalnego serwera WWW (w tym przypadku Apache) ORAZ do zdalnego serwera (serwerów). W ten sposób możemy dostosować konfiguracje i użyć innego / zaktualizowanego kodu na zdalnym serwerze (serwerach) do testów porównawczych i porównania z bieżącym serwerem na żywo. Obecnie serwer nasłuchuje około. 60 dodatkowych portów oprócz 80 i 443, ze względu na strukturę klienta.


Pytanie: Jak można wdrożyć tę duplikację na jednym lub wielu zdalnych serwerach?

Próbowaliśmy już:

  • powielacz agnoster - wymagałoby to jednej otwartej sesji na port, co nie ma zastosowania. ( https://github.com/agnoster/duplicator )
  • kklis proxy - przesyła tylko ruch do zdalnego serwera, ale nie przekazuje go do serwera Lcoal. ( https://github.com/kklis/proxy )
  • iptables - DNAT przekazuje tylko ruch, ale nie przekazuje go do lokalnego serwera WWW
  • iptables - TEE duplikuje się tylko na serwerach w sieci lokalnej -> serwery nie znajdują się w tej samej sieci ze względu na strukturę centrum danych
  • sugerowane alternatywy dla pytania „zduplikowany ruch TCP z proxy” na stackoverflow ( https://stackoverflow.com/questions/7247668/duplicate-tcp-traffic-with-a-proxy ) okazały się nieskuteczne. Jak wspomniano, TEE nie działa ze zdalnymi serwerami poza siecią lokalną. teeproxy nie jest już dostępny ( https://github.com/chrislusf/tee-proxy ) i nie mogliśmy go znaleźć gdzie indziej.
  • Dodaliśmy drugi adres IP (który jest w tej samej sieci) i przypisaliśmy go do eth0: 0 (podstawowy adres IP jest przypisany do eth0). Bez powodzenia połączenie nowego IP lub interfejsu wirtualnego eth0: 0 z funkcją i trasami iptables TEE.
  • sugerowane alternatywy dla pytania „zduplikowany przychodzący ruch TCP przy ściśnięciu Debiana” ( Zduplikowany przychodzący ruch TCP przy ściśnięciu Debiana ) nie powiodły się. Sesje cat | nc (cat / tmp / prodpipe | nc 127.0.0.1 12345 i cat / tmp / testpipe | nc 127.0.0.1 23456) są przerywane po każdym żądaniu / połączeniu przez klienta bez powiadomienia lub dziennika. Keepalive nie zmieniło tej sytuacji. Pakiety TCP nie zostały przetransportowane do systemu zdalnego.
  • Dodatkowe próby z różnymi opcjami socat (HowTo: http://www.cyberciti.biz/faq/linux-unix-tcp-port-forwarding/ , https://stackoverflow.com/questions/9024227/duplicate-input- unix-stream-to-multiple-tcp-client-using-socat ) i podobne narzędzia zakończyły się niepowodzeniem, ponieważ podana funkcja TEE zapisze tylko FS.
  • Oczywiście przeglądanie i wyszukiwanie tego „problemu” lub konfiguracji również nie powiodło się.

Brakuje nam tutaj opcji.

Czy istnieje metoda wyłączenia wymuszania „serwera w sieci lokalnej” funkcji TEE podczas korzystania z IPTABLES?

Czy nasz cel może zostać osiągnięty poprzez różne użycie IPTABLES lub tras?

Czy znasz inne narzędzie do tego celu, które zostało przetestowane i działa w tych konkretnych okolicznościach?

Czy istnieje inne źródło tee-proxy (które idealnie pasowałoby do naszych wymagań, AFAIK)?


Z góry dziękuję za twoje odpowiedzi.

----------

edycja: 05.02.2014

oto skrypt Pythona, który działałby tak, jak go potrzebujemy:

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

Komentarze do użycia tego skryptu: Skrypt
ten przekazuje wiele skonfigurowanych portów lokalnych do innych lokalnych i zdalnych serwerów gniazd.

Konfiguracja:
Dodaj do pliku konfiguracyjnego linie port-forward.config z zawartością w następujący sposób:

Komunikaty o błędach są przechowywane w pliku „error.log”.

Skrypt dzieli parametry pliku konfiguracyjnego:
Podziel każdy wiersz konfiguracji spacjami
0: port lokalny, aby nasłuchiwać
1: port lokalny, aby przekazać do
2: zdalny adres IP serwera docelowego
3: zdalny port serwera docelowego
i ustawienia powrotu

Sise
źródło
Czy cały ruch HTTP?
longneck
tak, cały ruch jest HTTP.
Sise
1
btw. teeproxy jest dostępny tutaj: github.com/chrislusf/teeproxy
Tombart
1
Inna możliwość: github.com/ebowman/splitter Scala / Netty.
Rich K.,

Odpowiedzi:

11

To jest niemożliwe. TCP jest stanowym protokołem. Komputer końcowy użytkownika jest zaangażowany w każdy etap połączenia i nigdy nie będzie odpowiadać dwóm oddzielnym serwerom próbującym się z nim komunikować. Wszystko, co możesz zrobić, to zebrać wszystkie żądania HTTP na serwerze internetowym lub serwerze proxy i odtworzyć je. Ale to nie da dokładnych warunków współbieżności lub ruchu na żywo serwera.

Kazimieras Aliulis
źródło
Duplikowanie TCP jest niemożliwe - zgodzę się z tym. Powielanie ruchu warstwy 7 nie jest. Możesz przechwytywać żądania od klienta i odtwarzać je na innych serwerach. Proste 1 żądanie na odtwarzanie sesji TCP powinno być dość łatwe. Trwałe połączenia będą wymagały przemyślenia, jeśli chodzi o czas oczekiwania na dodatkowe żądania klienta.
Evan Anderson
@Kazimieras Aliulis: komunikacja z dwoma oddzielnymi serwerami nie jest wymagana. klient komunikuje się z serwerem podstawowym = serwerem na żywo. serwer na żywo przetwarza żądania klienta i odpowiada na klienta. oprócz przetwarzania i odpowiadania klientowi serwer główny powtarza żądania do drugiego serwera = serwer testowy. odpowiedzi z drugiego serwera na serwer główny zostaną odrzucone / zignorowane na serwerze głównym i nie zostaną przesłane do klienta.
Sise
@Evan Anderson: duplikacja na poziomie HTTP również była naszym pierwszym pomysłem, ale np. Serwer proxy Apache lub podobne narzędzia lub moduły nie pozwalają na jednoczesne przetwarzanie żądań lokalnie i duplikowanie ich na zdalnym hoście. jeśli masz inny pomysł, proszę o poradę! :) wolimy duplikację niż nagrywanie i odtwarzanie, aby uzyskać natychmiastowe wyniki porównania.
Sise
1
@Sise: możesz spróbować napisać własne proxy HTTP, które przekazuje ruch do dwóch serwerów. To powinno być dość łatwe w Pythonie Twisted Framework twistedmatrix.com .
Kazimieras Aliulis
@Kazimieras Aliulis: to zdecydowanie alternatywa! Nigdy o tym nie słyszałem. ale sprawdzenie to pokazuje, że idealnie pasowałoby do naszych celów. Wcześniej nie rozważaliśmy Pythona, ale obecnie przyglądamy się frameworkowi Twisted i możliwościom ogólnego Pythona. Odniosę się, jeśli nam się uda!
Sise
20

Z tego, co opisujesz, GOR wydaje się pasować do twoich potrzeb. https://github.com/buger/gor/ "Odtwarzanie ruchu HTTP w czasie rzeczywistym. Odtwarzanie ruchu z produkcji do środowisk inscenizacyjnych i programistycznych." ?

Arthur Lutz
źródło
2
To jest dokładnie to, czego szukałam, dziękuję, uratowałeś mi pisanie dokładnie to, w Go! :-)
chmac
nginx ma moduł lustrzany. nginx.org/en/docs/http/ngx_http_mirror_module.html
Jimmy MG Lim
7

Teeproxy można wykorzystać do replikacji ruchu. Użycie jest bardzo proste:

./teeproxy -l :80 -a localhost:9000 -b localhost:9001
  • a serwer produkcyjny
  • b serwer testowy

Kiedy umieścisz HAproxy (z roundrobin) przed serwerem, możesz łatwo przekierować 50% swojego ruchu na stronę testową:

         /------------------> production
HAproxy /                 ^
        \                /
         \---- teeproxy -.....> test (responses ignored)
Tombart
źródło
4

TCP, będący protokołem stanowym, nie może po prostu wysadzić kopii pakietów na innym hoście, jak wskazuje @KazimierasAliulis.

Pobieranie pakietów na poziomie zakończenia TCP i przekazywanie ich jako nowego strumienia TCP jest rozsądne. Narzędzie powielacz jesteś związana wygląda najlepiej. Działa jako proxy TCP, pozwalając maszynie stanów TCP działać poprawnie. Odpowiedzi z twoich maszyn testowych zostaną po prostu odrzucone. Wygląda na to, że pasuje dokładnie do tego, czego dokładnie chcesz.

Nie jest dla mnie jasne, dlaczego spisałeś narzędzie do powielania jako niedopuszczalne. Będziesz musiał uruchomić wiele instancji narzędzia, ponieważ nasłuchuje tylko na jednym porcie, ale prawdopodobnie chcesz przekazać każdy z tych różnych portów nasłuchu do różnych portów w systemie zaplecza. Jeśli nie, możesz użyć iptables DNAT, aby skierować wszystkie porty nasłuchujące do pojedynczej nasłuchującej kopii narzędzia powielającego.

O ile testowane aplikacje nie są proste, spodziewam się, że będziesz mieć problemy z tą metodologią testowania związaną z czasem i wewnętrznym stanem aplikacji. To, co chcesz zrobić, brzmi zwodniczo prosto - spodziewam się, że znajdziesz wiele skrzynek.

Evan Anderson
źródło
tak, masz całkowitą rację, narzędzie do powielania agnoster spełniałoby nasze wymagania, z wyjątkiem sytuacji z wieloma portami. Również odrzucanie odpowiedzi maszyny testowej jest spełnione. Aby osiągnąć nasz cel, jakim jest jak najdokładniejsza symulacja sytuacji rzeczywistej / na żywo, nie możemy połączyć wszystkich portów na serwerze na żywo z jednym portem na maszynie testowej. Różne porty służą do dzielenia urządzeń klienckich na różnych klientów. Tym samym musimy otworzyć 60–70 sesji tego narzędzia do powielania. Nie jest to zbyt praktyczne, jak można sobie wyobrazić.
Sise
@Sise - Komputery potrafią robić nudne rzeczy. Sądzę, że możesz napisać skrypt analizujący konfiguracje Apache i wyrzucić niezbędne linie poleceń, aby uruchomić 60 - 70 instancji narzędzia powielającego. Nie mogę sobie wyobrazić, że narzędzie do powielania wymaga dużych zasobów, ale nawet gdyby tak było, można uruchomić te 60 - 70 wystąpień na innym komputerze i wykonać pewne sztuczki sieciowe, aby uzyskać tam ruch. Przynajmniej dla mnie wydaje się to całkowicie praktyczne i całkiem prosty sposób na poradzenie sobie z tym.
Evan Anderson
1

Próbuję zrobić coś podobnego, jednak jeśli próbujesz po prostu symulować obciążenie serwera, spojrzałbym na coś w rodzaju struktury testowania obciążenia. W przeszłości korzystałem z locust.io i działało to bardzo dobrze do symulacji obciążenia serwera. Powinno to pozwolić na symulację dużej liczby klientów i umożliwić zabawę z konfiguracją serwera bez konieczności przechodzenia przez bolesny proces przekazywania ruchu na inny serwer.

snowbirdSkiBum
źródło
0

O ile „chcielibyśmy zduplikować przychodzący ruch HTTP na serwerze na żywo do jednego lub wielu zdalnych serwerów w czasie rzeczywistym”, nie ma jednego sposobu, o którym nie wspomniano powyżej, czyli skonfigurowania portu lustrzanego na przełączniku, z którym jest on podłączony.

W przypadku przełączników Cisco Catalyst nazywa się to SPAN (więcej informacji tutaj ). W środowisku Cisco możesz nawet mieć port lustrzany na innym przełączniku.

Ale ma to na celu analizę ruchu, więc będzie jednokierunkowe - słowo kluczowe w cytowanym tekście w pierwszym akapicie powyżej: przychodzące . Nie sądzę, aby ten port zezwalał na ruch powrotny, a jeśli tak, to jak poradziłbyś sobie z powielonym ruchem powrotnym? Prawdopodobnie spowoduje to spustoszenie w twojej sieci.

Więc ... chciałem tylko dodać jedną opcję do listy, ale z zastrzeżeniem, że rzeczywiście będzie to ruch jednokierunkowy. Być może możesz umieścić hub na tym porcie lustrzanym i mieć zduplikowane odpowiedzi serwera przekazywane przez lokalny symulator klienta, który odbierze zainicjowane sesje i odpowie na nie, ale wtedy będziesz duplikował ruch przychodzący na twój duplikat serwera ... prawdopodobnie nie to, co ty chcieć.

James
źródło
pomyśleliśmy o tym, czytałem o alternatywnym użyciu SPAN. Ponieważ jednak serwery znajdują się w centrum danych zewnętrznego dostawcy, mamy ograniczone możliwości zmian sprzętu. Poprosiłem już o bezpośrednie połączenie 2 serwerów w drugiej nici. Ta akcja w połączeniu z siecią lokalną tylko dla tych 2 serwerów pozwoliłaby mi używać IPTABLES z TEE. Ale aby skorzystać z tej alternatywy, musielibyśmy zmienić zewnętrzne adresy IP serwerów, co nie jest konieczne, ponieważ urządzenia klienckie są skonfigurowane do łączenia się z ustawionym adresem IP.
Sise
0

Napisałem również odwrotny serwer proxy / moduł równoważenia obciążenia do podobnego celu w Node.js (jest to po prostu dla zabawy, a nie jest obecnie gotowe do produkcji).

https://github.com/losnir/ampel

Jest bardzo opiniotwórczy i obecnie obsługuje:

  • GET Korzystanie z selekcji round-robin (1: 1)
  • POSTKorzystanie z podziału żądań. Nie ma pojęcia „master” i „shadow” - pierwszy backend, który odpowiada to ten, który obsłuży żądanie klienta, a następnie wszystkie pozostałe odpowiedzi zostaną odrzucone.

Jeśli ktoś uzna to za przydatne, mogę go ulepszyć, aby był bardziej elastyczny.

losnir
źródło
Node.js to bardzo dziwny wybór języka dla aplikacji takich jak ta, która będzie wymagała bardzo wysokiej wydajności. Nie jestem pewien, czy kiedykolwiek będzie gotowy do produkcji.
Michael Hampton
Masz absolutną rację. To nie miało być bardzo wydajne - po prostu łatwe do napisania (dla mnie). Myślę, że to zależy od wymaganego obciążenia. Udało mi się jednak osiągnąć nieco ponad 1000 rps na maszynie niższej klasy (2 rdzenie).
losnir
0

moja firma miała podobny wymóg, aby sklonować pakiet i wysłać go do innego hosta (prowadzimy symulatory danych rynkowych i potrzebowaliśmy tymczasowego rozwiązania, które nasłuchiwałoby kanału TCP danych rynkowych, przyjmował każdy pakiet, ale także wysyłał klon każdego pakietu do innego symulatora serwer)

ten plik binarny działa bardzo dobrze, jest to wersja TCP Duplicator, ale napisana w golang zamiast w jscript, więc jest szybsza i działa zgodnie z reklamą,

https://github.com/mkevac/goduplicator

perfecto25
źródło
-1

istnieje narzędzie stworzone przez faceta z chińskiej firmy i być może jest to, czego potrzebujesz: https://github.com/session-replay-tools/tcpcopy

Musikoder
źródło
2
Cześć, witamy w błędzie serwera. Czy możesz podać bardziej szczegółową odpowiedź? Co dokładnie robi program? Czy jest napisane w C ...?
bgtvfr