问题描述
在AWS Network Load Balancer文档中,它表示在为目标组指定实例时,它必须在注册有Load Balancer的每个可用区中都包含一个实例。
如果您在3个可用区中注册了一个NLB,但在AZ1中只有一个目标EC2实例,那么流量将会如何?如果启用跨可用区负载平衡,那会有什么不同?
解决方法
您的方案不需要启用跨区域负载平衡。正如 Marcin 指出的那样,它对您没有任何作用。事实上,解析您的 NLB 的 DNS,您将看到它只为每个具有在 NLB 的所有目标组中聚合的健康实例的可用区返回 A 记录。 Marcin 的反应非常适合深潜。
有些人在这里说“是的,但我们仍然会超时。”。这是因为您的场景比 OP 更复杂。简而言之,您的 NLB 可能包含多个目标组,其中多个 AZ 中存在不同的目标。启用跨区域负载平衡将解决您的次优配置,但代价是您的账单上会产生额外的数据传输费用。胶带和口香糖包装纸在 AWS VPC 中工作。
更多信息:
NLB 对 DNS 是“聪明的”,因为它们的 VIP 只会解析到具有健康目标的 A 记录(在及时的原因内)。如果一个 NLB 有多个目标组,这些目标组具有跨三个 AZ 的不同实例,您将获得三个 A 记录返回(每个具有健康目标的 AZ 一个)。这就是 NLB + RR DNS 的工作原理。
但是,如果您的目标组在单个可用区中包含 EC2 实例,那么 DNS 循环法解析正确可用区的可能性为 33%(给定三个可用区)。
最好的办法是开启跨区负载均衡。这会增加数据传输成本,但对于打破 NLB 的替代方案来说并不复杂。请注意,启用跨区域负载平衡需要几分钟才能启动。不要启用它,立即启动 telnet 并在它不起作用时感到难过。等待 5 到 10 分钟,然后启动您的 telnet。
来源:使用 AWS 和 janky EC2 解决方案的轶事和实践经验。
,如果您在3个可用区中注册了一个NLB,但是在AZ1中只有一个目标EC2实例,那么流量将会如何?如果启用跨可用区负载平衡,那会有什么不同?
在这种特定情况下(3个可用区中的NLB,1个可用区中的单个实例),什么都没有发生。从最终用户的角度来看,无论是否有跨区域负载平衡,没有明显差异。无论哪种情况,该实例都可以访问。
为了验证这一点,我开发了一个简单的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中启用或禁用跨区域之间没有明显的区别。但是,长期差异可能是高可用性。也就是说,如果您禁用了跨区域,并且实例所在的可用区中的NLB节点发生故障,则NLB无法将流量从其他可用区路由到您的实例。这是我的推测,因为您无法手动检查。原因是,一旦将AZ /子网与NLB关联,就无法解除关联,以检查在这种情况下会发生什么。
相反,如果启用了跨区域,则在上述情况下,来自其他区域的NLB节点可能会跨区域将流量路由到实例。
启用跨区域流量的主要好处是,您different number of instances位于不同的可用区中。在这种情况下,跨区域平衡使所有实例将获得大致相同的流量。如果没有跨区域平衡,则隔离实例将比其他可用区中的实例集合获得更多的流量。
您可以使用第二个模板检查区域平衡的效果。该模板与以前几乎相同,但是现在1个可用区将具有3个实例,而另一个将具有1个可用区。
---
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网址,您将看到隔离的实例将获得大约50%的流量,而无需跨区域平衡。启用跨区域平衡后,它将达到20%。以下是根据100个请求得出的结果: