前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Impala 2.12.0与3.4.0版本的compute stats兼容问题

Impala 2.12.0与3.4.0版本的compute stats兼容问题

作者头像
skyyws
发布于 2022-05-20 00:31:35
发布于 2022-05-20 00:31:35
98800
代码可运行
举报
运行总次数:0
代码可运行

对于Impala来说,compute [incremental] stats [partition_spec]是我们经常会使用到的语句,这个语句的功能就是对表,执行统计信息计算。Impala在进行SQL解析的时候,就可以利用这些统计信息进行更好地优化,生成更高效地执行计划。但是,最近我们在将集群从2.12.0升级到3.4.0版本的时候,遇到了一些compute stats相关的问题。 本文在第一章和第三章分别描述了问题以及重现的步骤,第二章是详细的代码探究。如果不感兴趣的话,可以直接略过。

问题描述

当我们在3.4.0版本,对表的某个具体分区执行compute incremental stats table_name [partition_spec]时,发现执行过程中,会出现TableLoadingException的异常,如下所示:

这个exception主要是由于列统计信息不符合约束导致的,这里就是由于numNulls_的约束检查失败导致的。我们可以在相关的类中找到如下代码,该方法在2.12.0中是不存在的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  // 3.4.0  ColumnStats.java
  public void validate(Type colType) {
    // avgSize_ and avgSerializedSize_ must be set together.
    Preconditions.checkState(avgSize_ >= 0 == avgSerializedSize_ >= 0, this);

    // Values must be either valid or -1.
    Preconditions.checkState(avgSize_ == -1 || avgSize_ >= 0, this);
    Preconditions.checkState(avgSerializedSize_ == -1 || avgSerializedSize_ >= 0, this);
    Preconditions.checkState(maxSize_ == -1 || maxSize_ >= 0, this);
    Preconditions.checkState(numDistinctValues_ == -1 || numDistinctValues_ >= 0, this);
    Preconditions.checkState(numNulls_ == -1 || numNulls_ >= 0, this);
    if (colType != null && colType.isFixedLengthType()) {
      Preconditions.checkState(avgSize_ == colType.getSlotSize(), this);
      Preconditions.checkState(avgSerializedSize_ == colType.getSlotSize(), this);
      Preconditions.checkState(maxSize_ == colType.getSlotSize(), this);
    }
  }

我们观察Impala的页面发现,compute stats的两条相关SQL执行是成功的,如下所示:

这就说明,新版本部署启动之后,第一次加载这个表是正常的,并且compute stats相关的两条SQL都能正常执行成功。因此,问题应该是出在了计算完成之后,更新到metastore中导致的,我们通过查看元数据库对应的表发现,确实numNulls_对应的值是-6(这些统计信息位于元数据库的TAB_COL_STATS表,其中numNulls_对应的列是NUM_NULLS)。

深入研究
两个版本统计信息对比

当我们对表执行了compute stats之后,我们可以通过show column stats table_name来查看表的列统计信息,如下所示:

以上是我们表的初始列统计信息状态,当我们执行了compute stats table_name之后,2.12.0版本的结果如下所示:

而3.4.0版本的结果如下所示:

通过上面两幅图对比,我们可以发现,“#Nulls”这一列在两个版本中的值是不一样的。2.12.0版本对于这一列,即使执行了compute stats之后,仍然是-1(除去分区列),而3.4.0版本则是实际的数值,是大于等于0的。这里的“#Nulls”列对应的就是异常日志中的“numNulls”。 值得一提的是,对于每一个分区(Hdfs表对应的是THdfsPartition结构体,这个thrift结构体包括了单个分区详细信息,如果存在多层分区的话,那么该结构体包含的是到最里层的分区,例如day=20200101/type=xxx/id=xxx这种),其中每一个THdfsPartition都有一个has_incremental_stats变量,这个变量默认是false(即没有执行compute stats),当我们执行相关SQL的时候,情况分别如下所示:

  • 执行compute stats table_name,所有分区对应的has_incremental_stats参数变为false;
  • 执行compute incremental stats table_name,所有分区对应的has_incremental_stats参数变为true;
  • 执行compute incremental stats table_name partition(day=‘2020-12-01’),这个分区对应的has_incremental_stats参数变为true,其他分区的仍然为false。

我们这里讨论的前提是:这个表是默认没有进行任何的compute stats操作的,上述情况对于2.12.0和3.4.0都是同样的情况。因此,当has_incremental_stats为true,就表示对应的某个分区包含了增量的历史统计信息,而初始状态,或者compute stats table_name是不算做增量统计信息计算的。我们后续的分析,都是基于增量的统计信息计算。

初始状态分析

为了研究,到底是哪里导致的这个“#Nulls”的值小于-1,我们接下来跟着代码一步一步看下去(这里以3.4.0的代码为例)。 首先,假设表为初始状态,当我们第一次访问,加载表的时候,此时表没有任何统计信息,加载操作由catalogd执行。Catalogd会对表信息、分区信息等进行初始化,主要就是从metastore中进行加载,然后转换成Impala对应的各种类和结构体。我们这里主要关注HDFS表的加载,下面我们简单看下相关的函数调用栈:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
HdfsTable.load()
-HdfsTable.loadAllPartitions()
--HdfsTable.createPartition() 分区表会循环调用这个函数
---HdfsPartition.ctor() public
----HdfsPartition.ctor() private
-----HdfsPartition.extractAndCompressPartStats()
------PartitionStatsUtil.partStatsBytesFromParameters()
------HdfsPartition.setPartitionStatsBytes() 使用上面函数的返回结果作为输入参数

可以看到,在加载表分区的信息时,会调用partStatsBytesFromParameters这个函数,我们将相关的代码粘贴出来:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    // PartitionStatsUtil.java
    public static final String INCREMENTAL_STATS_NUM_CHUNKS =
      "impala_intermediate_stats_num_chunks";
   // 省略后续代码
  /**
   * Reconstructs the intermediate stats from chunks and returns the corresponding
   * byte array. The output byte array is deflate-compressed. Sets hasIncrStats to
   * 'true' if the partition stats contain intermediate col stats.
   */
  public static byte[] partStatsBytesFromParameters(
      Map<String, String> hmsParameters, Reference<Boolean> hasIncrStats) throws
      ImpalaException {
    if (hmsParameters == null) return null;
    String numChunksStr = hmsParameters.get(INCREMENTAL_STATS_NUM_CHUNKS);
    if (numChunksStr == null) return null;
    int numChunks = Integer.parseInt(numChunksStr);
    if (numChunks == 0) return null;
   // 省略后续代码

我们通过上述函数代码可以看到:当分区的参数列表中(分区的参数列表,可以直接从metastore中加载),没有INCREMENTAL_STATS_NUM_CHUNKS参数时,整个函数会返回null。这里先提一下,当函数初始没有计算统计信息的时候,就不会有这个参数,后续我们还会再提到这个参数。紧接着就会使用上述函数的返回结果,来执行setPartitionStatsBytes这个函数。这里又涉及到了两个成员变量:partitionStats_和hasIncrementalStats_。这里我们暂且不详细探究其含义,我们只需要知道,在初始状态下,对于具体的某个分区而言,partitionStats_为null,而hasIncrementalStats_为false。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  // Binary representation of the TPartitionStats for this partition. Populated
  // when the partition is loaded and updated using setPartitionStatsBytes().
  private byte[] partitionStats_;

  // True if partitionStats_ has intermediate_col_stats populated.
  private boolean hasIncrementalStats_ ;
  // 省略后续代码
  public void setPartitionStatsBytes(byte[] partitionStats, boolean hasIncrStats) {
    if (hasIncrStats) Preconditions.checkNotNull(partitionStats);
    partitionStats_ = partitionStats;
    hasIncrementalStats_ = hasIncrStats;
  }

对于初始的状态而言,2.12.0和3.4.0版本,虽然在代码处理逻辑上有所不同,但是总体而言,这些主要的结构和成员变量都是相差不大的。

增量计算后的状态变化

上面我们已经了解一些,初始状态下的分区相关统计信息。现在来看一下,当我们执行了compute [incremental] stats [partition_spec]之后,状态会发生哪些变化,而这也跟我们最初的问题有关系。 当我们提交了SQL之后,Impala会自动提交两条子SQL来进行相应信息的获取,相关的SQL我们可以在第一章的第二幅图中看到,3.4.0和2.12.0版本的两个SQL略有不同。从截图中我们可以看到,这两条SQL的执行是没有问题,因此我们当前不关注这两条SQL的生成以及执行,着重于后续的统计信息更新部分。 我们假设当前表处于初始状态,此时提交执行compute incremental stats table_name partition(day=‘2020-12-01’)这种SQL。我们来看一下状态是如何更新的: 首先,当SQL提交到Impalad的时候,会进行一系列的计算操作,主要就是执行上述的两个子查询。计算完成之后,会生成相应的变量来保存信息,然后将变量传到catalogd进程进行元数据的更新。这里我们先看下catalogd的相关处理流程,主要的api调用如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ExecDdl(catalog-server.cc)
-ExecDdl(catalog.cc)
--execDdl(JniCatalog.java)
---CatalogOpExecutor.execDdlRequest
----CatalogOpExecutor.alterTable

可以看到,catalogd首先是在c++端通过JNI调用了Java的api,最终执行了一个alterTable的函数,来更新表的元数据信息(这里主要是统计信息),这里我们涉及到了一些thrift结构体信息:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CatalogService.TDdlExecRequest
-alter_table_params: JniCatalog.TAlterTableParams
--update_stats_params: JniCatalog.TAlterTableUpdateStatsParams
---partition_stats: map<list<string>, CatalogObjects.TPartitionStats>
----CatalogObjects.TPartitionStats
-----intermediate_col_stats: map<string, TIntermediateColumnStats>
------CatalogObjects.TIntermediateColumnStats
---column_stats: map<string, CatalogObjects.TColumnStats>
----CatalogObjects.TColumnStats

我们将一些相关的结构体包含关系列了出来。从上面的包含关系可以看到:本次计算涉及到的分区都会保存在partition_stats这个数组中,数组的每一个成员都是一个TPartitionStats结构体,代表一个分区的信息。这个结构体主要包括两个成员:TTableStats和一个map,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Per-partition statistics
struct TPartitionStats {
  // so would interfere with the non-incremental stats path
  1: required TTableStats stats

  // Intermediate state for incremental statistics, one entry per column name.
  2: optional map<string, TIntermediateColumnStats> intermediate_col_stats
}

每个TPartitionStats都包含一个map,叫intermediate_col_stats。这个map的key表示列名,而value就是TIntermediateColumnStats,表的每一列都会对应一条KV记录。其中TIntermediateColumnStats的结构体如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Intermediate state for the computation of per-column stats. Impala can aggregate these
// structures together to produce final stats for a column.
struct TIntermediateColumnStats {
  // One byte for each bucket of the NDV HLL computation
  1: optional binary intermediate_ndv

  // If true, intermediate_ndv is RLE-compressed
  2: optional bool is_ndv_encoded

  // Number of nulls seen so far (or -1 if nulls are not counted)
  3: optional i64 num_nulls

  // The maximum width, in bytes, of the column
  4: optional i32 max_width

  // The average width (in bytes) of the column
  5: optional double avg_width

  // The number of rows counted, needed to compute NDVs from intermediate_ndv
  6: optional i64 num_rows
}

如果执行了增量的统计信息计算,那么partition_stats这个变量就会包含当前正在进行计算的各个分区信息,而每个分区又会包含各自的intermediate_col_stats成员,其中有相应的列的统计信息。这里需要注意的是,3.4.0版本和2.12.0版本是不一样的:

  • 在两个版本中,初始状态下,列的num_nulls都是-1;
  • 在3.4.0版本,如果执行了统计信息计算,num_nulls是一个大于等于0的值;
  • 在2.12.0版本,如果执行了统计信息计算,num_nulls仍然是-1;

但是,如果我们执行的是compute stats,而不是增量的话,那么每个分区的intermediate_col_stats是空的(注意,partition_stats不为空,其包含的stats也不为空,只是intermediate_col_stats这个变量为空)。这块的处理主要是在BE端进行的,只有当执行增量统计信息计算的时候,才会将分区的列统计信息存入intermediate_col_stats中,相关代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  // catalog-op-executor.cc ExecComputeStats()
  // 其中FinalizePartitionedColumnStats方法就是用来构造intermediate_col_stats的相关信息
  // col_stats_schema and col_stats_data will be empty if there was no column stats query.
  if (!col_stats_schema.columns.empty()) {
    if (compute_stats_params.is_incremental) {
      RuntimeProfile::Counter* incremental_finalize_timer =
          ADD_TIMER(profile_, "FinalizeIncrementalStatsTimer");
      SCOPED_TIMER(incremental_finalize_timer);
      FinalizePartitionedColumnStats(col_stats_schema,
          compute_stats_params.existing_part_stats,
          compute_stats_params.expected_partitions,
          col_stats_data, compute_stats_params.num_partition_cols, &update_stats_params);
    } else {
      SetColumnStats(col_stats_schema, col_stats_data, &update_stats_params);
    }
  }

这里我们可以看到,只有执行增量统计信息计算的时候(is_incremental为true),FinalizePartitionedColumnStats函数才会被调用。我们接着上面的catalogd处理流程继续往下看:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CatalogOpExecutor.alterTable
-CatalogOpExecutor.alterTableUpdateStats
--CatalogOpExecutor.alterTableUpdateStatsInner
---CatalogOpExecutor.updatePartitionStats
----PartitionStatsUtil.partStatsToPartition
-----HdfsPartition.setPartitionStatsBytes
---CatalogOpExecutor.bulkAlterPartitions
----HdfsPartition.toHmsPartition
-----PartitionStatsUtil.partStatsToParams

统计信息计算的结果,最终通过catalogd对表的分区进行了元数据更新,上述updatePartitionStats函数调用后两步,刚好与我们第一节中,提到的HDFS表加载形成了呼应,我们提到的INCREMENTAL_STATS_NUM_CHUNKS参数也会在partStatsToParams函数中进行设置。之后如果表再重新加载元数据的话,partStatsBytesFromParameters就不会返回空了。 除此之外,我们之前提到的partitionStats_和hasIncrementalStats_,最终在这里也进行了设置。我们将本节中涉及到的partition_stats数组,通过循环处理,将数组中的成员TPartitionStats进行压缩,最终保存到了HdfsPartition的partitionStats_成员变量中;hasIncrementalStats_保存是一个布尔值:TPartitionStats中的intermediate_col_stats成员是否为空,就是我们是否对该分区执行了增量统计信息计算(上面的分析已经提到过,只有执行增量统计信息计算的时候,intermediate_col_stats才不会为空)。这里我们对几种情况进行归纳:

状态

INCREMENTAL_STATS_NUM_CHUNKS

partition_stats

intermediate_col_stats

partitionStats_

hasIncrementalStats_

初始状态

不包括

false

compute stats

包括

不为空

不为空

false

增量compute stats

包括

不为空

不为空

不为空

true

这里有几个地方,我们需要注意一下:

  • partition_stats包含了本次操作涉及到的分区信息集合,而partitionStats_和hasIncrementalStats_是针对单个分区的信息;
  • partitionStats_是由partition_stats中的单个成员,也就是TPartitionStats,经过处理之后得到的;
  • intermediate_col_stats是TPartitionStats的一个成员,所以它是否为空,不会影响TPartitionStats,继而也不会影响partitionStats_;

总结一下,当我们执行compute incremental stats [partition_spec]的时候,会在Impalad的BE端根据SQL解析和计算的结果,构造一个TDdlExecRequest变量,并且传到catalogd端,catalogd通过JNI调用Java的api对表的元数据信息进行更新。之后如果再加载表的元数据时,就能获取到这些已经计算的增量统计信息。

错误产生分析

上一节提到,当我们执行了compute incremental stats [partition_spec]的时候,表就会包含一些增量的统计信息,例如partitionStats_。因为我们最开始是在2.12.0版本每天执行了增量的统计信息计算,当我们升级到3.4.0版本之后,HDFS表被加载起来之后,就会包含相关的历史增量统计信息。此时,当我们在3.4.0版本再次执行增量统计信息计算的时候,就会出现了第一章中的问题。接下来就结合代码来看一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
executeAndWait(impala-beeswax-server.cc)
-Execute(impala-server.cc)
--ExecuteInternal(impala-server.cc)
---Exec(client-request-stats.cc)
----ExecDdlRequest(client-request-stats.cc)
-----ExecAsync(child-query.cc)
------ExecChildQueries(child-query.cc)
-------ExecAndFetch(child-query.cc)
-Wait(client-request-state.cc)
--WaitInternal(client-request-state.cc)
---UpdateTableAndColumnStats(client-request-state.cc)
----ExecComputeStats(catalog-op-executor.cc)
-----SetTableStats(catalog-op-executor.cc)
-----FinalizePartitionedColumnStats(incr-stats-util.cc)
------Update(incr-stats-util.cc)

上述的代码调用都是属于BE模块的,这里主要分为两个分支流程:1)Execute函数,主要就是对两个子查询就行计算,并且保存相应地结果,这里我们不展开;2)Wait函数,这个后续的相关操作就是对统计信息的结构体进行更新。从上一节的代码中我们可以看到,在ExecComputeStats函数中,对FinalizePartitionedColumnStats进行了调用,其中涉及到了existing_part_stats这个成员变量。我们来看下相关的结构体:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Frontend.TExecRequest
-catalog_op_request: Frontend.TCatalogOpRequest
--ddl_params: CatalogService.TDdlExecRequest
---compute_stats_params: JniCatalog.TComputeStatsParams
----existing_part_stats: list<CatalogObjects.TPartitionStats>
-----CatalogObjects.TPartitionStats
------intermediate_col_stats: map<string, TIntermediateColumnStats>
-------CatalogObjects.TIntermediateColumnStats

从这里,我们就可以很明显的看出来,这个existing_part_stats变量,与我们上一节中提及到的partition_stats成员,其实是一样的内容。我们这里来看一下partition_stats是如何转换为existing_part_stats的: 首先,通过上一节的分析我们可以知道,如果某个分区进行了增量的统计信息计算,那么该分区包含的partitionStats_就不为空,并且hasIncrementalStats_为true(这两个成员变量都位于HdfsPartition类中)。 其次,Impala在进行SQL解析的时候,compute [incremental] stats [partiiton_spec]最终都会被解析为一个ComputeStatsStmt类,而这个类中就有一个变量:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  // The list of valid partition statistics that can be used in an incremental computation
  // without themselves being recomputed. Populated in analyze().
  private final List<TPartitionStats> validPartStats_ = new ArrayList<>();

validPartStats_这个变量就是在解析的过程中,根据表的元数据信息(这里就是每个分区的partitionStats_),将partition_stats解析出来,并保存下来,相关的解析流程位于ComputeStatsStmt.analyze()。最后,再构造TComputeStatsParams,通过thrift传到BE端,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  // ComputeStatsStmt.toThrift()
  public TComputeStatsParams toThrift() {
    TComputeStatsParams params = new TComputeStatsParams();
    params.setTable_name(new TTableName(table_.getDb().getName(), table_.getName()));
    params.setTbl_stats_query(tableStatsQueryStr_);
    if (columnStatsQueryStr_ != null) {
      params.setCol_stats_query(columnStatsQueryStr_);
    } else {
      params.setCol_stats_queryIsSet(false);
    }
    params.setIs_incremental(isIncremental_);
    params.setExisting_part_stats(validPartStats_);
    params.setExpect_all_partitions(expectAllPartitions_);
    // 省略后续代码

最终我们就在BE端获取到了existing_part_stats。也就是说,只有分区执行过增量的统计信息计算,existing_part_stats才不为空。最终在FinalizePartitionedColumnStats函数中,对existing_part_stats进行循环处理,调用了Update函数。我们来看下最后的Update函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  // Updates all aggregate statistics with a new set of measurements.
  void Update(const string& ndv, int64_t num_new_rows, double new_avg_width,
      int32_t max_new_width, int64_t num_new_nulls) {
    DCHECK_EQ(intermediate_ndv.size(), ndv.size()) << "Incompatible intermediate NDVs";
    DCHECK_GE(num_new_rows, 0);
    DCHECK_GE(max_new_width, 0);
    DCHECK_GE(new_avg_width, 0);
    DCHECK_GE(num_new_nulls, 0);
    for (int j = 0; j < ndv.size(); ++j) {
      intermediate_ndv[j] = ::max(intermediate_ndv[j], ndv[j]);
    }
    num_nulls += num_new_nulls;
    max_width = ::max(max_width, max_new_width);
    avg_width += (new_avg_width * num_new_rows);
    num_rows += num_new_rows;
  }

我们可以很明显的看到,这个函数里面都是对统计信息的更新,而其中就有num_nulls的处理。到这里,这个问题产生的原因基本就已经明了:我们通过2.12.0版本执行了compute incremental stats [partition_spec],这些分区对应的列统计信息中,Nulls都是-1。当我们在3.4.0版本再次执行compute incremental stats [partition_spec],会对之前的增量分区统计信息进行汇总(对于Nulls,是多个-1相加,最终结果小于-1),并写入到metastore中。当catalogd再次触发表的元数据加载时,由于Nulls的约束检查失败,导致了表的加载失败。 需要注意的是,当我们使用debug模式进行编译、调试的话,那么当执行到DCHECK_GE(num_new_nulls, 0)这一行代码的时候,Impalad会直接挂掉,只有使用release进行编译,才会发生最上面提到的异常。

复现步骤

这里我们使用一个测试表进行测试,在2.12.0版本执行如下SQL:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CREATE TABLE stats_test (id INT, name STRING)
PARTITIONED BY (day STRING)
STORED AS PARQUET;
insert into stats_test partition(day='2020-01-01') values(1,'Jack');
insert into stats_test partition(day='2020-01-02') values(1,'Jack');
compute incremental stats stats_test;

启动3.4.0版本之后,再执行如下的SQL:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
compute incremental stats stats_test partition(day='2020-01-01');

要触发这个错误,需要保证除当前待计算的分区之外,还有其他分区有增量的历史统计信息(如果我们在2.12.0中只对2020-12-02分区进行增量统计信息计算,3.4.0执行同样的SQL仍然会重现这个错误)。 目前的解决方法有两种:

  • 对于已经计算过统计信息的表,执行drop stats table_name,去掉已有的统计信息,然后再重新计算;
  • 将社区IMPALA-9699这个patch backport到较低的版本上来。
后续补充

后续我们发现,社区也已经有了类似的JIRA:IMPALA-10230

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-12-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Nginx模块开发:http handler实现流量统计(进阶篇)
Nginx通过模块化的方式提供了丰富的功能扩展能力。其中,HTTP Handler是Nginx模块开发中非常重要的一个概念。HTTP Handler可以用来拦截、处理和操作传入的HTTP请求,在请求的生命周期中执行特定的逻辑。它可以用于实现各种功能,如流量统计、访问控制、缓存管理等。
Lion 莱恩呀
2025/01/12
2100
Nginx模块开发:http handler实现流量统计(进阶篇)
Nginx模块开发:自定义HTTP过滤器filter
/src/http/ngx_http_config.h中定义的相关宏(type会用到):
Lion 莱恩呀
2025/01/07
4130
Nginx模块开发:自定义HTTP过滤器filter
编写 Nginx 模块进行 RSA 加解密
在《Nginx 模块系统:前篇》一文中,曾提过要展开聊聊如何编写和编译一个 Nginx 模块。
soulteary
2021/08/16
2K0
编写 Nginx 模块进行 RSA 加解密
nginx0.1.0之http模块初始化源码分析(1)
http模块的初始化类似event模块,初始化的起点在解析到http指令的时候。对应的处理函数是ngx_http_block,因为该函数比较长,所以我们分段解析。第一部分先解析http模块的pre_conf、create_main_conf函数的实现。
theanarkh
2019/03/06
6040
nginx0.1.0之http模块初始化源码分析(4)
我们继续分析ngx_http_block函数剩余的代码,剩下的代码就是处理phases和监听的端口、地址、servername的。
theanarkh
2019/03/06
4330
nginx源代码分析–模块分类
比方。对一个普通的訪问本地静态文件的请求处理,从 Nginx 收到请求并開始处理。到处 理结果的响应包体发送到网络上结束,整个过程的两个步骤 – 请求处理和响应处理 – 分别 由 handler 和 filter 处理完毕。
全栈程序员站长
2022/07/07
7470
Nginx 第三方模块使用与开发
Nginx 允许引入第三方模块来扩展 Nginx 的功能。官方网站 NGINX 3rd Party Modules 列出了 Nginx 很多的第三方模块。除此之外,很多很有用的模块也能在 github 等网站上找到。
Se7en258
2021/07/01
2.5K0
Nginx解读内置非默认模块 ngx_http_stub_status_module
http://nginx.org/en/docs/http/ngx_http_stub_status_module.html
星哥玩云
2022/07/24
8790
深入理解nginx的请求限流模块
  当构建高流量的Web应用程序时,保护服务器免受过多请求的影响是至关重要的。过多的请求可能会导致服务器过载,降低性能甚至导致系统崩溃。为了解决这个问题,nginx提供了一个强大的请求限速模块。该模块允许您根据自定义规则限制客户端请求的速率,并且还可以使用延迟机制来平滑处理超出限制的请求。在本文中,我们将深入探讨nginx的请求限速模块,了解它的工作原理、配置选项以及如何在实际应用中使用它来保护您的服务器免受恶意或异常请求的影响。
码农心语
2024/04/09
1.1K0
深入理解nginx的请求限流模块
nginx的timeout(基于nginx1.17.9)
nginx中使用timeout的地方非常多,本文主要分析客户端和nginx通信时涉及到的几个timeout。
theanarkh
2020/06/19
8410
接入层Nginx架构及模块介绍分享
1)帮助大家对Nginx有一定的认识 2)熟悉Nginx有哪些应用场景 3)熟悉Nginx特点和架构模型以及相关流程 4)熟悉Nginx定制化开发的几种模块分类
Lucien168
2020/07/20
9550
接入层Nginx架构及模块介绍分享
深入理解nginx mp4流媒体模块[上]
  在当今数字化时代,视频已成为互联网上最主要的内容形式之一。NGINX作为一款高性能的Web服务器和反向代理服务器,提供了强大的MP4模块,用于优化MP4视频的点播传输功能,并支持播放器的任意拖拽功能。本文将通过通过源码分析深入探讨NGINX MP4模块的实现源码,介绍其功能和实现原理。
码农心语
2024/04/09
1.2K0
深入理解nginx mp4流媒体模块[上]
Nginx模块之Upstream解析
Nginx模块一般被分成三大类:handler、filter和upstream。前面的文章系列中,读者已经了解了handler、filter。利用这两类模块,可以使nginx轻松完成任何单机工作。而本文介绍的upstream模块,将使nginx跨越单机的限制,完成网络数据的接收、处理和转发。 数据转发功能,为nginx提供了跨越单机的横向处理能力,使nginx摆脱只能为终端节点提供单一功能的限制,而使它具备了网路应用级别的拆分、封装和整合的战略功能。在云模型大行其道的今天,数据转发是nginx有能力构建一个
用户1263954
2018/01/30
2.4K0
Nginx模块之Upstream解析
聊聊nginx的keepalive_time参数
nginx/src/http/ngx_http_header_filter_module.c
code4it
2023/12/05
3250
Nginx(三):http模块的处理流程解析之正向代理
无疑,在nginx的核心服务中,http服务占据了相当大的份量。那么,要想多了解nginx多一点,则必须要了解其http模块的工作机制。
烂猪皮
2021/01/28
2K0
Nginx(三):http模块的处理流程解析之正向代理
nginx0.1.0 access_handler模块源码分析
access模块主要是对连接到nginx中的客户端进行权限管理,nginx会根据access模块注册的命令,在解析命令的时候,遇到对应的命令的时候,会调用access注册的处理函数,access模块的处理函数会解析并记录这些配置,然后在每个连接到来时,判断ip是否在封禁的池子了。nginx只判断deny的规则,即同一个ip命中多条规则的时候,只要有一条是deny则结果就是deny。即deny优先。
theanarkh
2019/04/24
4160
解读Nginx:深入剖析HTTP启动流程
1、遇到conf文件的http模块。http不是在Nginx的mian函数中启动,而是解析conf文件时遇到http才会去解析并启动。
Lion 莱恩呀
2025/01/08
1400
解读Nginx:深入剖析HTTP启动流程
nginx源码阅读(6)http处理流程
Nginx作为一款开源的、高性能的HTTP服务器和反向代理服务器而闻名,本文基于nginx-1.15.0,将为读者简要介绍其HTTP处理流程。
golangLeetcode
2022/08/02
1.2K0
nginx源码阅读(6)http处理流程
Nginx(六):配置解析之location解析
nginx成为非常流行的代理服务软件,最根本的原因也许是在于其强悍性能。但还有一些必要的条件,比如功能的完整,配置的易用,能够解决各种各样的实际需求问题,这些是一个好的软件的必备特性。
烂猪皮
2021/01/28
2K0
Nginx(六):配置解析之location解析
Nginx(二): worker 进程处理流程框架解析
Nginx 启动起来之后,会有几个进程运行:1. master 进程接收用户命令并做出响应; 2. worker 进程负责处理各网络事件,并同时接收来自master的处理协调命令;
烂猪皮
2021/01/28
1.4K0
Nginx(二): worker 进程处理流程框架解析
相关推荐
Nginx模块开发:http handler实现流量统计(进阶篇)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档