IP

IP 地址在系统设计里的三个实际问题:CIDR 怎么切子网、私网地址怎么经 NAT 出公网、VPC 子网为什么经常不够用。含 RFC 1918 私网段、AWS 每子网保留 5 个地址、NAT 网关 55,000 并发连接上限、公网 IPv4 计费和 IPv6 的算例与翻车表。

IP address 是用来标识 device 在 internet 或 local network 上的地址。IP 是 “Internet Protocol”,是一套规则,规定 data 在 internet / local network 上传输的格式(IPv4 见 RFC 791,IPv6 见 RFC 8200)。

在系统设计里,IP 很少作为独立题目出现,但它决定三件事:一个网络能放下多少台机器和容器、内网服务怎么访问公网和被公网访问、地址不够时从哪里扩。 这些问题在 VPC 规划和 Kubernetes 集群扩容时一定会遇到。

有约束的设计问题

在 AWS 上给一个 SaaS 后端规划网络,要求如下:

  1. 跨 3 个可用区(AZ),每个 AZ 有公网入口(负载均衡器)和私有应用层。
  2. 应用跑在 EKS 上,高峰约 3,000 个 Pod,每个 Pod 都要一个 VPC 地址(假设使用 AWS VPC CNI 的默认模式)。
  3. 数据库和缓存不能有公网地址。
  4. 私有子网里的服务要调第三方支付 API。
  5. 将来要和公司办公网(10.0.0.0/16)打通。

后文每一节都回到这五条。

Versions

IPv4

最早的 Internet Protocol 是 IPv4,使用 32-bit 地址,写成点分十进制,总量 2^32 ≈ 43 亿。早期够用,但随着 internet adoption 增长就不够了,这也是后面 NAT 和私网地址普及的原因。

Example: 102.22.192.181

IPv6

IPv6 是 1998 年发布的新协议(RFC 2460,现行版本是 RFC 8200),2000 年代中期开始部署,至今仍在推进。

IPv6 使用 128-bit 地址,写成 8 组十六进制,总量 2^128 ≈ 3.4 × 10^38。连续的全零组可以用 :: 缩写一次。

Example: 2001:0db8:85a3:0000:0000:8a2e:0370:7334,缩写为 2001:db8:85a3::8a2e:370:7334

CIDR:一个网段有多少地址

CIDR(RFC 4632)用「地址/前缀长度」表示一个网段,前缀之后的位可自由分配:

CIDR可变位地址总数AWS 子网可用数(减 5)
/161665,53665,531
/20124,0964,091
/248256251
/2841611

AWS 文档规定:IPv4 子网大小在 /28 到 /16 之间,每个子网的前 4 个和最后 1 个地址保留,不能分给任何资源。以 10.0.0.0/24 为例,.0 是网络地址,.1 给 VPC 路由器,.2 给 DNS,.3 预留,.255 是广播地址。小子网被这 5 个吃掉的比例很高:/28 只剩 11 个。

Types

Public 与 Private

Public IP 在公网上唯一、可路由,由 ISP 或云厂商分配。

Private IP 只在内网有效,RFC 1918 预留了三段:

  • 10.0.0.0/8
  • 172.16.0.0/12
  • 192.168.0.0/16

公网路由器不转发这些地址,所以不同公司可以重复使用同一段。另外 RFC 6598 预留了 100.64.0.0/10 给运营商级 NAT(CGNAT),在云上有时被用来扩 Pod 地址。

Example: 家用 router 从 ISP 拿到一个 public IP,给家里的电脑、手机分配 192.168.x.x 的 private IP。家里所有设备对外看起来都是同一个 public IP。

Static 与 Dynamic

Static IP 不会变化,手动配置或长期保留。服务端入口、对方要把你加进 IP 白名单的出口,都需要固定地址。在 AWS 上对应 Elastic IP。

Dynamic IP 会变化,由 DHCP server(RFC 2131)按租期分配。它是最常见的类型,方便在网络内复用地址,消费级宽带和普通云主机的默认公网地址通常都是动态的。

NAT:私网地址怎么访问公网

NAT(RFC 3022)把内网包的源地址改写成自己的公网地址,并记住映射,回包时再改回去。多台机器共用一个公网 IP 时还要改写源端口,所以一个公网 IP 对同一个目标能同时承载的连接数受端口数限制。

AWS NAT 网关的文档给出了具体上限:每个 IPv4 地址对每个唯一目标(目标 IP + 目标端口 + 协议)最多 55,000 个并发连接,一个 NAT 网关最多可关联 8 个 IPv4 地址来提高这个上限。

算一下场景第 4 条。假设支付 API 只有一个入口 IP:443,高峰 3,000 个 Pod 各自维持 20 条连接,就是 60,000 条,超过单个地址的 55,000,会出现连接失败(NAT 网关的 CloudWatch 指标里 ErrorPortAllocation 会增长)。修法:Pod 侧用连接池降低连接数;给 NAT 网关加辅助 IP;或按 AZ 拆多个 NAT 网关。

NAT 的另一个用途是给出口一个固定 IP:第三方要求 IP 白名单时,把 NAT 网关的 Elastic IP 报给对方,不管后面的 Pod 怎么扩缩、IP 怎么变,出口不变。

回到场景:子网规划

一个可行的规划(数字按上文 CIDR 表计算):

VPC: 10.1.0.0/16                  # 避开办公网 10.0.0.0/16
├── 公有子网 x3  /24  每个 251 可用   # ALB、NAT 网关
├── 应用子网 x3  /19  每个 8,187 可用 # EKS 节点和 Pod
└── 数据子网 x3  /24  每个 251 可用   # RDS、ElastiCache,无公网路由
  • 3,000 个 Pod 放得下吗:3 个 /19 共约 24,500 个地址,按 AZ 平均 1,000 个 Pod 加节点自身地址,余量充足。VPC CNI 默认会给每个节点预留一整块 ENI 的空闲 IP 作为 warm pool,实际占用高于 Pod 数;如果只给 /24(251 个),节点一多地址很快耗尽,新 Pod 起不来、事件里报分配不到 IP。
  • 数据库无公网:数据子网的路由表里没有指向 Internet Gateway 的路由。
  • 不与办公网冲突:两边都用 10.0.0.0/16 的话,打通后路由不知道同一个地址该去哪边,只能 NAT 或重建 VPC。地址不够可以给 VPC 追加辅助 CIDR,但已经和别人重叠的网段靠追加解决不了,所以网段冲突要在第一天规划时避开。

IPv6 在这里能解决什么

IPv6 地址多到不必省:AWS 的 IPv6 子网前缀在 /44 到 /64 之间,最小的 /64 也有 2^64 个地址,EKS 最佳实践文档把 IPv6 列为解决 Pod IP 耗尽的首选办法。代价是依赖和客户端必须支持 IPv6,只支持 IPv4 的第三方 API 仍要经过 NAT64 之类的转换。另一个现实动力是费用:AWS 对公网 IPv4 地址按 $0.005/小时收费(使用中和闲置的都收),一个地址一个月约 0.005 × 730 = $3.65,大量实例各带公网 IP 时这笔钱不可忽略。

常见翻车

翻车现象修法
应用子网切得太小扩容时 Pod 卡在 ContainerCreating,报分配不到 IP按峰值 Pod 数的数倍规划;追加辅助 CIDR;考虑 IPv6
VPC 与办公网 / 其他 VPC 网段重叠打通 VPN 或 peering 后部分地址不可达公司级统一分配网段,建 VPC 前查登记表
所有 Pod 经一个 NAT IP 打同一个外部 API高峰连接失败,ErrorPortAllocation 增长连接池;NAT 网关加 IP;按 AZ 拆 NAT 网关
服务直接用公网 IP 互相调用流量绕出公网,多付 NAT 和数据传输费内网调用走私有地址或内部负载均衡
把 DHCP 分配的动态 IP 写进配置实例重启后换 IP,调用方全部失败用 DNS 名或 Elastic IP,不写死地址

面试时这样回答

  1. 复述约束:几个 AZ、峰值多少实例或 Pod、哪些层不能有公网地址、要不要和别的网络打通。
  2. 给网段:VPC /16,公有 / 应用 / 数据三层子网,每层每 AZ 一个;说明应用子网因为 Pod 占 IP 要切大。
  3. 说出口:私有子网经 NAT 网关出公网,NAT 的 Elastic IP 就是给第三方白名单的固定出口。
  4. 说一个上限:NAT 每个地址对同一目标 55,000 并发连接,超过要加地址或做连接池。
  5. 说一个长期问题:网段不能和办公网重叠;地址不够时追加 CIDR 或转 IPv6。

相关章节:OSI Model、TCP 与 UDP、DNS、Proxy vs Reverse Proxy、Load Balancer、N-tier architecture。

一手证据