amazon-web-services - 每个 AZ 中没有目标的 AWS 网络负载均衡器
问题描述
在 AWS 网络负载均衡器文档中,它说在为目标组指定实例时,它必须在负载均衡器注册的每个可用区中包含一个实例。这不是强制执行的。
如果您在 3 个 AZ 中注册了 NLB,但在 AZ1 中只有一个目标 EC2 实例,流量会怎样?如果启用跨 AZ 负载均衡,会有什么不同吗?
解决方案
如果您在 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 路由到您的实例。这是我的猜测,因为这不是您可以手动检查的东西。原因是一旦您将可用区/子网与您的 NLB 关联起来,您就无法解除关联,以检查在这种情况下会发生什么。
相反,如果启用跨区域,在上述场景中,来自其他区域的 NLB 节点可能会跨区域将流量路由到实例。
启用跨区域流量的主要好处是,当您在不同 AZ 中拥有不同数量的实例时。在这种情况下,跨区域平衡可以使所有实例获得大致相同的流量。如果没有跨区域平衡,隔离实例将获得比其他 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 个请求的结果:
推荐阅读
- ruby - 作业上的 Rails ArgumentError - 参数数量错误 - 如何调试?
- reactjs - 如何用来自两个不同数组的数据表示一个复选框?
- html - 在 CSS 中隐藏 HTML 标签
- flask - Kubernetes 上没有持久的 Prometheus 指标
- android - 如何正确使用 Google Drive Rest API?
- nodemon - 带有 bable-node 的 nodemon 在终端崩溃但服务器运行良好?
- python-3.x - docker build:返回一个非零代码:5
- c# - 正则表达式模式只需要匹配第一次出现而不是“贪婪”
- python - 使用“application/octet-stream”内容类型上传 Django 文件
- python - 如何在seaborn中调整标签的字体大小?