如何解决 Amazon ECS 中的“OutOfMemory”问题?

2 分钟阅读
0

我想解决我的 Amazon Elastic Container Service (Amazon ECS) 任务中的内存使用问题。或者,由于“OutOfMemory”错误,Amazon ECS 任务中的容器退出了。

简短描述

默认情况下,容器没有资源限制,并且可以使用主机的内核调度器允许的任意数量的资源。使用 Docker 可以控制容器使用的内存量。切勿让正在运行的容器消耗主机的大部分内存。在 Linux 主机上,当内核检测到内存不足以执行重要的系统功能时,便会抛出 OutOfMemory 异常。然后,内核将结束进程以释放内存。

在 Docker 中,您可以使用以下任一内存限制:

  • 硬内存限制:允许容器使用不超过一定数量的用户或系统内存
  • 软限制:允许容器使用必要的内存,除非出现某些情况,例如内存不足或主机争用

当 Amazon ECS 任务因 OutOfMemory 错误而结束时,Amazon ECS 控制台可能会显示以下错误消息。要查看消息,请选择任务 ID,然后参阅详细信息部分以查看容器的详细信息:

OutOfMemoryError: Container killed due to memory usage

在这种情况下,任务中的容器会退出,因为容器的进程消耗的内存超过了任务定义中分配的内存量。

解决方法

要排除 Amazon ECS 任务中的“OutOfMemory”错误,请完成以下步骤:

stats max(MemoryUtilized) as mem, max(MemoryReserved ) as memreserved by bin (5m) as period, TaskId, ContainerName| sort period desc | filter ContainerName like "example-container-name" | filter TaskId = "example-task-id"

要降低由于 OutOfMemory 错误导致任务不稳定的风险,请完成以下步骤:

  • 在将应用程序投入生产之前,执行测试以了解应用程序的内存需求。您可以在主机或服务器内的容器上执行负载测试。然后,使用 docker stats(从 Docker Docs 网站)检查容器的内存使用情况。
  • 确保仅在资源充足的主机上运行应用程序。
  • 限制容器可以使用的内存量。为容器的硬限制和软限制设置适当的值。Amazon ECS 使用多个参数为任务分配内存:memoryReservation 用于软限制,memory 用于硬限制。指定这些值后,容器所在容器实例的可用内存资源便会扣除相应数量。**注意:**Windows 容器不支持 memoryReservation 参数。
  • 您可以为具有高瞬态内存需求的容器启用交换功能。这样做可以降低容器处于高负载状态时出现 OutOfMemory 错误的几率。**注意:**如果所用任务使用 AWS Fargate 启动类型,则不支持参数 maxSwapsharedMemorySize。**重要事项:**在 Docker 主机上配置交换功能时需谨慎。启用交换功能可能会减慢应用程序的速度并降低其性能。但是,此功能可防止应用程序耗尽系统内存。

要检测因 OutOfMemory 事件而结束的 Amazon ECS 任务,请使用以下 AWS CloudFormation 模板。使用此模板可以创建 Amazon EventBridge 规则、Amazon Simple Notification Service (Amazon SNS) 主题和 Amazon SNS 主题策略。运行模板时,模板会要求提供电子邮件列表、主题名称和用于开启或关闭监控的标记:

AWSTemplateFormatVersion: 2010-09-09
Description: >
        - Monitor OOM Stopped Tasks with EventBridge rules with AWS CloudFormation.

Parameters:
  EmailList:
    Type: String
    Description: "Email to notify!"
    AllowedPattern: '[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z]+'
    Default: "mail@example.com"

  SNSTopicName:
    Type: String
    Description: "Name for the notification topic."
    AllowedPattern: '[a-zA-Z0-9_-]+'
    Default: "oom-monitoring-topic"

  MonitorStatus:
    Type: String
    Description: "Enable / Disable monitor."
    AllowedValues:
      - ENABLED
      - DISABLED
    Default: ENABLED

Resources:
  SNSMonitoringTopic:
    Type: AWS::SNS::Topic
    Properties:
      Subscription:
        - Endpoint: !Ref EmailList
          Protocol: email
      TopicName: !Sub ${AWS::StackName}-${SNSTopicName}

  SNSMonitoringTopicTopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties:
      Topics:
        - !Ref SNSMonitoringTopic
      PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Sid: SnsOOMTopicPolicy
            Effect: Allow
            Principal:
              Service: events.amazonaws.com
            Action: [  'sns:Publish' ]
            Resource: !Ref SNSMonitoringTopic
          - Sid: AllowAccessToTopicOwner
            Effect: Allow
            Principal:
              AWS: '*'
            Action: [  'sns:GetTopicAttributes',
                       'sns:SetTopicAttributes',
                       'sns:AddPermission',
                       'sns:RemovePermission',
                       'sns:DeleteTopic',
                       'sns:Subscribe',
                       'sns:ListSubscriptionsByTopic',
                       'sns:Publish',
                       'sns:Receive' ]
            Resource: !Ref SNSMonitoringTopic
            Condition:
              StringEquals:
                'AWS:SourceOwner': !Ref 'AWS::AccountId'

  EventRule:
    Type: AWS::Events::Rule
    Properties:
      Name: ECSStoppedTasksEvent
      Description: Triggered when an Amazon ECS Task is stopped
      EventPattern:
        source:
          - aws.ecs
        detail-type:
          - ECS Task State Change
        detail:
          desiredStatus:
            - STOPPED
          lastStatus:
            - STOPPED
          containers:
            reason:
              - prefix: "OutOfMemory"
      State: !Ref MonitorStatus
      Targets:
        - Arn: !Ref SNSMonitoringTopic
          Id: ECSOOMStoppedTasks
          InputTransformer:
            InputPathsMap:
              taskArn: $.detail.taskArn
            InputTemplate: >
                "Task '<taskArn>' was stopped due to OutOfMemory."

创建 CloudFormation 堆栈后,验证电子邮件以确认订阅。任务因 OutOfMemory 问题而结束后,系统会向您发送一封电子邮件,其中包含类似于以下示例的消息:

"Task 'arn:aws:ecs:eu-west-1:555555555555:task/ECSFargate/0123456789abcdef0123456789abcdef' was stopped due to OutOfMemory."

相关信息

如何解决 Amazon ECS 任务在容器退出时停止或无法启动的问题?

AWS 官方
AWS 官方已更新 9 个月前