create_request |
バックエンドサーバーに送信するリクエストバッファ(バッファチェーン)を生成し、上流の初期化時に使用します |
reinit_request |
バックエンド サーバーでエラーが発生した場合、nginx は別のバックエンド サーバーを試行します。 nginx は新しいサーバーを選択した後、最初にこの関数を呼び出してアップストリーム モジュールの動作ステータスを再初期化し、次にアップストリームに再度接続します |
process_header |
バックエンドの処理サーバーから返された情報ヘッダー。いわゆるヘッダーは、HTTP プロトコルのヘッダー部分や memcached プロトコルの応答ステータス部分など、上流サーバーと通信するためのプロトコルによって指定されます |
abort_request |
クライアントでの中止 要求されたときに呼び出されます。関数内にバックエンド サーバー接続を閉じる関数を実装する必要はありません。システムが接続を閉じる手順を自動的に完了するため、通常、この関数は特定の作業を実行しません |
#finalize_request | この関数は、バックエンド サーバーとのリクエストが正常に完了した後に呼び出されます。abort_request と同じであり、通常は特定の作業は実行されません |
#input_filter
バックエンド サーバーを処理します。返された応答本文。 nginx のデフォルトの input_filter は、受信したコンテンツをバッファー チェーン ngx_chain にカプセル化します。このチェーンはアップストリームの out_bufs ポインター フィールドによって配置されるため、開発者はこのポインターを使用して、モジュールの外部のバックエンド サーバーから返されるテキスト データを取得できます。 memcached モジュールは独自の input_filter を実装していますが、このモジュールについては後で詳しく分析します。 |
|
input_filter_init
入力フィルター コンテキストを初期化します。 nginx のデフォルトの input_filter_init は |
|
を直接返します。memcached モジュール分析
memcache は、広く使用されている高性能分散キャッシュ システムです。 memcache は、HTTP リクエストを通じて memcache にアクセスできないように、プライベート通信プロトコルのセットを定義します。ただし、プロトコル自体はシンプルで効率的であり、memcache は広く使用されているため、最新の開発言語とプラットフォームのほとんどは、開発者が memcache を使用しやすくするために memcache サポートを提供しています。
nginx は ngx_http_memcached モジュールを提供します。これは、memcache からデータを読み取る機能を提供しますが、memcache にデータを書き込む機能は提供しません。
上流モジュールはハンドラー モジュールのアクセス メソッドを使用します。
同時に、上流モジュールの命令システムの設計もハンドラー モジュールの基本ルールに従います。モジュールは、モジュールを構成した後にのみ実行されます。
それでは、アップストリーム モジュールの何が特別なのでしょうか?それが上流モジュールの処理関数です。上流モジュールの処理関数によって実行される操作には、固定のプロセスが含まれます: (memcached モジュールを例として、memcached の処理関数 ngx_http_memcached_handler 内)
Create上流のデータ構造:
ngx_http_upstream_t *u;
if (ngx_http_upstream_create(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
u = r->upstream;
ログイン後にコピー
モジュールのタグとスキーマを設定します。現在、スキーマはログにのみ使用され、タグは buf_chain 管理に使用されます:
ngx_str_set(&u->schema, "memcached://");
u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;
ログイン後にコピー
上流のバックエンド サーバー リスト データ構造を設定します:
mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
u->conf = &mlcf->upstream;
ログイン後にコピー
上流のコールバック関数を設定します:
u->create_request = ngx_http_memcached_create_request;
u->reinit_request = ngx_http_memcached_reinit_request;
u->process_header = ngx_http_memcached_process_header;
u->abort_request = ngx_http_memcached_abort_request;
u->finalize_request = ngx_http_memcached_finalize_request;
u->input_filter_init = ngx_http_memcached_filter_init;
u->input_filter = ngx_http_memcached_filter;
ログイン後にコピー
アップストリーム環境のデータ構造を作成して設定する:
ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t));
if (ctx == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ctx->request = r;
ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);
u->input_filter_ctx = ctx;
ログイン後にコピー
アップストリームの初期化と仕上げ作業を完了する:
r->main->count++;
ngx_http_upstream_init(r);
return NGX_DONE;
ログイン後にコピー
これは、memcached のように単純なものから、プロキシのように複雑なものまで、あらゆるアップストリーム モジュールに当てはまります。そしてfastcgi。
これらの 6 つのステップにおけるさまざまなアップストリーム モジュール間の最大の違いは、ステップ 2、3、4、および 5 に現れます。
ステップ 2 と 4 は理解しやすいですが、モジュールごとに設定されるフラグと使用されるコールバック関数は明らかに異なります。ステップ5も理解するのは難しくありません。
ステップ 3 だけが少しわかりにくいです。バックエンド サーバー リストを取得する際、モジュールによって戦略が大きく異なります。memcached のように単純で明確なものもあれば、プロキシのように論理的に複雑なものもあります。
ステップ 6 は通常、異なるモジュール間で一貫しています。 count を 1 増やして NGX_DONE を返します。
nginx はこの状況に遭遇すると、現在のリクエストの処理が終了したとみなしますが、リクエストで使用されていたメモリ リソースを解放したり、クライアントとの接続を閉じたりしません。
これが必要な理由は、nginx がアップストリーム リクエストとクライアント リクエストの間に 1 対 1 の関係を確立しているためです。その後、ngx_event_pipe を使用してアップストリーム レスポンスをクライアントに送り返すときに、これらの保存されたクライアント情報も使用されます。 。 データ構造。
アップストリーム リクエストとクライアント リクエストを 1 対 1 でバインドします。この設計には長所と短所があります。利点は、モジュール開発が簡素化され、モジュール ロジックに集中できることですが、欠点も同様に明白で、多くの場合、1 対 1 設計では複雑なロジックのニーズを満たすことができません。
コールバック関数: (引き続き memcached モジュールの処理関数を例として取り上げます)
ngx_http_memcached_create_request: コールバック関数を生成するのは非常に簡単です設定されたコンテンツ キーに従って、「get $key」リクエストを生成し、r->upstream->request_bufs に配置します。
ngx_http_memcached_reinit_request: 初期化は必要ありません。
ngx_http_memcached_abort_request: 追加のアクションは必要ありません。
ngx_http_memcached_finalize_request: 追加のアクションは必要ありません。
ngx_http_memcached_process_header: モジュールのビジネス フォーカス機能。 memcache プロトコルのヘッダー情報はテキストの最初の行として定義されており、コードは次のとおりです:
#define LF (u_char) '\n'
for (p = u->buffer.pos; p < u->buffer.last; p++) {
if (*p == LF) {
goto found;
}
}
ログイン後にコピー
LF (‘\n’) 文字が見つからない場合バッファに読み込まれたデータの場合、関数は NGX_AGAIN を返します。これは、ヘッダーが完全に読み取られておらず、データの読み取りを続ける必要があることを示します。 nginx は、新しいデータを受信した後、この関数を再度呼び出します。
nginx は、バックエンド サーバーの応答ヘッダーを処理するときに 1 つのキャッシュのみを使用します。すべてのデータはこのキャッシュ内にあるため、ヘッダー情報を解析するときに、ヘッダー情報が複数のキャッシュにまたがります。ヘッダーが大きすぎてこのキャッシュに保存できない場合、nginx はクライアントにエラー メッセージを返し、キャッシュが十分に大きくないことを示すエラー ログを記録します。
ngx_http_memcached_process_header の重要な役割は、バックエンド サーバーから返されたステータスをクライアントに返されたステータスに変換することです。例:
u->headers_in.content_length_n = ngx_atoof(start, p - start);
···
u->headers_in.status_n = 200;
u->state->status = 200;
···
u->headers_in.status_n = 404;
u->state->status = 404;
ログイン後にコピー
u->state は、上流関連の変数を計算するために使用されます。たとえば、u->state->status は、変数「upstream_status」の値を計算するために使用されます。 u->headers_in は、クライアントへの応答でステータス コードとして返されます。そして、u->headers_in.content_length_n は、クライアントに返される応答の長さを設定します。
この関数では、ヘッダー情報の処理後に読み取りポインター pos を後方に移動する必要があります。そうしないと、このデータがクライアントに返される応答の本文にもコピーされ、本文の内容が次のようになります。矛盾していますが、正しいです。
ngx_http_memcached_process_header 関数は、応答ヘッダーの正しい処理を完了し、NGX_OK を返す必要があります。 NGX_AGAIN が返された場合は、完全なデータが読み取られていないため、バックエンド サーバーからデータを引き続き読み取る必要があることを意味します。 NGX_DECLINED を返すことは無意味であり、それ以外の戻り値はエラー ステータスとみなされ、nginx はアップストリーム リクエストを終了し、エラー メッセージを返します。
ngx_http_memcached_filter_init: バックエンド サーバーから受信したコンテンツの長さを修正しました。これは、ヘッダーの処理時に長さのこの部分が追加されないためです。
ngx_http_memcached_filter:
memcached モジュールは、テキストを処理するためのコールバック関数を備えた珍しいモジュールです。
memcached モジュールはテキストの終わりにある CRLF "END" CRLF をフィルターする必要があるため、独自のフィルター コールバック関数を実装します。
テキストを処理するという実際の意味は、バックエンド サーバーから受信したテキストの有効な内容を ngx_chain_t にカプセル化し、それを u->out_bufs の最後に追加することです。
nginx はデータをコピーしませんが、これらのデータ メモリ領域を指す ngx_buf_t データ構造を確立し、ngx_chain_t によってこれらの buf を編成します。この実装により、大規模なメモリ再配置が回避され、nginx が効率的である理由の 1 つとなります。