tomcat再開 その48 ミドルウェア設計に関する課題 ー再考ー
tomcat再開 その35 httpコネクション数とスレッド数とjdbcコネクション数の関係
■ブラウザ⇔nginx⇔tomcat⇔postgresql の構成で各ミドルウェアの最大接続数は、
「ブラウザ⇔nginx」<「nginx⇔tomcat」<「tomcat⇔postgresql」にしないといけない理由を考える。
→フロントエンドが受信したのにバックエンドで受信できないと基本おかしいでしょって話?
→フロントエンドまで受信しといてバックエンドで500番台エラーじゃなぜだめなのか?
→バックエンドに行くほど処理時間が増大し、リソース消費も大きくなるので、バックエンドの最大接続数はリソースと供される遅延時間で小さめの値が決まりそう。フロントエンドをバックエンドよりも最大接続数を小さくしたらかなりリクエストを絞り込まなくてはいけなくならないか?
→フロントエンドは正当クライアントのほかに過負荷攻撃をしてくる不正クライアントも見込まれるが、過負荷攻撃のせいで、容易に最大接続数に達してしまってサービスダウンの頻度が増えてしまわないか?(nginxは多少の過負荷攻撃では落ちないし並行してサービス提供をおこなえるキャパシティがある)
■「ブラウザ⇔nginx」の接続数と「nginx⇔tomcat」の接続数は、もしnginxでコンテンツを提供していない場合は同じ(串刺し)になる。「nginx⇔tomcat」がHTTP NIO Connectorの場合、下記はすべて同じになる。
①「ブラウザ⇔nginx」のKeep Aliveでプールされているコネクションのうち「使用中」の数
②「nginx⇔tomcat」のKeep Aliveでプールされているコネクションのうち「使用中」の数
③tomcatのHTTP NIO Connectorスレッドプールのうち「使用中」の数
上記の場合、①のコネクションは、正当ユーザからのリクエストでトリガーされてバックエンドからのレスポンス待ちのコネクションと、不当ユーザからの過負荷攻撃や間違ったアクセスでトリガーされたコネクッション。不当ユーザとのコネクションは数が多い場合があるがエラーコードで返す短時間のものが多い?
上記の②のコネクションは、nginxのリバースプロキシを経由して、tomcatと確立されたコネクションのうち、tomcat上のicon、css、javascriptなどのリクエストのためのトランザクションは短時間しか使用されない。一方、tomcat上のサーブレットやJSPへのリクエストはアプリ実行やデータベースへのクエリなどのトリガーを引き、処理結果を受け取ってからレスポンスするので比較的長時間使用される。
③は②と同様、静的コンテンツを応答するだけなら短時間しか使用されない。tomcat上のサーブレットやJSPで重い処理を行ったり、データベースへクエリを実行した結果を応答する場合は比較的長時間使用される。
「同時接続」とは、リクエストを受信してからレスポンスを返信するまでの「処理時間」に重複する部分がある接続が存在することを意味する。
「同時接続」が発生するケースは、複数のブラウザからほぼ同時刻にリクエストを受信した場合と、一つのブラウザから「同時リクエスト」を「スループット以内」に発信した場合。
とくに後者では、ブラウザ自身にそなわる「同時接続機能」によるものと、レスポンスを受信したブラウザがレスポンスのLocationヘッダへのリダイレクトや、HTMLの<meta>や<img>や、javascriptの逐次処理を実行した結果発信されるリクエストが「スループット以内」に発信した場合に該当する。
■同時接続を受信した各ミドルウェアの振る舞い
・nginx
- keep aliveされたコネクションプールがあれば即座にこれを利用する
- keep aliveされたコネクションプールがなく、最大接続数以内ならばブラウザとworkerプロセ
ス(nginx)の間に新規コネクションが張られて受信され即座に処理する。
- 最大接続数以上なら? 待ち行列に登録されて処理される?即座に500番台エラーがレス
ポンスされる?
※ETAG?では、コンテンツに変更がなかった場合、ブラウザキャッシュを参照するようにレスポンスする?
※プロキシキャッシュ内にもし同じコンテンツが居たらバックエンドにフォワードせずにプロキシキャッシュ内のコンテンツをレスポンスする? → 動的コンテンツではやっちゃいけないわけだけど、プロキシはどこで判断する?
※不正ユーザからのアクセス(SYNフラッド攻撃、DOS攻撃、異常リクエストなど)はnginxまたはkernelが対処する → 具体的にどんな不正アクセスに対してどんな対処をするのか?
・tomcat HTTPコネクタ
- keep aliveされたコネクションプールがあれば即座にこれと対応するスレッドプールを利用する
- keep aliveされたコネクションプールがなく、最大接続数(maxConnections? maxThreads?)以内で、スレッドプールに空きがあれば即座にこれを使用してnginxとコネクションを張ってこれを利用する
- keep aliveされたコネクションプールがなく、最大接続数以内で、スレッドプールに空きがなければ、新規スレッドを生成してnginxとコネクションを結んでこれを利用する。使用済みのスレッドはmaxIdleTime?時間後に削除される。
- 最大接続数以上の場合は、acceptCount数までは、コネクションを待ち行列?に登録し、スレッドの空きができるまで保留する。空きが出来たら即座にスレッドを使用して通信を続行する。
※保留のタイムアウト時間は?
※保留中にフロントエンド側(リバースプロキシサーバやロードバランサやFW)やブラウザやセッションがタイムアウトした場合は?
- 最大接続数以上で、かつacceptCount数以上の場合は、connection refusedになる。
・JDBCコネクタ
- JDBCコネクションプールに空きがあれば即座にこれを利用して対応するpostgresqlバックエンドプロセスと通信を開始する
- JDBCコネクションプールに空きがなく、JDBCコネクションプール上限数以内で、かつpostgresqlのmax_connections以内なら、JDBCコネクタはpostgresqlバックエンドプロセスとlコネクションを張って即座にこれを使用する。なお、使用済みのJDBCコネクションは、??時間後に削除される。
- JDBCコネクションプール上限数以上または、postgresqlのmax_connections上なら、
※即座にエラーになるか?それともtomcat HTTP connectorのacceptCountのように一定時間待ち行列にバッファしてコネクションの空きができるまで保留させることはできるのか?
■最大接続数を増やしすぎた場合の各ミドルウェアのリソース(CPU時間、メモリ)消費
・nginx
- メモリ
- CPU時間
・tomcatHTTPコネクタ(スレッド?)
- メモリ
- CPU時間
→jvm(で実行してるtomcat)は半端ねえ粘り腰
・tomcatJDBCコネクタ
- メモリ
- CPU時間
・postgresql
- メモリ
- CPU時間
■最大接続数を増やしすぎた場合の各ミドルウェアの遅延
※どういうメカニズムでどんな遅延症状が現れる?
→ロードアベレージがコア数以上になると常に実行待ちプロセスがrunキューに順番待ちしてる状態となり、スループットが低下する。
→具体的にどのくらい?
・nginx
・tomcatHTTPコネクタ(スレッド?)
→ヒープ使用量が増大するとFull GCの頻度が増大し、Full GC中のストップザワールドの時間は一切何の処理も行われなくなる。
→実際にはどのくらいスループットが低下する?
・tomcatJDBCコネクタ
・postgresql
■各ミドルウェアのタイムアウト
・nginx
・tomcatHTTPコネクタ(スレッド?)
・tomcatJDBCコネクタ
・postgresql