nginx-1.22.1 limit_req功能在C底层实现

news/2025/2/4 16:08:53/

##nginx.conf配置文件limit_req配置

##nginx限制访问频率,限流

http {

        limit_req_zone $binary_remote_addr zone=one:30m rate=1r/s;

        server {
                listen       8103;
                server_name  localhost;

                location ~ ^/yym/ {
                    root   /home/yym/nginx_web/yym-vue3/;
                    index  index.html index.htm;
                    try_files $uri $uri/ /index.html;
                    limit_req zone=one burst=1 nodelay;
                    #limit_conn addr 1;
                    #limit_conn_status 503;
                    #limit_rate_after 10240K;
                    #limit_rate 50k;
                }

        }

}

##ngx_http_limit_req_init方法

#0  ngx_http_limit_req_init (cf=0x7fffffffdc80) at src/http/modules/ngx_http_limit_req_module.c:1092
#1  0x00005555555b8a89 in ngx_http_block (cf=0x7fffffffdc80, cmd=0x5555556640a0 <ngx_http_commands>, conf=0x555555696988) at src/http/ngx_http.c:310
#2  0x0000555555594031 in ngx_conf_handler (cf=0x7fffffffdc80, last=1) at src/core/ngx_conf_file.c:463
#3  0x0000555555593b34 in ngx_conf_parse (cf=0x7fffffffdc80, filename=0x5555556958e8) at src/core/ngx_conf_file.c:319
#4  0x000055555558f2fb in ngx_init_cycle (old_cycle=0x7fffffffde50) at src/core/ngx_cycle.c:284
#5  0x000055555556e66b in main (argc=3, argv=0x7fffffffe1f8) at src/core/nginx.c:292

##ngx_http_limit_req_handler函数指针初始化到cmcf结构体

 ngx_http_core_main_conf_t  *cmcf;

*h = ngx_http_limit_req_handler;

指针函数赋予cmcf结构体handlers

##ngx_http_limit_req_handler方法

#0  ngx_http_limit_req_handler (r=0x5555556c6fd0) at src/http/modules/ngx_http_limit_req_module.c:196
#1  0x00005555555bcd66 in ngx_http_core_generic_phase (r=0x5555556c6fd0, ph=0x5555556c92c0) at src/http/ngx_http_core_module.c:897
#2  0x00005555555bcd00 in ngx_http_core_run_phases (r=0x5555556c6fd0) at src/http/ngx_http_core_module.c:875
#3  0x00005555555bcc69 in ngx_http_handler (r=0x5555556c6fd0) at src/http/ngx_http_core_module.c:858
#4  0x00005555555cb829 in ngx_http_process_request (r=0x5555556c6fd0) at src/http/ngx_http_request.c:2120
#5  0x00005555555ca302 in ngx_http_process_request_headers (rev=0x5555556cd5b0) at src/http/ngx_http_request.c:1498
#6  0x00005555555c981e in ngx_http_process_request_line (rev=0x5555556cd5b0) at src/http/ngx_http_request.c:1165
#7  0x00005555555c8f10 in ngx_http_wait_request_handler (rev=0x5555556cd5b0) at src/http/ngx_http_request.c:503
#8  0x00005555555b6e69 in ngx_epoll_process_events (cycle=0x5555556956d0, timer=60000, flags=1) at src/event/modules/ngx_epoll_module.c:901
#9  0x00005555555a63ca in ngx_process_events_and_timers (cycle=0x5555556956d0) at src/event/ngx_event.c:248
#10 0x00005555555b4701 in ngx_worker_process_cycle (cycle=0x5555556956d0, data=0x0) at src/os/unix/ngx_process_cycle.c:721
#11 0x00005555555b1309 in ngx_spawn_process (cycle=0x5555556956d0, proc=0x5555555b4645 <ngx_worker_process_cycle>, data=0x0, name=0x555555646757 "worker process", respawn=-3)at src/os/unix/ngx_process.c:199
#12 0x00005555555b3898 in ngx_start_worker_processes (cycle=0x5555556956d0, n=1, type=-3) at src/os/unix/ngx_process_cycle.c:344
#13 0x00005555555b3069 in ngx_master_process_cycle (cycle=0x5555556956d0) at src/os/unix/ngx_process_cycle.c:130
#14 0x000055555556ea45 in main (argc=3, argv=0x7fffffffe1f8) at src/core/nginx.c:383

##ngx_http_complex_value方法 if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) {

key 使用请求来源ip

1、计算key:通过ngx_http_complex_value函数,基于请求和配置中的key指令计算出实际的key值
2、检查key值:计算出的key值会被检查是否为空或过长

ngx_int_t
ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val,ngx_str_t *value)
{size_t                        len;ngx_http_script_code_pt       code;ngx_http_script_len_code_pt   lcode;ngx_http_script_engine_t      e;if (val->lengths == NULL) {*value = val->value;return NGX_OK;}ngx_http_script_flush_complex_value(r, val);ngx_memzero(&e, sizeof(ngx_http_script_engine_t));e.ip = val->lengths;e.request = r;e.flushed = 1;len = 0;while (*(uintptr_t *) e.ip) {lcode = *(ngx_http_script_len_code_pt *) e.ip;len += lcode(&e);}value->len = len;value->data = ngx_pnalloc(r->pool, len);if (value->data == NULL) {return NGX_ERROR;}e.ip = val->values;e.pos = value->data;e.buf = *value;while (*(uintptr_t *) e.ip) {code = *(ngx_http_script_code_pt *) e.ip;code((ngx_http_script_engine_t *) &e);}*value = e.buf;return NGX_OK;
}

##ngx_http_limit_req_lookup 函数中,处理未找到匹配键并准备在红黑树中插入新节点的部分

static ngx_int_t
ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash,ngx_str_t *key, ngx_uint_t *ep, ngx_uint_t account)
{size_t                      size;ngx_int_t                   rc, excess;ngx_msec_t                  now;ngx_msec_int_t              ms;ngx_rbtree_node_t          *node, *sentinel;ngx_http_limit_req_ctx_t   *ctx;ngx_http_limit_req_node_t  *lr;now = ngx_current_msec;ctx = limit->shm_zone->data;node = ctx->sh->rbtree.root;sentinel = ctx->sh->rbtree.sentinel;while (node != sentinel) {if (hash < node->key) {node = node->left;continue;}if (hash > node->key) {node = node->right;continue;}/* hash == node->key */lr = (ngx_http_limit_req_node_t *) &node->color;rc = ngx_memn2cmp(key->data, lr->data, key->len, (size_t) lr->len);if (rc == 0) {ngx_queue_remove(&lr->queue);ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);ms = (ngx_msec_int_t) (now - lr->last);if (ms < -60000) {ms = 1;} else if (ms < 0) {ms = 0;}excess = lr->excess - ctx->rate * ms / 1000 + 1000;if (excess < 0) {excess = 0;}*ep = excess;if ((ngx_uint_t) excess > limit->burst) {return NGX_BUSY;}if (account) {lr->excess = excess;if (ms) {lr->last = now;}return NGX_OK;}lr->count++;ctx->node = lr;return NGX_AGAIN;}node = (rc < 0) ? node->left : node->right;}*ep = 0;size = offsetof(ngx_rbtree_node_t, color)+ offsetof(ngx_http_limit_req_node_t, data)+ key->len;ngx_http_limit_req_expire(ctx, 1);node = ngx_slab_alloc_locked(ctx->shpool, size);if (node == NULL) {ngx_http_limit_req_expire(ctx, 0);node = ngx_slab_alloc_locked(ctx->shpool, size);if (node == NULL) {ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,"could not allocate node%s", ctx->shpool->log_ctx);return NGX_ERROR;}}node->key = hash;lr = (ngx_http_limit_req_node_t *) &node->color;lr->len = (u_short) key->len;lr->excess = 0;ngx_memcpy(lr->data, key->data, key->len);ngx_rbtree_insert(&ctx->sh->rbtree, node);ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);if (account) {lr->last = now;lr->count = 0;return NGX_OK;}lr->last = 0;lr->count = 1;ctx->node = lr;return NGX_AGAIN;
}

##ngx_http_limit_req_expire尝试清理过期节点,ngx_slab_alloc_locked分配node空间

 ngx_http_limit_req_expire(ctx, 1);

 node = ngx_slab_alloc_locked(ctx->shpool, size);

##共享内存初始化,分配内存

if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {

            goto failed;

 }

ngx_int_t
ngx_shm_alloc(ngx_shm_t *shm)
{shm->addr = (u_char *) mmap(NULL, shm->size,PROT_READ|PROT_WRITE,MAP_ANON|MAP_SHARED, -1, 0);if (shm->addr == MAP_FAILED) {ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,"mmap(MAP_ANON|MAP_SHARED, %uz) failed", shm->size);return NGX_ERROR;}return NGX_OK;
}
#0  ngx_shm_alloc (shm=0x555555695d70) at src/os/unix/ngx_shmem.c:17
#1  0x000055555558fdbb in ngx_init_cycle (old_cycle=0x7fffffffde60) at src/core/ngx_cycle.c:485
#2  0x000055555556e66b in main (argc=3, argv=0x7fffffffe208) at src/core/nginx.c:292(gdb) p *shm
$1 = {addr = 0x0, size = 31457280, name = {len = 3, data = 0x5555556aa179 "one:30m"}, log = 0x5555556956e8, exists = 0}


http://www.ppmy.cn/news/1551215.html

相关文章

Swift 实现链表重新排列:L0 → Ln → L1 → Ln-1

前言 本题由于没有合适答案为以往遗留问题&#xff0c;最近有时间将以往遗留问题一一完善。 143. 重排链表 不积跬步&#xff0c;无以至千里&#xff1b;不积小流&#xff0c;无以成江海&#xff0c;Swift社区 伴你前行。如果大家有建议和意见欢迎在文末留言&#xff0c;我们会…

【北京迅为】iTOP-4412全能版使用手册-第二十二章 时间函数专题

iTOP-4412全能版采用四核Cortex-A9&#xff0c;主频为1.4GHz-1.6GHz&#xff0c;配备S5M8767 电源管理&#xff0c;集成USB HUB,选用高品质板对板连接器稳定可靠&#xff0c;大厂生产&#xff0c;做工精良。接口一应俱全&#xff0c;开发更简单,搭载全网通4G、支持WIFI、蓝牙、…

Linux 僵尸进程和孤儿进程, 进程优先级

僵尸进程 之间在进程状态中了解到了 "僵尸状态". 那么处于僵尸状态的进程就是僵尸进程. 僵尸状态是一种特殊的进程状态, 它表示一个进程已经完成执行, 但其父进程尚未回收其终止状态. "僵尸状态" 的本质就是死亡状态. 如何理解僵尸进程: 举个例子: 一个正…

KAN-Transfomer——基于新型神经网络KAN的时间序列预测

1.数据集介绍 ETT(电变压器温度)&#xff1a;由两个小时级数据集&#xff08;ETTh&#xff09;和两个 15 分钟级数据集&#xff08;ETTm&#xff09;组成。它们中的每一个都包含 2016 年 7 月至 2018 年 7 月的七种石油和电力变压器的负载特征。 traffic(交通) &#xff1a;描…

解决vue3,动态添加路由,刷新页面出现白屏或者404

解决vue3&#xff0c;动态添加路由&#xff0c;刷新页面出现白屏或者404 1.解决出现刷新页面&#xff0c;出现404的情况 1.问题的出现 在做毕设的时候&#xff0c;在权限路由得到时候&#xff0c;我问通过router**.**addRoute(item)的方式&#xff0c;在路由守卫动态添加路由…

计算机毕业设计Spark+大模型知识图谱中药推荐系统 中药数据分析可视化大屏 中药爬虫 机器学习 中药预测系统 中药情感分析 大数据毕业设计

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

洛谷 P1162 填涂颜色 C语言 bfs

题目&#xff1a; https://www.luogu.com.cn/problem/P1162 由数字 0 组成的方阵中&#xff0c;有一任意形状的由数字 1 构成的闭合圈。现要求把闭合圈内的所有空间都填写成 22。例如&#xff1a;66的方阵&#xff08;n6&#xff09;&#xff0c;涂色前和涂色后的方阵如下&am…

深信服技术服务工程师(网络安全、云计算方向)面试题

1.tcp3次握手和四次挥手的过程。 2.简述ospf动态路由。 3.哪些地方用静态路由&#xff0c;哪些地方用动态路由&#xff0c;说说他们的区别 4.在数据包在二层交换机中是如何转发的 5.两个三层交换机如何进行通信 6.trunk和access模式区别 7.对http协议的了解&#xff08;https&a…