AWS VPC与负载均衡器:云架构的地基与流量中枢设计实战
2026/6/7 14:59:42 网站建设 项目流程

1. 项目概述:为什么VPC和负载均衡器是云架构的“地基”与“交通指挥中心”

我在AWS上搭过不下五十套生产环境,从三台EC2跑WordPress的小站,到支撑日活百万用户的微服务集群,所有稳定运行超过一年的系统,无一例外都严格遵循一个铁律:先建VPC,再配负载均衡器,最后才部署应用。这不是教科书里的流程图,而是我踩着服务器告警邮件、半夜被电话叫醒、客户投诉截图堆出来的血泪经验。今天聊的这两个东西——Virtual Private Cloud(VPC)和Load Balancer(负载均衡器),在AWS生态里根本不是可选项,它们是云上系统的呼吸系统和血液循环系统。你可能听过“安全组像防火墙”“子网像房间”,但这些比喻太浅了。真实情况是:VPC定义了你的整个网络宇宙的物理法则,而负载均衡器则是这个宇宙里所有数据流的中央调度台。没有它,你的应用就像在没有红绿灯的十字路口开车;没有VPC,你的应用就像把保险柜直接摆在菜市场中央。关键词里提到的“Towards AI - Medium”,说明原文偏重概念科普,但我要给你的是能直接抄进工单、贴进团队Wiki、让运维同事拍着桌子说“就按这个干”的实操手册。它适合三类人:刚考完AWS SAA认证但没碰过真机的新人,正在为线上服务卡顿、偶发502错误焦头烂额的中级工程师,以及需要向老板解释“为什么这周不能上线新功能,得先重构网络层”的技术负责人。接下来的内容,不讲虚的,只拆解“为什么必须这么设计”“参数背后藏着什么坑”“配置时手抖输错一个数字会引发什么连锁反应”。

2. VPC核心设计逻辑:不是画个框,而是重建一套网络物理定律

2.1 为什么“默认VPC”是新手最大的温柔陷阱

几乎所有AWS教程第一步都是让你点开控制台,看到那个自动生成的“Default VPC”,然后告诉你“恭喜,你已经有VPC了”。我带过的三个实习生,全栽在这上面。他们用默认VPC部署了测试环境,一切顺利,直到上线前做安全审计——审计报告第一条就是:“生产环境使用默认VPC,违反公司《云基础设施安全基线v3.2》第7条”。问题出在哪?默认VPC的底层设计,本质上是AWS为你预装的一套“共享公寓样板间”:它自动创建一个公有子网(Public Subnet),IP段是172.31.0.0/16,路由表默认指向Internet Gateway(IGW),安全组放行全部入站流量。这就像你租房子,房东说“厨房冰箱随便用”,结果你发现冰箱里塞满了隔壁租客的剩菜。默认VPC的“默认”二字,意味着它被设计成“开箱即用”,而非“生产就绪”。它的子网CIDR块(172.31.0.0/16)和路由规则,是AWS为全球用户统一预留的,你无法修改其基础属性。更致命的是,它的网络ACL(Network ACL)默认是“允许所有”,这在生产环境等于把大门钥匙挂在门把手上。我见过最惨的案例:一家电商公司用默认VPC跑订单服务,某天开发误操作,把一个调试用的SSH端口(22)暴露在公网上,结果被自动化扫描工具捕获,半小时内服务器被植入挖矿程序,CPU飙到99%,订单支付接口全部超时。所以我的第一条硬性规定是:任何生产环境、预发布环境、甚至重要测试环境,必须手动创建专属VPC,且命名必须包含环境标识(如prod-vpc-us-east-1、staging-vpc-ap-southeast-1)。这不是形式主义,这是把“责任”刻进资源ID里的第一道防线。

2.2 CIDR规划:不是数学题,而是未来三年的扩张地图

很多人以为VPC的CIDR块(比如10.0.0.0/16)只是个IP地址池,填个数字就行。错。它是一张精确到毫米的施工蓝图。我曾接手一个客户项目,他们的VPC CIDR是10.10.0.0/24——注意,是/24,只有256个IP。当时他们只有5台EC2,看起来绰绰有余。但三个月后,他们要接入Kubernetes集群,每个Node需要独立IP,每个Pod需要Service IP,还要加Elasticsearch节点、Redis集群、监控Agent……最后发现IP不够用,被迫停服4小时做VPC迁移。CIDR的本质,是给未来所有可能的网络组件预留“物理空间”。我的计算公式是:所需IP总数 = (当前EC2数量 × 1.5) + (预期容器数量 × 2) + (数据库节点数 × 3) + (预留冗余20%)。为什么乘系数?因为EC2可能需要多网卡(ENI),容器网络(如CNI插件)会消耗额外IP,数据库主从复制、读写分离会增加节点。以中型业务为例,我推荐起步就用10.0.0.0/16(65536个IP),它能轻松支撑500台EC2+2000个容器。关键在于子网划分:/16不能直接当子网用,必须切分成多个/20或/21的子网。比如,我把10.0.0.0/16切成四个/20:10.0.0.0/20(可用IP 4094)、10.0.16.0/20、10.0.32.0/20、10.0.48.0/20。每个/20子网约4000个IP,足够一个AZ内的所有资源。这里有个反直觉的细节:子网的CIDR必须完全落在VPC CIDR范围内,且不能重叠,但可以不连续。比如10.0.0.0/20和10.0.64.0/20之间空着10.0.16.0/20到10.0.63.0/20这段,这完全合法,且是刻意为之——为未来跨AZ扩展、专线接入(Direct Connect)或VPN网关预留“隔离带”。我见过最聪明的客户,直接把10.0.0.0/16的前半段(10.0.0.0/17)划给云上资源,后半段(10.0.128.0/17)留给未来混合云场景,物理隔离,逻辑清晰。

2.3 公有子网 vs 私有子网:不是“能不能上网”,而是“谁来决定你能不能上网”

教科书常说:“公有子网连IGW,私有子网连NAT网关”。这没错,但漏掉了最关键的控制权问题。公有子网的“公有”,本质是子网路由表里有一条指向IGW的0.0.0.0/0路由;私有子网的“私有”,本质是它的路由表里没有这条路由,或者这条路由指向的是NAT网关(NAT Gateway)。但NAT网关本身是个“单向阀门”:它允许子网内的实例主动发起出站请求(比如yum update、访问S3 API),但绝不允许外部流量通过NAT网关反向打进来。这才是安全的核心。我曾经优化过一个金融客户的架构,他们把Web服务器放在公有子网,App服务器放在私有子网,数据库在更深层的私有子网。表面看很标准,但问题出在Web服务器的安全组:它开放了80/443端口给0.0.0.0/0,同时又开放了22端口给运维IP。攻击者一旦攻破Web服务器(比如利用一个未修复的Log4j漏洞),就能直接SSH登录,进而横向移动到App服务器——因为App服务器的安全组,为了调用Web API,开放了8080端口给Web服务器所在的安全组ID(sg-xxxx)。真正的隔离,不是靠子网位置,而是靠安全组的“最小权限原则”和网络ACL的“白名单机制”。我的做法是:公有子网只放ALB(Application Load Balancer)和跳板机(Bastion Host),ALB的安全组只开放443/80给互联网,跳板机安全组只开放22给公司办公网IP段;所有应用服务器(EC2/ECS)全部放在私有子网,它们的安全组只允许来自ALB安全组的流量,且端口精确到应用监听端口(如8080),绝不开放22端口。这样,即使ALB被攻破(极难),攻击者也拿不到任何EC2的SSH权限,因为ALB根本不走SSH协议。

2.4 安全组与网络ACL:双保险还是双刃剑?

安全组(Security Group)和网络ACL(Network ACL)常被并列讲解,但它们是完全不同的物种。安全组是“状态化”的实例级防火墙,网络ACL是“无状态”的子网级防火墙。这句话的意思是:如果你在安全组里允许入站HTTP(80),那么对应的出站HTTP响应(比如TCP ACK包)会自动被允许,无需额外配置;而网络ACL必须显式配置入站和出站两条规则,且规则按编号顺序执行,一旦匹配就停止检查。这导致一个经典坑:有人为了“加强安全”,在私有子网的网络ACL里,只配置了入站规则允许来自ALB的8080端口,却忘了配出站规则允许返回的流量。结果所有请求都卡在TCP三次握手的SYN-ACK阶段,应用日志里全是Connection Timeout。我的经验是:网络ACL只做“兜底防护”,安全组做“精细控制”。具体怎么用?网络ACL只配三条规则:1)入站:允许来自ALB安全组的流量(源IP用ALB的私有IP段,如10.0.0.0/16);2)入站:拒绝所有其他入站流量(规则号999);3)出站:允许所有(规则号100)。这样,网络ACL只拦住“不该进来的”,不干预“该出去的”。安全组则要细到毛:Web服务器安全组,入站只允许ALB的443/80,出站只允许到App服务器安全组的8080;App服务器安全组,入站只允许Web服务器安全组的8080,出站只允许到RDS安全组的3306和ElastiCache安全组的6379。每一条规则,我都要求写明注释,比如“Allow ALB health check - sg-abc123”。有一次,客户环境出现间歇性502,排查三天,最后发现是安全组规则注释写着“Allow all for testing”,但没人记得删掉,导致某个测试脚本疯狂刷请求,触发了ALB的健康检查失败阈值。注释不是可选项,它是故障定位的救命稻草

3. 负载均衡器深度解析:ALB、NLB、GLB不是选择题,而是解剖刀

3.1 三种负载均衡器的本质差异:别再被“应用层/网络层”忽悠了

AWS官方文档把ALB(Application Load Balancer)归为“七层”,NLB(Network Load Balancer)归为“四层”,GLB(Gateway Load Balancer)归为“网关层”。这种分法容易让人陷入协议栈的迷思。真正决定你选哪个的,不是OSI模型,而是你的流量“长什么样”和“你要对它做什么”。ALB的核心能力是“理解HTTP/HTTPS协议”,它能看懂URL路径(/api/v1/users)、Host头(api.example.com)、Cookie(Session ID),并基于这些做路由。NLB的核心能力是“透传原始IP和端口”,它不解析应用层内容,只做TCP/UDP转发,延迟低至100微秒,且支持静态IP和Zonal DNS。GLB则完全不同,它是为第三方网络安全设备(如防火墙、IDS)设计的“流量镜像分发器”,把所有进出流量按规则分发给后端虚拟设备集群。举个真实案例:一个在线教育平台,直播课用RTMP协议(基于TCP),点播课用HLS(基于HTTP)。他们最初全用ALB,结果直播流卡顿严重,因为ALB要解析每个TCP包的HTTP头,增加了毫秒级延迟,而直播对延迟极度敏感。换成NLB后,RTMP流直接透传,端到端延迟从800ms降到120ms。但点播的HLS请求,又需要ALB做基于Host头的路由(cdn.example.com → S3,api.example.com → API Gateway)。所以他们最终方案是:NLB处理RTMP入口,ALB处理HLS和API入口,两者共存于同一VPC,通过不同DNS域名区分。这打破了“一个应用只能用一种LB”的思维定式。另一个坑是:有人听说NLB性能好,就把所有Web服务迁过去,结果发现无法做基于路径的灰度发布(比如/api/v2/* 路由到新版本),因为NLB根本不认识URL路径。ALB是“智能交警”,能看车牌(Host)、查路线(Path)、管车速(Rate Limiting);NLB是“高速公路收费站”,只收钱(转发),不问去哪

3.2 ALB的Target Group配置:健康检查不是“勾个框”,而是生命线校准

ALB后端的Target Group(目标组)配置,90%的人只改了端口和协议,却忽略了健康检查(Health Check)这个生死攸关的参数。健康检查的默认设置是:路径/,间隔30秒,超时5秒,健康阈值3次,不健康阈值3次。这在测试环境没问题,但在生产环境,它可能成为雪崩的导火索。想象一下:你的应用启动需要45秒(加载大模型、初始化缓存),而ALB每30秒就发一次健康检查,超时5秒。这意味着应用启动过程中,ALB会连续3次收到超时响应,判定实例“不健康”,立刻从流量池中摘除。等应用终于启动完成,ALB又开始新一轮检查,又超时……形成恶性循环,所有实例永远无法注册成功。我的解决方案是:健康检查路径必须是一个轻量级、无副作用的端点,比如/healthz,且该端点只检查核心依赖(DB连接、Redis连接),不查磁盘、不查外部API。参数必须根据应用特性调整:启动慢的应用,把健康检查间隔设为60秒,超时设为10秒,健康阈值设为2(避免误判),不健康阈值设为5(避免频繁摘除)。更狠的技巧是:在应用启动脚本里,先启动一个轻量HTTP服务监听/healthz,返回200,等所有初始化完成后,再启动主应用服务。这样ALB在30秒内就能看到健康响应,提前注入流量。还有一个隐藏雷区:健康检查的“成功码”默认是200,但有些老系统用204(No Content)或302(Redirect)作为健康信号。如果ALB只认200,就会永远认为实例不健康。务必在Target Group的健康检查设置里,把“成功码”改成你的应用实际返回的HTTP状态码,支持逗号分隔,比如200,204,302。我帮一个政府项目调优时,发现他们的健康检查返回302跳转到登录页,而ALB配置只认200,导致所有实例被标记为Unhealthy,整个系统瘫痪。改完这一项,5分钟内恢复。

3.3 SSL/TLS卸载:为什么证书必须存在ALB上,而不是EC2里?

很多开发者习惯在EC2上自己装Nginx,把SSL证书配在Nginx里,再反向代理到后端应用。这在单机时代没问题,但在AWS上,这是巨大的资源浪费和安全风险。ALB的SSL卸载(SSL Termination)是硬件级加速,它用专用芯片处理TLS握手,性能是软件Nginx的10倍以上,且完全免维护。更重要的是,它解耦了安全和业务:证书更新、密钥轮换、协议版本升级(如禁用TLS 1.0),全部在ALB控制台点几下就完成,无需重启任何EC2,不影响业务。而如果证书在EC2上,每次更新都要登录每台机器,手动替换证书文件,重启Nginx,稍有不慎就导致服务中断。更危险的是密钥管理:EC2上的私钥文件(.key)如果权限设置错误(比如chmod 777),或者被恶意脚本读取,整个HTTPS通信就形同裸奔。ALB的证书由AWS Certificate Manager(ACM)托管,私钥永不离开AWS KMS加密环境,你连看都看不到。我的标准流程是:在ACM申请免费证书(支持通配符,如*.example.com),验证DNS后,直接在ALB的Listeners里绑定。ALB监听443端口,协议HTTPS,后端Target Group用HTTP协议(端口8080)。这样,客户端到ALB是HTTPS,ALB到EC2是HTTP,既保证了传输安全,又避免了EC2的TLS计算开销。唯一要注意的是:如果应用需要获取客户端真实IP(比如做风控),不能直接读X-Forwarded-For,因为ALB会覆盖它。正确做法是:在ALB的Target Group里启用“Preserve client IP address”,并在EC2的安全组里,只允许来自ALB私有IP段的流量(10.0.0.0/16),这样X-Forwarded-For里的第一个IP就是真实的客户端IP,且无法被伪造。

3.4 Sticky Sessions(会话保持):不是“勾个框”,而是分布式锁的替代方案

ALB的Sticky Sessions功能,常被用来解决“用户登录态丢失”问题。默认是基于Cookie的粘性,ALB生成一个AWSELBCookie,把用户固定到某台EC2。这看似简单,但埋着深坑。最大的问题是:它破坏了负载均衡的“无状态”本质,把水平扩展变成了垂直扩展。当某台EC2因故障下线,ALB会把所有粘在这个实例上的用户流量,瞬间转移到其他实例,导致那台实例CPU飙升,可能连锁崩溃。更糟的是,如果用户清除了浏览器Cookie,或者换了设备,AWSELBCookie丢失,用户就被随机分配到新实例,登录态没了,体验极差。真正的解决方案,从来不是粘性,而是把会话状态外置。我的标配是:所有Web应用,会话(Session)数据必须存到ElastiCache(Redis)或DynamoDB,而不是本地内存。这样,任何EC2实例都能读取同一个用户的会话,ALB可以自由地把请求分发到任意健康实例,彻底消除粘性需求。Sticky Sessions只在两种极端场景下启用:1)遗留系统无法改造,必须依赖本地Session;2)实时音视频应用,需要极低的端到端延迟,且客户端与服务器有长连接状态(如WebRTC信令)。即便如此,我也把粘性持续时间设为最短(1小时),并配合CloudWatch告警:当某台EC2的HealthyHostCount低于2时,立即触发Lambda函数,强制刷新所有AWSELBCookie,把用户流量重新均衡。记住:粘性是止痛药,不是疫苗;外置状态才是根治方案

4. VPC与负载均衡器协同实战:从零搭建高可用Web架构

4.1 架构蓝图:一张图看清所有组件的血缘关系

我们以一个典型的PHP+MySQL Web应用为例,构建一个生产级架构。整个VPC设计为三层网络:边缘层(Edge)、应用层(App)、数据层(Data)。边缘层只放ALB和NAT网关,应用层放所有EC2和ECS,数据层放RDS和ElastiCache。具体IP规划如下:

组件子网类型AZCIDR用途
ALB公有子网us-east-1a10.0.1.0/24接收互联网流量
NAT网关公有子网us-east-1a10.0.1.0/24为私有子网提供出站访问
Web服务器(EC2)私有子网us-east-1a10.0.11.0/24运行PHP-FPM,处理HTTP请求
App服务器(EC2)私有子网us-east-1b10.0.12.0/24运行后台任务,调用API
RDS主库私有子网us-east-1a10.0.21.0/24MySQL主实例,处理写请求
RDS只读副本私有子网us-east-1b10.0.22.0/24MySQL只读实例,处理读请求
ElastiCache私有子网us-east-1a10.0.31.0/24Redis集群,存储Session和缓存

关键点在于:所有私有子网(10.0.11.0/24, 10.0.12.0/24等)的路由表,都有一条指向NAT网关的0.0.0.0/0路由;而ALB所在的公有子网(10.0.1.0/24)的路由表,有一条指向IGW的0.0.0.0/0路由。这样,ALB能直接访问互联网(用于ACM证书验证),而EC2只能通过NAT网关访问互联网(用于yum update),无法被互联网直接访问。RDS和ElastiCache的子网,路由表里不配置0.0.0.0/0路由,它们完全与互联网隔离,只接受来自应用层子网的流量。这就是“纵深防御”的物理体现:攻击者突破ALB,只能到达Web服务器;突破Web服务器,只能到达App服务器;突破App服务器,才能触达RDS——每一层都有子网隔离、安全组过滤、网络ACL兜底三重保护。

4.2 ALB Listener配置:如何用一个ALB承载多个域名和协议

一个ALB可以配置多个Listener(监听器),每个Listener监听一个端口和协议。我们的目标是:用一个ALB,同时处理www.example.com(HTTP重定向到HTTPS)、api.example.com(HTTPS,路由到API Gateway)、cdn.example.com(HTTPS,路由到CloudFront)。步骤如下:

  1. 创建HTTP Listener(端口80):协议HTTP,添加一个“重定向操作”,目标协议HTTPS,目标端口443,目标主机名${host}(保持原Host头)。这样,所有HTTP请求自动301跳转到HTTPS,无需在EC2上配置Nginx重定向。

  2. 创建HTTPS Listener(端口443):协议HTTPS,选择ACM证书(*.example.com),添加一个“基于Host头的条件路由”:

    • 条件:Host header iswww.example.com→ 目标组:tg-web-servers
    • 条件:Host header isapi.example.com→ 目标组:tg-api-gateway(指向API Gateway的VPC Link)
    • 条件:Host header iscdn.example.com→ 目标组:tg-cloudfront(指向CloudFront分发的Origin Access Identity)
  3. 为每个Target Group配置健康检查tg-web-servers的健康检查路径设为/healthz,超时10秒;tg-api-gateway的健康检查,由于API Gateway是托管服务,我们用ALB自带的“HTTP Ping”检查其/端点,超时5秒;tg-cloudfront则不需要健康检查,因为CloudFront是全局CDN,ALB只负责将请求转发过去。

提示:ALB的Listener规则是“先进先出”,规则顺序很重要。必须把最具体的Host头(如www.example.com)放在前面,把通配符(如*.example.com)放在最后,否则www.example.com的请求会被通配符规则提前匹配,永远到不了Web服务器。

4.3 安全组精细化配置:每一条规则都是一个承诺

安全组是VPC安全的最后也是最灵活的一道防线。我们的配置原则是:“只允许必要的,其余一律拒绝;来源和目标,必须精确到安全组ID或IP段,绝不写0.0.0.0/0”。以下是各组件的安全组配置:

  • ALB安全组(sg-alb-edge)

    • 入站:TCP 443,来源:0.0.0.0/0(必须,因为是面向互联网)
    • 入站:TCP 80,来源:0.0.0.0/0(必须,用于HTTP重定向)
    • 出站:TCP 443,目标:sg-web-servers(允许ALB访问Web服务器)
    • 出站:TCP 443,目标:sg-api-gateway(允许ALB访问API Gateway)
    • 出站:TCP 443,目标:sg-cloudfront(允许ALB访问CloudFront)
  • Web服务器安全组(sg-web-servers)

    • 入站:TCP 8080,来源:sg-alb-edge(只允许ALB流量)
    • 入站:TCP 22,来源:sg-bastion(只允许跳板机SSH,跳板机有自己的安全组)
    • 出站:TCP 3306,目标:sg-rds-master(只允许访问RDS主库)
    • 出站:TCP 6379,目标:sg-elasticache(只允许访问Redis)
  • RDS主库安全组(sg-rds-master)

    • 入站:TCP 3306,来源:sg-web-servers(只允许Web服务器读写)
    • 入站:TCP 3306,来源:sg-app-servers(只允许App服务器读写)
    • 出站:全部拒绝(RDS不需要主动出站)
  • ElastiCache安全组(sg-elasticache)

    • 入站:TCP 6379,来源:sg-web-servers(只允许Web服务器访问)
    • 入站:TCP 6379,来源:sg-app-servers(只允许App服务器访问)
    • 出站:全部拒绝

注意:安全组的“来源”和“目标”字段,填写的是另一个安全组的ID(如sg-xxxx),而不是IP地址。这是AWS的精髓——用逻辑组代替IP,当EC2数量变化时,安全策略自动生效,无需手动更新IP列表。

4.4 自动化部署:用CloudFormation模板固化最佳实践

手动在控制台点几十次鼠标,不仅效率低,而且极易出错。我所有的生产环境,都用AWS CloudFormation(CFN)模板一键部署。以下是一个简化版的CFN YAML片段,展示如何声明VPC和ALB:

Resources: # 创建VPC MyVPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 EnableDnsHostnames: true EnableDnsSupport: true Tags: - Key: Name Value: !Sub "${AWS::StackName}-vpc" # 创建公有子网(us-east-1a) PublicSubnetA: Type: AWS::EC2::Subnet Properties: VpcId: !Ref MyVPC CidrBlock: 10.0.1.0/24 AvailabilityZone: !Sub "${AWS::Region}a" MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub "${AWS::StackName}-public-a" # 创建ALB MyALB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub "${AWS::StackName}-alb" Scheme: internet-facing SecurityGroups: - !Ref ALBSecurityGroup Subnets: - !Ref PublicSubnetA - !Ref PublicSubnetB # 另一个AZ的公有子网,实现跨AZ高可用 Type: application # 创建ALB的HTTPS Listener HTTPSListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref WebTargetGroup LoadBalancerArn: !Ref MyALB Port: 443 Protocol: HTTPS Certificates: - CertificateArn: !Ref MyACMCert SslPolicy: ELBSecurityPolicy-TLS-1-2-Ext-2018-06

这个模板的关键在于:所有资源(VPC、子网、ALB、安全组)都通过!Ref!Sub动态引用,确保参数一致性;所有硬编码的值(如CIDR、AZ)都抽成Parameters,便于不同环境复用。部署时,只需执行aws cloudformation create-stack --stack-name prod-web --template-body file://web-infra.yaml --parameters ParameterKey=Environment,ParameterValue=prod,5分钟内,一套符合所有安全规范的VPC+ALB环境就准备就绪。比手动操作快10倍,且100%可重复、可审计。

5. 常见故障排查与独家避坑指南:那些文档里不会写的血泪教训

5.1 故障现象:ALB显示“Unhealthy”状态,但EC2明明在运行

这是最高频的故障。表面看是健康检查失败,但根因千差万别。我的排查清单是:

  1. 检查EC2安全组:是否真的放行了ALB的入站流量?ALB的私有IP段是10.0.0.0/16,但很多人只写了10.0.1.0/24(ALB子网),漏掉了ALB可能使用的其他IP。正确做法是:安全组入站规则,源IP写10.0.0.0/16,端口写ALB监听的端口(如8080)

  2. 检查EC2的防火墙:Linux系统默认有iptables或firewalld。执行sudo iptables -L -n,看是否有REJECT规则挡住了8080端口。临时关闭:sudo systemctl stop firewalld(CentOS)或sudo ufw disable(Ubuntu)。

  3. 检查应用监听地址:很多应用(如Node.js的app.listen(8080))默认只监听127.0.0.1(localhost),不监听0.0.0.0。健康检查请求从ALB发来,目标是EC2的私有IP(如10.0.11.10),如果应用只监听127.0.0.1,必然超时。必须改成app.listen(8080, '0.0.0.0')

  4. 检查健康检查路径的权限/healthz端点是否需要登录?是否被中间件拦截?用curl -v http://10.0.11.10:8080/healthz在EC2内部测试,确认返回200。

实操心得:我写了一个一键诊断脚本,部署在每台EC2上。它自动检查:1)端口监听状态(ss -tuln | grep :8080);2)防火墙状态;3)健康检查端点响应。运维人员只需SSH登录,执行./diag.sh,3秒内输出所有问题点。这个脚本救了我至少20次深夜告警。

5.2 故障现象:用户访问网站,页面加载一半就卡住,F12看到大量Pending请求

这通常是TCP连接耗尽的表现。根源在ALB的“空闲超时”(Idle Timeout)设置。ALB默认空闲超时是60秒,意思是:如果一个TCP连接建立后,60秒内没有任何数据传输,ALB会主动断开它。但很多前端框架(如React、Vue)会建立长连接用于WebSocket或Server-Sent Events(SSE),这些连接在静默期远超60秒。当ALB断开连接,前端JS还在等响应,就一直Pending。解决方案是:在ALB的Attributes里,把Idle Timeout调高到3600秒(1小时)。但这不是万能的,因为过高的超时会占用ALB连接数。更优雅的做法是:在前端代码里,加入心跳保活机制,每隔30秒发一个空的fetch('/ping')请求,维持连接活跃。

5.3 故障现象:跨AZ部署后,RDS只读副本延迟飙升到10分钟

这往往不是RDS的问题,而是VPC路由的问题。当RDS主库在us-east-1a,只读副本在us-east-1b,它们之间的复制流量,必须经过VPC内部网络。如果两个AZ之间的网络ACL或安全组,意外阻断了RDS的复制端口(MySQL默认3306),或者限制了带宽,就会导致复制延迟。排查命令:在RDS主库的“Connectivity & security”页,找到“Replication lag”指标,如果持续>60秒,立即检查主库和副本所在子网的安全组和网络ACL,确保3306端口双向畅通。我的经验是:RDS主从复制的流量,应该走VPC内部,绝不经过NAT网关或IGW,所以主从子网的路由表里,不能有任何指向NAT或IGW的0.0.0.0/0路由。

5.4 那些文档里绝不会提的“灰色地带”技巧

  • **ALB日志的妙

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询