ngx_shm_zone_t 是 Nginx 封装共享内存区域的核心结构,用于跨 worker 进程共享状态;它包含内存地址、大小、名称、锁、初始化/清理回调及模块标签等字段,由模块在配置解析时自动创建并注册,支撑限流、连接限制、SSL 会话缓存等功能。

ngx_shm_zone_t 是 Nginx 内部用于管理共享内存(shared memory)区域的核心数据结构,它不直接暴露给配置层,而是由模块(如 limit_req、limit_conn、ssl_session_cache、stream_upstream 等)在初始化时创建并注册,为跨 worker 进程的协同提供统一、高效、线程安全的内存基础。
共享内存区的本质与作用
在多 worker 进程模型下,Nginx 需要一种机制让所有 worker 共享状态(如限流计数器、连接数统计、SSL 会话缓存条目)。操作系统级的共享内存(通过 shm_open/mmap 或 posix_ipc)是唯一可行方案。ngx_shm_zone_t 就是对这块底层内存的封装:它记录了虚拟地址、大小、名称、同步锁、初始化回调、清理回调等元信息,使不同模块能复用同一块内存,避免重复映射和资源冲突。
关键字段解析(基于主流开源版本,如 nginx-1.24+)
该结构体定义在 src/core/ngx_cycle.h 中,主要成员包括:
-
shm:类型为
ngx_shm_t,包含实际内存句柄(addr指向 mmap 后的起始地址)、大小(size)、名称(name,用于 shm_open 的标识符)、标志位(如log); -
name:
ngx_str_t类型,对应配置中zone=name:size的name,全局唯一,用于查找和重用; -
nodes:红黑树根节点指针(
ngx_rbtree_node_t *),仅当该 zone 被用作红黑树存储(如limit_req的 key 存储)时有效; - init 和 data:初始化函数指针及传入参数,在共享内存映射完成后由主进程调用一次,用于构建 zone 内部数据结构(如初始化哈希表头、分配 slab 管理器);
- cleanup:清理函数指针,在 Nginx 退出或 reload 时被调用,负责释放 zone 关联的动态资源(如销毁红黑树、释放 slab 缓存);
-
tag:
void *类型,通常指向模块的静态ngx_module_t变量,用于区分不同模块注册的同名 zone(防止误覆盖); -
noreuse:布尔标记,指示该 zone 是否允许被其他模块复用(例如
ssl_session_cache shared:SSL:10m与limit_req zone=SSL:10m若 tag 不同则不会冲突)。
如何触发 ngx_shm_zone_t 的创建
用户不手动构造该结构,而是通过配置指令间接驱动。典型流程如下:
- 在
http或stream块中写入类似limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;; - Nginx 解析配置时,
ngx_http_limit_req_module的命令处理函数(ngx_http_limit_req_zone)被调用; - ngx_shared_memory_add(cycle, &value[1], size, &ngx_http_limit_req_module);
-
ngx_shared_memory_add查找已存在同名 zone(按 name + tag 匹配),若无则分配ngx_shm_zone_t并加入 cycle->shared_memory 链表; - 在 master 进程启动阶段(
ngx_init_cycle),遍历所有 zone,调用mmap创建共享内存,并执行其init回调完成内部初始化。
调试与观测技巧
虽属底层结构,但可通过以下方式验证其行为:
- 启动时加
-t参数,观察日志是否报 “using the shared memory zone "xxx"”; - 查看
/proc/,搜索/maps nginx.shm或自定义 name(取决于系统 shm 实现),确认 mmap 地址与大小; - 使用
nginx -V 2>&1 | grep -o 'with-\(http\|stream\)_.*_module'确认启用模块,再检查对应模块是否注册了 zone; - 在 GDB 中断点设在
ngx_shared_memory_add或模块的 init 函数,可观察ngx_shm_zone_t *实例的地址与字段值。
理解 ngx_shm_zone_t 不是为了手写模块,而是为了精准诊断共享内存类问题:比如 zone 名称冲突导致限流失效、size 设置过小引发频繁淘汰、init 失败导致 worker 启动异常等。它把“一块跨进程可见的内存”从系统概念落地为 Nginx 可调度、可复用、可生命周期管理的对象。











