nginx共享内存由master进程通过mmap分配并fork继承,所有worker直接读写同一物理内存,零拷贝协同;需显式声明zone,由slab管理、原子操作和锁机制保障安全读写,大小固定且需预估。

Nginx 的共享内存不是多个 worker 各存一份数据,而是所有 worker 进程直接读写同一块物理内存——由 master 进程一次性分配、fork 继承,实现零拷贝、毫秒级协同。
master 创建,worker 自动继承
启动时,master 进程调用 mmap() 配合 MAP_SHARED | MAP_ANONYMOUS 分配一块匿名内存,内容初始化为 0。随后 fork 出多个 worker 进程:
- 初始只读访问时,所有 worker 共享同一物理页,无复制开销
- 写操作仅对修改页做私有拷贝,不影响其他 worker 对原始共享区的读取
- 虚拟地址可能不同,但 Nginx 内部统一用相对偏移量定位数据,避免指针失效
- 生命周期由 master 全权管理,worker 退出不释放,reload 或退出前需确保无活跃访问
必须显式声明 zone,不能自动启用
共享内存本身没有通用接口,必须通过具体模块的 zone 指令显式创建命名区域:
-
limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=10r/s;→ 限流用,存令牌桶状态 -
proxy_cache_path ... keys_zone=cache_one:50m ...;→ 缓存用,存 key 和过期时间 -
ssl_session_cache shared:SSL:10m;→ SSL 复用,存 session ticket -
lua_shared_dict rate_limit 10m;→ Lua 脚本用,支持原子增减和 TTL
安全读写靠内置机制,不是裸内存操作
直接往共享内存写结构体是危险的。Nginx 提供安全抽象层:
- 底层使用 slab 分配器管理内存,避免碎片和越界
- 计数类操作(如
incr)默认用原子指令(ngx_atomic_fetch_add),无需手动加锁 - 复合更新(如更新缓存状态+时间戳)需包裹
ngx_shmtx_lock/unlock - 哈希表/红黑树等数据结构在初始化时由模块注册回调构建,字段布局严格按偏移计算
大小要一次定好,不可运行时扩容
共享内存区域大小在配置中固定,上线前需预估:
- 缓存
keys_zone:每 1MB 约存 8000–12000 个 key(取决于 key 长度) - 限流/连接限制 zone:按并发 key 数 ×(结构体大小 + 哈希表冗余)× 1.5 估算
- 过小 → 哈希冲突高、条目被 LRU 强制淘汰;过大 → 浪费内存,影响 slab 效率
- reload 会清空 zone(除非配置未改动 zone 定义),TTL 过期由后台惰性回收,不阻塞请求











