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
EXPERTE
gefragt vor 8 Monaten90 Aufrufe
1 Antwort
0

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

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

profile picture
EXPERTE
beantwortet vor 8 Monaten

Du bist nicht angemeldet. Anmelden um eine Antwort zu veröffentlichen.

Eine gute Antwort beantwortet die Frage klar, gibt konstruktives Feedback und fördert die berufliche Weiterentwicklung des Fragenstellers.

Richtlinien für die Beantwortung von Fragen