Nginx中多个Worker进程监听同一个端口为什么不会冲突?

魔法一:传统模式下的“影分身之术” (Fork 与 FD 继承)

在早期的 Linux 内核(或没有开启特定优化的配置)中,Nginx 其实并没有让多个 Worker 去分别绑定端口

  1. Master 进程开门营业:Nginx 刚启动时,是老大(Master 进程)出面,调用 socket() 创建好监听的 Socket,然后执行 bind()listen(),稳稳地占住了 80 或 443 端口。

  2. 子进程继承家产:接着,Master 进程会调用 fork() 孵化出多个 Worker 进程。重点来了!在 Linux 操作系统的机制里,子进程会无条件继承父进程打开的文件描述符(File Descriptor, FD)

    💡 天才的比喻时间: 这就好比 Master 老板租下了一个店面,并拉了一根唯一的电话线(监听端口的 Socket)。然后他用“影分身”变出了好几个长得一模一样的接线员(Worker 进程)。所有的接线员都坐在同一部电话机前盯着它。 因为自始至终只有这一个 Socket 绑定了端口,大家只是共享了对这个 Socket 的引用,当然就不存在“抢占端口冲突”这种低级错误啦!

    (补充说明:这种模式会带来著名的“惊群效应 Thundering Herd”——电话一响,所有接线员都去抢电话,但只有一个能接通。为此 Nginx 在用户态加了一把 accept_mutex 互斥锁,保证同一时刻只有一个接线员把手放在电话上。)

魔法二:现代模式下的“超级总机” (SO_REUSEPORT)

随着技术的发展,Linux 内核在 3.9 版本之后放出了一个大招,也就是现在的 Nginx 默认推荐使用的高性能绝招:SO_REUSEPORT 套接字选项。

如果你在 Nginx 配置里加上了 reuseport 参数,整个架构就变了:操作系统真的允许多个完全独立的 Socket 绑定到同一个 IP 和端口上!

  1. 独立成家:Master 进程不再只建一个 Socket,而是让每个 Worker 进程都各自创建一个 Socket,并全部打上 SO_REUSEPORT 的标记,大家光明正大地绑定同一个端口。
  2. 内核级分配:当有新的客户端连接到来时,就不再是 Worker 们去抢了。Linux 内核化身成为了电信局的“超级总机”,它会在底层对客户端的 IP 和端口做一个哈希计算(Hash),然后极其公平且精准地将这个连接直接塞给其中一个 Worker 的 Socket。

知识点

# 1. 全局块 (Global) —— 酒店大环境
worker_processes auto; # 决定雇佣多少个接线员(Worker进程),auto通常等于CPU核心数

# 2. Events 块 —— 前台接待规则
events {
worker_connections 1024; # 每个接线员最多能同时处理多少个电话(连接)
}

# 3. Http 块 —— 酒店餐饮/住宿通用规则
http {
include mime.types; # 告诉浏览器发过去的是HTML、CSS还是图片

# 4. Server 块 —— 具体的某栋主楼(虚拟主机)
server {
listen 80; # 监听80端口(默认HTTP端口)
server_name localhost; # 大楼的名字

# 5. Location 块 —— 楼层导航员
location / {
root /var/www/html; # 告诉客人,当访问根目录 '/' 时,去物理硬盘的哪个房间找文件
index index.html; # 如果客人没报具体文件名,默认递给他这本叫 index.html 的册子
}
}
}

Nginx中常用的命令

启动 Nginx:
sudo service nginx start

查看状态(看看它是不是活蹦乱跳的):
sudo service nginx status

优雅重启(划重点!):
sudo nginx -s reload

#这个 -t 代表 test。如果它输出 syntax is ok 和 test is successful,说明你的代码完美;如果有红字报错,它会精确告诉你是在哪一个文件的第几行漏了分号
sudo nginx -t

你的 root 路径设在 /home/jh/devCode。虽然你给 nginx.conf 权限过户了,但 Nginx 运行时的身份通常是 www-data

💡 权限穿透逻辑: 如果 www-data 用户想要读取 /home/jh/devCode/index.html,它必须拥有进入你家目录 (/home/jh) 的权限。但在很多 Linux 系统里,家目录默认是 700 (只有你自己能进)。 如果 Nginx 进不去你的家门,它就会报 403 Forbidden 或者干脆拒绝服务。

✅ 修正方案(如果访问 8080 报错 403): 执行这行命令,给 Nginx 的访问留一条缝:

Bash

chmod 755 /home/jh