前書き:
私は最近プロジェクトを開始し、そのプロジェクトのアーキテクチャ設計と実装を担当しました。同社はもともと社外の人向けに API をたくさん作っていたが、社外の人が使うとインターフェースのリンクが他人に与えられ、暗号化や同時実行制御もなく、インターフェースプログラムが置かれているマシンのどこにでも与えられてしまう。 IP は存在しますが、それを管理するプラットフォームはありません。したがって、これらのインターフェイスの価値 (どのインターフェイスが他のインターフェイスによってより多く使用され、どのインターフェイスが他のインターフェイスによってあまり使用されないか) を発見するのは難しいことがはっきりとわかります。
「監視」の必要性だけを考慮して、中間層として redis を導入しました。まず、ユーザー インターフェイスの登録プロセスを改善し、ユーザー情報とアドレスを介してキーをハッシュしました。このキーは、対応するキーです。アドレスを指定して、この (キー - アドレス) ペアを redis に保存します。次は nginx です。私たちのプロジェクトにおける nginx のプロセスは大まかに次のとおりです:
1. ユーザーは登録後、キーを取得し、元のキーとはまったく異なるキーを含む URL を介してアクセスします。 URL
2. nginx はユーザーの特別なキーをキャプチャし、プログラムはこのキーに基づいて redis からターゲット アドレスを取得し、nginx はユーザーに代わって実際のアドレスにアクセスして戻ります。
(このプロセスには多くの利点があります)
(1). 実際のアドレスは隠蔽され、プログラムは上流サーバーの外でユーザーのアクセスに介入し、セキュリティを向上させ、プロセスに介入することができます。非常に複雑になる可能性があります
(2) ユーザー情報を取得して redis に保存します。上流サーバーは、タイマー プログラムを通じて redis 内のログを oracle に保存し、削除してから、さらに分析して視覚化します。彼ら
ここで問題が発生します
#このプロジェクトはまだテスト段階です。リソースはウィンドウ サーバー サーバーと centos6.5 サーバーです。テスト段階では約 100,000 の同時実行があります。 10 秒以内にデプロイされたばかりで、1 ~ 2 日は問題がありませんでしたが、その後 Redis 接続に失敗しました。プロセスアクセスを見ると以下のような状況になります。 (ウィンドウサーバー下) FiN_WAIT_2 TCP リンクが多数表示されます。 (学習ビデオ共有:redis ビデオ チュートリアル)
分析1. Redis は単一のスレッドを使用して接続を処理します。以下の 2 つの状況が発生します。 2. 明らかに、これは nginx と redis の間の多くの未解放リソースが原因です。TCP ステータス FIN_WAIT_2 を確認して、次のように説明してください: HTTP アプリケーションでは、サーバーがKEEPALIVE のタイムアウトなど、何らかの理由で接続を閉じます。このようにして、アクティブに閉じているサーバーは FIN_WAIT2 状態になりますが、TCP/IP プロトコル スタックに問題があります。FIN_WAIT2 状態にはタイムアウトがありません。 (TIME_WAIT 状態とは異なります)。そのため、CLIENT が閉じられていない場合、この FIN_WAIT_2 状態はシステムが再起動されるまで残り、FIN_WAIT_2 状態が増えるとカーネルのクラッシュが発生します。 わかりました、私は大学であまり勉強しませんでした。http 接続のステータスの変化は次のとおりです。クライアント ステータスの移行CLOSED->SYN_SENT->ESTABLISHED ->FIN_WAIT_1 ->FIN_WAIT_2->TIME_WAIT->CLOSEDb.サーバーステータス移行CLOSED->LISTEN->SYN受信->ESTABLISHED->CLOSE_WAIT -> LAST_ACK->CLOSED欠陥のあるクライアントと永続的接続一部のクライアントには永続的接続 (akakeepalives) の処理に問題があります。接続がアイドル状態になり、サーバーが (KeepAliveTimeout ディレクティブに基づいて) 接続を閉じると、 クライアントはサーバーに FIN と ACK を返さないようにプログラムされています。これは、次のいずれかが発生するまで、接続は FIN_WAIT_2 状態に留まるということを意味します。 クライアントは、同じサイトまたは別のサイトへの新しい接続を開きます。これにより、ソケットの以前の接続が完全に閉じられます。 ユーザーがクライアント プログラムを終了すると、一部の (おそらくほとんどの) クライアントでは、オペレーティング システムが接続を完全に閉じます。 FIN_WAIT_2 タイムアウト (FIN_WAIT_2 ステータス タイムアウト設定があるサーバー上)。 運が良ければ、欠陥のあるクライアントが接続を完全に閉じ、サーバーのリソースが解放されることを意味します。 ただし、ダイヤルアップ クライアントがクライアント プログラムを閉じる前に ISP から切断するなど、ソケットが完全に閉じられない状況もあります。 さらに、一部のクライアントは新しい接続を作成せずに数日間アイドル状態になる可能性があるため、ソケットが使用されなくなった場合でも、ソケットは数日間有効なままになります。これは、ブラウザまたはオペレーティング システムの TCP 実装のバグです。 理由は次のとおりです: 1. 接続が長く、接続が常に IDLE 状態で SERVERCLOSE が発生すると、CLIENT プログラミングの欠陥により FIN および ACK パケットが SERVER に送信されません 2 、APACHE1.1 および APACHE1.2 では、前回の投稿で紹介した linger_close() 関数が追加されました。この関数がこの問題を引き起こした可能性があります (理由はわかりません) 解決策:###1。 FIN_WAIT_2 状態にタイムアウト メカニズムを追加します。この機能はプロトコルには反映されていませんが、LINUX、SOLARIS、FREEBSD、HP-UNIX、IRIX などの一部の OS
に実装されています。 ###2。 linger_close() 3 を使用してコンパイルしないでください。代わりに SO_LINGER を使用してください。これは一部のシステム 4 で適切に処理できます。カーネル クラッシュ 5 を防ぐために、ネットワーク接続ステータスの保存に使用されるメモリ mbuf を増やします。キープアライブを無効にする この状況を考慮して、いくつかの議論を行った結果、いくつかの結論が得られました: 1. nginx と redis の接続プールを設定し、キープアライブ時間をそれぞれ 10 に設定します。秒、5 秒、しかし結果は同じです2.キープアライブなし、つまり接続プールは使用されず、つまり、close() は使い果たされるたびに閉じられます。接続数は少ないですが、接続プールは使用されていません。つまり、10 秒間に 100,000 回開閉する必要があり、コストが高すぎます。 3. Redis クラスター。Redis の追加クラスタを元のクラスタシステムに戻すと問題が解決する可能性がありますが、10 秒間に 10 万回というのは実際には多くありません。これは裏技かもしれません。問題は見つかっていません。 4. アイドル時間を設定するRedis の制限を設定しても、結果は同じです。 解決策: は、redis のメモリ メカニズムが放棄され、nginx 独自のメモリ テクノロジが使用されるため、実際には解決策ではありません。 Redis のオンライン最適化のほとんどは適用できないため、この問題を分析して解決する必要があります。 関連する推奨事項:redis データベース チュートリアル
以上が高同時実行時のRedisのパフォーマンス解析についての詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。