Taobaoオンラインアプリケーションの従来のソフトウェアスタック構造は、nginx + velocity + javaです。
このシステムでは、NginxはリクエストをJavaアプリケーションに転送します。これにより、トランザクションを処理し、速度テンプレートを使用してデータを最終ページにレンダリングします。
node.jsを導入した後、必然的に次の問題に直面します。
テクノロジースタックのトポロジ構造を設計する方法と展開方法を選択する方法は、科学的で合理的であると考えられていますか?プロジェクトが完了した後、トラフィックを分割する方法は、運用とメンテナンスに便利で高速なものですか?オンラインの問題に遭遇したとき、できるだけ早く危険を排除し、より大きな損失を避ける方法は?アプリケーションの健康を確保し、負荷分散スケジューリングレベルで管理する方法は?システムトポロジ
フロントエンドとバックエンドの分離に関する私たちの思考と実践によれば(ii) - フロントエンドとバックエンドのテンプレート探索に基づいて、速度をnode.jsに置き換える必要があります。
これはもちろん理想的な目標です。ただし、従来のスタックでのnode.jsレイヤーの最初の導入は、結局のところ新しい試みです。安全にするために、お気に入りのお気に入りのページ(shoucang.taobao.com/item_collect.htm)での新しいテクノロジーのみを有効にすることにしましたが、他のページは従来のソリューションを使用し続けています。つまり、nginxはリクエストのページタイプを決定し、要求をnode.jsまたはjavaに転送するかどうかを決定します。だから、最終的な構造は次のとおりです。
展開計画
上記の構造は問題ないようですが、実際、新しい問題はまだ正面を待っています。従来の構造では、NginxとJavaが同じサーバーに展開されます。 Nginxはポート80に耳を傾け、Javaと通信します。 node.jsが導入されたので、リスニングポートを実行する必要がある新しいプロセスが必要です。 Node.jsは、Nginx + Javaを使用して同じマシンに展開する必要がありますか、それとも別のクラスターにnode.jsを展開する必要がありますか?
2つの方法の特性を比較しましょう。
Taobaoのお気に入りは、毎日平均PVが数千万人のアプリケーションであり、安定性のための非常に高い要件があります(実際、どの製品のオンライン不安定性も受け入れられません)。同じクラスター展開ソリューションを採用する場合は、ファイルを1回配布し、2回再起動してリリースを完了するだけです。ロールバックする必要がある場合は、ベースラインパッケージを1回操作するだけです。パフォーマンスに関しては、同じクラスターの展開にもいくつかの理論的利点があります(ただし、イントラネットのスイッチ帯域幅とレイテンシは非常に楽観的です)。 1対多または多面的な関係については、理論的にはサーバーによってより完全に利用される可能性がありますが、安定性要件と比較すると、この点は解決するのにそれほど緊急ではありません。そのため、お気に入りの変換では、同じクラスター展開ソリューションを選択しました。
グレースケール
最大の安定性を確保するために、この変換では速度コードを完全に除去しませんでした。アプリケーションクラスターには、ほぼ100個のサーバーがあります。サーバーを粒度として使用し、トラフィックを徐々に導入します。言い換えれば、Java + node.jsプロセスはすべてのサーバーで実行されていますが、Nginxに対応する転送ルールがあるかどうかは、このサーバーのベビーコレクションを取得するリクエストがnode.jsを介して処理されるかどうかを決定します。 nginxの構成は次のとおりです。
場所= "/item_collect.htm" {proxy_pass http://127.0.0.1:6001; #Node.jsプロセスリスニングポート}このnginxルールを追加したサーバーのみが、node.jsが対応するリクエストを処理できるようにします。 Nginx構成により、グレースケールのトラフィックを迅速に増加および削減するのは非常に便利で迅速であり、コストは非常に低くなります。問題が発生した場合、Nginx構成を直接ロールバックし、すぐに従来のテクノロジースタック構造に戻って危険を緩和できます。
最初にリリースしたとき、2つのサーバーでこのルールのみを有効にしました。つまり、オンライントラフィックの2%未満がnode.jsで処理され、残りのトラフィックのリクエストはまだ速度によってレンダリングされます。将来的には、状況に応じてトラフィックが徐々に増加し、最後に3週目にはすべてのサーバーが有効になります。この時点で、生産環境に100%のトラフィックを持つ製品収集ページは、node.jsによってレンダリングされます(ソースコードを確認して、node.jsキーワードを検索できます)。
変化
グレースケールプロセスはスムーズではありません。フローを完全に切る前に、私は大規模であろうと小さくても、いくつかの問題に遭遇しました。ほとんどのビジネスは特定のビジネスに関連しており、学ぶ価値のあるものは技術的な詳細に関連するtrapです。
健康チェック
従来のアーキテクチャでは、ロードバランシングスケジューリングシステムは、各サーバーのポート80の特定のURLに毎秒getリクエストを開始し、返されたHTTPステータスコードが200あるかどうかに基づいてサーバーが通常動作しているかどうかを判断します。 1S後のタイムアウトが要求された場合、またはHTTPステータスコードが200でない場合、オンラインの問題を回避するためにサーバーにトラフィックは導入されません。
このリクエストへのパスはnginx-> java-> nginxです。つまり、 200が返されている限り、このサーバーのnginxとJavaは健康な状態です。 node.jsを導入した後、このパスはnginx-> node.js-> java-> node.js-> nginxになります。対応するコードは次のとおりです。
var http = require( 'http'); app.get( '/status.taobao'、function(req、res){http.get({host: '127.1'、port:7001、path: '/status.taobao'}、function(res){res.send(res.statuscode);})。 res.send(404));ただし、テストプロセス中に、node.jsがそのようなリクエストを転送すると、Javaサイドが6〜7回1回戻るのに数秒または10秒かかることがわかりました。これにより、負荷分散スケジューリングシステムは、サーバーで異常が発生し、トラフィックを遮断すると考えるようになりますが、実際にはサーバーは正常に動作できます。これは明らかに大きな問題です。
検索の後、デフォルトではnode.jsがHTTP Agentクラスを使用してHTTP接続を作成することがわかりました。このクラスは、ソケット接続プールを実装します。各ホスト +ポートペアの接続数のデフォルト上限は5です。同時に、 HTTP Agentクラスによって開始されたリクエストにはConnection: Keep-Aliveが含まれます。
3つの最終的な解決策があります。
HTTP Agentを無効にします。つまり、追加のパラメーターagent: false get最終コードは次のとおりです。
var http = require( 'http'); app.get( '/status.taobao'、function(req、res){http.get({host: '127.1'、port:7001、agent:false、path: '/status.taobao'}、function(res){res.send(res.statuscode);})。 res.send(404)); httpオブジェクトのグローバルソケット番号の上限を設定します。
http.globalagent.maxsockets = 1000;
リクエストが返されると、タイムリーで積極的に切断されます。
http.get(options、function(res){})。実際には、最初の方法を選択しました。この調整後、健康診断で他の問題は見つかりませんでした。
組み合わせる
node.jsと従来のビジネスシナリオを組み合わせる実践は始まったばかりであり、詳細に探索する価値のある最適化ポイントはまだたくさんあります。たとえば、Javaアプリケーションが完全に集中化された後、サーバーの使用率を改善するためにクラスター展開のテストを受けることができますか?または、リリースおよびロールバックの方法はより柔軟で制御可能になりますか?すべての詳細はさらに調査する価値があります。