AWS Elastic Load Balancer:将请求转发到所有实例

Par*_*ggi 0 load-balancing amazon-ec2 amazon-web-services terraform

使用 Terraform 在 AWS 中创建 Autoscaling Group(有 2 个实例)和 Elastic Load Balancer (ELB)。

这些实例在端口 3000 上运行用 Go 编写的简单http-echo服务器。

当通过浏览器访问负载均衡器的 DNS 名称时,请求会记录在两个实例中,而不是一个。预期行为应该是向其中一个实例发送请求。

Instance1 的日志:

2019/01/23 05:03:53 <DNS Name of LB> 
10.0.21.217:31904 "GET /favicon.ico HTTP/1.1" 200 58 
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) 
Chrome/71.0.3578.98 Safari/537.36" 9.018µs
Run Code Online (Sandbox Code Playgroud)

Instance2的日志:

2019/01/23 05:03:53 <DNS Name of LB> 
10.0.21.217:47620 "GET / HTTP/1.1" 200 58 
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/71.0.3578.98 Safari/537.36" 9.074µs
Run Code Online (Sandbox Code Playgroud)

但是当请求发送curl到同一地址时,负载均衡器按预期工作,只将请求发送到实例之一,并且还会在重复请求时循环遍历实例。这是期望的行为。

curl请求日志:

2019/01/23 05:43:15 <DNS Name of LB> 10.0.21.217:49364 
"GET / HTTP/1.1" 200 58 "curl/7.47.0" 8.397µs
Run Code Online (Sandbox Code Playgroud)

两个实例都“健康”并响应负载均衡器的健康请求。

负载均衡器的配置如下:

resource "aws_elb" "go_app" {
  name               = "terraform-asg-go-app"
  security_groups    = ["${aws_security_group.elastic_lb.id}"]
  subnets            = ["${aws_subnet.public.*.id}"]

  listener {
    lb_port           = 80
    lb_protocol       = "http"
    instance_port     = 3000
    instance_protocol = "http"
  }

  cross_zone_load_balancing   = true
  idle_timeout                = 400
  connection_draining         = true
  connection_draining_timeout = 400
}
Run Code Online (Sandbox Code Playgroud)

负载均衡器安全组具有以下配置:

resource "aws_security_group" "elastic_lb" {
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
Run Code Online (Sandbox Code Playgroud)

虽然实例安全组具有以下配置:

resource "aws_security_group" "go_app" {    
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 3000 
    to_port     = 3000
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
Run Code Online (Sandbox Code Playgroud)

aan*_*dis 5

这是预期的行为。查看两个实例中获取的路径 -

实例 1

10.0.21.217:31904 "GET /favicon.ico HTTP/1.1" 200 58 
Run Code Online (Sandbox Code Playgroud)

实例2

10.0.21.217:47620 "GET / HTTP/1.1" 200 58
Run Code Online (Sandbox Code Playgroud)

第二个请求获取页面本身,第一个请求获取页面的图标。当您部署 Web 应用程序时,浏览器会发出单独的请求来获取与您的 Web 应用程序相关的所有资产,图标就是这样的资产之一。其他资产可能是 css/js 文件、图像等。所有引用的资产都被单独提取,然后呈现在页面上。

当浏览器发出多个请求时,它们会命中负载均衡器,然后负载均衡器将请求分发给它后面的实例,通常以循环方式,这就是为什么您会在两个实例上看到单独的请求。

curl 另一方面,它只是获取 html 页面,不会发出任何额外的请求。