博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Nginx解读内置非默认模块 ngx_http_stub_status_module
阅读量:5239 次
发布时间:2019-06-14

本文共 12126 字,大约阅读时间需要 40 分钟。

1 Background

http://nginx.org/en/docs/http/ngx_http_stub_status_module.html

ngx_http_stub_status_module 是一个 Nginx 的内置 HTTP 模块,该模块可以提供 Nginx 的状态信息。默认情况下这个模块是不被编译进来的,所以在编译 Nginx 时要指定加载该模块:

--with-http_stub_status_module

为什么拿它做例子?因为它也是个足够短小精悍的模块,是一个典型 handler 模块。那么以后我们讲解模块的过程,都是:

  1. 简要的介绍
  2. 使用的实例
  3. 指令介绍
  4. 源码分析

2 Simple example

location /nginx_status {  stub_status on;  access_log   off; access_log /usr/local/nginx/logs/status.log;    #日志  allow SOME.IP.ADD.RESS;  deny all;}

我们假设你是在本机上实验,并且开启的是 80 端口,那么在浏览器中输入:

http://localhost/nginx_status

会看到这样的信息:

Active connections: 291server accepts handled requests  16630948 16630948 31070465Reading: 6 Writing: 179 Waiting: 106

其含义很容易理解:

  • 第一行
    • 当前的活跃连接数:291
  • 第二行
    • 服务器已接受的连接数:16630948(accepted connection #)
    • 服务器已处理的连接数:16630948(handled connection #)
    • 服务器已处理的请求:31070465(可以算出,平均每个连接有 1.8 个请求)(handled connection #)
  • 第三行
    • Reading – Nginx 读取的请求头次数为 6;
    • Writting – Nginx 读取请求体、处理请求并发送响应给客户端的次数为 179;
    • Waiting – 当前活动的长连接数:106。

Nginx 官方的解释如下:

  • active connections – number of all open connections
  • server accepts handled requests – nginx accepted 16630948 connections, handled 16630948 connections (no one was closed just it was accepted), and handles 31070465 requests (1.8 requests per connection)
  • reading – nginx reads request header
  • writing – nginx reads request body, processes request, or writes response to a client
  • waiting – keep-alive connections, actually it is active - (reading + writing)

3 Directives

这个模块中的唯一一个指令,是:

stub_status
  • 语法:stub_status on
  • 作用域:location
  • 功能:统计这个 location 的信息。

4 Source analysis

先看完整代码:

/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */#include 
#include
#include
static char *ngx_http_set_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);static ngx_command_t ngx_http_status_commands[] = { { ngx_string("stub_status"), NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_http_set_status, 0, 0, NULL }, ngx_null_command};static ngx_http_module_t ngx_http_stub_status_module_ctx = { NULL, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ NULL, /* create location configuration */ NULL /* merge location configuration */};ngx_module_t ngx_http_stub_status_module = { NGX_MODULE_V1, &ngx_http_stub_status_module_ctx, /* module context */ ngx_http_status_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING};static ngx_int_t ngx_http_status_handler(ngx_http_request_t *r){ size_t size; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t out; ngx_atomic_int_t ap, hn, ac, rq, rd, wr; if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } ngx_str_set(&r->headers_out.content_type, "text/plain"); if (r->method == NGX_HTTP_HEAD) { r->headers_out.status = NGX_HTTP_OK; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } } size = sizeof("Active connections: \n") + NGX_ATOMIC_T_LEN + sizeof("server accepts handled requests\n") - 1 + 6 + 3 * NGX_ATOMIC_T_LEN + sizeof("Reading: Writing: Waiting: \n") + 3 * NGX_ATOMIC_T_LEN; b = ngx_create_temp_buf(r->pool, size); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } out.buf = b; out.next = NULL; ap = *ngx_stat_accepted; hn = *ngx_stat_handled; ac = *ngx_stat_active; rq = *ngx_stat_requests; rd = *ngx_stat_reading; wr = *ngx_stat_writing; b->last = ngx_sprintf(b->last, "Active connections: %uA \n", ac); b->last = ngx_cpymem(b->last, "server accepts handled requests\n", sizeof("server accepts handled requests\n") - 1); b->last = ngx_sprintf(b->last, " %uA %uA %uA \n", ap, hn, rq); b->last = ngx_sprintf(b->last, "Reading: %uA Writing: %uA Waiting: %uA \n", rd, wr, ac - (rd + wr)); r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = b->last - b->pos; b->last_buf = 1; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } return ngx_http_output_filter(r, &out);}static char *ngx_http_set_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){ ngx_http_core_loc_conf_t *clcf; clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); clcf->handler = ngx_http_status_handler; return NGX_CONF_OK;}

的确够短小精悍吧?关键在于 Nginx 提供的模块扩展方式比较好,让你可以少写一些代码(NDK 可以让你写的更少,这是后话)。

4.1 模块定义 ngx_http_stub_status_module

ngx_module_t  ngx_http_stub_status_module = {    NGX_MODULE_V1,    &ngx_http_stub_status_module_ctx,      /* module context */    ngx_http_status_commands,              /* module directives */    NGX_HTTP_MODULE,                       /* module type */    NULL,                                  /* init master */    NULL,                                  /* init module */    NULL,                                  /* init process */    NULL,                                  /* init thread */    NULL,                                  /* exit thread */    NULL,                                  /* exit process */    NULL,                                  /* exit master */    NGX_MODULE_V1_PADDING};

与此前介绍的 ngx_http_hello_world_module 并无本质区别。

4.2 命令集定义 ngx_http_status_commands

static ngx_command_t  ngx_http_status_commands[] = {    { ngx_string("stub_status"),      NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,      ngx_http_set_status,      0,      0,      NULL },      ngx_null_command};

命令集定义如上,得到如下信息:

  • name:stub_status
  • type:server conf、location conf、conf flag,其中最后一个比较陌生,相似的取值有:
    • #define NGX_CONF_ARGS_NUMBER 0x000000ff
    • #define NGX_CONF_BLOCK 0x00000100
    • #define NGX_CONF_FLAG 0x00000200
    • #define NGX_CONF_ANY 0x00000400
    • #define NGX_CONF_1MORE 0x00000800
    • #define NGX_CONF_2MORE 0x00001000
    • #define NGX_CONF_MULTI 0x00002000
  • set:ngx_http_set_status

下面解释下一些 types:

4.2.1 NGX_CONF_XXX

以下宏定义来自 ngx_conf_file.h:

#define NGX_CONF_NOARGS      0x00000001 // 命令不接受参数#define NGX_CONF_TAKE1       0x00000002 // 命令携带1个参数#define NGX_CONF_TAKE2       0x00000004 // 命令携带2个参数#define NGX_CONF_TAKE3       0x00000008 // 命令携带3个参数#define NGX_CONF_TAKE4       0x00000010 // 命令携带4个参数#define NGX_CONF_TAKE5       0x00000020 // 命令携带5个参数#define NGX_CONF_TAKE6       0x00000040 // 命令携带6个参数#define NGX_CONF_TAKE7       0x00000080 // 命令携带7个参数#define NGX_CONF_TAKE12      (NGX_CONF_TAKE1|NGX_CONF_TAKE2) // 命令携带1个或2个参数#define NGX_CONF_TAKE13      (NGX_CONF_TAKE1|NGX_CONF_TAKE3) // 命令携带1个或3个参数#define NGX_CONF_TAKE23      (NGX_CONF_TAKE2|NGX_CONF_TAKE3) // 命令携带2个或3个参数#define NGX_CONF_TAKE123     (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3) // 命令携带1个、2个或3个参数#define NGX_CONF_TAKE1234    (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3|NGX_CONF_TAKE4) // 命令携带1个、2个、3个或4个参数#define NGX_CONF_ARGS_NUMBER 0x000000ff // 命令#define NGX_CONF_BLOCK       0x00000100 // 块域,后面跟 {…},比如 server {...}#define NGX_CONF_FLAG        0x00000200 // 命令接受“on|off”参数#define NGX_CONF_ANY         0x00000400#define NGX_CONF_1MORE       0x00000800 // 命令携带至少1个参数#define NGX_CONF_2MORE       0x00001000 // 命令携带至少2个参数#define NGX_CONF_MULTI       0x00002000 // 命令携带多个参数

4.3 上下文定义 ngx_http_stub_status_module_ctx

static ngx_http_module_t  ngx_http_stub_status_module_ctx = {    NULL,                                  /* preconfiguration */    NULL,                                  /* postconfiguration */    NULL,                                  /* create main configuration */    NULL,                                  /* init main configuration */    NULL,                                  /* create server configuration */    NULL,                                  /* merge server configuration */    NULL,                                  /* create location configuration */    NULL                                   /* merge location configuration */};

这个都是 NULL,够简单,无话可说了⋯⋯

4.4 命令设置函数 ngx_http_set_status

static char *ngx_http_set_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {    ngx_http_core_loc_conf_t  *clcf;    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);    clcf->handler = ngx_http_status_handler;    return NGX_CONF_OK;}

和 ngx_http_hello_world_module 对比下:

static char* ngx_http_hello_world(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) {    ngx_http_core_loc_conf_t* clcf;    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);    clcf->handler = ngx_http_hello_world_handler;    ngx_conf_set_str_slot(cf, cmd, conf);    return NGX_CONF_OK;}

唯一的区别,就是 ngx_http_hello_world_module 多了一句 ngx_conf_set_str_slot。这个先留做一个问题,后面会介绍,暂时与关键主题无关。

4.5 命令处理函数 ngx_http_status_handler

static ngx_int_t ngx_http_status_handler(ngx_http_request_t *r){    size_t             size;    ngx_int_t          rc;    ngx_buf_t         *b;    ngx_chain_t        out;    ngx_atomic_int_t   ap, hn, ac, rq, rd, wr;

这个模块要求接受的请求类是 GET、HEAD,其他类型的请求会被拒绝。

if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {        return NGX_HTTP_NOT_ALLOWED;    }

放弃请求体,因为这个模块用不上。

rc = ngx_http_discard_request_body(r);    if (rc != NGX_OK) {        return rc;    }

如果请求是 HEAD 类型的,则直接设置响应头的 content_type、status 字段,并发送响应头。

ngx_str_set(&r->headers_out.content_type, "text/plain");    if (r->method == NGX_HTTP_HEAD) {        r->headers_out.status = NGX_HTTP_OK;        rc = ngx_http_send_header(r);        if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {            return rc;        }    }

创建一个缓冲区,向缓冲区写入我们上面在浏览器中看到的东西。

size = sizeof("Active connections:  \n") + NGX_ATOMIC_T_LEN           + sizeof("server accepts handled requests\n") - 1           + 6 + 3 * NGX_ATOMIC_T_LEN           + sizeof("Reading:  Writing:  Waiting:  \n") + 3 * NGX_ATOMIC_T_LEN;    b = ngx_create_temp_buf(r->pool, size);    if (b == NULL) {        return NGX_HTTP_INTERNAL_SERVER_ERROR;    }    out.buf = b;    out.next = NULL;    ap = *ngx_stat_accepted;    hn = *ngx_stat_handled;    ac = *ngx_stat_active;    rq = *ngx_stat_requests;    rd = *ngx_stat_reading;    wr = *ngx_stat_writing;    // 封装了 sprintf    b->last = ngx_sprintf(b->last, "Active connections: %uA \n", ac);    // 封装了 memcpy    b->last = ngx_cpymem(b->last, "server accepts handled requests\n",                         sizeof("server accepts handled requests\n") - 1);    b->last = ngx_sprintf(b->last, " %uA %uA %uA \n", ap, hn, rq);    b->last = ngx_sprintf(b->last, "Reading: %uA Writing: %uA Waiting: %uA \n",                          rd, wr, ac - (rd + wr));

缓冲区写完了。然后设置下响应头的 status、content_length_n(还记得吗?b->last - b->pos 刚好是缓冲区的第二个区域,是已写入数据部分。)

r->headers_out.status = NGX_HTTP_OK;    r->headers_out.content_length_n = b->last - b->pos;    b->last_buf = 1;

发送响应头。

rc = ngx_http_send_header(r);    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {        return rc;    }

filter。

return ngx_http_output_filter(r, &out);}

5 Reference

  1. http://wiki.nginx.org/HttpStubStatusModule
  2. http://blog.csdn.net/lengzijian/article/details/7356064
  3. http://www.codinglabs.org/html/intro-of-nginx-module-development.html

转载于:https://www.cnblogs.com/felixzh/p/9016133.html

你可能感兴趣的文章
文件语音识别Google语音识别学习札记 - Windows PC机上测试语音识别Strut2教程-java教程...
查看>>
μC/OS-III---I笔记13---中断管理
查看>>
:after,:before,content
查看>>
FTTB FTTC FTTH FTTO FSA
查看>>
OpenAI Gym
查看>>
stap-prep 需要安装那些内核符号
查看>>
网易杭研后台技术中心的博客 -MYSQL :OOM
查看>>
第二章 数据通信的基础知识 计算机网络笔记 学堂在线 2.1 数据传输系统 2.2 信号...
查看>>
如何解决click事件的重复触发问题
查看>>
2016寒假自学笔记
查看>>
VC++2012编程演练数据结构《21》二叉排序树
查看>>
第一章练习
查看>>
MySQL 的实时性能监控利器
查看>>
from表单连接数据库
查看>>
去除bootstrap轮播阴影
查看>>
使用nodeJS的 crypto模块来为你的密码hash加盐
查看>>
C用函数指针模拟重载 C++重载
查看>>
【全家福】多项式的各种板子
查看>>
2016.7.14 generator基于注解和基于xml自动生成代码的区别
查看>>
eclipse上的jsp代码高亮显示,括号配对和双击全选,代码提示,link
查看>>