Carry の Blog Carry の Blog
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • Python
  • Shell
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carry の Blog

好记性不如烂键盘
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • Python
  • Shell
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 工作笔记

  • K8S

  • Systemd

  • Nginx

    • Nginx添加用户认证
    • 利用nginx+sftp实现一个可供用户下载的服务
    • nginx配置文件及模块
    • 通过脚本按天切割nginx的日志
    • nginx通过四层代理实现端口转发
    • NGINX基于cookie针对同一域名进行分流转发
    • nginx利用内置模块配置限速限流
    • 利用NGINX内置模块mirror进行流量复制等操作
    • 使用$remote_user字段记录访问NGINX的用户
    • 从NGINX自身配置文件中定义访问日志按时间切割
    • NGINX配置单独代理百度的sitemap文件
    • nginx配置微信小程序校验及其他
    • nginx配置gzip压缩
    • 由Nginx集中代理分散的PHP集群的实践
    • http状态码详解
    • OpenResty-1-13-6-2-新增ldap模块儿
    • 排查NGINX的open_file_cache导致发布后访问404的问题
    • 制作OpenResty-1-19-9-1的RPM包
    • nginx-proxy-managar使用笔记
    • Nginx 的端口复用:提升服务器并发能力
    • Supervisord

    • OpenLdap

    • OpenVPN

    • GitLab

    • Sshd

    • WebDev

    • Docker

    • Prometheus

    • Rclone

    • Iptables

    • Firewalld

    • Linux笔记
    • Nginx
    Carry の Blog
    2022-09-22
    目录

    Nginx 的端口复用:提升服务器并发能力

    在高并发服务器环境中,端口复用是一项非常重要的技术。它可以显著提升服务器的并发处理能力,尤其是在 Nginx 等高性能服务器中。本文将详细介绍 Nginx 中的端口复用技术,特别是 SO_REUSEADDR 和 SO_REUSEPORT 的使用方法和原理。

    # 1. 背景

    在 TCP 连接关闭后,会进入 TIME_WAIT 状态,持续一段时间(通常是 2 * MSL,最大报文段生存时间),以确保所有数据包都能被正确处理。在 TIME_WAIT 状态期间,端口默认情况下是无法立即被重新使用的。这对于需要频繁重启的服务器进程或高并发连接的服务器来说,是一个性能瓶颈。

    # 2. TCP TIME_WAIT 状态

    在 TCP 连接关闭的四次挥手(Four-Way Handshake)过程中,主动关闭方在发送最后一个 ACK 报文后会进入 TIME_WAIT 状态。这个状态的存在是为了确保所有数据包都能被正确处理,防止旧连接的数据包影响新连接。

    # 3. SO_REUSEADDR 的作用

    SO_REUSEADDR 是一个 socket 选项,允许在端口处于 TIME_WAIT 状态时重新使用该端口。通过设置这个选项,可以在端口处于 TIME_WAIT 状态时,允许新的连接请求绑定到这个端口,从而提高服务器的可用性和性能。

    # 代码示例

    以下是一个在 C 语言中使用 SO_REUSEADDR 的示例代码:

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdio.h>
    
    int main() {
        int sockfd;
        int opt = 1;
        struct sockaddr_in addr;
    
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) {
            perror("socket");
            return 1;
        }
    
        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
            perror("setsockopt");
            return 1;
        }
    
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_ANY;
        addr.sin_port = htons(8080);
    
        if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
            perror("bind");
            return 1;
        }
    
        // listen, accept, etc...
    
        close(sockfd);
        return 0;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39

    # 4. SO_REUSEPORT 的作用

    SO_REUSEPORT 是另一个 socket 选项,允许多个套接字绑定到同一个端口,从而实现负载均衡和提高并发处理能力。它在高性能服务器(如 Nginx、Redis 等)中广泛使用。

    # 代码示例

    以下是一个在 C 语言中使用 SO_REUSEPORT 的示例代码:

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdio.h>
    
    int main() {
        int sockfd;
        int opt = 1;
        struct sockaddr_in addr;
    
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) {
            perror("socket");
            return 1;
        }
    
        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)) < 0) {
            perror("setsockopt");
            return 1;
        }
    
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_ANY;
        addr.sin_port = htons(8080);
    
        if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
            perror("bind");
            return 1;
        }
    
        // listen, accept, etc...
    
        close(sockfd);
        return 0;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39

    # 5. 在 Nginx 中配置 SO_REUSEADDR 和 SO_REUSEPORT

    # 确认 Nginx 版本

    首先,确保你的 Nginx 版本支持 SO_REUSEPORT。Nginx 1.9.1 及以上版本支持这个选项。

    # 编译 Nginx 以支持 SO_REUSEPORT

    如果你的 Nginx 是从源代码编译的,可以在编译时添加支持 SO_REUSEPORT 的模块。具体步骤如下:

    ./configure --with-stream --with-stream_ssl_module --with-stream_realip_module
    make
    make install
    
    1
    2
    3

    # 修改 Nginx 配置文件

    在 Nginx 配置文件中,SO_REUSEADDR 默认已启用,为了启用 SO_REUSEPORT,需要在配置文件中添加相应的指令。

    编辑你的 Nginx 配置文件(通常是 /etc/nginx/nginx.conf 或 /usr/local/nginx/conf/nginx.conf),在相应的 server 块中添加 reuseport 指令。例如:

    worker_processes  4;
    
    events {
        worker_connections  1024;
    }
    
    http {
        include       mime.types;
        default_type  application/octet-stream;
    
        sendfile        on;
        tcp_nopush     on;
        tcp_nodelay    on;
        keepalive_timeout  65;
        types_hash_max_size 2048;
        include /etc/nginx/conf.d/*.conf;
    
        server {
            listen 80 reuseport;
            server_name localhost;
    
            location / {
                root   html;
                index  index.html index.htm;
            }
    
            error_page  500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32

    在 listen 指令后添加 reuseport,即可启用 SO_REUSEPORT。

    # 重启 Nginx

    配置修改后,重启 Nginx 使配置生效:

    sudo nginx -s reload
    
    1

    # 6. 验证配置

    通过以下命令可以查看端口的复用情况:

    ss -lntp | grep nginx
    
    1

    如果 SO_REUSEPORT 配置成功,你会看到多个 Nginx 进程都在监听同一个端口。

    # 总结

    通过配置 SO_REUSEADDR 和 SO_REUSEPORT,可以显著提升 Nginx 服务器的并发处理能力和性能。SO_REUSEADDR 允许在端口处于 TIME_WAIT 状态时重新使用该端口,而 SO_REUSEPORT 允许多个套接字绑定到同一个端口,实现负载均衡。这些配置在高并发服务器环境中非常有用,能够有效提高服务器的可用性和稳定性。


    上次更新: 4/24/2025

    ← nginx-proxy-managar使用笔记 supervisor管理服务→

    最近更新
    01
    tidb fast ddl
    04-04
    02
    TiDB配置文件调优 原创
    04-03
    03
    如何移除TiDB中的表分区 原创
    04-03
    更多文章>
    Theme by Vdoing
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式