范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

18Nginx入门教程Nginx的基础架构解析(下)

  1. Nginx模块1.1 Nginx中的模块化设计
  Nginx 的内部结构是由核心部分和一系列的功能模块所组成。这样划分是为了使得每个模块的功能相对简单,便于开发,同时也便于对系统进行功能扩展。Nginx 将各功能模块组织成一条链,当有请求到达的时候,请求依次经过这条链上的部分或者全部模块,进行处理。例如前面讲到的 http 请求,会有11个处理阶段,而每个阶段有对应着许多在此阶段生效的模块对该 http 请求进行处理。同时,Nginx 开放了第三方模块编写功能,用户可以自定义模块,控制 http 请求的处理与响应,这种高度可定制化催生了 Nginx 的大量第三方模块,也使得 Nginx 定制化开发在各大互联网公司十分流行。 1.2 Nginx中的模块分类
  关于 Nginx 模块的分类有很多种方式,目前网上博客中写的较多的是按照功能进行分类,有如下几大类: event 模块: 搭建 独立于操作系统的事件处理机制的框架,以及 提供各种具体事件的处理。代表性的模块有:ngx_events_module, ngx_event_core_module, ngx_epoll_module; handler 模块: 主要负责处理客户端请求并产生待响应的内容,比如 ngx_http_static_module 模块,负责客户端的静态页面请求处理并将对应的磁盘 文件准备为响应内容输出; filter 模块: 主要 负责处理输出的内容,包括修改输出内容。代表性的模块有: ngx_http_sub_module; upstream 模块: 该类模块都是用于实现反向代理功能,将真正的请求转发到后端服务器上,并从后端服务器上读取响应,发回给客户端。比如前面介绍到转发 http、websocket、grpc、rtmp等协议的模块都可以划分为这一类; 负载均衡模块: 负载均衡的模块,实现相应算法。这类模块都是用于实现 Nginx 的负载均衡功能。 extend 模块: 又称第三方模块,非 Nginx 官方提供,由各大企业的开发人员结合自身业务开发而成。Nginx 提供了非常好的模块编写机制,遵循相关的标准可以很快定制出符合我们业务场景的模块,而且内部调用 Nginx 内部提供的方法进行处理,使得第三方模块往往都具备很好的性能
  对于官方提供的模块,我们可以直接在官网文档上学习,学习的方式和学习其他互联网组件的方式一致,首先学习如何使用,在用至熟练后可以深入分析其源码了解功能实现背后的原理。
  我们以前面介绍到的 Nginx 的限速模块(limit_req模块)进行说明。首先是掌握该模块的用法,在该模块的官方地址中,有关于该模块的详细介绍,包括该模块提供的所有指令以及所有变量说明。此外,还有比较丰富的指令用例。在多次使用该指令并自认为掌握了该模块的用法之后,想了解限速背后的原理以及相关算法时,就可以深入到源码学习了。
  进入 Nginx 的源码目录,使用 ls  查看源码文件,限速模块是在 http 目录中的。 [root@server nginx-1.17.6]# cd src/  [root@server src]# ls core  event  http  mail  misc  os  stream  [root@server src]# ls http/modules/ngx_http_limit_*.c http/modules/ngx_http_limit_conn_module.c http/modules/ngx_http_limit_req_module.c 代码块12345678
  找到 Nginx 模块对应的代码文件后,我们就可以阅读里面的代码进行学习。往往源码的阅读是枯燥无味的,我们可以借助海量的网络资源辅助我们学习。这里就有一篇文章,作者深入分析了 Nginx 的限流模块的源码以及相应限流算法,最后进行了相关的实验测试。通过这样一个个模块深入学习,最后在使用每一个 Nginx 指令时,也会非常熟练,最后成为 Nginx 高手。 1.3 如何学习和使用第三方模块
  这里我们演示在 Nginx 中使用第三方模块。 Openresty 社区提供了一款 Nginx 中的 Echo 模块,即echo-nginx-module。在 Nginx 中添加了该模块后,我们在配置文件中可以使用该模块提供的 echo 指令返回用户响应,简单方便。该模块的源码在 github 上,并且有良好的文档和使用示例,非常方便开发者使用。
  现在我们在 Nginx 的源码编译阶段加入该第三方模块,具体操作如下: [root@server shencong]# pwd /root/shencong [root@server shencong]# mkdir nginx-echo # 下载 nginx 源码包和第三方模块的源码包  [root@server shencong]# wget http://nginx.org/download/nginx-1.17.6.tar.gz [root@server shencong]# wget https://github.com/openresty/echo-nginx-module/archive/v0.62rc1.tar.gz  # 解压 [root@server shencong]# tar -xzf nginx-1.17.6.tar.gz [root@server shencong]# tar -xzf v0.62rc1.tar.gz  [root@server shencong]# ls echo-nginx-module-0.62rc1  nginx-1.17.6  nginx-1.17.6.tar.gz  nginx-echo  v0.62rc1.tar.gz  [root@server shencong]# cd nginx-1.17.6 # 使用--add-module添加第三方模块,参数为第三方模块源码 [root@server shencong]# ./configure --prefix=/root/shencong/nginx-echo  --add-module=/root/shencong/echo-nginx-module-0.62rc1
  编译完成后,我们就可以去 nginx-echo  目录中的  nginx.conf  文件中添加 echo   指令 。准备如下的配置(可以参参考社区提供的示例): ... http {    server {         listen       80;         server_name  localhost;          #charset koi8-r;          #access_log  logs/host.access.log  main;          location / {             root   html;             index  index.html index.htm;         }                  # 新增测试 echo 指令配置         location /timed_hello {             default_type text/plain;             echo_reset_timer;             echo hello world;             echo ""hello world" takes about $echo_timer_elapsed sec.";             echo hiya igor;             echo ""hiya igor" takes about $echo_timer_elapsed sec.";         }          location /echo_with_sleep {             default_type text/plain;             echo hello world;             echo_flush;  # ensure the client can see previous output immediately             echo_sleep   2.5;  # in sec             echo ""hello" takes about $echo_timer_elapsed sec.";         }      } } ...
  启动 Nginx 后,我们就可以在浏览器上请求者两个 URI 地址,看到相应 echo 返回的信息了。第二个配置是使用了 echo_sleep 指令,会使得请求在休眠 2.5s 后才返回。 1.4 如何编写自己的模块
  想要编写 Nginx 模块,首先需要对 Nginx 模块中的源码以及相关的数据结构有所了解,还要知晓 Nginx HTTP 模块的调用流程。假设我要实现前面第三方模块Echo的最简单形式,即只输出相应的字符串即可。假定模块支持的指令名称还是 echo, 这个 echo 指令需要跟一个参数,即输出的字符串。我们需要做如下几步: 确定模块名称,以及模块中的指令以及参数,还有运行的环境。这里涉及的结构是 ngx_command_t,它定义了模块里的所有指令格式。下面的代码表示该模块中只有一个 echo 指令,它出现的上下文环境为 location,且有一个参数(NGX_CONF_TAKE1)。当某个配置块中出现 echo  指令时,Nginx 将调用 ngx_http_echo  方法。然后在该方法中,会设置处理请求的 handler,这个 handler 就是处理请求的方法。   static ngx_command_t  ngx_http_echo_commands[] = {            { ngx_string("echo"),      /* 指令名称,利用ngx_string宏定义 */           NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,  /* 用在 location 指令块内,且有1个参数 */           ngx_http_echo,            /* 处理回调函数 */           NGX_HTTP_LOC_CONF_OFFSET,               offsetof(ngx_http_echo_loc_conf_t, ed), /* 指定参数读取位置 */           NULL },           ngx_null_command   }; 完成请求处理的 handler 函数,最重要的部分就在这里;  static char *  ngx_http_echo(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)  {      ngx_http_core_loc_conf_t  *clcf;      /* 找到指令所属的配置块,这里我们限定echo指令的上下文环境只有location */      clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);      /* 指定处理的handler */      clcf->handler = ngx_http_echo_handler;      ...      return NGX_CONF_OK;  }    static ngx_int_t  ngx_http_echo_handler(ngx_http_request_t *r)  {      ...            /* 向用户发送相应包 */      return ngx_http_output_filter(r, &out);  } 一些收尾工作,比如配置模块介入 http 请求的哪些阶段等。   /* Http context of the module */   static ngx_http_module_t  ngx_http_echo_module_ctx = {       NULL,                                  /* preconfiguration */       NULL,                                  /* postconfiguration */       NULL,                                  /* create main configuration */       NULL,                                  /* init main configuration */       NULL,                                  /* create server configuration */       NULL,                                  /* merge server configuration */       ngx_http_echo_create_loc_conf,         /* create location configration */       ngx_http_echo_merge_loc_conf           /* merge location configration */   };   /* Module */   ngx_module_t  ngx_http_echo_module = {       NGX_MODULE_V1,       &ngx_http_echo_module_ctx,             /* module context */       ngx_http_echo_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   };
  完成以上几步,一个简易的自定义模块就算大功告成了。接下来我们动手完成第一个自定义的模块,将其编译进Nginx 二进制文件中并进行测试。 2. 案例
  我们来完成一个简单的自定义 http 模块,来实现前面Echo模块的最简单形式,即使用指令输出 "hello, world" 字符串。首先新建一个目录 echo-nginx-module  ,然后在目录下新建两个文件 config  和 ngx_http_echo_module.c  [root@server echo-nginx-module]# pwd /root/shencong/echo-nginx-module  [root@server echo-nginx-module]# ls config  ngx_http_echo_module.c
  两个文件内容分别如下: [root@server echo-nginx-module]# cat config  ngx_addon_name=ngx_http_echo_module # 指定模块名称 HTTP_MODULES="$HTTP_MODULES ngx_http_echo_module" # 指定模块源码路径 NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_echo_module.c"  [root@server echo-nginx-module]# cat ngx_http_echo_module.c #include  #include  #include   /* Module config */ typedef struct {     ngx_str_t  ed; } ngx_http_echo_loc_conf_t;  static char *ngx_http_echo(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void *ngx_http_echo_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child);  /* 定义指令 */ static ngx_command_t  ngx_http_echo_commands[] = {     { ngx_string("echo"),      /* 指令名称,利用ngx_string宏定义 */         NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,  /* 用在 location 指令块内,且有1个参数 */         ngx_http_echo,         /* 处理回调函数 */         NGX_HTTP_LOC_CONF_OFFSET,             offsetof(ngx_http_echo_loc_conf_t, ed), /* 指定参数读取位置 */         NULL },         ngx_null_command }; /* Http context of the module */ static ngx_http_module_t  ngx_http_echo_module_ctx = {     NULL,                                  /* preconfiguration */     NULL,                                  /* postconfiguration */     NULL,                                  /* create main configuration */     NULL,                                  /* init main configuration */     NULL,                                  /* create server configuration */     NULL,                                  /* merge server configuration */     ngx_http_echo_create_loc_conf,         /* create location configration */     ngx_http_echo_merge_loc_conf           /* merge location configration */ }; /* Module */ ngx_module_t  ngx_http_echo_module = {     NGX_MODULE_V1,     &ngx_http_echo_module_ctx,             /* module context */     ngx_http_echo_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 }; /* Handler function */ static ngx_int_t ngx_http_echo_handler(ngx_http_request_t *r) {     ngx_int_t rc;     ngx_buf_t *b;     ngx_chain_t out;     ngx_http_echo_loc_conf_t *elcf;     /* 获取指令的参数 */     elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module);     if(!(r->method & (NGX_HTTP_HEAD|NGX_HTTP_GET|NGX_HTTP_POST)))     {         /* 如果不是 HEAD/GET/PUT 请求,则返回405 Not Allowed错误 */         return NGX_HTTP_NOT_ALLOWED;     }     r->headers_out.content_type.len = sizeof("text/html") - 1;     r->headers_out.content_type.data = (u_char *) "text/html";     r->headers_out.status = NGX_HTTP_OK;     r->headers_out.content_length_n = elcf->ed.len;     if(r->method == NGX_HTTP_HEAD)     {         rc = ngx_http_send_header(r);         if(rc != NGX_OK)         {             return rc;         }     }     b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));     if(b == NULL)     {         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");         return NGX_HTTP_INTERNAL_SERVER_ERROR;     }     out.buf = b;     out.next = NULL;     b->pos = elcf->ed.data;     b->last = elcf->ed.data + (elcf->ed.len);     b->memory = 1;     b->last_buf = 1;     rc = ngx_http_send_header(r);     if(rc != NGX_OK)     {         return rc;     }     /* 向用户发送相应包 */     return ngx_http_output_filter(r, &out); } static char * ngx_http_echo(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);     /* 指定处理的handler */     clcf->handler = ngx_http_echo_handler;     ngx_conf_set_str_slot(cf,cmd,conf);     return NGX_CONF_OK; } static void * ngx_http_echo_create_loc_conf(ngx_conf_t *cf) {     ngx_http_echo_loc_conf_t  *conf;     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_loc_conf_t));     if (conf == NULL) {         return NGX_CONF_ERROR;     }     conf->ed.len = 0;     conf->ed.data = NULL;     return conf; } static char * ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) {     ngx_http_echo_loc_conf_t *prev = parent;     ngx_http_echo_loc_conf_t *conf = child;     ngx_conf_merge_str_value(conf->ed, prev->ed, "");     return NGX_CONF_OK; }
  这样一个第三方模块包就完成了,接下来我们要向之前使用第三方模块一样,将它编译进 Nginx,具体操作如下。 [root@server shencong]# cd nginx-1.17.6/ [root@server nginx-1.17.6]# ./configure --prefix=/root/shencong/nginx-echo --add-module=/root/shencong/echo-nginx-module ... [root@server nginx-1.17.6] # make && make install ... [root@server nginx-1.17.6]# cd ../nginx-echo/sbin/ [root@server sbin]# ./nginx -V nginx version: nginx/1.17.6 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)  configure arguments: --prefix=/root/shencong/nginx-echo --add-module=/root/shencong/echo-nginx-module
  接下来,我们只要在 nginx.conf 中加入我们的指令,并给一个参数,就能看到我们自定义的输出了。 ... http {    ...    server {        listen       80;        server_name  localhost;        location / {             root   html;             index  index.html index.htm;        }                location /test {             echo hello,world;        }        ...    } } ...
  最后我们请求主机的80端口,URI=/test,浏览器输出"hello, world",说明我们的自定义模块成功了!
  3. 小结
  在 Nginx 基础架构介绍的最后,主要是介绍了 Nginx 的模块设计以及相应的模块用法。最后,我们简单给出了一个简单编写自己模块的案例作为本章的实战案例。希望这一节之后,大家能对 Nginx 的模块化设计有所了解,并有兴趣在模块的源码方向深入学习。

深圳弘法寺建筑之美来到深圳最大的寺庙弘法寺,用华为Mate40Pro的4。6倍潜望式超长焦来记录,它带来完全不一样的视角和构图,它的视场融合技术大大提升了3。04。6倍变焦的画质,爽!这一代Mate光威弈PROSATA3长江存储1TB国产固态硬盘开箱与评测拿真金白银支持了一波国产核心技术的光威(Gloway)GLOWAYYCT1TS3S7Pro,1TBSSD固态硬盘,SATA3。0接口弈Pro系列国产颗粒国产崛起,核心零件都是国产技在别国领土上搞147次核试验,还说是为了保护人家,真虚伪法国总统马克龙在波利尼西亚开展的访问期间,发表的一番言论遭到了当地民众的批评。他说戴高乐将军当初选择在此进行核试验,是因为这里地处太平洋腹地,但这也是为开发先进的核武器保护波利尼西俄罗斯防长为何一再提出迁都?普京会采纳他的提议么?俄罗斯国防部长谢尔盖绍伊古提议将首都迁往西伯利亚,并在这里建造几个新城市,周围还要建五个百万人口级别的卫星城,而且每个城市要有明确的产业分工,组成一个大型的科学工业经济中心。简单的啥?奥运冠军用枪来自国外?我们造不出来么?奥运会上有一个项目叫射击,一般来说在奥运会前几天这个射击就会比完,这个射击大家都看得懂,你不用管规则是啥,反正就是谁打的准谁赢。记得以前最早的奥运会还有拿橡胶子弹互相对射的那种,特前脸酷似蔚来ES8赛力斯中大型SUV曝光,搭载激光雷达日前,网络上曝光了一组赛力斯全新中大型SUV的专利图。据悉,该车或搭载华为HI智能汽车解决方案。新车采用了赛力斯最新的家族设计,纤细的前大灯组采用贯穿式设计,整体看上去更加有未来感最新动态简报近期新品动态内容一文速览近期关键讯息集结,一篇速读帮助您快速了解掌握京华飞利浦近期核心性产品及服务最新动态发展情况。近期,京华飞利浦不但连续推出两款高效智能新品飞利浦智能AI录音一体机VTR5201及飞利美国人为啥想占领华尔街?华尔街是美国财富的象征,本名叫做WallStreet,原本是一段欧洲殖民者为了抵御美国土著印第安人而修的墙,后来一群人在这段墙附近交易股票,后来也成了一个金融中心。但是在2011年用金钱主宰美国!号称华尔街拿破仑的摩根财团是如何崛起的?摩根财团是美国十大财团之一,号称是华尔街的拿破仑,摩根财团的强大在这个外号中就可见端倪了。在摩根财团最鼎盛的时候,他所控制的大银行大企业占美国八大财团资产的以上,所以也被称为银行家美元如何强势崛起成为世界货币?在第二次世界大战打得差不多的时候,欧洲已经是一堆废墟了,亚洲在内的各洲也是不成样子,原本的帝国列强基本上都烂掉,除了美利坚合众国。美利坚合众国在二战期间除了在珍珠港被日本擦破点皮,飞利浦会务通VTR9800正式发布,高频应用带来高端体验2019年10月28日,飞利浦携正式发布智能会议设备会务通VTR9800,带来未来会议全新智能终端集成体验,为未来商务会议办公注入全新智能血液!在安博会期间,飞利浦音视频设备团队通
Linux需巧学众所周知,Linux在互联网技术中的重要程度堪比windows,当今很多大型软件系统后台等等都运用了Linux技术,对于一个程序员或者想成为程序员的初学者来说,无论你未来从事前端,AI四小龙之一云从科技IPO获批4月6日,中国证券监督管理委员会发布关于同意云从科技集团股份有限公司首次公开发行股票注册的批复,同意云从科技首次公开发行股票的注册申请。至此,AI四小龙中除了商汤(00020。HK从5799元跌至3499元,12GB256GB,小米MIX4冰点破价加速退场从5799元跌至3499元,12GB256GB,小米MIX4冰点破价加速退场本文原创,禁止搬运和抄袭,违者必究!导语很多人都知道,小米品牌最近几年主打的几款新旗舰手机都在尝试着打破特斯拉进入锂矿的最佳方式入股龙头企业传闻1赣锋锂业副董事长王晓申近日对外表示福特通用或特斯拉拟投资赣锋锂业在墨西哥的Sonora锂粘土项目,以便就近建立北美原材料供应链。赣锋锂业对此持开放态度,并表示在吸收这些汽车商迅游科技股东袁旭所持2185。39万股公司股份新增轮候冻结中证网讯(记者康曦)迅游科技4月10日晚公告称,公司近日接到公司持股5以上股东袁旭告知,并通过中国证券登记结算有限责任公司深圳分公司系统查询,获悉袁旭所持公司股份存在新增轮候冻结的斯瑞新材(688102。SH)预计一季度净利润增长130150格隆汇4月10日丨斯瑞新材(688102。SH)公布,2022年第一季度,公司预计归属于上市公司股东的净利润3000。63万元3261。55万元,比上年同期增长130150扣除非经官方直降5000元,16GB512GB陶瓷机身,折叠屏旗舰售价更亲民了提起高端旗舰,之前消费者们第一时间所想到的要么是顶级iPhone,要么就是华为旗下的保时捷定制版手机,因为这两类机型确实高端,均售价过万,不过如今提起高端旗舰,许多人率先所想到的却普通家庭选新能源车合适不合适?现如今大家想买车最头疼的就是到底是选燃油车还是选新能源车?那么咱们来一起分析一下吧首先看看大家是选什么价位的车。如果只是选个几万块钱的代步小车,其实没什么比较,开几年也损失不了多少大力推进充电桩建设,才能更好的确保生态环境品质我们也知道,虽然燃油车开销很大,油价很高,电动车又有政府补贴,可是买电动车的人依旧不多,起码相对燃油车更是如此。为什么会这样,主要是新能源车受到很多限制。一是续航能力,尤其是冬天天腾讯官宣涨价继去年4月会员费涨价后4月9日腾讯视频官方宣布将在今年4月20日零点对腾讯视频VIP及超级影视VIP会员价格再次进行调整记者注意到,此次调整后,腾讯视频VIP连续包月价格变为25元投石问路手机摄影与长变焦镜头的对比体验(北海公园篇)前言随着摄影入门门槛的急剧降低,手机摄影越来越成为摄影爱好者的最爱,并且美颜效果更受到美女们的喜欢和沉迷,至于单反相机的终结,或许在无反相机越来越轻便和智能化之后,35年内退出爱好