Nginxを使ってTCP/WebSocketプロトコルのために逆エージェントといくつかの踏みやすい穴をします


通常、私たちはNginxを使用してバックエンドWEBサービスのために逆エージェントや負荷バランスをしていますが、もし私たちのバックエンドサービスがHTTP/HTTPSプロトコルではなく、TCPプロトコルやWebSocketプロトコルだったら、最近需要に遭遇しました.私たちのHTTPSとMQTTサービス側は海外のクラウドホスト上で、大陸からの直結遅延によるパケット損失が深刻ですが、香港から転送すれば、ネットワークの品質はずっと良くなることができて、そこで香港のクラウドホストで逆方向の代理を構築して、同時にHTTPSとMQTTサービスを代理します.TCPプロトコルサービスの逆エージェントといえば、HAProxyという有名なソフトウェアがありますが、HAProxyはTCPエージェントの面でもっと集中しています.しかし、私たちのサーバはNginxを大量に使用しているため、追加のソフトウェアを使用したくないので、Nginxでこのタスクを完了するつもりです.実はNginxは1.9と1.11の2つの大バージョンの大躍進的な開発を経て、現在機能と特性の上で、すでに大幅にHAProxyを超えています.TCP/UDPプロトコルのエージェントではすでに完璧で、彼が適任かどうか心配する必要はありません.ただし、Nginxは1.9.0からTCPプロトコルエージェントをサポートし、1.9.13からUDPエージェントをサポートし、使用前に--with-streamモジュールをインストールする必要があります.
nginx -V

あなたのバージョンとモジュールのインストール状況をチェックします.出力された情報はすべて1行にあるので、非常に乱れています.このようにして、行ごとに出力して見ることができます.
2>&1 nginx -V | tr ' '  '
'

Ubuntuシステムの場合、デフォルトのaptソースにインストールされているnginxにはこのモジュールがありません.また、nginx-extrasをインストールして--with-stream機能をオンにする必要があります.
sudo apt install nginx
sudo apt install nginx-extras

次に、Nginx構成TCP逆エージェントを変更し、mq.mypig.comの8883ポートでMQTTサービスが実行されていると仮定します.
stream {
    server {
        listen 8883;
        proxy_pass mq.mypig.com:8883;
    }
}

なお、nginxの構成は通常/etc/nginx/sites-enabled/で構成されていますが、/etc/nginx/nginx.confを見ると、/etc/nginx/sites-enabled/の構成ファイルは、実際にはhttp{}ブロックに含まれており、上のstream{}ブロックを/etc/nginx/sites-enabled/の構成ファイルに入れると、実際にstream{}ブロックをhttp{}ブロックに入れると、自然にエラーが発生するので、TCPエージェントサービスを構成するために/etc/nginx/nginx.confにstream{}ブロックを追加する必要があります.詳細パラメータは、Nginxの公式ドキュメントを参照して構成します.http://nginx.org/en/docs/stream/ngx_stream_proxy_module.html通常、タイムアウトの問題に注目する必要があるのは、主に次の2つのパラメータです.proxy_connect_timeoutエージェントサーバからバックエンドサーバへの接続タイムアウト値、デフォルト60秒proxy_timeoutエージェントタイムアウト値、すなわち、TCP接続が確立され、その値を超える時間に接続上でデータが転送されない場合、Nginxは接続を閉じ、デフォルトで10分
ポイント:NginxエージェントTCP接続を使用して、私たちは注意しなければならない点、私たちのTCP接続、keep-aliveハートビートパケットを開いたかどうか、私たちのこの例では、エージェントはMQTTのTCP接続で、MQTTクライアントとサービス側のため、デフォルトは60秒ごとにハートビートパケットを送信するように設定されているので、いつもTCP接続でデータが伝送されていますが、NginxエージェントTCP接続の場合、proxy_timeoutはデフォルトで10分なので、問題はありません.しかし、エージェントのTCP接続がMQTTのようにドキドキしない場合は、データ転送がない場合はproxy_を超えます.timeoutが設定した10分で、NginxはTCP接続を切断します.TCPベースのカスタムプロトコルをエージェントする場合は、プロトコルの実装に注目し、socketを使用してTCP接続を確立する必要があります.デフォルトではkeep-aliveは有効ではありません.アクティブに有効になっても、デフォルトの心拍時間は2時間です.したがって、コードを作成するときにTCP keep-aliveをオンにし、合理的な心拍時間を設定する必要があります.
これで、TCPプロトコルの逆エージェントが完了し、MQTTサービスはエージェントを通じて正常に動作することができますが、MQTTサービスでは、すべてのクライアントIPが同じ、すなわちNginxマシンのIPであり、NginxはTCPパケットを脳なしで転送するだけなので、バックエンドサーバのソースIPが何であるかを教えることができません.これにより、ビジネスロジックに影響はありませんが、お客様のソースを分析して回線を最適化、調整するのに不利です.
そこで,MQTTのWebSocket接続機能をオンにし,クライアントがWebSocketプロトコルを介して接続できるようにすることを検討した.MQTTサービスはWebSocketを使用するのに多くの利点があります.一例として、よく見られるMQTTクライアントは、AndroidクライアントでもPCクライアントでも、WebSocketプロトコル接続MQTTをサポートし、シームレスに切り替えることができます.二例として、フロントエンドページのjavascriptもWebSocket協定で直接MQTTサービスに接続することができます.
私たちにとってもっと重要なのは、WebSocketが接続を確立する時、まず標準HTTP要求ヘッダを送信し、このHTTP要求ヘッダを利用して、私たちは中間で多くの追加のことをすることができて、例えば認証、権限制御、私たちはHTTP要求ヘッダの情報に基づいて、この接続を放行するか、それとも直接閉じるかを決定することができます.同様に、Nginxにとって、NginxはWebSocketを逆エージェントする場合、接続を確立する際のHTTPリクエストヘッダにX-Forwarded-Forなどのコンテンツを入れることができ、バックエンドサービスはクライアントのソースIPを知ることができます.
やると言えばやるが、Nginx上でWebSocketを代理し、実際にはHTTP/HTTPSと差が少なく、Nginxの公式ドキュメントを見て構成することができる.http://nginx.org/en/docs/http/websocket.html
構成はstream{}ブロックではなくhttp{}ブロックに書く必要があるので、/etc/nginx/sites-enabled/の下で直接構成すれば、バックエンドはSSLで暗号化されたWebSocketプロトコルで8084ポートで実行され、パスは/mqttです.wss://mq.mypig.com:8084/mqtt Nginxリバースエージェントでは、次のように構成されます.
server {
    listen 443 ssl;
    server_name mq.mypig.com;
    ssl_certificate /home/ubuntu/cert/mq.mypig.com.crt;
    ssl_certificate_key /home/ubuntu/cert/mq.mypig.com.key;

    location = /mqtt {
        proxy_http_version 1.1;
        proxy_pass https://mq.mypig.com:8084;
        proxy_set_header Host $host:$server_port;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Port $remote_port;
        proxy_connect_timeout 60s;
        proxy_read_timeout 120s;
        proxy_send_timeout 120s;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Nginxプロキシサーバで443ポートを使用すると、HTTPSサービスと同じポートを多重化できますが、PATHで区別するだけです.実際には、構成全体とHTTPSの逆エージェントの差は多くありません.バックエンドのSSL証明書をNginxの逆エージェントサーバに取得する必要があります.Nginx上でデータを復号する必要があるため、Nginxはリクエストヘッダの内容(X-Forwarded-Forリクエストヘッダの追加)をチェックし、変更し、SSL暗号化でバックエンドに送信することができます.もちろん、負荷バランスをとるために使用される場合、Nginxとバックエンドサービスは同じ機械室、同じVPCであれば、データはNginx上でSSLを復号した後、直接バックエンドに明文すればよく、バックエンドサービスはSSL証明書を構成する必要がなく、同時にバックエンド復号の計算圧力を軽減することができる.HTTPのリバースエージェントとは異なる点は、
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

1つはHTTP 1.1を有効にすることです.NginxはHTTPのリバースエージェントに対して、デフォルトでHTTP 1.0を使用してバックエンドに接続しているので、長い接続を維持することができません.バックエンドがHTTP応答をすると、接続が切断されます.そのため、HTTP 1.1を有効にして長い接続をサポートします.UpgradeとConnectionでは、なぜNginxにこのリクエストヘッダを追加させるのか、WebSocketプロトコルではクライアントにUpgradeとConnectionリクエストヘッダが追加されているのではないでしょうか.それはHTTPプロトコル仕様によると、UpgradeとConnectionはhop-by-hopリクエストヘッダに属し、Nginxは中間のエージェントとして、仕様に従ってhop-by-hopヘッダを直接転送することはできないので、手動で強制的に設定する必要があるからです.
proxy_set_header Host $host:$server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Port $remote_port;

これらのHTTPリクエストヘッダを追加することにより、Nginxは、クライアントが本来要求していたターゲットHOSTとターゲットポート、クライアント自身のIPとクライアントが接続を開始したポートをバックエンドサーバに伝えることができる.同様に、接続のタイムアウト値:proxy_に関心を持つ必要があります.read_timeout proxy_send_timeoutの2つの構成の役割はTCPエージェントのproxy_に等しいtimeoutパラメータ、Nginxがproxy_を超えている場合read_timeoutの時間はバックエンドからデータを読み取らなかったり、proxy_を超えたりします.send_timeoutの時間がバックエンドにデータを送信しない場合、Nginxは接続を閉じます.
ポイント:多くの学生はここで穴をあけられて、この2つのパラメータを配置していません.NginxはWebSocketのエージェントに対して、HTTP/HTTPSエージェントに属しているので、Nginxの2つのパラメータのデフォルトのタイムアウト値は60秒です.もしあなたがそれを使用してMQTTをエージェントすると、MQTTのデフォルトの心拍時間は60秒なので、接続が頻繁に切断されていることがわかります.WebSocketプロトコルで実行されるサービスに注目する必要があります.ハートビートパケットが発生するかどうか、ハートビートパケット間隔はどのくらいですか.Nginxのタイムアウト値より小さくするか、Nginxのタイムアウト値を高くして、Nginxに接続を閉じられないようにする必要があります.
最後に、私たちのMQTTサービス側はEMQを使用しています.http://www.emqtt.com/再び安利といういいものは、プロファイルで有効にするだけです.
listener.wss.external.proxy_address_header = X-Forwarded-For
listener.wss.external.proxy_port_header = X-Forwarded-Port

Nginxエージェントが追加した要求ヘッダを自動的に処理し、クライアントIPとポートを正しく表示
本文はencoderleeからCSDNブログに発表された.https://blog.csdn.net/CharlesSimonyi/article/details/90122916 転載は出典を明記してください