【发布时间】:2020-09-16 17:28:12
【问题描述】:
在 AWS 网络负载均衡器文档中,它说在为目标组指定实例时,它必须在负载均衡器注册的每个可用区中包含一个实例。这不是强制执行的。
如果您在 3 个 AZ 中注册了 NLB,但在 AZ1 中只有一个目标 EC2 实例,流量会怎样?如果启用跨 AZ 负载均衡,会有什么不同吗?
【问题讨论】:
标签: amazon-web-services networking amazon-ec2 nlb
在 AWS 网络负载均衡器文档中,它说在为目标组指定实例时,它必须在负载均衡器注册的每个可用区中包含一个实例。这不是强制执行的。
如果您在 3 个 AZ 中注册了 NLB,但在 AZ1 中只有一个目标 EC2 实例,流量会怎样?如果启用跨 AZ 负载均衡,会有什么不同吗?
【问题讨论】:
标签: amazon-web-services networking amazon-ec2 nlb
如果您在 3 个 AZ 中注册了 NLB,但在 AZ1 中只有一个目标 EC2 实例,流量会怎样?如果启用跨 AZ 负载均衡,会有什么不同吗?
在这个特定场景中(NLB 在 3 个 AZ 中,单个实例在 1 个 AZ 中),什么都没有发生。从最终用户的角度来看,使用或不使用跨区域负载平衡没有明显区别。在任何一种情况下都可以访问该实例。
为了证明这一点,我开发了一个简单的 CloudFormation 模板,用于创建 NLB,带或不带跨区域负载平衡,以及 1 个实例。该模板允许对 NLB、跨区域和实例位置的不同设置进行简单实验。我在us-east-1区域和默认VPC中使用了模板。
为模板指定几个参数,包括:
NLBSubnetsIds - 启用 NLB 的子网。您必须先在控制台中检查,哪些子网在哪些可用区中。
InstanceSubnetId - 实例的子网。如果您想使用实例位置,您可以再次检查哪个子网位于哪个 AZ。您必须确保在为您的 NLB 设置的可用区之一中创建实例。
CrossZoneEnabled - 启用或禁用 NLB 的跨区域平衡。
从模板和实例运行状况检查通过创建堆栈后(可能需要 1 或 2 分钟),您可以在浏览器中访问 NLB DNS 以查看实例上托管的示例网页。
---
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
NLBSubnetsIds:
Type: List<AWS::EC2::Subnet::Id>
InstanceSubnetId:
Type: AWS::EC2::Subnet::Id
AmazonLinux2AMIId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
CrossZoneEnabled:
Type: String
Default: false
AllowedValues: [true, false]
Resources:
BasicSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Enable www port
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
VpcId: !Ref VpcId
MyInstance1:
Type: AWS::EC2::Instance
CreationPolicy:
ResourceSignal:
Timeout: PT5M
Properties:
ImageId: !Ref AmazonLinux2AMIId
InstanceType: t2.micro
Monitoring: false
SecurityGroupIds: [!Ref BasicSecurityGroup]
SubnetId: !Ref InstanceSubnetId
UserData:
Fn::Base64: !Sub |
#!/bin/bash -xe
yum install -y httpd aws-cfn-bootstrap
echo "<h2>Hello world from $(hostname -f)</h2>" \
> /var/www/html/index.html
systemctl start httpd
# check if website is working
curl -s localhost | grep "Hello"
# Signal the status from cfn-init
/opt/aws/bin/cfn-signal -e $? \
--stack ${AWS::StackName} \
--resource MyInstance1 \
--region ${AWS::Region}
MyNLB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
IpAddressType: ipv4
LoadBalancerAttributes:
- Key: load_balancing.cross_zone.enabled
Value: !Ref CrossZoneEnabled
Scheme: internet-facing
Subnets: !Ref NLBSubnetsIds
Type: network
MyListner1:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- TargetGroupArn: !Ref MyTargetGroup
Type: forward
LoadBalancerArn: !Ref MyNLB
Port: 80
Protocol: TCP
MyTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckEnabled: true
HealthCheckIntervalSeconds: 10
HealthCheckPath: /
HealthCheckProtocol: HTTP
HealthyThresholdCount: 2
UnhealthyThresholdCount: 2
Port: 80
Protocol: TCP
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: 30
Targets:
- Id: !Ref MyInstance1
Port: 80
TargetType: instance
VpcId: !Ref VpcId
Outputs:
DNSName:
Value: !GetAtt MyNLB.DNSName
从最终用户的角度来看,在您的场景中,在 NLB 中启用或禁用跨区域没有明显区别。但是,长期的差异可能在于高可用性。也就是说,如果您禁用了跨区域,并且如果实例所在 AZ 中的 NLB 节点发生问题,则 NLB 将无法将流量从其他 AZ 路由到您的实例。这是我的猜测,因为这不是您可以手动检查的东西。原因是一旦您将 AZ/子网与您的 NLB 关联,您就无法解除关联,以检查在这种情况下会发生什么。
相比之下,如果启用跨区域,在上述场景中,来自其他区域的 NLB 节点可能会跨区域将流量路由到实例。
启用跨区域流量的主要好处是当您different number of instances 在不同的可用区时。在这种情况下,跨区域平衡可以使所有实例获得大致相同的流量。如果没有跨区域平衡,隔离实例将获得比其他 AZ 中的实例集合更多的流量。
您可以使用第二个模板检查区域平衡的效果。模板与之前几乎相同,但现在 1 个 AZ 将有 3 个实例,而另一个将有 1 个 AZ。
---
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
NLBSubnetsIds:
Type: List<AWS::EC2::Subnet::Id>
InstanceSubnetId1:
Type: AWS::EC2::Subnet::Id
InstanceSubnetId2:
Type: AWS::EC2::Subnet::Id
AmazonLinux2AMIId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
CrossZoneEnabled:
Type: String
Default: false
AllowedValues: [true, false]
Resources:
BasicSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Enable www port
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
VpcId: !Ref VpcId
MyInstance1:
Type: AWS::EC2::Instance
CreationPolicy:
ResourceSignal:
Timeout: PT3M
Properties:
ImageId: !Ref AmazonLinux2AMIId
InstanceType: t2.micro
Monitoring: false
SecurityGroupIds: [!Ref BasicSecurityGroup]
SubnetId: !Ref InstanceSubnetId1
UserData:
Fn::Base64: !Sub |
#!/bin/bash -xe
yum install -y httpd aws-cfn-bootstrap
echo "<h2>Hello world from $(hostname -f)</h2>" \
> /var/www/html/index.html
systemctl start httpd
# check if website is working
curl -s localhost | grep "Hello"
# Signal the status from cfn-init
/opt/aws/bin/cfn-signal -e $? \
--stack ${AWS::StackName} \
--resource MyInstance1 \
--region ${AWS::Region}
MyInstance2:
Type: AWS::EC2::Instance
CreationPolicy:
ResourceSignal:
Timeout: PT3M
Properties:
ImageId: !Ref AmazonLinux2AMIId
InstanceType: t2.micro
Monitoring: false
SecurityGroupIds: [!Ref BasicSecurityGroup]
SubnetId: !Ref InstanceSubnetId2
UserData:
Fn::Base64: !Sub |
#!/bin/bash -xe
yum install -y httpd aws-cfn-bootstrap
echo "<h2>Hello2 world from $(hostname -f)</h2>" \
> /var/www/html/index.html
systemctl start httpd
# check if website is working
curl -s localhost | grep "Hello"
# Signal the status from cfn-init
/opt/aws/bin/cfn-signal -e $? \
--stack ${AWS::StackName} \
--resource MyInstance2 \
--region ${AWS::Region}
MyInstance3:
Type: AWS::EC2::Instance
CreationPolicy:
ResourceSignal:
Timeout: PT3M
Properties:
ImageId: !Ref AmazonLinux2AMIId
InstanceType: t2.micro
Monitoring: false
SecurityGroupIds: [!Ref BasicSecurityGroup]
SubnetId: !Ref InstanceSubnetId2
UserData:
Fn::Base64: !Sub |
#!/bin/bash -xe
yum install -y httpd aws-cfn-bootstrap
echo "<h2>Hello2 world from $(hostname -f)</h2>" \
> /var/www/html/index.html
systemctl start httpd
# check if website is working
curl -s localhost | grep "Hello"
# Signal the status from cfn-init
/opt/aws/bin/cfn-signal -e $? \
--stack ${AWS::StackName} \
--resource MyInstance3 \
--region ${AWS::Region}
MyInstance4:
Type: AWS::EC2::Instance
CreationPolicy:
ResourceSignal:
Timeout: PT3M
Properties:
ImageId: !Ref AmazonLinux2AMIId
InstanceType: t2.micro
Monitoring: false
SecurityGroupIds: [!Ref BasicSecurityGroup]
SubnetId: !Ref InstanceSubnetId2
UserData:
Fn::Base64: !Sub |
#!/bin/bash -xe
yum install -y httpd aws-cfn-bootstrap
echo "<h2>Hello2 world from $(hostname -f)</h2>" \
> /var/www/html/index.html
systemctl start httpd
# check if website is working
curl -s localhost | grep "Hello"
# Signal the status from cfn-init
/opt/aws/bin/cfn-signal -e $? \
--stack ${AWS::StackName} \
--resource MyInstance4 \
--region ${AWS::Region}
MyNLB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
IpAddressType: ipv4
LoadBalancerAttributes:
- Key: load_balancing.cross_zone.enabled
Value: !Ref CrossZoneEnabled
Scheme: internet-facing
Subnets: !Ref NLBSubnetsIds
Type: network
MyListner1:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- TargetGroupArn: !Ref MyTargetGroup
Type: forward
LoadBalancerArn: !Ref MyNLB
Port: 80
Protocol: TCP
MyTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckEnabled: true
HealthCheckIntervalSeconds: 10
HealthCheckPath: /
HealthCheckProtocol: HTTP
HealthyThresholdCount: 2
UnhealthyThresholdCount: 2
Port: 80
Protocol: TCP
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: 30
Targets:
- Id: !Ref MyInstance1
Port: 80
- Id: !Ref MyInstance2
Port: 80
- Id: !Ref MyInstance3
Port: 80
- Id: !Ref MyInstance4
Port: 80
TargetType: instance
VpcId: !Ref VpcId
Outputs:
DNSName:
Value: !GetAtt MyNLB.DNSName
如果你使用上面的模板,反复请求NLB url,你会看到隔离实例将获得大约50%的流量,没有跨区域均衡。启用跨区域平衡后,它将约为 20%。以下是我根据 100 个请求得出的结果:
【讨论】:
您的方案不需要启用跨区域负载平衡。正如 Marcin 指出的那样,它对您没有任何作用。事实上,解析您的 NLB 的 DNS,您会看到它只为每个 AZ 返回一条 A 记录,该记录在所有 NLB 的目标组中聚合了一个健康的实例。 Marcin 的回答非常适合深入研究。
有些人在这里说“是的,但我们仍然会超时。”。这是因为您的场景比 OP 更复杂。简而言之,您的 NLB 可能具有多个目标组,其中不同的目标存在于多个 AZ 中。启用跨区域负载平衡将解决您的次优配置问题,但会产生额外的数据传输费用。鸭带和口香糖包装可在 AWS VPC 中使用。
更多信息:
NLB 使用 DNS 是“智能的”,因为它们的 VIP 只会解析到具有健康目标的 A 记录(在及时的原因内)。如果 NLB 具有跨三个 AZ 的多个具有不同实例的目标组,您将获得返回的三个 A 记录(每个具有健康目标的 AZ 一个记录)。这就是 NLB + RR DNS 的工作原理。
但是,如果您的目标组在单个 AZ 中包含 EC2 实例,那么 DNS 循环将解析正确的 AZ 的可能性为 33%(给定三个 AZ)。
最好的解决方案是开启跨区负载均衡。这增加了数据传输成本,但与拆分 NLB 的替代方案相比,它没有那么复杂。请注意,启用跨区域负载平衡需要几分钟才能启动。不要启用它,立即启动 telnet,当它不起作用时很难过。等待 5 到 10 分钟,然后启动您的 telnet。
来源:使用 AWS 和 janky EC2 解决方案的轶事和实践经验。
【讨论】: