《Docker 运维入门实战:服务器不止一台——多副本怎么互相发现、分摊流量》
关键词:多副本、服务发现、负载均衡、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,到今天的多副本与分摊流量,这条线已经从“一台机器上把服务跑起来”走到了“多个副本互相发现、分摊流量”。单机上练熟服务名发现和网关分发,再看集群,就不是从零开始。下一篇可以往副本背后的数据走一步:多副本时,状态、会话和数据该放哪,才不会一个请求换个副本就丢东西。
- 点赞
- 收藏
- 关注作者
评论(0)