通过ALB连接优雅中断实现业务平稳下线

当您移除某个后端服务器或者后端服务器健康检查异常时,该后端服务器已建立的连接不会立即中断,客户端访问时仍持续有请求转发至这些后端服务器。此时会导致后端服务器的业务长期无法下线或出现请求错误。为了避免该问题,您可以使用ALB的连接优雅中断功能,当移除后端服务器或健康检查异常时,该后端服务器现有连接在一定时间内正常传输,到达中断时间后主动断开连接,保障业务平稳下线。

应用场景

连接优雅中断功能在以下两种场景下使用。

  • 移除后端服务器:移除后端服务器前应设置较长的连接优雅中断超时时间,以便最大程度将连接中的请求处理完成。

  • 健康检查异常:健康检查异常应设置较短的超时时间,以便尽快终止错误连接,避免用户发起请求后才收到连接异常。

由于以上两种场景共用连接优雅中断功能,您需要根据具体业务需求设置合适的优雅中断超时时间。

场景一:移除后端服务器

本文以下图场景为例进行说明。当移除后端服务器ECS01,ALB停止将请求发送到正在移除的后端服务器ECS01,此时ECS01只处理连接中的请求,不接收新的请求。

  • 关闭连接优雅中断功能,ECS01将在处理完连接中的所有请求后关闭会话。

  • 开启连接优雅中断功能并设置中断超时时间:

    • 如果移除的后端服务器ECS01有进行中的请求,ALB会在设置的优雅中断超时时间到达时关闭ECS01上的存量连接会话。

    • 如果移除的后端服务器ECS01中没有进行中的请求且没有活跃连接,ALB将立即完成移除过程,无需等待连接优雅中断超时时间。

    • 如果移除的后端服务器ECS01有正在发送的请求,对应的连接在移除过程结束时被终止,客户端将收到500错误响应(例如,设置的优雅中断超时时间为15秒,但ECS01的请求处理时间为30秒,实际ECS01还未发送完响应之前就会被中断,此时客户端会收到500错误响应)。

    说明

    移除后端服务器ECS01后再次新增ECS01,不会影响移除ECS01后已经开始优雅中断计时的存量连接会话。在存量连接会话关闭前ECS01的状态不会改变(即只处理连接中的请求,不接收新请求)。同时ALB会在设置的优雅中断超时时间到达时,关闭ECS01上的存量连接会话。

image

移除后端服务器ECS01,开启连接优雅中断功能并设置超时时间后,ECS01的状态流程如下图所示:

image

场景二:健康检查异常

后端服务器ECS01健康检查异常时,ALB停止将请求发送到ECS01。此时ECS01的状态只处理连接中的请求,不接收新请求。

  • 关闭连接优雅中断功能时,ECS01会一直处于该状态,直到健康检查成功后ECS01才会接收新请求。

  • 开启连接优雅中断并设置优雅中断超时时间:

    • ALB会在连接优雅中断超时时间到达时,关闭ECS01上的存量连接会话。

    • 如果发生了后端服务器组更新行为(例如更改ECS01的配置),ECS01的连接状态不会改变,即只处理连接中的请求,不接收新请求。即使更新后对应ECS01的健康检查成功,ALB仍旧会在连接优雅中断超时时间到达时,关闭ECS01上的存量连接会话。

    说明
    • 当ALB在连接优雅中断超时时间到达时,关闭ECS01上的存量连接会话,此时若健康检查正常,ECS01可以正常接收新请求。若健康检查异常,ECS01将不会接收新请求。

    • 配置更新过程中导致健康检查异常,不会触发连接优雅中断。系统只会对检测到后端服务器业务故障导致的健康检查异常,启动连接优雅中断。

    image

    后端服务器ECS01健康检查异常时,ECS01的状态流程如下图所示:

    image

您可以根据实际的业务场景配置连接优雅中断。本文以场景一:移除后端服务器为例,通过中断WebSocket会话和HTTP会话进行配置说明。

注意事项

  • 仅标准版和WAF增强版的ALB实例支持连接优雅中断,基础版ALB实例不支持。

  • 函数计算类型的服务器组不支持连接优雅中断。

  • 您可以在使用WebSocket协议时,开启连接优雅中断功能。若您仅在HTTP场景下使用,因HTTP请求有超时和请求个数限制,建议您设置的连接优雅中断超时时间大于ALB的连接请求超时时间(ALB默认设置的优雅中断超时时间,已大于连接请求超时时间),以防HTTP请求异常关闭。关于如何设置连接请求超时时间,请参见添加HTTP监听

前提条件

  • 您已创建标准版或WAF增强版ALB实例并为该ALB实例创建服务器类型的服务器组。本文以标准版ALB实例为例进行配置说明。具体操作,请参见创建应用型负载均衡创建和管理服务器组

  • 您已为该ALB实例配置HTTP监听且设置监听端口为80,该监听已关联服务器组。具体操作,请参见添加HTTP监听

  • 您已创建后端服务器ECS01和ECS02实例。具体操作,请参见自定义购买实例

  • 您已在服务器组中添加ECS02实例,且登录客户端可以访问服务器端ECS02中的服务。具体操作,请参见ALB快速实现IPv4服务的负载均衡ALB快速实现IPv6服务的负载均衡

    说明
    • 本文的客户端以Alibaba Cloud Linux 3.2104 64位操作系统为例,请确保您客户端的操作系统和后端服务器ECS01均安装了Python。如果您的操作系统未安装Python,请参考Python官网进行安装。本文以Python3.x为例进行配置说明。

    • 本文的后端服务器ECS02为业务正常运行的服务器,如果您已有该后端服务器,则无需创建。

配置步骤

开启连接优雅中断并设置中断超时时间后,本文通过演示中断WebSocket会话和HTTP会话,来展现ALB在不同优雅中断状态下对请求的处理效果。

WebSocket会话中断效果

步骤一:开启连接优雅中断

本文前提条件中已创建过服务器组,本步骤仅以编辑服务器组并开启连接优雅中断为例进行配置说明。如果您未创建服务器组,您也可以在创建服务器组时开启连接优雅中断功能。

  1. 登录应用型负载均衡ALB控制台
  2. 在顶部菜单栏,选择后端服务器组所属的地域。

  3. 在左侧导航栏,选择应用型负载均衡ALB > 服务器组

  4. 服务器组页面,找到目标服务器组,单击服务器组ID。

  5. 详细信息基本信息区域,单击编辑基本信息

  6. 编辑基本信息对话框,单击高级配置,然后开启连接优雅中断

  7. 设置连接优雅中断超时时间300秒,然后单击保存

步骤二:结果验证

登录服务器端进行配置

  1. 远程登录ECS01实例,具体操作,请参见ECS远程连接方式概述

  2. 执行以下命令创建一个WebSocket文件夹并进入WebSocket目录。

    mkdir WebSocket
    cd WebSocket
  3. 执行以下命令安装相关依赖包。

    pip install tornado
    pip install websocket-client
  4. 执行以下命令,编辑server.py配置文件。

    vim server.py
    1. i键切换至编辑模式,配置以下参数以启动一个WebSocket服务。

      #!/usr/bin/env python3
      # encoding=utf-8
      
      import tornado.websocket
      import tornado.ioloop
      import tornado.web
      from datetime import datetime
      
      
      # WebSocket处理程序
      class WebSocketHandler(tornado.websocket.WebSocketHandler):
          def open(self):
              current_time = datetime.now()
              formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
              print("时间:", formatted_time, "WebSocket连接已打开")
      
          def on_message(self, message):
              current_time = datetime.now()
              formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
              print("时间:", formatted_time, "接收到消息:", message)
              self.write_message("服务器收到了你的消息:" + message)
      
          def on_close(self):
              current_time = datetime.now()
              formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
              print("时间:", formatted_time, "WebSocket连接已关闭")
      
      # 路由
      application = tornado.web.Application([
          (r"/websocket", WebSocketHandler),
      ])
      
      if __name__ == "__main__":
          print("WebSocket Server Start on 8080 ...")
          application.listen(8080)
          tornado.ioloop.IOLoop.current().start()
      
    2. 修改完成后,按下Esc键,输入:wq并回车以保存并关闭配置文件。

  5. 进入server.py所在的目录,执行以下命令,启动WebSocket服务。

    python3 server.py

    当收到以下回复信息时,表示 WebSocket后端服务已开启。

    Websocket Server Start on 8080 ...

添加后端服务器ECS01到服务器组

  1. 登录应用型负载均衡ALB控制台
  2. 在顶部菜单栏,选择后端服务器组所属的地域。

  3. 在左侧导航栏,选择应用型负载均衡ALB > 服务器组

  4. 服务器组页面,找到目标服务器组,然后在操作列单击编辑后端服务器

  5. 后端服务器页签,单击添加后端服务器,然后在添加后端服务器面板选择ECS01并单击下一步

  6. 配置端口和权重配置向导中,勾选ECS01实例并设置端口为8080,然后单击确定

登录客户端进行配置

  1. 登录客户端,打开命令行窗口。执行以下命令创建一个WebSocket文件夹并进入WebSocket目录。

    mkdir WebSocket
    cd WebSocket
  2. 执行以下命令安装相关依赖包。

    pip install websocket-client
  3. 执行以下命令,编辑client.py文件。

    vim client.py
    1. i键切换至编辑模式,配置以下参数启动一个WebSocket Client访问服务。

      #!/usr/bin/env python3
      # encoding=utf-8
      
      import websocket
      import time
      from datetime import datetime
      
      def on_message(ws, message):
          print("接收到服务器的消息:", message)
      
      if __name__ == "__main__":
          ws = websocket.WebSocket()
          ws.connect("ws://<域名>:80/websocket") # 域名请根据实际情况配置
          print("WebSocket连接已打开")
          try:
              while True:
                  current_time = datetime.now()
                  formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
                  print("发送时间:", formatted_time)
                  ws.send("Hello, Server!")
                  result = ws.recv()
                  on_message(ws, result)
                  time.sleep(1)
          except Exception:
              print("WebSocket连接已关闭")
      
    2. 修改完成后,按下Esc键,输入:wq并回车以保存并关闭配置文件。

  4. 进入client.py所在的目录,执行以下命令,访问ECS01服务器端。

    python3 client.py

    当收到以下回复信息时,表示访问成功。

    WebSocket连接已打开
    发送时间: 2024-04-28 17:00:53
    接收到服务器的消息: 服务器收到了你的消息:Hello, Server!
    发送时间: 2024-04-28 17:00:54
    接收到服务器的消息: 服务器收到了你的消息:Hello, Server!

    此时ECS01服务器端输出以下回复信息。

    WebSocket Server Start on 8080 ...
    时间: 2024-04-28 17:00:53 WebSocket连接已打开
    时间: 2024-04-28 17:00:53 接收到消息: Hello, Server!
    时间: 2024-04-28 17:00:54 接收到消息: Hello, Server!

移除后端服务器

重要

需要先设置优雅中断超时时间,再移除后端服务器。

  1. 登录应用型负载均衡ALB控制台
  2. 在顶部菜单栏,选择后端服务器组所属的地域。

  3. 在左侧导航栏,选择应用型负载均衡ALB > 服务器组

  4. 找到目标服务器组,单击服务器组ID。

  5. 单击后端服务器页签,找到目标后端服务器ECS01,然后在操作列单击移除

  6. 移除服务器对话框中,单击确定。

等待连接优雅中断

本文设置的优雅中断超时时间为300秒,因此通过测试结果可以看到ALB会在移除ECS01后约300秒终止会话。

说明

测试结果中ECS01服务端WebSocket连接打开到关闭的时间差为330秒,优雅中断超时时间为移除后端服务器ECS01至WebSocket连接关闭的时间,约为300秒。

  • 客户端输出以下回复信息。

    发送时间: 2024-04-28 17:06:23
    接收到服务器的消息: 服务器收到了你的消息:Hello, Server!
    发送时间: 2024-04-28 17:06:24
    WebSocket连接已关闭

  • ECS01服务端实例输出以下回复信息。

    时间: 2024-04-28 17:06:22 接收到消息: Hello, Server!
    时间: 2024-04-28 17:06:23 接收到消息: Hello, Server!
    时间: 2024-04-28 17:06:23 WebSocket连接已关闭

HTTP会话中断效果

HTTP场景下优雅中断超时时间连接请求超时时间以及后端服务器处理时长设置的不同,客户端收到的响应不同。

  • 优雅中断超时时间<后端服务器处理时长,则ECS01还未发送完响应之前就会被中断,此时客户端会收到500错误响应。

  • 后端服务器处理时长>连接请求超时时间,则ECS01会响应超时,此时客户端会收到504错误响应。

本文以优雅中断超时时间为15秒,后端服务器处理时长为30秒进行配置说明。在此场景下,ECS01在未发送完响应之前会被中断,客户端会收到500错误响应。

说明
  • 本文通过步骤二设置连接请求超时时间为60秒(默认值),已大于后端服务器处理时长(30秒),因此不会返回504错误响应,而会因为优雅中断超时时间(15秒)小于后端服务器处理时长(30秒)返回500错误响应。

  • 本文通过设置Python代码里的time.sleep函数,模拟后端服务器处理时长

步骤一:开启连接优雅中断

本文前提条件中已创建过服务器组,本步骤仅以编辑服务器组并开启连接优雅中断为例进行配置说明。如果您未创建服务器组,您也可以在创建服务器组时开启连接优雅中断功能。

  1. 登录应用型负载均衡ALB控制台
  2. 在顶部菜单栏,选择后端服务器组所属的地域。

  3. 在左侧导航栏,选择应用型负载均衡ALB > 服务器组

  4. 服务器组页面,找到目标服务器组,单击服务器组ID。

  5. 详细信息基本信息区域,单击编辑基本信息

  6. 编辑基本信息对话框,单击高级配置,然后开启连接优雅中断

  7. 设置连接优雅中断超时时间15秒,然后单击保存

步骤二:设置ALB连接请求超时时间

  1. 登录应用型负载均衡ALB控制台
  2. 在顶部菜单栏,选择ALB实例所属的地域。

  3. 实例页面,找到目标ALB实例,单击实例ID。

  4. 单击监听页签,找到目标HTTP监听,然后单击监听实例ID。

  5. 监听基本信息区域,单击编辑监听

  6. 编辑监听对话框,单击高级配置后的修改

  7. 修改连接请求超时时间60秒(默认值),然后单击保存

步骤三:设置域名解析

实际业务场景中,建议您使用自有域名,通过CNAME解析的方式将自有域名指向ALB实例域名。

  1. 在左侧导航栏,选择应用型负载均衡 ALB > 实例

  2. 实例页面,复制已创建的ALB实例的DNS名称。

  3. 执行以下步骤添加CNAME解析记录。

    说明

    对于非阿里云注册域名,需先将域名添加到云解析控制台,才可以进行域名解析设置。具体操作,请参见域名管理。如果您是阿里云注册的域名,请直接执行以下步骤。

    1. 登录域名解析控制台

    2. 权威域名解析页面,找到目标域名,在操作列单击解析设置

    3. 解析设置页面,单击添加记录

    4. 添加记录面板,配置以下信息完成CNAME解析配置,然后单击确定

      配置

      说明

      记录类型

      在下拉列表中选择CNAME

      主机记录

      您的域名的前缀。本文输入@

      说明

      创建域名为根域名时,主机记录为@

      解析请求来源

      选择默认。

      记录值

      输入域名对应的CNAME地址,即您复制的ALB实例的DNS名称。

      TTL

      全称Time To Live,表示DNS记录在DNS服务器上的缓存时间,本文使用默认值。

步骤四:结果验证

登录服务器端进行配置

  1. 远程登录ECS01实例,具体操作,请参见ECS远程连接方式概述

  2. 执行以下命令创建一个HTTP文件夹并进入HTTP目录。

    mkdir http
    cd http
  3. 执行以下命令编辑http_server.py配置文件。

    vim http_server.py
    1. i键切换至编辑模式,配置以下参数启动一个http server服务。

      #!/usr/bin/env python3
      # encoding=utf-8
      
      from http.server import SimpleHTTPRequestHandler, HTTPServer
      from datetime import datetime
      import time
      
      class DelayedHTTPRequestHandler(SimpleHTTPRequestHandler):
          def do_GET(self):
              current_time = datetime.now()
              formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
              print("时间:", formatted_time, "收到GET请求,延迟30秒响应....")
              time.sleep(30) # 设置time.sleep函数,模拟后端服务器处理时长
              SimpleHTTPRequestHandler.do_GET(self)
      
      PORT = 8080
      server = HTTPServer(("", PORT), DelayedHTTPRequestHandler)
      print(f"Serving HTTP on 0.0.0.0 port {PORT} (http://0.0.0.0:{PORT}/) ...")
      server.serve_forever()
      
    2. 修改完成后,按下Esc键,输入:wq并回车以保存并关闭配置文件。

  4. 进入http_server.py所在的目录,执行以下命令,启动http server服务。

    python3 http_server.py

    当收到以下回复信息时,表示http server后端服务已开启。

    Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...

添加后端服务器ECS01到服务器组

  1. 登录应用型负载均衡ALB控制台
  2. 在顶部菜单栏,选择后端服务器组所属的地域。

  3. 服务器组页面,找到目标服务器组,然后在操作列单击编辑后端服务器

  4. 后端服务器页签,单击添加后端服务器,然后在添加后端服务器面板选择ECS01并单击下一步

  5. 配置端口和权重配置向导中,勾选ECS01实例并设置端口为8080,然后单击确定

登录客户端进行配置

  1. 登录客户端,打开命令行窗口。执行以下命令访问后端服务器ECS01。

    curl http://<域名>:80/ -v

    当收到以下回复信息时,表示ALB可以访问后端服务。

    * About to connect() to www.example.com port 80 (#0)
    *   Trying 10.X.X.225...
    * Connected to www.example.com (10.X.X.225) port 80 (#0)
    > GET / HTTP/1.1
    > User-Agent: curl/7.29.0
    > Host: www.example.com
    > Accept: */*

    此时服务端收到如下回复信息。

    Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
    时间:2024-02-07 13:57:33 收到Get请求,延迟30秒响应....

移除后端服务器

重要

需要先设置优雅中断超时时间,再移除后端服务器。

  1. 登录应用型负载均衡ALB控制台
  2. 在顶部菜单栏,选择后端服务器组所属的地域。

  3. 在左侧导航栏,选择应用型负载均衡ALB > 服务器组

  4. 找到目标服务器组,单击服务器组ID。

  5. 单击后端服务器页签,找到目标后端服务器ECS01,然后在操作列单击移除

  6. 移除服务器对话框中,单击确定。

等待连接优雅中断

通过测试结果可以看出,当ALB设置的优雅中断超时时间<后端服务器处理时长时,客户端会收到500错误响应。

* About to connect() to www.example.com port 80 (#0)
*   Trying 10.X.X.224...
* Connected to www.example.com (10.XX.XX.224) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.example.com
> Accept: */*
> 
< HTTP/1.1 500 Internal Server Error
< Date: Wed, 07 Feb 2024 06:02:24 GMT
< Content-Type: text/html
< Content-Length: 186
< Connection: close
< Via: HTTP/1.1 SLB.87
< 
<html>
<head><title>500 Internal Server Error</title></head>
<body bgcolor="white">
<center><h1>500 Internal Server Error</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Closing connection 0

相关文档