nginx共有メモリの仕組みの詳細な説明

nginx共有メモリの仕組みの詳細な説明

Nginx の共有メモリは、高いパフォーマンスを実現できる主な理由の 1 つであり、主にファイル キャッシュに使用されます。この記事では、まず共有メモリの使用方法を説明し、次に nginx が共有メモリを管理する方法について説明します。

1. 使用例

nginx が共有メモリを宣言するための手順は次のとおりです。

proxy_cache_path /Users/Mike/nginx-cache レベル=1:2 キー_ゾーン=one:10m 最大サイズ=10g 非アクティブ=60m 使用テンポパス=オフ;

ここでは、使用可能な最大メモリが 10g である、 one という名前の共有メモリを宣言します。ここでの各パラメータの意味は次のとおりです。

  • /Users/Mike/nginx-cache: これは、共有メモリにキャッシュされたファイルの保存場所を指定するパス パラメーターです。ここでファイルを生成する理由は、上流サービスからのレスポンスをファイルに生成して nginx 上に保存できるためです。後から同様のリクエストがあった場合、ファイルを直接読み込んだり、共有メモリ内のキャッシュを読み込んでクライアントに応答することができます。
  • レベル: Linux オペレーティング システムでは、すべてのファイルが 1 つのフォルダーに配置されている場合、ファイル数が非常に多いと、1 つのディスク ドライブで多数のファイルを読み取ることができない場合があります。複数のフォルダーに配置されている場合は、複数のドライブを利用してファイルを読み取ることができます。ここでの levels パラメータは、フォルダーの生成方法を指定します。アップストリーム サービスの応答データ用に nginx によって生成されたファイル名が e0bd86606797639426a92306b1b98ad9 であると仮定すると、上記の levels=1:2 の場合、ファイル名の末尾から開始し、最初に 1 桁目 (つまり、9) を第 1 レベルのサブディレクトリ名として取得し、次に 2 桁目 (つまり、ad) を第 2 レベルのサブディレクトリ名として取得します。
  • keys_zone: このパラメータは、現在の共有メモリの名前を指定します。ここでは 1 です。次の 10m は、キーを格納するために使用される現在の共有メモリのサイズが 10m であることを示します。
  • max_size: このパラメータは、現在の共有メモリに使用可能な最大メモリを指定します。
  • 非アクティブ: このパラメータは、現在の共有メモリの最大存続時間を指定します。この期間中にメモリ データへのアクセス要求がない場合、LRU アルゴリズムによってメモリは削除されます。
  • use_temp_path: このパラメーターは、生成されたファイルを最初に一時フォルダーに配置し、後で指定されたフォルダーに移動するかどうかを指定します。

2. 動作原理

共有メモリの管理は、次の図に示すように、主にいくつかの部分に分かれています。

ご覧のとおり、主に初期化、共有メモリの管理、共有メモリの読み込み、共有メモリの使用など、いくつかの側面に分かれています。初期化プロセスでは、まず proxy_cache_path 命令が解析され、次にキャッシュ マネージャー プロセスとキャッシュ ローダー プロセスがそれぞれ起動されます。キャッシュ マネージャー プロセスは主に共有メモリの管理を担当し、主に LRU アルゴリズムを通じて期限切れのデータをクリアするか、リソースが不足しているときに参照されていないメモリ データの一部を強制的に削除します。キャッシュ ローダー プロセスの主なタスクは、nginx の起動後にファイル ストレージ ディレクトリ内の既存のファイルを読み取り、共有メモリにロードすることです。共有メモリの使用は主に、リクエストが処理された後に応答データをキャッシュすることです。この部分については、次の記事で説明します。この記事では、主に最初の 3 つの部分の動作原理について説明します。

上記の区分に従って、共有メモリの管理は 3 つの部分に分けられます (共有メモリの使用については後で説明します)。以下は、これら 3 つの部分の処理フローの概略図です。

上記のフローチャートからわかるように、メインプロセスでは、proxy_cache_path 命令を解析し、キャッシュ マネージャー プロセスを開始して、キャッシュ ローダー プロセスを開始することが主な作業です。キャッシュ マネージャー プロセスでは、主な作業は 2 つの部分に分かれています。1. キューの末尾にある要素が期限切れかどうかを確認します。期限切れで参照カウントが 0 の場合は、要素と要素に対応するファイルを削除します。2. 現在の共有メモリ リソースが不足していないかどうかを確認します。リソースが不足している場合は、期限切れかどうかに関係なく、参照カウントが 0 のすべての要素とそのファイルを削除します。キャッシュ ローダー プロセスの処理フローでは、ファイルが格納されているディレクトリとそのサブディレクトリ内のファイルを再帰的に走査し、それらのファイルを共有メモリにロードします。キャッシュ マネージャー プロセスは毎回すべての共有メモリ ブロックを走査した後に次のループに入りますが、キャッシュ ローダー プロセスは nginx の起動後 60 秒ごとに 1 回実行され、その後プロセスを終了することに注意してください。

3. ソースコードの解釈

3.1 proxy_cache_path ディレクティブの分析

各 nginx 命令の解析のために、対応するモジュールで ngx_command_t 構造体が定義されます。構造体には、現在の命令を解析するために使用されるメソッドを指定する set メソッドがあります。以下は、proxy_cache_path に対応する ngx_command_t 構造体の定義です。

静的 ngx_command_t ngx_http_proxy_commands[] = {
 { ngx_string("proxy_cache_path"), // 現在の命令の名前を指定します // 現在の命令が使用される場所、つまり http モジュールを指定します。また、現在のモジュールのパラメータの数を指定します。これは 2 以上である必要があります。
   NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE、
  //set() メソッドが指す ngx_http_file_cache_set_slot メソッドを指定します。
   NGX_HTTP_MAIN_CONF_OFFSET、
   offsetof(ngx_http_proxy_main_conf_t、キャッシュ)、
   &ngx_http_proxy_module }
}

ご覧のとおり、この命令で使用される解析メソッドは ngx_http_file_cache_set_slot() です。ここでは、このメソッドのソース コードを直接読み取ります。

char *ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
  confp は conf に格納されます。

  off_t 最大サイズ;
  u_char *最後、*p;
  time_t 非アクティブ;
  ssize_t サイズ;
  ngx_str_t s、名前、*値;
  ngx_int_t ローダーファイル、マネージャーファイル;
  ngx_msec_t ローダースリープ、マネージャースリープ、ローダーしきい値、
              マネージャーしきい値;
  ngx_uint_t i、n、use_temp_path;
  ngx_array_t *キャッシュ;
  ngx_http_file_cache_t *キャッシュ、**ce;

  キャッシュ = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t));
  キャッシュ == NULL の場合 {
    NGX_CONF_ERROR を返します。
  }

  cache->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
  キャッシュパスがNULLの場合
    NGX_CONF_ERROR を返します。
  }

  // 各属性のデフォルト値を初期化します use_temp_path = 1;

  非アクティブ = 600;

  ローダーファイル = 100;
  ローダースリープ = 50;
  ローダーしきい値 = 200;

  マネージャーファイル = 100;
  マネージャースリープ = 50;
  マネージャーしきい値 = 200;

  名前.len = 0;
  サイズ = 0;
  NGX_MAX_OFF_T_VALUE のデフォルト値は 0 です。

  // 設定例: proxy_cache_path /Users/Mike/nginx-cache levels=1:2 keys_zone=one:10m max_size=10g inactive=60m use_temp_path=off;

  // ここで、cf->args->elts は、proxy_cache_path 命令を解析するときにその命令に含まれるトークン項目を格納します。
  // いわゆるトークン項目は、スペースで区切られた文字フラグメントを参照します value = cf->args->elts;

  // value[1]は構成の最初のパラメータであり、キャッシュファイルが保存されるルートパスです。cache->path->name = value[1];

  if (cache->path->name.data[cache->path->name.len - 1] == '/') {
    キャッシュ->パス->名前.len--;
  }

  ngx_conf_full_name(cf->cycle, &cache->path->name, 0) != NGX_OK の場合 {
    NGX_CONF_ERROR を返します。
  }

  // 3番目のパラメータから解析を開始します for (i = 2; i < cf->args->nelts; i++) {

    // 3番目のパラメータが "levels=" で始まる場合は、levels サブパラメータを解析します if (ngx_strncmp(value[i].data, "levels=", 7) == 0) {

      p = value[i].data + 7; // 解析を開始する実際の位置を計算します last = value[i].data + value[i].len; // 最後の文字の位置を計算します // 解析を開始します 1:2
      (n = 0; n < NGX_MAX_PATH_LEVEL && p < last; n++) の場合 {

        (*p > '0' && *p < '3') の場合 {

          // 解析する必要がある 1 や 2 などの現在のパラメータ値を取得します。
          キャッシュ->パス->レベル[n] = *p++ - '0';
          キャッシュ->パス->len += キャッシュ->パス->レベル[n] + 1;

          (p == 最後) の場合 {
            壊す;
          }

          // 現在の文字がコロンの場合、次の文字の解析を続行します。
          // ここでの NGX_MAX_PATH_LEVEL の値は 3 です。これは、levels パラメータの後に最大 3 つのサブディレクトリがあることを意味します。if (*p++ == ':' && n < NGX_MAX_PATH_LEVEL - 1 && p < last) {
            続く;
          }

          無効なレベルに移動します。
        }

        無効なレベルに移動します。
      }

      キャッシュ->パス->長さ<10+NGX_MAX_PATH_LEVELの場合{
        続く;
      }

    無効なレベル:

      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "無効な \"レベル\" \"%V\"", &value[i]);
      NGX_CONF_ERROR を返します。
    }

    // 現在のパラメータが "use_temp_path=" で始まる場合は、オンまたはオフにできる use_temp_path パラメータを解析します。
    // 現在のキャッシュファイルが最初に一時フォルダに保存され、その後ターゲットフォルダに書き込まれるかどうかを示します。オフの場合は、ターゲットフォルダに直接保存されます if (ngx_strncmp(value[i].data, "use_temp_path=", 14) == 0) {

      // オンの場合、use_temp_path を 1 としてマークします
      ngx_strcmp(&value[i].data[14], "on") == 0の場合
        使用_temp_path = 1;

        // オフの場合は、use_temp_path を 0 としてマークします
      } そうでない場合 (ngx_strcmp(&value[i].data[14], "off") == 0) {
        使用_temp_path = 0;

        // 100を超える場合は解析例外を返します} else {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                  "use_temp_path 値 \"%V\" が無効です"
                  「\"オン\"または\"オフ\"でなければなりません」
                  &値[i]);
        NGX_CONF_ERROR を返します。
      }

      続く;
    }

    // パラメータが "keys_zone=" で始まる場合は、keys_zone パラメータを解析します。このパラメータの形式は、keys_zone=one:10m です。
    // ここで、1 は後続の場所設定の名前であり、10m はサイズです。
    // キーを保存するためのキャッシュサイズを示します if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) {

      名前.データ = 値[i].データ + 10;

      p = (u_char *) ngx_strchr(name.data, ':');

      もし(p){
        // 現在のバッファの名前を記録するnameの長さを計算します。ここでは1です。
        名前.len = p - 名前.data;

        p++;

        // 指定されたサイズを解析します s.len = value[i].data + value[i].len - p;
        s.データ = p;

        // サイズを解析し、指定されたサイズをバイトに変換します。ここでのバイト数は 8191 より大きくなければなりません
        サイズ = ngx_parse_size(&s);
        (サイズ > 8191)の場合{
          続く;
        }
      }

      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "無効なキーゾーンサイズ \"%V\"", &value[i]);
      NGX_CONF_ERROR を返します。
    }

    // パラメータが「inactive=」で始まる場合は、非アクティブなパラメータを解析します。パラメータの形式は、inactive=60mなどです。
    // キャッシュされたファイルがアクセスされなかった後に期限切れになる期間を示します if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {

      s.len = 値[i].len - 9;
      s.data = 値[i].data + 9;

      // 時間を解析し、秒単位の時間の長さに変換します。 inactive = ngx_parse_time(&s, 1);
      非アクティブの場合 == (time_t) NGX_ERROR) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                  "無効な非アクティブな値 \"%V\"", &value[i]);
        NGX_CONF_ERROR を返します。
      }

      続く;
    }

    // パラメータが "max_size=" で始まる場合は、max_size パラメータを解析します。パラメータの形式はmax_size=10gなどです。
    // 現在のキャッシュが使用できる最大メモリ領域を示します if (ngx_strncmp(value[i].data, "max_size=", 9) == 0) {

      s.len = 値[i].len - 9;
      s.data = 値[i].data + 9;

      // 解析された値をバイト数に変換します。max_size = ngx_parse_offset(&s);
      (最大サイズ<0)の場合{
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                  "max_size値\"%V\"が無効です", &value[i]);
        NGX_CONF_ERROR を返します。
      }

      続く;
    }

    // パラメータが "loader_files=" で始まる場合は、loader_files パラメータを解析します。パラメータは loader_files=100 の形式です。
    // nginx を起動するときに、キャッシュディレクトリ内のファイルがデフォルトでキャッシュにロードされる数を示します if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) {

      // loader_filesパラメータの値を解析します。loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13);
      loader_files == NGX_ERRORの場合{
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
              "loader_files値\"%V\"が無効です", &value[i]);
        NGX_CONF_ERROR を返します。
      }

      続く;
    }

    // パラメータが「loader_sleep=」で始まる場合は、loader_sleep パラメータを解析します。パラメータは loader_sleep=10s の形式です。
    // 各ファイルをロードした後、次のファイルをロードするまでのスリープ時間を示します if (ngx_strncmp(value[i].data, "loader_sleep=", 13) == 0) {

      s.len = 値[i].len - 13;
      s.data = 値[i].data + 13;

      // loader_sleep の値をミリ秒単位で変換します。loader_sleep = ngx_parse_time(&s, 0);
      (loader_sleep == (ngx_msec_t)NGX_ERROR)の場合{
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
              "loader_sleep値\"%V\"が無効です", &value[i]);
        NGX_CONF_ERROR を返します。
      }

      続く;
    }

    // パラメータが「loader_threshold=」で始まる場合は、loader_threshold=10s の形式の loader_threshold パラメータを解析します。
    // ファイルをロードするのに使用できる最大時間を示します if (ngx_strncmp(value[i].data, "loader_threshold=", 17) == 0) {

      s.len = 値[i].len - 17;
      s.data = 値[i].data + 17;

      // loader_threshold の値を解析してミリ秒に変換します。loader_threshold = ngx_parse_time(&s, 0);
      (loader_threshold == (ngx_msec_t)NGX_ERROR)の場合{
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
              "loader_threshold 値 \"%V\" が無効です", &value[i]);
        NGX_CONF_ERROR を返します。
      }

      続く;
    }

    // パラメータが「manager_files=」で始まる場合は、manager_files=100 の形式の manager_files パラメータを解析します。
    // キャッシュスペースが使い果たされると、LRUアルゴリズムを使用してファイルが削除されることを示しますが、各反復では、manager_filesで指定された最大数のファイルを削除します if (ngx_strncmp(value[i].data, "manager_files=", 14) == 0) {

      // manager_filesパラメータ値を解析します。 manager_files = ngx_atoi(value[i].data + 14, value[i].len - 14);
      (manager_files == NGX_ERROR)の場合{
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
              "無効な manager_files 値 \"%V\"", &value[i]);
        NGX_CONF_ERROR を返します。
      }

      続く;
    }

    // パラメータが「manager_sleep=」で始まる場合は、manager_sleep=1s の形式の manager_sleep パラメータを解析します。
    // 各反復が manager_sleep パラメータで指定された期間スリープすることを示します if (ngx_strncmp(value[i].data, "manager_sleep=", 14) == 0) {

      s.len = 値[i].len - 14;
      s.data = 値[i].data + 14;

      // manager_sleep で指定された値を解析します。 manager_sleep = ngx_parse_time(&s, 0);
      (manager_sleep == (ngx_msec_t) NGX_ERROR) の場合 {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
              "無効な manager_sleep 値 \"%V\"", &value[i]);
        NGX_CONF_ERROR を返します。
      }

      続く;
    }

    // パラメータが「manager_threshold=」で始まる場合、manager_threshold パラメータが解析されます。パラメータは manager_threshold=2s の形式です。
    // ファイルのクリアの各反復の最長時間がこのパラメータで指定された値を超えないことを示します if (ngx_strncmp(value[i].data, "manager_threshold=", 18) == 0) {

      s.len = 値[i].len - 18;
      s.data = 値[i].data + 18;

      // manager_threshold パラメータ値を解析し、ミリ秒単位の値に変換します。 manager_threshold = ngx_parse_time(&s, 0);
      (manager_threshold == (ngx_msec_t)NGX_ERROR)の場合{
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
              "無効な manager_threshold 値 \"%V\"", &value[i]);
        NGX_CONF_ERROR を返します。
      }

      続く;
    }

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
              "無効なパラメータ\"%V\"", &value[i]);
    NGX_CONF_ERROR を返します。
  }

  (name.len == 0 || size == 0)の場合{
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
              "\"%V\" には \"keys_zone\" パラメータが必要です",
              &cmd->名前);
    NGX_CONF_ERROR を返します。
  }

  // ここでのcache->path->managerとcache->path->loaderの値は2つの関数です。
  // nginx が起動すると、キャッシュ マネージャーとキャッシュ ローダーの 2 つの別個のプロセスが開始されます。
  // ループ内の各共有メモリに対してcache->path->managerで指定されたメソッドを継続的に実行します。
  // キャッシュをクリーンアップします。もう 1 つのプロセスであるキャッシュ ローダーは、nginx の起動後 60 秒後に 1 回だけ実行されます。
  // 実行方法はcache->path->loaderで指定された方法です。
  // このメソッドの主な機能は、既存のファイル データを現在の共有メモリにロードすることです。cache->path->manager = ngx_http_file_cache_manager;
  キャッシュ->パス->ローダー = ngx_http_file_cache_loader;
  cache->path->data = キャッシュ;
  cache->path->conf_file = cf->conf_file->file.name.data;
  cache->path->line = cf->conf_file->line;
  cache->loader_files = loader_files;
  キャッシュ->loader_sleep = loader_sleep;
  キャッシュ->loader_threshold = loader_threshold;
  キャッシュ->manager_files = manager_files;
  キャッシュ->manager_sleep = manager_sleep;
  キャッシュ->manager_threshold = manager_threshold;

  // 現在のパスをサイクルに追加します。これらのパスは後でチェックされます。パスが存在しない場合は、対応するパスが作成されます if (ngx_add_path(cf, &cache->path) != NGX_OK) {
    NGX_CONF_ERROR を返します。
  }

  // 現在の共有メモリを cf->cycle->shared_memory で指定された共有メモリ リストに追加します。cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post);
  キャッシュ->shm_zone == NULLの場合{
    NGX_CONF_ERROR を返します。
  }

  if (cache->shm_zone->data) {
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
              "重複ゾーン \"%V\"", &name);
    NGX_CONF_ERROR を返します。
  }


  // これは、マスタープロセスの開始時に実行される各共有メモリの初期化方法を指定します。cache->shm_zone->init = ngx_http_file_cache_init;
  キャッシュ->shm_zone->データ = キャッシュ;

  キャッシュ->use_temp_path = use_temp_path;

  cache->inactive = 非アクティブ;
  キャッシュ->max_size = max_size;

  キャッシュ = (ngx_array_t *) (confp + cmd->offset);

  ce = ngx_array_push(キャッシュ);
  ce == NULLの場合{
    NGX_CONF_ERROR を返します。
  }

  *ce = キャッシュ;

  NGX_CONF_OK を返します。
}

上記のコードからわかるように、proxy_cache_path メソッドでは、主に ngx_http_file_cache_t 構造体が初期化されます。この構造体のさまざまなプロパティは、proxy_cache_path のさまざまなパラメータを解析することによって取得されます。

3.2 キャッシュマネージャとキャッシュローダープロセスの起動

nginx プログラムの開始メソッドは、nginx.c の main() メソッドです。マスター ワーカー プロセス モードがオンになっている場合は、最終的に ngx_master_process_cycle() メソッドに入ります。このメソッドは、最初にワーカー プロセスを開始してクライアント要求を受信し、次にキャッシュ マネージャー プロセスとキャッシュ ローダー プロセスをそれぞれ開始し、最後に無限ループに入り、ユーザーがコマンド ラインで nginx に送信した指示を処理します。以下は、キャッシュ マネージャーとキャッシュ ローダー プロセスを開始するためのソース コードです。

空所
ngx_master_process_cycle(ngx_cycle_t *サイクル)
{
  ...
   
  // コアモジュール構成を取得します ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);

  // 各ワーカープロセスを開始します ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN);
  // キャッシュプロセスを開始します ngx_start_cache_manager_processes(cycle, 0);
 
  ...
}

キャッシュ マネージャーとキャッシュ ローダー プロセスの起動については、主に ngx_start_cache_manager_processes() メソッドで行われていることがわかります。このメソッドのソース コードは次のとおりです。

静的 void ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn) {
  ngx_uint_t i、マネージャー、ローダー;
  ngx_path_t **パス;
  ngx_channel_t ch;

  マネージャー = 0;
  ローダー = 0;

  パス = ngx_cycle->paths.elts;
  (i = 0; i < ngx_cycle->paths.nelts; i++) の場合 {

    // パスのいずれかがマネージャを 1 として指定しているかどうかを確認します
    if (path[i]->manager) {
      マネージャー = 1;
    }

    // パスのいずれかがローダーを 1 として指定しているかどうかを確認します
    if (path[i]->loader) {
      ローダー = 1;
    }
  }

  // パスのマネージャーが 1 に指定されていない場合は、直接戻ります if (manager == 0) {
    戻る;
  }

  // ngx_cache_manager_process_cycle() メソッドで実行されるサイクルを実行するプロセスを作成します。
  // ngx_cache_manager_process_cycle メソッドをコールバックする場合、ここで渡される 2 番目のパラメータは ngx_cache_manager_ctx です。
  ngx_spawn_process(サイクル、ngx_cache_manager_process_cycle、
           &ngx_cache_manager_ctx、「キャッシュ マネージャー プロセス」、
           リスポーン? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN);

  ngx_memzero(&ch, sizeof(ngx_channel_t));

  // 現在のプロセスの作成メッセージをブロードキャストするための ch 構造体を作成します。ch.command = NGX_CMD_OPEN_CHANNEL;
  ch.pid = ngx_processes[ngx_process_slot].pid;
  ch.slot = ngx_process_slot;
  ch.fd = ngx_processes[ngx_process_slot].channel[0];

  // キャッシュ マネージャー プロセスが作成されたというメッセージをブロードキャストします ngx_pass_open_channel(cycle, &ch);

  ローダー == 0 の場合
    戻る;
  }

  // ngx_cache_manager_process_cycle()で指定されたプロセスを実行するプロセスを作成します。
  // ngx_cache_manager_process_cycle メソッドをコールバックする場合、ここで渡される 2 番目のパラメータは ngx_cache_loader_ctx です。
  ngx_spawn_process(サイクル、ngx_cache_manager_process_cycle、
           &ngx_cache_loader_ctx、「キャッシュローダープロセス」、
           リスポーン? NGX_PROCESS_JUST_SPAWN : NGX_PROCESS_NORESPAWN);

  // 現在のプロセスの作成メッセージをブロードキャストするための ch 構造体を作成します。ch.command = NGX_CMD_OPEN_CHANNEL;
  ch.pid = ngx_processes[ngx_process_slot].pid;
  ch.slot = ngx_process_slot;
  ch.fd = ngx_processes[ngx_process_slot].channel[0];

  // キャッシュ ローダー プロセスが作成されたというメッセージをブロードキャストします ngx_pass_open_channel(cycle, &ch);
}

上記のコードは実際には非常に単純です。まず、パスがキャッシュ マネージャーまたはキャッシュ ローダーの使用を指定しているかどうかを確認します。指定されている場合は、対応する継承が開始されます。そうでない場合、キャッシュ マネージャーとキャッシュ ローダーのプロセスは作成されません。これら 2 つのプロセスを開始するために使用される方法は次のとおりです。

// キャッシュマネージャプロセスを開始する ngx_spawn_process(cycle, ngx_cache_manager_process_cycle,
         &ngx_cache_manager_ctx、「キャッシュ マネージャー プロセス」、
         リスポーン? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN);

// キャッシュローダープロセスを開始する ngx_spawn_process(cycle, ngx_cache_manager_process_cycle,
           &ngx_cache_loader_ctx、「キャッシュローダープロセス」、
           リスポーン? NGX_PROCESS_JUST_SPAWN : NGX_PROCESS_NORESPAWN);

ここでの ngx_spawn_process() メソッドの主な機能は、新しいプロセスを作成することです。プロセスが作成されると、2 番目のパラメータで指定されたメソッドが実行され、メソッド実行時に渡されるパラメータは、ここで 3 番目のパラメータで指定された構造体オブジェクトです。上記のプロセスを開始する 2 つの方法を確認してください。新しいプロセスが作成された後に実行されるメソッドは ngx_cache_manager_process_cycle() ですが、このメソッドを呼び出すときに渡されるパラメーターは異なります。1 つは ngx_cache_manager_ctx で、もう 1 つは ngx_cache_loader_ctx です。ここではまず、これら 2 つの構造の定義を見てみましょう。

// ここでの ngx_cache_manager_process_handler は、現在のキャッシュ マネージャー プロセスが実行するメソッドを指定します。
// キャッシュマネージャプロセスはプロセス名を指定し、最後の 0 は現在のプロセスが開始後に実行される時間を示します。 // ngx_cache_manager_process_handler() メソッドはここですぐに実行されます static ngx_cache_manager_ctx_t ngx_cache_manager_ctx = {
  ngx_cache_manager_process_handler、「キャッシュ マネージャー プロセス」、0
};

// ここでの ngx_cache_loader_process_handler は、現在のキャッシュ ローダー プロセスが実行するメソッドを指定します。
// キャッシュローダープロセスが開始されてから60秒後にngx_cache_loader_process_handler()メソッドを実行します。static ngx_cache_manager_ctx_t ngx_cache_loader_ctx = {
  ngx_cache_loader_process_handler、「キャッシュ ローダー プロセス」、60000
};


ご覧のとおり、これら 2 つの構造は主に、キャッシュ マネージャー プロセスとキャッシュ ローダー プロセスの異なる動作をそれぞれ定義しています。 ngx_cache_manager_process_cycle() メソッドがこれら 2 つのメソッドを呼び出す方法を見てみましょう。

静的 void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) {
  ngx_cache_manager_ctx_t *ctx = データ;

  void *ident[4];
  ngx_event_t ev;

  ngx_process = NGX_PROCESS_HELPER;

  // 現在のプロセスは主にキャッシュ マネージャーとキャッシュ ローダーの作業を処理するために使用されるため、ソケットをリッスンする必要がないため、ここで閉じる必要があります ngx_close_listening_sockets(cycle);

  /* ヘルパー プロセスの接続数を適度に設定します。 */
  サイクル->接続_n = 512;

  // 現在のプロセスを初期化し、主にいくつかのパラメータ属性を設定し、最後に現在のプロセスがマスタープロセスのメッセージを受信するためにチャネル[1]ハンドルをリッスンするイベントを設定します。ngx_worker_process_init(cycle, -1);

  ngx_memzero(&ev, sizeof(ngx_event_t));
  // キャッシュ マネージャーの場合、ここでのハンドラーは ngx_cache_manager_process_handler() メソッドを参照します。
  // キャッシュ ローダーの場合、ここでのハンドラーは ngx_cache_loader_process_handler() メソッドを指します。ev.handler = ctx->handler;
  ev.data = ident;
  ev.log = サイクル->log;
  識別子[3] = (void *) -1;

  // キャッシュ モジュールは共有ロックを使用する必要はありません ngx_use_accept_mutex = 0;

  ngx_setproctitle(ctx->name);

  // 現在のイベントをイベント キューに追加します。イベントの遅延時間は ctx->delay です。キャッシュ マネージャーの場合、この値は 0 です。
  // キャッシュ ローダーの場合、値は 60 秒です。
  // 現在のイベント処理メソッドでは、ngx_cache_manager_process_handler() が現在のイベントを処理した場合、
  // 現在のイベントはイベント キューに再度追加され、時間指定処理の機能が実現されます。また、ngx_cache_loader_process_handler() メソッドの場合、一度処理した後は、現在のイベントはイベント キューに再度追加されません。つまり、現在のイベントは 1 回だけ実行され、その後キャッシュ ローダー プロセスが終了されることと同じです。ngx_add_timer(&ev, ctx->delay);

  のために ( ;; ) {

    // マスターが現在のプロセスを終了または終了としてマークした場合、プロセスを終了します if (ngx_terminate || ngx_quit) {
      ngx_log_error(NGX_LOG_NOTICE、cycle->log、0、"終了しています");
      終了(0);
    }

    // マスタープロセスが再オープンメッセージを送信した場合、すべてのキャッシュファイルを再オープンします if (ngx_reopen) {
      ngx_reopen = 0;
      ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "ログを再開しています");
      ngx_reopen_files(サイクル、-1);
    }

    //イベント キュー内のイベントを実行します ngx_process_events_and_timers(cycle);
  }
}

上記のコードでは、まずイベント オブジェクトが作成されます (ev.handler = ctx->handler)。イベントによって処理されるロジックが指定されます (つまり、上記の 2 つの構造体の最初のパラメーターに対応するメソッド)。次に、イベントがイベント キューに追加されます (ngx_add_timer(&ev, ctx->delay)。ここでの 2 番目のパラメーターは、上記の 2 つの構造体で指定された 3 番目のパラメーターであることに注意してください。つまり、handler() メソッドの実行時間は、イベントの遅延時間によって制御されます。最後に、無限 for ループで、ngx_process_events_and_timers() メソッドを使用して、イベント キュー内のイベントを継続的にチェックし、イベントを処理します。

3.3 キャッシュマネージャプロセス処理ロジック

キャッシュマネージャ処理プロセスについては、上記の説明から、キャッシュマネージャ構造体で定義された ngx_cache_manager_process_handler() メソッド内で実行されることがわかります。以下はこのメソッドのソースコードです。

静的 void ngx_cache_manager_process_handler(ngx_event_t *ev) {
  ngx_uint_t i;
  ngx_msec_t 次、n;
  ngx_path_t **パス;

  次 = 60 * 60 * 1000;

  パス = ngx_cycle->paths.elts;
  (i = 0; i < ngx_cycle->paths.nelts; i++) の場合 {

    // ここでのマネージャーメソッドは ngx_http_file_cache_manager() メソッドを参照します if (path[i]->manager) {
      n = パス[i]->マネージャー(パス[i]->データ);

      次 = (n <= 次) ? n : 次;

      ngx_time_update() 関数は、
    }
  }

  次 == 0 の場合
    次 = 1;
  }

  // 1 つの処理が完了すると、現在のイベントは次の処理のためにイベント キューに再度追加されます ngx_add_timer(ev, next);
}

ここでは、まずすべてのパス定義が取得され、次にそれらの manager() メソッドが空かどうかがチェックされます。空でない場合は、メソッドが呼び出されます。ここで manager() メソッドによって指し示される実際のメソッドは、セクション 3.1 の proxy_cache_path ディレクティブの解析で定義されたメソッド、つまり cache->path->manager = ngx_http_file_cache_manager; であり、これはこのメソッドがキャッシュを管理するための主なメソッドであることを意味します。管理メソッドを呼び出すと、現在のイベントが次のキャッシュ管理サイクルのイベント キューに追加されます。以下は ngx_http_file_cache_manager() メソッドのソース コードです。

静的 ngx_msec_t ngx_http_file_cache_manager(void *データ) {
  // ここでの ngx_http_file_cache_t 構造は、proxy_cache_path 構成項目を解析することによって取得されます。ngx_http_file_cache_t *cache = data;

  off_t サイズ;
  time_t 待機;
  ngx_msec_t 経過、次;
  ngx_uint_t カウント、ウォーターマーク;

  キャッシュ->last = ngx_current_msec;
  キャッシュ->ファイル = 0;

  // ここでの ngx_http_file_cache_expire() メソッドは無限ループになっており、キャッシュ キューの末尾に期限切れの共有メモリがあるかどうかを常にチェックしています。存在する場合は、それと対応するファイルを削除します。 next = (ngx_msec_t) ngx_http_file_cache_expire(cache) * 1000;

  // 次は ngx_http_file_cache_expire() メソッドの戻り値です。次の 2 つの場合にのみ 0 を返します。
  // 1. 削除されたファイルの数が manager_files で指定されたファイル数を超えた場合。
  // 2. 各ファイルの削除にかかる合計時間が manager_threshold で指定された合計時間を超えた場合
  // next が 0 の場合、キャッシュのクリーンアップ作業のバッチが完了したことを意味します。この時点で、次のクリーンアップ作業の前にしばらくスリープする必要があります。
  // このスリープの持続時間は manager_sleep で指定された値です。つまり、ここでの next の値は、実際には次の // キャッシュクリーンアップの待機時間です if (next == 0) {
    次はcache->manager_sleepです。
    完了しました。
  }

  のために ( ;; ) {
    ngx_shmtx_lock(&cache->shpool->mutex);

    // ここでの size は、現在のキャッシュで使用される合計サイズを指します // count は、現在のキャッシュ内のファイル数を指定します // watermark は、保存できるファイル総数の 7/8 である水位を示します
    サイズ = cache->sh->size;
    count = cache->sh->count;
    ウォーターマーク = cache->sh->ウォーターマーク;

    ngx_shmtx_unlock(&cache->shpool->mutex);

    ngx_log_debug3(NGX_LOG_DEBUG_HTTP、ngx_cycle->log、0、
            "http ファイル キャッシュ サイズ: %O c:%ui w:%i",
            サイズ、カウント、(ngx_int_t) ウォーターマーク);

    // 現在のキャッシュで使用されているメモリサイズが使用可能な最大サイズより小さく、キャッシュされたファイルの数がウォーターマークより少ない場合、
    // キャッシュ ファイルが引き続き保存できることを示し、ループを終了します if (size < cache->max_size && count < watermark) {
      壊す;
    }

    // ここに行くと、利用可能な共有メモリ リソースが不足していることを意味します // ここでは主に、期限切れかどうかに関係なく、現在のキュー内の参照されていないファイルを強制的に削除します wait = ngx_http_file_cache_forced_expire(cache);

    // 次の実行時間を計算します if (wait > 0) {
      次 = (ngx_msec_t) 待機 * 1000;
      壊す;
    }

    // 現在の nginx が終了または終了した場合は、ループから抜け出します if (ngx_quit || ngx_terminate) {
      壊す;
    }

    // 現在削除中のファイルの数が manager_files で指定された数を超える場合は、ループを終了します。
    // 次のクリーンアップまでに必要なスリープ時間を指定します if (++cache->files >= cache->manager_files) {
      次はcache->manager_sleepです。
      壊す;
    }

    ngx_time_update() 関数は、

    経過時間 = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last));

    // 現在の削除アクションが manager_threshold で指定された時間よりも長くかかる場合は、ループを終了します。
    // 次のクリーンアップまでに必要なスリープ時間を指定します if (elapsed >= cache->manager_threshold) {
      次はcache->manager_sleepです。
      壊す;
    }
  }

終わり:

  経過時間 = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last));

  ngx_log_debug3(NGX_LOG_DEBUG_HTTP、ngx_cycle->log、0、
          "http ファイル キャッシュ マネージャー: %ui e:%M n:%M",
          cache->files、経過時間、次);

  次へ戻る;
}

ngx_http_file_cache_manager() メソッドでは、まず ngx_http_file_cache_expire() メソッドに入ります。このメソッドの主な機能は、現在の共有メモリ キューの末尾にある要素が期限切れかどうかをチェックすることです。期限切れの場合は、参照回数と削除中かどうかに基づいて、要素と要素に対応するディスク ファイルを削除する必要があるかどうかを判断します。このチェックの後、無限 for ループに入ります。ここでのループの主な目的は、現在の共有メモリ リソースが逼迫しているかどうか、つまり、使用されているメモリが max_size で定義された最大メモリを超えているかどうか、または現在キャッシュされているファイルの合計数がファイルの合計数の 7/8 を超えているかどうかをチェックすることです。これら2つの条件のいずれかが満たされている場合、キャッシュファイルを強制的にクリアする試みが行われます。ここでは、最初にngx_http_file_cache_expire()メソッドを読みます。

static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache){
  u_char *name、 *p;
  size_t 長さ;
  time_t今、待ってください。
  ngx_path_t *パス;
  ngx_msec_t Elapsed;
  ngx_queue_t *q;
  ngx_http_file_cache_node_t *fcn;
  u_charキー[2 * ngx_http_cache_key_len];

  ngx_log_debug0(ngx_log_debug_http、ngx_cycle-> log、0、
          「httpファイルキャッシュの有効期限が切れる」);

  path = cache-> path;
  len = path-> name.len + 1 + path-> len + 2 * ngx_http_cache_key_len;

  name = ngx_alloc(len + 1、ngx_cycle-> log);
  if(name == null){
    10 を返します。
  }

  ngx_memcpy(name、path-> name.data、path-> name.len);

  now = ngx_time();

  ngx_shmtx_lock(&cache-> shpool-> mutex);

  のために ( ;; ) {

    //現在のnginxが終了または終了した場合、現在のループからジャンプしてくださいif(ngx_quit || ngx_terminate){
      wait = 1;
      壊す;
    }

    //現在の共有メモリキューが空の場合、現在のループからジャンプしてくださいif(ngx_queue_empty(&cache-> sh-> queue)){
      待機= 10;
      壊す;
    }

    //キューの最後の要素を取得q = ngx_queue_last(&cache-> sh-> queue);

    //キューノードfcn = ngx_queue_data(q、ngx_http_file_cache_node_t、queue)を取得します。

    //ノードの有効期限と現在の時間の間の時間の長さを計算します

    //現在のノードが有効期限が切れていない場合は、現在のループを終了します(wait> 0){
      待機= 10> 10:待ってください。
      壊す;
    }

    ngx_log_debug6(ngx_log_debug_http、ngx_cycle-> log、0、
            「HTTPファイルキャッシュの期限切れ:#%d%d%02xd%02xd%02xd%02xd」、
            fcn-> count、fcn->存在する、
            fcn-> key [0]、fcn-> key [1]、fcn-> key [2]、fcn-> key [3]);

    //ここでのカウントは、現在のノードが参照されている場合、(fcn-> count == 0){{fcn-> count == 0)の回数を示します。
      //ここでの主なアクションは、キューから現在のノードを削除し、ノードngx_http_file_cache_delete(cache、q、name)に対応するファイルを削除することです。
      次へ進む;
    }

    //現在のノードが削除されている場合、現在のプロセスは(fcn->削除){の場合それを処理する必要がありません。
      wait = 1;
      壊す;
    }

    //ここに進むには、現在のノードが有効期限が切れているが、参照カウントが0より大きく、ノードの削除はありません
    len = ngx_http_cache_key_len -sizeof(ngx_rbtree_key_t);
    (void)ngx_hex_dump(p、fcn-> key、len);

    //現在のノードは時間内に期限切れになっているが、ノードを参照するリクエストがあり、ノードを削除するプロセスはないため、
    //ノードを保持する必要があることを示しているので、ここではキューの端からノードを削除し、次の有効期限を再計算しようとします。
    //次に、キューヘッダーngx_queue_remove(q)に挿入します。
    fcn-> expire = ngx_time() + cache-> incactive;
    ngx_queue_insert_head(&cache-> sh-> queue、&fcn-> queue);

    ngx_log_error(ngx_log_alert、ngx_cycle-> log、0、
           「長いロックされた非アクティブキャッシュエントリ%*s、count:%dを無視する」、
           (size_t)2 * ngx_http_cache_key_len、key、fcn-> count);

次://キューの最後のノードが削除され、ここで実行される前に対応するファイルが削除されます。
    // LRUアルゴリズムを実行してファイルを強制的にクリアすると、このパラメーターで指定されたファイルの最大数がクリアされ、デフォルトは100です。
    //ここでcache->ファイルがmanager_filesよりも大きい場合、ループはジャンプします(++ cache-> files> = cache-> manager_files){
      wait = 0;
      壊す;
    }

    //現在のnginxキャッシュ時間ngx_time_update()を更新します。

    // Elapsedは、現在の削除アクションに費やされた合計時間に等しくなります= ngx_abs((ngx_msec_int_t)(ngx_current_msec -cache-> last));

    //合計時間がmanager_thresholdによって指定された値を超えて消費する場合、現在のループがポップアップします(Elapsed> = cache-> manager_threshold){
      wait = 0;
      壊す;
    }
  }

  //現在のロックngx_shmtx_unlock(&cache-> shpool-> mutex)をリリースします。

  ngx_free(name);

  待ってください。
}

ここでの主な処理ロジックは、最初にキューの尾の要素を刺激することであることがわかります。次に、要素が有効期限が切れない場合は、現在の要素の参照が0であるかどうかを確認します。現在の要素の参照番号が0でない場合、削除されているかどうかを確認します。削除されている場合、現在のプロセスは削除されていない場合、現在のプロセスはキューの尾からキューのヘッドに移動しようとします。

リソースがタイトな場合、キャッシュマネージャーがどのようにクリアされるかを見てみましょう。

static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache){
  u_char *名前;
  size_t 長さ;
  time_t wait;
  ngx_uint_t tries;
  ngx_path_t *パス;
  ngx_queue_t *q;
  ngx_http_file_cache_node_t *fcn;

  ngx_log_debug0(ngx_log_debug_http、ngx_cycle-> log、0、
          「HTTPファイルキャッシュが強制的に期限切れ」);

  path = cache-> path;
  len = path-> name.len + 1 + path-> len + 2 * ngx_http_cache_key_len;

  name = ngx_alloc(len + 1、ngx_cycle-> log);
  if(name == null){
    10 を返します。
  }

  ngx_memcpy(name、path-> name.data、path-> name.len);

  待機= 10;
  試行= 20;

  ngx_shmtx_lock(&cache-> shpool-> mutex);

  //キュー内の各ノードを継続的にトラバースします(q = ngx_queue_last(&cache-> sh-> queue);
     q!= ngx_queue_sentinel(&cache-> sh-> queue);
     q = ngx_queue_prev(q))
  {
    //現在のノードfcn = ngx_queue_data(q、ngx_http_file_cache_node_t、queue)のデータを取得します。

    ngx_log_debug6(ngx_log_debug_http、ngx_cycle-> log、0、
         「HTTPファイルキャッシュが強制された期限切れ:#%d%d%02xd%02xd%02xd」
         fcn-> count、fcn->存在する、
         fcn-> key [0]、fcn-> key [1]、fcn-> key [2]、fcn-> key [3]);

    //現在のノードの参照番号が0の場合、(fcn-> count == 0){if(fcn-> count == 0){
      ngx_http_file_cache_delete(cache、q、name);
      wait = 0;

    } それ以外 {
      //次のノードを試みます。
        続く;
      }

      wait = 1;
    }

    壊す;
  }

  ngx_shmtx_unlock(&cache-> shpool-> mutex);

  ngx_free(name);

  待ってください。
}

ご覧のとおり、ここでの処理ロジックは、主にキューの終わりから始まり、キュー内の要素の参照の数が0であるかどうかを確認します。 0ではない場合は、次の要素をチェックして繰り返します。ここでは、要素の合計20倍が参照されている場合、現在のループが飛び出すことに注意する必要があります。

3.4キャッシュローダープロセス処理ロジック

前述のように、キャッシュローダーの主な処理プロセスは、NGX_CACHE_LOADER_PROCESS_HANDLER()メソッドです。

静的void ngx_cache_loader_process_handler(ngx_event_t *ev)
{
  ngx_uint_t i;
  ngx_path_t **パス;
  ngx_cycle_t *cycle;

  Cycle =(ngx_cycle_t *)ngx_cycle;

  path = cycle-> paths.elts;
  for(i = 0; i <cycle-> paths.nelts; i ++){

    if(ngx_terminate || ngx_quit){
      壊す;
    }

    //ここでローダーメソッドは、ngx_http_file_cache_loader()メソッドif(path [i]  - > loader){を指します{
      path [i]  - > loader(path [i]  - > data);
      ngx_time_update();
    }
  }

  //読み込み後に現在のプロセスを終了しますexit(0);
}

ここでは、キャッシュマネージャーは、主に各パスのローダー()メソッドを呼び出すことでデータをロードします。

cache->path->loader = ngx_http_file_cache_loader;

ここでは、ngx_http_file_cache_loader()メソッドのソースコードを引き続き読み続けます。

static void ngx_http_file_cache_loader(void *data){
  ngx_http_file_cache_t *cache = data;

  ngx_tree_ctx_tツリー;

  //読み込みが完了した場合、または読み込まれている場合、if(!cache-> sh-> cold || cache-> sh-> loading){cache-> cache-> cache-> cache-> cache-> cache-> cache->を直接返す
    戻る;
  }

  // if(!ngx_atomic_cmp_set(&cache-> sh-> loading、0、ngx_pid)){
    戻る;
  }

  ngx_log_debug0(ngx_log_debug_http、ngx_cycle-> log、0、
          「HTTPファイルキャッシュローダー」);

  //ここのツリーは主要なプロセスオブジェクトの読み込みであり、読み込みプロセスは再帰ツリーを介して実行されます。Init_handler= null;
  //単一のファイルtree.file_handler = ngx_http_file_cache_manage_fileをロードする操作をカプセル化します。
  //ディレクトリをロードする前の操作は、主に現在のディレクトリに操作許可ツリーがあるかどうかを確認することです。
  //ディレクトリを読み込んだ後、これは実際には空のメソッドツリーです。post_tree_handler= ngx_http_file_cache_noop;
 //これは、主に特別なファイル、つまりファイルもフォルダーでもないファイルを扱うために使用されます。
  tree.data = cache;
  tree.alloc = 0;
  tree.log = ngx_cycle-> log;

  キャッシュ - > last = ngx_current_msec;
  キャッシュ - >ファイル= 0;

  //指定されたディレクトリ内のすべてのファイルを再帰的に通過し、上記のメソッドに従って処理します。つまり、共有メモリにロードする場合は(ngx_walk_tree(&tree、&cache-> path-> name)== ngx_abort){
    キャッシュ - > sh-> loading = 0;
    戻る;
  }

  //マークロードステータスキャッシュ - > sh-> cold = 0;
  キャッシュ - > sh-> loading = 0;

  ngx_log_error(ngx_log_notice、ngx_cycle-> log、0、
         「HTTPファイルキャッシュ:%V%.3FM、BSIZE:%UZ」、
         &cache-> path-> name、
         ((double)キャッシュ - > sh-> size * cache-> bsize) /(1024 * 1024)、
         キャッシュ - > bsize);
}

読み込みプロセス中、ターゲットロードディレクトリは最初にNGX_TREE_CTX_T構造にカプセル化され、ファイルのロードに使用される方法が指定されています。最終的な読み込みロジックは主にNGX_WALK_TREE()メソッドで実行され、ロードプロセス全体も再帰を通じて実装されます。以下は、NGX_WALK_TREE()メソッドの実装原則です。

ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx、ngx_str_t *tree){
  void *data、 *prev;
  u_char *p、 *name;
  size_t 長さ;
  ngx_int_t rc;
  ngx_err_t エラー;
  ngx_str_tファイル、buf;
  ngx_dir_t dir;

  ngx_str_null(&buf);

  ngx_log_debug1(ngx_log_debug_core、ctx-> log、0、
          「walk tree \ "%v \" "、ツリー);

  //ターゲットディレクトリを開きますif(ngx_open_dir(tree、&dir)== ngx_error){
    ngx_log_error(ngx_log_crit、ctx-> log、ngx_errno、
           ngx_open_dir_n "\"%s \ "failed"、tree-> data);
    NGX_ERROR を返します。
  }

  prev = ctx-> data;

  //ここで通過したアロックは0ですので、(ctx-> alloc){{ctx-> alloc)の場合、現在のブランチに入りません。
    data = ngx_alloc(ctx-> alloc、ctx-> log);
    if(data == null){
      gotoは失敗しました。
    }

    if(ctx-> init_handler(data、prev)== ngx_abort){
      gotoは失敗しました。
    }

    ctx-> data = data;

  } それ以外 {
    data = null;
  }

  のために ( ;; ) {

    ngx_set_errno(0);

    //現在のサブディレクトリのコンテンツを読むif(ngx_read_dir(&dir)== ngx_error){
      err = ngx_errno;

      if(err == ngx_enomorefiles){
        rc = ngx_ok;

      } それ以外 {
        ngx_log_error(ngx_log_crit、ctx-> log、err、
               ngx_read_dir_n "\"%s \ "failed"、tree-> data);
        rc = ngx_error;
      }

      成し遂げた;
    }

    len = ngx_de_namelen(&dir);
    name = ngx_de_name(&dir);

    ngx_log_debug2(ngx_log_debug_core、ctx-> log、0、
           「ツリー名%uz:\ "%s \" "、len、name);

    //現在読まれている場合、それは現在のディレクトリをスキップすることを意味します(len == 1 && name [0] == '){){)
      続く;
    }

    //現在読み取られた場合、それは前のディレクトリをスキップするのはアイデンティティであることを意味します。
      続く;
    }

    file.len = tree-> len + 1 + len;

    //利用可能なキャッシュサイズを更新するif(file.len + ngx_dir_mask_len> buf.len){

      if(buf.len){
        ngx_free(buf.data);
      }

      buf.len = tree-> len + 1 + len + ngx_dir_mask_len;

      buf.data = ngx_alloc(buf.len + 1、ctx-> log);
      if(buf.data == null){
        gotoは失敗しました。
      }
    }

    p = ngx_cpymem(buf.data、tree-> data、tree-> len);
    *p ++ = '/';
    ngx_memcpy(p、name、len + 1);

    file.data = buf.data;

    ngx_log_debug1(ngx_log_debug_core、ctx-> log、0、
            「ツリーパス\ "%s \" "、file.data);

    if(!dir.valid_info){
      if(ngx_de_info(file.data、&dir)== ngx_file_error){
        ngx_log_error(ngx_log_crit、ctx-> log、ngx_errno、
               ngx_de_info_n "\"%s \ "failed"、file.data);
        続く;
      }
    }

    //現在ファイルを読んでいる場合は、ctx-> file_handler()を呼び出してファイルの内容をロードするif(ngx_de_is_file(&dir)){

      ngx_log_debug1(ngx_log_debug_core、ctx-> log、0、
              "tree file \"%s \ ""、file.data);

      //ファイルの関連プロパティを設定しますctx-> size = ngx_de_size(&dir);
      ctx-> fs_size = ngx_de_fs_size(&dir);
      ctx-> access = ngx_de_access(&dir);
      ctx-> mtime = ngx_de_mtime(&dir);

      if(ctx-> file_handler(ctx、&file)== ngx_abort){
        gotoは失敗しました。
      }

     //現在の読み取りがディレクトリの場合は、最初にset pre_tree_handler()メソッドを呼び出してから、// ngx_walk_tree()メソッドを呼び出し、サブディレクトリを再帰的に読み取り、最後にset post_tree_handler()メソッドを呼び出します} else(ngx_de_is_dir(&dir))

      ngx_log_debug1(ngx_log_debug_core、ctx-> log、0、
              「ツリーEnter dir \ "%s \" "、file.data);

      ctx-> access = ngx_de_access(&dir);
      ctx-> mtime = ngx_de_mtime(&dir);

      // readディレクトリの前のrcを適用しますrc = ctx-> pre_tree_handler(ctx、&file);

      if(rc == ngx_abort){
        gotoは失敗しました。
      }

      if(rc == ngx_declined){
        ngx_log_debug1(ngx_log_debug_core、ctx-> log、0、
                「tree skip dir \ "%s \" "、file.data);
        続く;
      }

      //現在のディレクトリを再帰的に読み取りますif(ngx_walk_tree(ctx、&file)== ngx_abort){
        gotoは失敗しました。
      }

      ctx-> access = ngx_de_access(&dir);
      ctx-> mtime = ngx_de_mtime(&dir);

      //ディレクトリのポストロジックロジックを適用するif(ctx-> post_tree_handler(ctx、&file)== ngx_abort){
        gotoは失敗しました。
      }

    } それ以外 {

      ngx_log_debug1(ngx_log_debug_core、ctx-> log、0、
              「ツリースペシャル\ "%s \" "、file.data);

      if(ctx-> spec_handler(ctx、&file)== ngx_abort){
        gotoは失敗しました。
      }
    }
  }

失敗した:

  rc = ngx_abort;

終わり:

  if(buf.len){
    ngx_free(buf.data);
  }

  if(data){
    ngx_free(data);
    ctx-> data = prev;
  }

  if(ngx_close_dir(&dir)== ngx_error){
    ngx_log_error(ngx_log_crit、ctx-> log、ngx_errno、
           ngx_close_dir_n "\"%s \ "failed"、tree-> data);
  }

  rc を返します。
}

上記の処理フローから、ファイルを読み込むという実際のロジックは、次のようにNGX_HTTP_FILE_CACHE_MANAGE_FILE()メソッドにあることがわかります。

static ngx_int_t ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx、ngx_str_t *path){
  ngx_msec_t Elapsed;
  ngx_http_file_cache_t *cache;

  cache = ctx-> data;

  //共有メモリにファイルを追加するif(ngx_http_file_cache_add_file(ctx、path)!= ngx_ok){
    (void)ngx_http_file_cache_delete_file(ctx、path);
  }

  //ロードされたファイルの数がLoader_Filesで指定された数を超える場合、(++ Cache-> files> = cache-> loader_files){++ cache-> files)の場合、一定期間スリープします
    ngx_http_file_cache_loader_sleep(cache);

  } それ以外 {
    //現在のキャッシュ時間ngx_time_update()を更新します。

    //負荷の時間のかかる時間のかかる誇大広告= ngx_abs((ngx_msec_int_t)(ngx_current_msec-cache-> last));

    ngx_log_debug1(ngx_log_debug_http、ngx_cycle-> log、0、
            「httpファイルキャッシュローダー時間経過:%m」、経過);

    // Loader_Thresholdで指定された時間を超えて読み込み操作が必要な場合は、指定された時間をスリープします(Elapsed> = cache-> loader_threshold){
      ngx_http_file_cache_loader_sleep(cache);
    }
  }

  return(ngx_quit || ngx_terminate)?ngx_abort:ngx_ok;
}

ここでのロードロジックは、ファイルを共有メモリにロードし、制限が制限を超えるかどうかを判断することです。

4. まとめ

この記事では、最初にNginxの共有メモリの使用と各パラメーターの特定の意味について説明し、共有メモリの実装原則を説明し、最終的に共有メモリ、キャッシュマネージャー、キャッシュローダーの作業原則を説明することに焦点を当てます。

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • nginxでの共有メモリの使用に関する詳細な説明

<<:  Mysql WorkBench のインストールと設定のグラフィックチュートリアル

>>:  vue-cli を使用してプロジェクトを作成し、webpack でパッケージ化する方法

推薦する

JavaScript Promise の徹底解説

目次1. Promise とは何ですか? 2. なぜ Promise が存在するのでしょうか? 3つ...

Ubuntu 18.0.4 は mysql をインストールし、エラー 1698 (28000): ユーザー ''root''@''localhost'' のアクセスが拒否されましたを解決します

序文最近 Linux を学び、その後 Win から Ubuntu に変更しました。以前インストールし...

Dockerでコンテナを作成するときのディレクトリ権限

昨日プロジェクトを書いていた時に、MySQL の派生版である Percona を使う必要があったので...

Ubuntuが仮想マシンでインターネットに接続できない問題の解決策

インターネットに接続できない仮想マシンをセットアップするのは非常に面倒です。ここでは、Ubuntu ...

MySQLをシンプルに学ぶ

序文データベースは常に私の弱点でした。自分の経験 (python+sqlalchemy) を組み合わ...

CSS のみを使用して折りたたまれたヘッダー効果を作成する方法の例コード

折りたたまれたヘッダーは、特別オファーや重要なお知らせなど、ユーザーにとって重要な情報を表示するのに...

VUE 3 テレポート コンポーネントと使用構文をすぐに使い始める

目次1. テレポートの紹介1.1. 複数のテレポートを使用する2. テレポートを使用する理由3. テ...

CSS の画像パスの問題に関する議論 (同じパッケージ/異なるパッケージ)

CSS ファイルでは、背景を使用する、つまり背景画像を追加する必要がある場合があります。これは通常、...

MySQL はどのようにしてマスターとスレーブの一貫性を確保するのでしょうか?

目次MySQLマスタースレーブの基本原理3つのbinlog形式の比較混合形式のバイナリログが存在する...

Mysql通信プロトコルの詳細な説明

1.Mysql接続方法MySQL 通信プロトコルを理解するには、まず MySQL サーバーへの接続に...

HTML のインラインブロックの空白を素早く削除する 5 つの方法

inline-block プロパティ値は、「インライン」要素のマージンとパディングを制御する必要があ...

js のループメソッドとさまざまなトラバーサルメソッド

目次forループwhileループdo-while ループループのネストトラバーサルメソッド~のために...

Vue3とElectronを使ったデスクトップアプリケーションの詳しい説明

目次Vue CLIはVueプロジェクトを構築しますVue プロジェクトをマークダウン エディターに変...

Linux での Tomcat8 のインストールとアンインストールに関する詳細なグラフィック チュートリアル

[ Tomcat8 の Linux インストール ] Tomcat をアンインストールする - まず...

MySQLアラームの詳細な分析と処理

最近、あるサービスにアラームが発生し、耐えられなくなっています。アラーム情報は次のとおりです。メトリ...