ベンチマークの目的でTCPトラフィックを1つまたは複数のリモートサーバーに複製する方法


30

インフラストラクチャ:データセンターのサーバー、OS-Debian Squeeze、ウェブサーバー-Apache 2.2.16


状況:

ライブサーバーは毎日お客様によって使用されているため、調整や改善をテストすることはできません。そのため、ライブサーバー上のインバウンドHTTPトラフィックをリアルタイムで1つまたは複数のリモートサーバーに複製したいと考えています。トラフィックは、ローカルWebサーバー(この場合はApache)およびリモートサーバーに渡す必要があります。これにより、構成を調整し、現在のライブサーバーとのベンチマークと比較のためにリモートサーバーで異なる/更新されたコードを使用できます。現在、ウェブサーバーは約をリッスンしています。クライアント構造のため、80および443以外に60個の追加ポート。


質問:1つまたは複数のリモートサーバーへのこの複製をどのように実装できますか?

私たちはすでに試しました:

  • agnoster duplicator-これには、ポートごとに1つのオープンセッションが必要ですが、これは適用されません。(https://github.com/agnoster/duplicator
  • kklisプロキシ-トラフィックをリモートサーバーに転送するだけで、lcoal Webサーバーには渡しません。(https://github.com/kklis/proxy
  • iptables-DNATはトラフィックを転送するだけで、ローカルWebサーバーには渡しません
  • iptables-TEEはローカルネットワーク内のサーバーにのみ複製します->データセンターの構造上、サーバーは同じネットワークに配置されていません
  • stackoverflow(https://stackoverflow.com/questions/7247668/duplicate-tcp-traffic-with-a-proxy)の「プロキシでtcpトラフィックを複製する」という質問に対して提供された代替案は失敗しました。前述のように、TEEはローカルネットワーク外のリモートサーバーでは機能しません。teeproxyは使用できなくなり(https://github.com/chrislusf/tee-proxy)、他の場所で見つけることができませんでした。
  • 2番目のIPアドレス(同じネットワーク内にある)を追加し、それをeth0:0に割り当てました(プライマリIPアドレスがeth0に割り当てられています)。この新しいIPまたは仮想インターフェイスeth0:0をiptables TEE機能またはルートと組み合わせても成功しません。
  • 「debian squeezeで着信TCPトラフィックを複製する」(Debian Squeezeで着信TCPトラフィックを複製する)の質問に対して提供された代替案は失敗しました。cat | ncセッション(cat / tmp / prodpipe | nc 127.0.0.1 12345およびcat / tmp / testpipe | nc 127.0.0.1 23456)は、クライアントによるすべての要求/接続後に、通知またはログなしで中断されます。キープアライブはこの状況を変えませんでした。TCPパッケージはリモートシステムに転送されませんでした。
  • socatに関するの異なるオプションで追加の試行(手引き:http://www.cyberciti.biz/faq/linux-unix-tcp-port-forwarding/https://stackoverflow.com/questions/9024227/duplicate-input- unix-stream-to-multiple-tcp-clients-using-socat)および同様のツールは、提供されたTEE機能がFSのみに書き込むため、失敗しました。
  • もちろん、この「問題」またはセットアップのグーグル検索は失敗しました。

ここでオプションが不足しています。

IPTABLESを使用する場合、TEE機能の「ローカルネットワークのサーバー」の実施を無効にする方法はありますか?

IPTABLESまたはRoutesをさまざまに使用することで目標を達成できますか?

これらの特定の状況でテストされ、機能するこの目的のための別のツールを知っていますか?

tee-proxyの別のソースはありますか(要件に完全に適合すると思いますが)。


返信ありがとうございます。

----------

編集:05.02.2014

pythonスクリプトは、必要な方法で機能します。

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

このスクリプトを使用するためのコメント:
このスクリプトは、構成された多数のローカルポートを別のローカルおよびリモートソケットサーバーに転送します。

構成:構成
ファイルにport-forward.config行を次の内容で追加します。

エラーメッセージは「error.log」ファイルに保存されます。

スクリプトは、構成ファイルのパラメーターを
分割します。各構成行をスペースで分割します
0:待機するローカルポート
1:転送するローカルポート
2:宛先サーバーのリモートIPアドレス
3:宛先サーバーのリモートポート
および設定を返す


トラフィックはすべてHTTPですか?
ロングネック14年

はい、すべてのトラフィックはHTTPです。
SISE

1
ところで。teeproxyはここから入手できます:github.com/chrislusf/teeproxy
トムバート

1
別の可能性:github.com/ebowman/splitter Scala / Nettyベース。
リッチK.

回答:


11

それは無理だ。TCPはステートフルプロトコルです。ユーザーエンドコンピューターは接続のすべてのステップに関与し、通信しようとする2つの別個のサーバーに応答することはありません。できることは、すべてのHTTPリクエストをWebサーバーまたはプロキシで収集して再生することだけです。しかし、それはライブサーバーの同時性やトラフィック状態を正確に示しません。


TCPを複製することは不可能です。それに同意します。レイヤー7トラフィックの複製はそうではありません。クライアントからの要求をキャプチャして、他のサーバーに再生できます。TCPセッションの再生ごとに1つの単純なリクエストを行うのは非常に簡単です。永続的な接続では、クライアントの追加リクエストのタイミングについては、ある程度の考慮が必要になります。
エヴァンアンダーソン14年

@Kazimieras Aliulis:2つの別個のサーバーと通信する必要はありません。クライアントは、プライマリサーバー=ライブサーバーと通信しています。ライブサーバーはクライアント要求を処理しており、クライアントに応答しています。クライアントへの処理と応答に加えて、プライマリサーバーはリクエストを2番目のサーバー=テストサーバーに複製しています。2次サーバーから1次サーバーへの応答は1次サーバーで破棄/無視され、クライアントに転送されません。
SISE

@Evan Anderson:HTTPレベルでの複製も私たちの最初のアイデアでしたが、たとえば、Apacheプロキシまたは同様のツールまたはモジュールでは、要求をローカルで同時に処理してリモートホストに複製することはできません。他にアイデアがあれば、アドバイスしてください!:)即時の比較結果を得るために、記録と再生よりも複製を好んでいます。
SISE

1
@Sise:トラフィックを2つのサーバーに渡す独自のHTTPプロキシを作成してみてください。python Twisted framework twistedmatrix.comを使用すると、非常に簡単に実行できます。
カジミエラスアリウリス14年

@Kazimieras Aliulis:それは間違いなく代替手段です!私はそれを聞いたことがありません。しかし、それをチェックすると、それが私たちの目的に完全に適合することを示しています。以前はpythonを検討していませんでしたが、現在はTwistedフレームワークと一般的なpythonの可能性も検討しています。成功したら報告します!
シセ14年

20

あなたの説明から、GORはあなたのニーズに合っているようです。 https://github.com/buger/gor/「HTTPトラフィックをリアルタイムでリプレイします。実稼働からステージングおよび開発環境へのトラフィックをリプレイします。」?


2
これはまさに私が探していたものです。ありがとう、Go!:-)
chmac 14

nginxにはミラーモジュールがあります。nginx.org/en/docs/http/ngx_http_mirror_module.html
ジミーMGリム

7

Teeproxyを使用してトラフィックを複製できます。使い方は本当に簡単です:

./teeproxy -l :80 -a localhost:9000 -b localhost:9001
  • a 本番サーバー
  • b テストサーバー

roundrobinWebサーバーの前にHAproxy(を使用)を配置すると、トラフィックの50%をテストサイトに簡単にリダイレクトできます。

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

4

TCPは、ステートフルプロトコルであるため、@ KazimierasAliulisが指摘するように、別のホストでパケットのコピーを単純にブラストすることはできません。

TCP終端の層でパケットを取得し、それらを新しいTCPストリームとして中継するのが妥当です。デュプリケータツール、あなたの最善の策のようなルックスにリンクされています。TCPプロキシとして動作し、TCPステートマシンが適切に動作できるようにします。テストマシンからの応答は破棄されます。それはあなたが正確に望むものの法案に合っているように聞こえます。

なぜ複製ツールを受け入れられないものとして書いたのか、私にはわかりません。ツールは単一のポートでのみリッスンするため、ツールの複数のインスタンスを実行する必要がありますが、おそらく、これらの異なるリッスンポートのそれぞれをバックエンドシステム上の異なるポートにリレーする必要があります。そうでない場合は、iptables DNATを使用して、すべてのリスニングポートを複製ツールの単一のリスニングコピーに向けることができます。

テストしているアプリケーションが非常に単純でない限り、タイミングと内部アプリケーションの状態に関連するこのテスト方法に問題があると予想しています。あなたがやりたいことは一見単純に聞こえます-多くのエッジケースを見つけることになると思います。


はい、あなたは完全に正しいです、agnoster複製ツールはマルチポートの状況を除いて私たちの要件に適合します。また、テストマシンの応答の破棄もいっぱいになります。実際の状況をできるだけ正確にシミュレートするという目標を達成するために、ライブサーバーのすべてのポートをテストマシンの1つのポートにバンドルすることはできません。さまざまなポートを使用して、クライアントデバイスをさまざまな顧客に分割します。そのため、この複製ツールの60〜70セッションを開く必要があります。これは想像できるほど実用的ではありません。
Sise 14年

@Sise-コンピューターは退屈なことをするのが得意です。Apacheの構成を解析し、必要なコマンドラインを吐き出して複製ツールの60〜70個のインスタンスを実行するスクリプトを作成できると思います。デュプリケーターツールが非常にリソースを消費することは想像できませんが、たとえそうであっても、それらの60〜70のインスタンスを別のマシンで実行し、そこからトラフィックを得るためにネットワークトリックを行うことができます。少なくとも私には、これは完全に実用的で、これを処理するための非常に簡単な方法のようです。
エヴァンアンダーソン14年

1

同様のことをしようとしていますが、単にサーバーの負荷をシミュレートしようとしている場合は、負荷テストフレームワークのようなものを見ます。私は過去にlocat.ioを使用しましたが、サーバーの負荷をシミュレートするために非常にうまく機能しました。これにより、多数のクライアントをシミュレートし、トラフィックを別のサーバーに転送するという苦痛なプロセスを経ることなく、サーバーの構成を試すことができます。


0

「ライブサーバーのインバウンドHTTPトラフィックをリアルタイムで1つまたは複数のリモートサーバーに複製したい」限り、上記以外の1つの方法があります。これは、接続先のスイッチにミラーポートを構成することです。

Cisco Catalystスイッチの場合、これはSPANと呼ばれます(詳細はこちら)。シスコ環境では、ミラー化されたポートを別のスイッチに配置することもできます。

ただし、この目的はトラフィック分析のためであるため、上記の最初の段落で引用されたテキストのキーワードであるinboundになります。そのポートはリターントラフィックを許可しないと思います。許可された場合、重複したリターントラフィックをどのように処理しますか。それはおそらくあなたのネットワークに大混乱をもたらすでしょう。

だから...あなたのリストに1つの可能性を追加したかっただけですが、それは確かに一方通行のものであるという警告があります。そのミラーポートにハブを配置し、開始されたセッションをピックアップして応答するローカルクライアントシミュレーターによって複製されたサーバー応答を渡すこともできますが、複製サーバーへの着信トラフィックを複製することになります...欲しいです。


私たちはそれについて考えました、私はSPANを使用する代替案について読みました。ただし、サーバーはサードパーティプロバイダーのデータセンターにあるため、ハードウェアの変更に関しては限られた可能性しかありません。私はすでに2番目のNICの2つのサーバーを直接接続するように要求しています。このアクションをこれら2つのサーバーだけのローカルネットワークと組み合わせることで、TEEでIPTABLESを使用できるようになります。しかし、この代替方法を採用するには、サーバーの外部IPを変更する必要があります。これは、クライアントデバイスが設定されたIPに接続するように構成されているため、NoGoです。
SISE

0

また、Node.jsで同様の目的でリバースプロキシ/ロードバランサーを作成しました(これはただの楽しみであり、現時点では本番用ではありません)。

https://github.com/losnir/ampel

非常に意見が多く、現在以下をサポートしています。

  • GET ラウンドロビン選択の使用(1:1)
  • POSTリクエストの分割を使用します。「マスター」と「シャドウ」の概念はありません。最初に応答するバックエンドはクライアント要求を処理するバックエンドであり、他のすべての応答は破棄されます。

誰かがそれを便利だと思うなら、私はそれをより柔軟に改善することができます。


Node.jsは、非常に高いパフォーマンスを必要とするこのようなアプリケーションの言語の非常に奇妙な選択です。これが本番用になるかどうかはわかりません。
マイケルハンプトン

あなたは、絶対に正しい。これは、高いパフォーマンスを発揮することを意図したものではありませんでした-簡単に書くことができます(私にとって)。必要な負荷に依存すると思います。しかし、ローエンドマシン(2コア)で1,000rpsを少し超えることができました。
ロスニア

0

私の会社には、パケットを複製して別のホストに送信するという同様の要件がありました(市場データシミュレーターを実行し、市場データのTCPフィードをリッスンし、各パケットを取り込み、各パケットのクローンを別のシミュレーターに送信する一時的なソリューションが必要でした)サーバ)

このバイナリは非常にうまく動作します。TCPDuplicatorのバージョンですが、jscriptではなくgolangで記述されているため、より高速で、宣伝どおりに動作します。

https://github.com/mkevac/goduplicator


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.