使用AWS re:Post即您表示您同意 AWS re:Post 使用条款

Sagemaker Batch Transform - “upstream prematurely closed connection” - 无法提供超过30分钟的请求服务。

0

【以下的问题经过翻译处理】 这是我在stackoverflow上问过的一个问题的副本。 我正在使用[AWS提供的指南]https://sagemaker-examples.readthedocs.io/en/latest/advanced_functionality/scikit_bring_your_own/scikit_bring_your_own.html#When-should-I-build-my-own-algorithm-container%3F通过自定义docker容器提供Sagemaker模型。这个docker容器运行一个简单的nginx->gunicorn/wsgi->flask服务器。 我的问题是,无论在哪个实例中,转换请求都会在约30分钟时超时,尽管应该能够一直持续到60分钟。由于请求数据密集,我需要使请求能够达到最大60分钟。通过几个月的调试经验,我知道有3个因素应影响服务器响应请求所需的时间:

  1. Sagemaker根据创建批处理转换作业时设置的“InvocationsTimeoutInSeconds”参数https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_ModelClientConfig.html#sagemaker-Type-ModelClientConfig-InvocationsTimeoutInSeconds
  2. nginx.conf配置文件里keepalive_timeout、proxy_read_timeout、proxy_send_timeout和proxy_connect_timeout都等于或大于最大超时。
  3. Gunicorn服务器必须配置为超时等于或大于最大超时。

我已验证,在创建批处理转换作业时,InvocationsTimeoutInSeconds设置为3600(1小时)。

nginx.conf配置如下:

worker_processes 1; daemon off; # Prevent forking

pid /tmp/nginx.pid; error_log /var/log/nginx/error.log;

events {

defaults

}

http { include /etc/nginx/mime.types; default_type application/octet-stream; access_log /var/log/nginx/access.log combined;

sendfile on; client_max_body_size 30M; keepalive_timeout 3920s;

upstream gunicorn { server unix:/tmp/gunicorn.sock; }

server { listen 8080 deferred; client_max_body_size 80m;

keepalive_timeout 3920s;
proxy_read_timeout 3920s;
proxy_send_timeout 3920s;
proxy_connect_timeout 3920s;
send_timeout 3920s;

location ~ ^/(ping|invocations) {
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;
  proxy_redirect off;
  proxy_pass http://gunicorn;
}

启动gunicorn服务如下:

def start_server():
print('Starting the inference server with {} workers.'.format(model_server_workers))
print('Model server timeout {}.'.format(model_server_timeout))

# link the log streams to stdout/err so they will be logged to the container logs
subprocess.check_call(['ln', '-sf', '/dev/stdout', '/var/log/nginx/access.log'])
subprocess.check_call(['ln', '-sf', '/dev/stderr', '/var/log/nginx/error.log'])

nginx = subprocess.Popen(['nginx', '-c', '/opt/program/nginx.conf'])
gunicorn = subprocess.Popen(['gunicorn',
                             '--timeout', str(3600),
                             '-k', 'sync',
                             '-b', 'unix:/tmp/gunicorn.sock',
                             '--log-level', 'debug',
                             '-w', str(1),
                             'wsgi:app'])

signal.signal(signal.SIGTERM, lambda a, b: sigterm_handler(nginx.pid, gunicorn.pid))

# If either subprocess exits, so do we.
pids = set([nginx.pid, gunicorn.pid])
while True:
    pid, _ = os.wait()
    if pid in pids:
        break

sigterm_handler(nginx.pid, gunicorn.pid)
print('Inference server exiting')

尽管如此,只要转换作业花费的时间超过30分钟,我就会在日志中看下面的内容,并且转换作业状态变为失败: 2023/01/07 08:23:14 [error] 11#11: *4 upstream prematurely closed connection while reading response header from upstream, client: 169.254.255.130, server: , request: "POST /invocations HTTP/1.1", upstream: "http://unix:/tmp/gunicorn.sock:/invocations", host: "169.254.255.131:8080"

我认为AWS批量转换中存在错误,但也许我缺少一些其他变量(可能在nginx.conf 中),这些变量可能会导致我的上游请求过早终止。

location / {
  return 404 "{}";
}

} }`

我像这样启动gunicorn服务器:(代码部分不翻译)尽管如此,每当转换作业持续时间超过约30分钟时,我会在日志中看到该消息,并且转换作业状态将变为失败。我接近认为AWS批处理转换存在缺陷,但也许我错过了其它一些变量(或许是在nginx.conf中)可能会导致请求的上游提前终止。

profile picture
专家
已提问 1 年前112 查看次数
1 回答
0

【以下的回答经过翻译处理】 通过查看硬件指标确定上游终止仅在服务器接近其内存限制时发生。所以猜测是操作系统正在杀死 gunicorn worker,而 0分钟标记只是长期运行的测试用例中发生的巧合。

我的解决方案是增加服务器上的可用内存

profile picture
专家
已回答 1 年前

您未登录。 登录 发布回答。

一个好的回答可以清楚地解答问题和提供建设性反馈,并能促进提问者的职业发展。

回答问题的准则