负载均衡配置:使用 Nginx 反向代理 MinIO 集群的实战教程

MinIO 分布式集群搭好了,4 个节点跑得挺欢,API 端口 9000,Console 端口 9001。

然后问题来了:客户端怎么访问?总不能让人记住 4 个节点的 IP 吧?万一某个节点挂了呢?

答案很明确:在集群前面加一层 Nginx 反向代理。但 MinIO 的代理配置和普通 Web 应用不太一样------文件上传可能是几个 G,请求可能是长连接,还有 API 和 Console 两套端口要分开代理。

这篇文章,从零开始配置一套生产可用的 Nginx 反向代理方案。


架构概览

先明确我们要达成的效果:

  • 用户访问 https://minio-api.example.com → Nginx → 后端 4 个 MinIO 节点的 9000 端口
  • 管理员访问 https://minio-console.example.com → Nginx → 后端 4 个 MinIO 节点的 9001 端口
  • 当某个节点挂了,Nginx 自动把流量切到其他节点
  • 大文件上传不受 buffer 限制
  • HTTPS 证书统一在 Nginx 层管理

第一步:基本 upstream 配置

在 Nginx 里定义 MinIO 集群的 upstream:

nginx 复制代码
# /etc/nginx/conf.d/minio-upstream.conf

upstream minio_api {
    server 192.168.1.11:9000 weight=1 max_fails=3 fail_timeout=30s;
    server 192.168.1.12:9000 weight=1 max_fails=3 fail_timeout=30s;
    server 192.168.1.13:9000 weight=1 max_fails=3 fail_timeout=30s;
    server 192.168.1.14:9000 weight=1 max_fails=3 fail_timeout=30s;
}

upstream minio_console {
    server 192.168.1.11:9001 weight=1 max_fails=3 fail_timeout=30s;
    server 192.168.1.12:9001 weight=1 max_fails=3 fail_timeout=30s;
    server 192.168.1.13:9001 weight=1 max_fails=3 fail_timeout=30s;
    server 192.168.1.14:9001 weight=1 max_fails=3 fail_timeout=30s;
    # Console 不是无状态的,建议 ip_hash 或只代理单节点
    # 下文详细说明
}

参数说明:

  • weight=1:所有节点权重相同,轮询分发
  • max_fails=3:连续失败 3 次后标记为不可用
  • fail_timeout=30s:标记不可用后,30 秒内不再分发到该节点

第二步:API 端口的代理配置

MinIO 的 S3 API 对代理有一些特殊要求,漏掉任何一项都可能导致上传失败或超时。

nginx 复制代码
# /etc/nginx/conf.d/minio-api.conf

server {
    listen 80;
    server_name minio-api.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name minio-api.example.com;

    # 证书配置
    ssl_certificate     /etc/nginx/ssl/minio-api.pem;
    ssl_certificate_key /etc/nginx/ssl/minio-api.key;

    # 大文件上传专用:允许最大 10G 的请求体
    client_max_body_size 10240M;

    # ★ 核心:关闭代理缓冲
    # MinIO 的 S3 API 使用 Chunked Transfer Encoding,如果开缓冲,
    # Nginx 会先把整个请求体存到磁盘再转发,导致上传超时
    proxy_buffering        off;
    proxy_request_buffering off;

    # 超时配置:大文件上传可能需要很长时间
    proxy_connect_timeout  60s;
    proxy_send_timeout     3600s;
    proxy_read_timeout     3600s;

    # 保持 Host 头,MinIO 用它做虚拟主机路由
    proxy_set_header Host $http_host;

    # 传递真实客户端 IP(用于审计和安全策略)
    proxy_set_header X-Real-IP       $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # 禁止缓存 S3 API 响应
    proxy_set_header X-NginX-Proxy true;
    add_header Cache-Control "no-cache, no-store, must-revalidate";

    # ★ 关键:对 WebSocket 升级支持(用于事件通知)
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    location / {
        proxy_pass http://minio_api;
    }
}

为什么要关闭 proxy_buffering

MinIO 的 S3 API 在上传大文件时使用 Transfer-Encoding: chunked。如果 Nginx 开了缓冲,它会先等客户端把整个文件发完,存到本地临时目录,再转发给 MinIO。对于几个 G 的文件,这不仅浪费磁盘空间,还会导致请求超时。

关闭之后,Nginx 收到多少就转发多少,数据以流式通过,不落地。


第三步:Console 端口的代理配置

Console 是 Web 管理界面,和 API 端口的代理需求不同------它涉及 WebSocket 连接和 Cookie。

nginx 复制代码
# /etc/nginx/conf.d/minio-console.conf

server {
    listen 80;
    server_name minio-console.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name minio-console.example.com;

    ssl_certificate     /etc/nginx/ssl/minio-console.pem;
    ssl_certificate_key /etc/nginx/ssl/minio-console.key;

    client_max_body_size 10M;

    # 超时配置
    proxy_read_timeout 300s;
    proxy_send_timeout 300s;

    # Cookie 域名重写,确保登录 Cookie 正确
    proxy_cookie_domain 192.168.1.11 minio-console.example.com;
    proxy_cookie_path / /;

    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # WebSocket 支持(Console 登录和实时刷新需要)
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    location / {
        proxy_pass http://minio_console;
    }
}

Console 负载均衡的坑

MinIO Console 不是完全无状态的------用户登录后的 Session 绑定在特定节点上。如果你在 Console 的 upstream 里用默认轮询,可能出现"登录成功但刷新后掉线"的问题。

解决方案有两种:

  • 推荐方案 :Console 的 upstream 只用 ip_hash,让同一个客户端的请求始终落到同一个节点
  • 更简单的方案:Console 只代理一个节点,不做负载均衡。管理界面不需要高可用
nginx 复制代码
upstream minio_console {
    ip_hash;  # ★ 同一个来源 IP 始终路由到同一个节点
    server 192.168.1.11:9001 weight=1 max_fails=3 fail_timeout=30s;
    server 192.168.1.12:9001 weight=1 max_fails=3 fail_timeout=30s;
    server 192.168.1.13:9001 weight=1 max_fails=3 fail_timeout=30s;
    server 192.168.1.14:9001 weight=1 max_fails=3 fail_timeout=30s;
}

第四步:健康检查

Nginx 的 max_failsfail_timeout 只能检测端口是否可达。如果你需要更精确的健康检查(比如检测 MinIO 服务是否正常响应),需要主动健康检查。

开源 Nginx 不支持主动健康检查,需要 nginx-plus 或使用 ngx_http_healthcheck_module。一个更实际的方案是用 proxy_next_upstream

nginx 复制代码
location / {
    proxy_pass http://minio_api;
    # 当后端返回以下错误时,自动重试下一个节点
    proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
    proxy_next_upstream_tries 2;       # 最多重试 2 次
    proxy_next_upstream_timeout 10s;    # 重试超时
}

如果用了 proxy_buffering off(API 端口),注意一个限制:当请求体已经部分转发给后端后,Nginx 无法再重试到其他节点。因此 proxy_next_upstream 对上传请求的保护有限。

对于大文件上传,更好的做法是在客户端层面做重试(MinIO 各语言的 SDK 都内置了重试机制)。


第五步:HTTPS 终结

生产环境统一在 Nginx 层处理 TLS,MinIO 节点之间跑 HTTP 就行。这样做的好处:

  • 证书集中管理(续期只需改 Nginx,不用动 4 个节点)
  • 减轻 MinIO 节点的 CPU 消耗(TLS 握手有一定开销)
  • 方便接入 WAF 和日志采集

使用 Let's Encrypt 免费证书:

bash 复制代码
# 安装 certbot
yum install -y certbot python3-certbot-nginx

# 申请证书
certbot --nginx -d minio-api.example.com -d minio-console.example.com

# 自动续期
echo "0 3 * * * certbot renew --quiet && systemctl reload nginx" >> /etc/crontab

如果你用的是自签名证书或企业 CA 签发的证书,直接配 ssl_certificatessl_certificate_key 即可。


第六步:完整的负载均衡策略选择

Nginx 提供了多种负载均衡算法,不同场景选择不同:

算法 指令 适用场景
轮询(默认) 不指定 API 端口,各节点同等能力
加权轮询 weight=N 节点配置不同(如有的节点磁盘更大)
IP 哈希 ip_hash Console 端口,需要 Session 保持
最少连接 least_conn 长连接场景,避免单节点过载
一致性哈希 hash $request_uri 特定对象的读写希望落到同一节点

对于 MinIO API,默认轮询就够用了。因为 MinIO 节点之间通过纠删码已经实现了数据分布,读取任意节点都能取到数据。


第七步:验证配置

配置完成后,分步骤验证:

bash 复制代码
# 1. 先检查 Nginx 配置语法
nginx -t

# 2. 重载配置
nginx -s reload

# 3. 测试 API 端口
curl -I https://minio-api.example.com/health

# 4. 用 mc 客户端测试连通性
mc alias set myminio https://minio-api.example.com ACCESS_KEY SECRET_KEY
mc ls myminio

# 5. 测试大文件上传
dd if=/dev/zero of=testfile bs=1M count=100
mc cp testfile myminio/testbucket/

# 6. 模拟节点故障
# 停掉一个 MinIO 节点,验证请求是否自动切换到其他节点
systemctl stop minio@node1
mc ls myminio  # 应该依然正常工作

常见问题排查

上传大文件时 504 Gateway Timeout

检查 proxy_read_timeoutproxy_send_timeout,大文件上传可能需要设置为 3600s 或更长。同时确认 proxy_buffering off 已生效。

Console 登录后频繁掉线

检查 Console 的 upstream 是否用了 ip_hash。如果没有,Cookie 里的 Session ID 可能被路由到了不持有该 Session 的节点。

上传报错 413 Request Entity Too Large

检查 client_max_body_size,默认只有 1M。根据业务需求设置为合适的值(如 10240M)。

部分节点离线后读写报错

检查 Nginx 错误日志 /var/log/nginx/error.log,看是否有连接超时。确认 max_failsfail_timeout 配置生效。如果节点已经恢复但流量仍不回来,可能是 fail_timeout 时间还没过。


写在最后

Nginx 反代 MinIO 的方案不算复杂,但细节不少。核心记住三条:

  • API 端口:关缓冲、长超时、加上流式转发
  • Console 端口:用 ip_hash 保持 Session
  • 健康检查:proxy_next_upstream 做兜底,但上传请求的容错最好靠客户端 SDK 重试

另外,如果你的 MinIO 集群跑在 Kubernetes 里,可以用 Ingress 来实现类似的效果,但这个话题留到以后再说。

相关推荐
hweiyu0013 小时前
Linux命令:iotop
linux·运维
齐潇宇13 小时前
Jenkins 自动化部署 Tomcat + PHP
linux·运维·容器·tomcat·jenkins
ruanyongjing13 小时前
元数据驱动开发 - 面向对象编程思想的补充 (十二)
nginx·macos·docker
小辰记事本13 小时前
从零读懂RDMA硬件排障:读数、看码、查计数器
运维·网络·数据库
hj28625113 小时前
Linux 进程、作业控制、定时任务 完整版整理笔记
linux·运维·笔记
深圳恒讯13 小时前
马来西亚服务器延迟怎么样?多少才算正常
运维·服务器
黄筱筱筱筱筱筱筱13 小时前
基于AI 文本生成的自动化Linux 运维文档系统
运维·自动化
Java成神之路-13 小时前
DNS、DNS 负载均衡、CDN 到底有什么区别?
计算机网络·负载均衡
2601_9488106013 小时前
Jenkins
运维·jenkins