《Docker 运维入门实战:服务器不止一台——多副本怎么互相发现、分摊流量》

举报
yd_274623194 发表于 2026/11/02 10:46:52 2026/11/02
【摘要】 关键词:多副本、服务发现、负载均衡、Compose、Nginx、集群入门上一篇我们把手动的尾巴去掉了:改了代码、推上去,服务器自己更新、自己验收。但这条线到现在还有一个默认前提:所有东西都在一台服务器上。gateway(Nginx 网关)、web(静态网页)、api(8000 端口的 Python 接口服务)同住一台机器,流量不大时没问题,可一旦 api 变慢、机器本身出问题,整条线就一起受...

关键词:多副本、服务发现、负载均衡、Compose、Nginx、集群入门

上一篇我们把手动的尾巴去掉了:改了代码、推上去,服务器自己更新、自己验收。但这条线到现在还有一个默认前提:所有东西都在一台服务器上。gateway(Nginx 网关)、web(静态网页)、api(8000 端口的 Python 接口服务)同住一台机器,流量不大时没问题,可一旦 api 变慢、机器本身出问题,整条线就一起受影响。今天往“服务器不止一台”走一步:多个服务、多个副本时,怎么让它们互相发现、怎么分摊流量——也就是从单机 Compose 往集群的方向看一眼。

先说清范围:本文不真的搭一个集群,不讲 Kubernetes 的完整部署。目标是把集群里最核心的两个问题讲明白:副本多了,请求该发给谁;容器换了地址,别人怎么找到它。理解了这两点,以后再看 Swarm、Kubernetes 那些名词,就不会觉得它们是凭空冒出来的。

一、什么时候一台不够了:三个信号

不是流量一上来就要上集群,先认清三个信号,再决定要不要往多副本走:

  • 单个服务成了瓶颈:api 的 CPU 或内存先到顶,web 和 gateway 还很闲。加机器不如先给 api 加副本,让请求分摊开。
  • 一台机器就是单点故障:机器宕机、重启、升级,三个服务一起停。副本分散开,坏一个还有别的能顶上。
  • 更新想更稳一点:前面讲过滚动更新是“只动改了的服务”,多副本时可以一个一个换,旧副本继续接请求,新副本健康了再接管,空档更小。

反过来也要说一句:如果流量还很小、服务也还简单,单机 Compose 加资源限制、健康检查、CI/CD,已经够用。多副本是为了解决具体问题,不是为了显得高级。

二、多副本第一步:先在单机上把副本扩出来

集群听起来大,但第一步可以在单机上练:把 api 从 1 个副本扩到 3 个。

docker compose up -d --scale api=3
docker compose ps api

这里有个容易卡住的点:三个 api 副本都在容器里监听 8000 端口,但不能三个都把 8000 映射到宿主机的同一个端口——端口会冲突。正确的做法是:api 不直接对外暴露端口,只让它在 Compose 的内部网络里被访问,真正对外的是 gateway。外面的人只找网关,网关再把请求分给三个副本。这一步做对了,后面讲的发现和分摊才有落点。

三、互相发现:服务名就是地址,别写死 IP

副本一多,最先坏掉的写法就是写死 IP:今天 api 容器的 IP 是 172.18.0.4,明天重启一换,网关配置就失效了。Compose 里有更省事的办法:服务名本身就是地址。

在同一个 Compose 网络里,gateway 不需要知道 api 每个副本的 IP,只要写服务名 api 就行。Compose 内置的 DNS 会把 api 这个名字解析到当前活着的副本上,副本增减、重启换 IP,解析结果跟着变,配置不用改。

# gateway 的 Nginx 配置里,关键是这一行思路
# 不写某个容器的 IP,只写服务名 api:8000
upstream api_backend {
    server api:8000;
}

这就是“服务发现”最朴素的样子:名字不变,背后的实例可以变。集群里的服务发现(比如 Kubernetes 的 Service)做的也是同一件事,只是规模更大、跨机器也能用。记住这个对应关系,以后看集群文档时就不会晕:名字是稳定的入口,实例是随时可换的。

四、分摊流量:网关把请求轮着发给副本

发现了解决了“找谁”,接下来是“怎么分”。网关收到请求后,把请求轮着发给三个 api 副本,这就是最简单的负载均衡:轮询(round-robin)。

upstream api_backend {
    server api:8000;
    # Compose 的 DNS 会把 api 解析到多个副本,
    # Nginx 按顺序把请求分给它们
}

server {
    listen 80;
    location /api/ {
        proxy_pass http://api_backend;
    }
}

用这个办法能顺带解决两个实际问题:第一,单个副本变慢时,别的副本还能分担,不至于一个请求拖垮整条线;第二,前面讲过的健康检查在这里也派得上用场——不健康的副本应该先从分发名单里拿掉,而不是继续往它身上发请求。验收时别只看“请求通了”,要看三个副本是不是真的都接到了请求:

docker compose logs api | grep -i "GET /health"
docker compose ps api   # 三个副本都应是 (healthy)

五、单机多副本还不是集群:差在哪三步

把 api 扩到 3 个副本,离真正的集群还差三步,提前认清这三步,就知道后面要学什么:

  • 跨机器:副本现在还在同一台机器上,机器一宕,全灭。集群要把副本分散到多台机器上,某台坏了,别的机器上的副本还能顶。
  • 调度:谁来决定某个副本该跑在哪台机器上、坏了在哪台上重建?单机 Compose 是人手动决定的,集群里是调度器自动决定的。
  • 跨机器的网络:副本不在同一台机器上时,服务名解析、容器互访要跨机器打通,这就是覆盖网络(overlay network)要解决的事。

这三步分别对应集群里的三个大概念:多节点、调度、跨节点网络。不用现在就全学会,先把名字和要解决的问题对上号,之后每学一个都有落点。

六、三个新手最容易踩的坑

1. 给每个副本写死 IP 或端口
容器重启就换 IP,写死等于给自己埋定时炸弹。用服务名、用内部网络,让发现机制去管地址。

2. 副本共享了不该共享的东西
多副本跑起来后,如果每个副本都在本地写文件、本地记会话,一个请求这次落在副本 A、下次落在副本 B,数据就对不上了。能做成无状态的服务先做成无状态,状态和数据要另外想办法——这是下一篇要看的方向。

3. 以为副本多了就等于高可用
api 有 3 个副本,但 gateway 只有一个、web 只有一个、数据库只有一个,任何一个单点坏了,整条线还是停。高可用要一环一环地补,不能只补最显眼的那一环。

结语

从单容器、Compose 编排、数据卷、反向代理和 HTTPS、日志与健康检查、滚动更新、资源限制和重启策略、CI/CD,到今天的多副本与分摊流量,这条线已经从“一台机器上把服务跑起来”走到了“多个副本互相发现、分摊流量”。单机上练熟服务名发现和网关分发,再看集群,就不是从零开始。下一篇可以往副本背后的数据走一步:多副本时,状态、会话和数据该放哪,才不会一个请求换个副本就丢东西。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。