[CRITICAL] WORKER TIMEOUT
์ค๋ฅ์ ๊ด๋ จํ์ฌ ์ด๋ฏธ ์ฌ๋ฌ ๋ณด๊ณ ์๊ฐ์๋ ๊ฒ ๊ฐ์ง๋ง ๊ณ์ ํ์
๋ฉ๋๋ค. ์ฌ๊ธฐ ๋ด ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
์ด Flask Hello World ์์ฉ ํ๋ก๊ทธ๋จ์ ์คํํ๊ณ ์์ต๋๋ค.
from flask import Flask
application = Flask(__name__)
@application.route('/')
def hello_world():
return 'Hello, World!'
gunicorn ๋ช ๋ น์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
gunicorn -b 0.0.0.0:5000 --log-level=debug hello
๊ทธ๋ฆฌ๊ณ ์ด๊ฒ์ ์ฝ์ ์ถ๋ ฅ์ ๋๋ค:
[2018-06-05 14:56:21 +0200] [11229] [INFO] Starting gunicorn 19.8.1
[2018-06-05 14:56:21 +0200] [11229] [DEBUG] Arbiter booted
[2018-06-05 14:56:21 +0200] [11229] [INFO] Listening at: http://0.0.0.0:5000 (11229)
[2018-06-05 14:56:21 +0200] [11229] [INFO] Using worker: sync
[2018-06-05 14:56:21 +0200] [11232] [INFO] Booting worker with pid: 11232
[2018-06-05 14:56:21 +0200] [11229] [DEBUG] 1 workers
[2018-06-05 14:56:32 +0200] [11232] [DEBUG] GET /
[2018-06-05 14:56:57 +0200] [11232] [DEBUG] Closing connection.
[2018-06-05 14:57:16 +0200] [11232] [DEBUG] GET /
[2018-06-05 14:57:47 +0200] [11229] [CRITICAL] WORKER TIMEOUT (pid:11232)
[2018-06-05 14:57:47 +0200] [11232] [INFO] Worker exiting (pid: 11232)
[2018-06-05 14:57:47 +0200] [11324] [INFO] Booting worker with pid: 11324
์ด ์์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ ์ด์ ์ ์์๋๋ ์ค๋ฅ๋ฅผ ๋ช ํํ๊ฒ ์ค๋ช ํด ์ฃผ์๊ฒ ์ต๋๊น? ์ด๋ป๊ฒ ์์ ํฉ๋๊น ๋๋ ์์๋๋ ๋์์ธ ๊ฒฝ์ฐ ์ฌ๊ฐํ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๊น?
์ค๋ฅ๊ฐ ์์๋์ง๋ ์์ง๋ง ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ ์ด์ ๋ฅผ ๋ณด์ฌ์ฃผ๋ ์์ ๋ ์์ต๋๋ค. ๊ทํ์ ํ๊ฒฝ์ ๋ํด ์์ธํ ์๋ ค์ฃผ์ญ์์ค.
๊ทํ์ ํ๊ฒฝ์ ๋ํด ์์ธํ ์๋ ค์ฃผ์ญ์์ค.
๋ฐฉ๊ธ ์์ ํ ์๋ก์ด ์ค์ ์์ ๋ฌธ์ ๋ฅผ ์ฌํํ์ต๋๋ค. ๋จ๊ณ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
mkdir gunicorn
cd gunicorn/
pipenv --python 3.6
pipenv install flask
pipenv install gunicorn
vim hello.py
pipenv shell
gunicorn -b 0.0.0.0:5000 --log-level=debug hello
hello.py
๋ ๋ด๊ฐ ์ด๊ธฐ ๋ณด๊ณ ์์ ๊ฒ์ํ ๊ฒ๊ณผ ์ ํํ ๋์ผํ Flask ์ ํ๋ฆฌ์ผ์ด์
์
๋๋ค.
์๋๋ ์ ์ฒด ๋ก๊ทธ์
๋๋ค.
~$ gunicorn -b 0.0.0.0:5000 --log-level=debug hello
[2018-06-06 09:16:21 +0200] [19829] [DEBUG] Current configuration:
config: None
bind: ['0.0.0.0:5000']
backlog: 2048
workers: 1
worker_class: sync
threads: 1
worker_connections: 1000
max_requests: 0
max_requests_jitter: 0
timeout: 30
graceful_timeout: 30
keepalive: 2
limit_request_line: 4094
limit_request_fields: 100
limit_request_field_size: 8190
reload: False
reload_engine: auto
reload_extra_files: []
spew: False
check_config: False
preload_app: False
sendfile: None
reuse_port: False
chdir: /home/dima/work/gunicorn
daemon: False
raw_env: []
pidfile: None
worker_tmp_dir: None
user: 1000
group: 985
umask: 0
initgroups: False
tmp_upload_dir: None
secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
forwarded_allow_ips: ['127.0.0.1']
accesslog: None
disable_redirect_access_to_syslog: False
access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"
errorlog: -
loglevel: debug
capture_output: False
logger_class: gunicorn.glogging.Logger
logconfig: None
logconfig_dict: {}
syslog_addr: udp://localhost:514
syslog: False
syslog_prefix: None
syslog_facility: user
enable_stdio_inheritance: False
statsd_host: None
statsd_prefix:
proc_name: None
default_proc_name: hello
pythonpath: None
paste: None
on_starting: <function OnStarting.on_starting at 0x7f9757112d08>
on_reload: <function OnReload.on_reload at 0x7f9757112e18>
when_ready: <function WhenReady.when_ready at 0x7f9757112f28>
pre_fork: <function Prefork.pre_fork at 0x7f9756c230d0>
post_fork: <function Postfork.post_fork at 0x7f9756c231e0>
post_worker_init: <function PostWorkerInit.post_worker_init at 0x7f9756c232f0>
worker_int: <function WorkerInt.worker_int at 0x7f9756c23400>
worker_abort: <function WorkerAbort.worker_abort at 0x7f9756c23510>
pre_exec: <function PreExec.pre_exec at 0x7f9756c23620>
pre_request: <function PreRequest.pre_request at 0x7f9756c23730>
post_request: <function PostRequest.post_request at 0x7f9756c237b8>
child_exit: <function ChildExit.child_exit at 0x7f9756c238c8>
worker_exit: <function WorkerExit.worker_exit at 0x7f9756c239d8>
nworkers_changed: <function NumWorkersChanged.nworkers_changed at 0x7f9756c23ae8>
on_exit: <function OnExit.on_exit at 0x7f9756c23bf8>
proxy_protocol: False
proxy_allow_ips: ['127.0.0.1']
keyfile: None
certfile: None
ssl_version: 2
cert_reqs: 0
ca_certs: None
suppress_ragged_eofs: True
do_handshake_on_connect: False
ciphers: TLSv1
raw_paste_global_conf: []
[2018-06-06 09:16:21 +0200] [19829] [INFO] Starting gunicorn 19.8.1
[2018-06-06 09:16:21 +0200] [19829] [DEBUG] Arbiter booted
[2018-06-06 09:16:21 +0200] [19829] [INFO] Listening at: http://0.0.0.0:5000 (19829)
[2018-06-06 09:16:21 +0200] [19829] [INFO] Using worker: sync
[2018-06-06 09:16:21 +0200] [19832] [INFO] Booting worker with pid: 19832
[2018-06-06 09:16:22 +0200] [19829] [DEBUG] 1 workers
[2018-06-06 09:16:48 +0200] [19832] [DEBUG] GET /
[2018-06-06 09:17:19 +0200] [19829] [CRITICAL] WORKER TIMEOUT (pid:19832)
[2018-06-06 09:17:19 +0200] [19832] [INFO] Worker exiting (pid: 19832)
[2018-06-06 09:17:19 +0200] [19872] [INFO] Booting worker with pid: 19872
^C[2018-06-06 09:17:26 +0200] [19829] [INFO] Handling signal: int
[2018-06-06 09:17:26 +0200] [19872] [INFO] Worker exiting (pid: 19872)
[2018-06-06 09:17:26 +0200] [19829] [INFO] Shutting down: Master
~$ pip list
Package Version
------------ -------
click 6.7
Flask 1.0.2
gunicorn 19.8.1
itsdangerous 0.24
Jinja2 2.10
MarkupSafe 1.0
pip 10.0.1
setuptools 39.2.0
Werkzeug 0.14.1
wheel 0.31.1
@bigunyak ๊ธฐ๋ณธ ์๊ฐ ์ด๊ณผ ๋๋ฌธ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ์์ ์๋ 30์ด ๋์ ์นจ๋ฌตํ์ต๋๋ค. http://docs.gunicorn.org/en/stable/settings.html#timeout
๊ทํ์ ๋ก๊ทธ์์,
[2018-06-05 14:57:16 +0200] [11232] [DEBUG] GET /
[2018-06-05 14:57:47 +0200] [11229] [CRITICAL] WORKER TIMEOUT (pid:11232)
[2018-06-06 09:16:48 +0200] [19832] [DEBUG] GET /
[2018-06-06 09:17:19 +0200] [19829] [CRITICAL] WORKER TIMEOUT (pid:19832)
๋์ผํ ๊ฒ์ ๋ณด๊ณ ์์ต๋๋ค. ๋๊ธฐํ ์์
์๋ฅผ ์ฌ์ฉํ์ฌ ์์ฒญ์ ์ ๊ณตํ์ง ์๋ ๊ฒฝ์ฐ์๋ ์์
์๊ฐ ์๊ฐ ์ด๊ณผ๋ฉ๋๋ค.
๊ทธ๋ฐ ์๋ฏธ์์ ์๊ณ ์์ค ๋ก๊ทธ๋ ์๋นํ ํผ๋์ค๋ฝ์ต๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ Gevent ์์ ์๋ฅผ ์ฌ์ฉํด ๋ณด์ญ์์ค.
๊ทธ๋ฐ ์๋ฏธ์์ ์๊ณ ์์ค ๋ก๊ทธ๋ ์๋นํ ํผ๋์ค๋ฝ์ต๋๋ค.
์ ํํ ๊ทธ๊ฒ์ ๋ด ์๋ ์ง๋ฌธ์ด์์ต๋๋ค. ์์๋๋ ๋์์ด๋ผ๋ฉด ์ ์ฌ๊ฐํ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๊น?
์์
์๋ฅผ ๋ค์ ์์ํด์ผ ํ๋ ์ด์ ์ ๋ํ ๋ฐฐ๊ฒฝ ์ง์์ ์ป๋ ๊ฒ๋ ์ข์ ๊ฒ์
๋๋ค. ์๋ง๋ ์ด๊ฒ์ด ์ค๊ณ ๋ฌธ์์ ์ถ๊ฐ๋ ์ ์์ ๊ฒ์
๋๋ค.
์ ๋ ์ด๊ฒ์ ๋ณด๊ณ ์์ผ๋ฉฐ( examples/test.py
with gunicorn test:app -b localhost:9595 --log-level=debug --timeout=5
๋ฅผ ์ฌ์ฉํ์ฌ ์ฌํํจ) ์๊ณ ์์ค์ด ์ฝ๊ฐ ํผ๋์ค๋ฝ๋ค๋ ๋ฐ ๋์ํฉ๋๋ค. ๋๋ฒ๊ทธ ์์ค์ผ๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์ด ์ข์ต๋๋ค. @benoitc @tilgovi ์ด๋ป๊ฒ ์๊ฐํ์ธ์?
์ ๋ณด ์์ค์ด ์กฐ๊ธ ๋ ๋์ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
๋๋ Win10์ MSYS2์ ๋์ผํ์ง๋ง ๋ง์นจ๋ด ํด๊ฒฐํ ์์์์ต๋๋ค.
...\gunicorn\workers\workertmp.py์ notify()์์๋ ์๋ os.fchmod๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๊ทธ๋ฌ๋ MSYS์์๋ ์๋ํ์ง ์์ต๋๋ค. os.fchmod ๋์ os.utime์ ์ฌ์ฉํ์ต๋๋ค. ์ฝ๋๋ฅผ ๋ฐ๋ฆ ๋๋ค. ๋ชจ๋ ํ๋ซํผ์์ ์๋ํ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
def notify(self):
try:
self.spinner = (self.spinner + 1) % 2
os.fchmod(self._tmp.fileno(), self.spinner)
if PLATFORM.startswith('MSYS') :
os.utime(self._tmp.fileno(), None)
except AttributeError:
# python < 2.6
self._tmp.truncate(0)
os.write(self._tmp.fileno(), b"X")
@berkerpeksag ์์ฒญ์ด ๋ฐ์ํ์ง ์๊ธฐ ๋๋ฌธ์ ์์ ์๊ฐ ์ข ๋ฃ๋ ๊ฒ์ผ๋ก ์์ํ์ง ์์ต๋๋ค. ์ด ์ค๋ฅ๋ ์์ ์๊ฐ ์๊ฐ ์ด๊ณผ๊น์ง > ๋์ ๋ฐ์๊ฒ ์ ์ง๋ ๊ฒฝ์ฐ์๋ง ๋ฐ์ํฉ๋๋ค. ๋ฐ๋ผ์ ์ค๋ฅ๊ฐ ์ค์ํฉ๋๋ค. ๋ ๋ง์ ์ฌ์ฉ ์ฌ๋ก์ ์ด๋ฌํ ์ค๋ฅ์ ๋ํ ์๋ต์ ์ ๊ณตํ๊ธฐ ์ํด ๋ฌธ์๋ฅผ ๊ฐ์ ํด์ผ ํฉ๋๋ค.
์์ ์๊ฐ ๋ฐ์์ง ์์ ๋ ์ค๋ฅ๊ฐ ๊ณ์ ๋ฐ์ํ๋ฉด ๋ค๋ฅธ ์ผ์ด ๋ฐ์ํ๊ณ ์์ผ๋ฉฐ ์๋ง๋ ๋ฒ๊ทธ๊ฐ ์๋ ๊ฒ์ ๋๋ค.
[ํธ์งํ๋ค]
๋์๊ฒ๋ ๊ฐ์ ๋ฒ๊ทธ.
Django 1.10 / gunicorn 19.6.0 / Python 2.7.15 in python2.7-alpine on Debian 8.8 ๋ฐ ์คํก ์ปค๋ 3.16์์๋ ๋ชจ๋ ์ ์๋ํ์ต๋๋ค.
Django 1.11 ๋ฐ gunicorn 19.8.1๋ก ์
๋ฐ์ดํธํ ํ ์์
์๊ฐ [CRITICAL WORKER TIMEOUT]๊ณผ ํจ๊ป ๋ถํ
์ ๊ณ์ ์คํจํฉ๋๋ค.
gunicorn์ 19.6.0์ผ๋ก ๋ค์ด๊ทธ๋ ์ด๋ํด๋ ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์ง ์์ต๋๋ค.
ํธ์คํธ ์ปค๋์ 4.9.0(์์ )์ผ๋ก ์
๋ฐ์ดํธํ๊ณ ์์
์๋ ์ค๋ฅ ์์ด ์ฑ๊ณต์ ์ผ๋ก ๋ถํ
๋์์ต๋๋ค.
ํ์ง๋ง:
์ฑ์ ๋ค์ ์จ๋ผ์ธ ์ํ๋ก ๋ง๋ค ์ ์๋์ง ํ์ธํ๊ธฐ ์ํด gunicorn gevent๋ฅผ ์๋ํ ๊ฒ์ ๋๋ค.
gevent์ ํจ๊ป gunicorn์ ์ฌ์ฉํด๋ ๋ฒ๊ทธ๊ฐ ์์ ๋์ง ์์์ต๋๋ค.
์ด ๋ฌธ์ ์ ๋ํ ์ ๋ฐ์ดํธ๊ฐ ์์ต๋๊น?
@neocolor ๊ฐ MSYS์์ ์ค์ ๋ฒ๊ทธ๋ฅผ ์๋ณํ ๊ฒ ๊ฐ์ต๋๋ค. ๋ณ๋์ ๋ฌธ์ ๊ฐ ๋ ์ ์์ต๋๋ค.
@bigunyak ์ด๋ค ํ๋ซํผ์์ ์คํ ์ค์ ๋๊น? ๊ฐ๋จํ ์์ ๋ก ์ฌํ์ ์๋ํ์ง๋ง ์์ ์ค๋ช ๋ ๋จ๊ณ๋ฅผ ์ ํํ ๋ฐ๋ผ ์ํํ ์ ์์ต๋๋ค. ์ด๋ ์ฌ๋ฌ ํ๋ ์์ํฌ์์ ํ๋ก๋์ ํ๊ฒฝ์์ ์ฌ๋ฌ ์์ฉ ํ๋ก๊ทธ๋จ์ ์คํํ ์ ๊ฒฝํ๊ณผ ์ผ์นํฉ๋๋ค. ๋ด๊ฐ ์๋ ํ ๊ทผ๋ก์ ์๋ฆผ ์์คํ ์ ์ต๊ทผ์ ๋ณ๊ฒฝ๋์ง ์์์ต๋๋ค. ๋ด ํ๋ซํผ์ MacOS 10.13.6์ Python 3.7์ด์ง๋ง Python 2.7 ๋ฐ 3.6.5์ ์ฌ๋ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ํด ๋๊ธฐํ ์์ ์์ ํจ๊ป ํ๋ก๋์ ํ๊ฒฝ์์ Gunicorn์ ์คํํ๊ณ ์์ ์๋ฅผ ์ฐจ๋จํ๋ ํฉ๋ฒ์ ์ผ๋ก ๊ธด ์์ฒญ์ด ์๋ ๊ฒฝ์ฐ์๋ง ์์ ์ ์๊ฐ ์ด๊ณผ๊ฐ ํ์๋ฉ๋๋ค.
@Tberdy์ ๊ฒฝ์ฐ : --worker-tmp-dir
๋ฅผ tmpfs ํ์ผ ์์คํ
์ธ๋ถ์ ์ด๋๊ฐ๋ก ์ค์ ํ๋ ค๊ณ ํ๋ฉด ์ด๋ป๊ฒ ๋ฉ๋๊น? ์ํ์ธ ๋๋ ๋์ปค ๋๋ ์กฐํฉ์ด ์์
์๊ฐ ์ค์ฌ์์๊ฒ ์๋ฆฌ๋ ๋ฐฉ์์ ์ด๋ป๊ฒ๋ ๋ฐฉํดํ๋์ง ๊ถ๊ธํฉ๋๋ค.
Docker ๊ด๋ จ tmpfs ๋ฌธ์ ๋ #1388๋ ์ฐธ์กฐํ์ธ์.
๋๋์ด ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
์ ๋ ์ด ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ์ด์ ๋ฐค๊น์ง gunicorn sync๊ฐ ์๋ฒฝํ๊ฒ ์๋ํ์ง๋ง ๋ณด๊ณ ๋ฅผ ์์ํ์ผ๋ฉฐ gevent๋ฅผ ์ฌ์ฉํ๋ ์์ ์ ์๊ฐ ์ด๊ณผ [CRITICAL]์ด ๋ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ฒ ๊ฐ์ง๋ง ์ ์ด๋ฐ ์ผ์ด ๋ฐ์ํ๋์ง ์๊ณ ์ถ์ต๋๋ค.
@timoj58 @cjmash ์ด ๋ฌธ์ ์ ๋ํด ๋ ์์ธํ ์๋ ค ์ฃผ์ค ์ ์์ต๋๊น? ์ด๋ค ํ์ผ ์์คํ , OS์์ gunicorn(vm์์?, ์ต์ ...)์ ์ด๋ป๊ฒ ์คํํ๊ณ ์์ต๋๊น? ๋ฒ์์ ๋์์ด ๋ ์ ์๋ ANthing์ ๋งค์ฐ ๋์์ด ๋ ๊ฒ์ ๋๋ค :)
@benoitc kubernetes์์ ๋ด Django ํ๋ก์ ํธ๋ฅผ ์์ํ๊ธฐ ์ํด gunicorn์ ์คํ ์ค์ ๋๋ค. ๋ด gunicorn ์ธ์๋ --bind=$port --workers=7 --timeout=1200 --log-level=debug --access-logfile - error-logfile - "
๋ด๊ฐ ๋ก๊ทธ์์ ์ป๋ ์ค๋ฅ
```E [2018-08-09 21:47:56 +0000] [13] [INFO] pid๊ฐ ์๋ ๋ถํ ์์ ์: 13
E [2018-08-09 21:47:56 +0000] [14] [INFO] pid: 14๋ก ์์ ์ ๋ถํ
E [2018-08-09 21:47:56 +0000] [12] [INFO] pid๊ฐ 12์ธ ๋ถํ ์์ ์
E [2018-08-09 21:47:56 +0000] [1] [DEBUG] ์์ ์ 7๋ช
E [2018-08-09 21:47:56 +0000] [11] [INFO] pid๊ฐ 11์ธ ์์ ์ ๋ถํ
E [2018-08-09 21:47:55 +0000] [10] [INFO] pid๊ฐ ์๋ ์์ ์ ๋ถํ : 10
E [2018-08-09 21:47:55 +0000] [9] [INFO] pid: 9๋ก ์์ ์ ๋ถํ
E [2018-08-09 21:47:55 +0000] [8] [INFO] pid๊ฐ 8์ธ ์์ ์ ๋ถํ
E [2018-08-09 21:47:55 +0000] [1] [INFO] ์์ ์ ์ฌ์ฉ: ๋๊ธฐํ
E [2018-08-09 21:47:55 +0000] [1] [INFO] ๋ฃ๊ธฐ: http://0.0.0.0 :4040 (1)
E [2018-08-09 21:47:55 +0000] [1] [DEBUG] Arbiter ๋ถํ ๋จ
E [2018-08-09 21:47:55 +0000] [1] [INFO] ๊ธฐ๋์ฝ ์์ 19.7.1
E raw_paste_global_conf: []
์ ์ ์ํธ: TLSv1
E do_handshake_on_connect: ๊ฑฐ์ง
E suppress_ragged_eofs: ์ฐธ
E ca_certs: ์์
์ ์ cert_reqs: 0
E SSL_๋ฒ์ : 2
์ ์ ์ธ์ฆ์ ํ์ผ: ์์
E ํค ํ์ผ: ์์
E proxy_allow_ips: ['127.0.0.1']
E proxy_protocol: ๊ฑฐ์ง
E on_exit:
E nworkers_changed:
E ์์
์_์ข
๋ฃ:
E child_exit:
์ ์ ์ฐํธ ์์ฒญ:
E ์ฌ์ ์์ฒญ:
E pre_exec:
E ์์
์_์ค๋จ:
E ์์
์_int:
E post_worker_init:
์ ์ ํฌ์คํธ_ํฌํฌ:
E pre_fork:
E when_ready:
E on_reload:
E on_starting:
E ๋ถ์ฌ๋ฃ๊ธฐ: ์์
E ํ์ด์ฌ ๊ฒฝ๋ก: ์์
E default_proc_name: art.wsgi
E proc_name: ์์
E statsd_prefix:
E statsd_host: ์์
E enable_stdio_inheritance: ๊ฑฐ์ง
E syslog_facility: ์ฌ์ฉ์
E syslog_prefix: ์์
E ์์คํ ๋ก๊ทธ: ๊ฑฐ์ง
E syslog_addr: udp://localhost :514
E logconfig: ์์
E logger_class: gunicorn.glogging.Logger
E capture_output: ๊ฑฐ์ง
E ๋ก๊ทธ ์์ค: ๋๋ฒ๊ทธ
E ์ค๋ฅ ๋ก๊ทธ: -
E access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%( ์ฒ๋ผ"
์ ์ ์ก์ธ์ค ๋ก๊ทธ: -
E forwarded_allow_ips: ['127.0.0.1']
E secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
E tmp_upload_dir: ์์
E ์ด๊ธฐ ๊ทธ๋ฃน: False
์ ๋ง์คํฌ: 0
E ๊ทธ๋ฃน: 0
์ ์ ์ฌ์ฉ์: 0
E worker_tmp_dir: ์์
E pidfile: ์์
E raw_env: []
E ๋ฐ๋ชฌ: ๊ฑฐ์ง
E chdir: /usr/src/app
E sendfile: ์์
E preload_app: ๊ฑฐ์ง
E check_config: ๊ฑฐ์ง
E ๋ถ์ถ: ๊ฑฐ์ง
E reload_engine: ์๋
E ์ฌ์ฅ์ : ๊ฑฐ์ง
E limit_request_field_size: 8190
E limit_request_fields: 100
E limit_request_line: 4094
์ ์ ํต์ผ๋ผ์ด๋ธ: 2
E Graceful_timeout: 30
์ ์ ํ์์์: 1200
E max_requests_jitter: 0
E max_requests: 0
E ์์ ์_์ฐ๊ฒฐ: 1000
E ์ค๋ ๋: 1
E worker_class: ๋๊ธฐํ
์ ์ ์์ ์: 7
์ ์ ๋ฐฑ๋ก๊ทธ: 2048
์ ์ ๋ฐ์ธ๋: ['0.0.0.0:4040']
์ ์ ๊ตฌ์ฑ: ์์
E [2018-08-09 21:47:55 +0000] [1] [DEBUG] ํ์ฌ ๊ตฌ์ฑ:
I ์ ์ฒญํ ๋ง์ด๊ทธ๋ ์ด์ ์ด ์์ต๋๋ค.
I ๋ง์ด๊ทธ๋ ์ด์ ์คํ:
I ๋ชจ๋ ๋ง์ด๊ทธ๋ ์ด์ ์ ์ฉ: admin, auth, contenttypes, core, ๋์๋ณด๋, jet, oauth2_provider, session
I ์ํํ ์์ :
E [2018-08-09 21:47:20 +0000] [13] [INFO] ์์ ์ ์ข ๋ฃ (pid: 13)
E os.path.dirname(os.path.dirname(__file__)), '.env'))
E /usr/src/app/art/wsgi.py:19: UserWarning: ์ฝ์ง ์์ /usr/src/app/.env - ์กด์ฌํ์ง ์์ต๋๋ค.
E [2018-08-09 21:47:00 +0000] [21] [INFO] pid: 21๋ก ์์ ์ ๋ถํ
E [2018-08-09 21:47:00 +0000] [1] [INFO] ์ฒ๋ฆฌ์ ํธ : ๊ธฐ๊ฐ
E [2018-08-09 21:46:35 +0000] [12] [INFO] pid: 12๋ก ์์ ์ ๋ถํ
E [2018-08-09 21:46:34 +0000] [13] [INFO] pid๊ฐ 13์ธ ๋ถํ ์์ ์
E [2018-08-09 21:46:34 +0000] [11] [INFO] pid๊ฐ 11์ธ ์์ ์ ๋ถํ
E [2018-08-09 21:46:34 +0000] [1] [DEBUG] ์์ ์ 7๋ช
E [2018-08-09 21:46:34 +0000] [10] [INFO] pid๊ฐ 10์ธ ์์ ์ ๋ถํ
E [2018-08-09 21:46:34 +0000] [9] [INFO] pid๊ฐ 9์ธ ์์ ์ ๋ถํ
E [2018-08-09 21:46:34 +0000] [8] [INFO] pid๊ฐ 8์ธ ์์ ์ ๋ถํ
E [2018-08-09 21:46:34 +0000] [7] [INFO] pid๊ฐ 7์ธ ์์ ์ ๋ถํ
E [2018-08-09 21:46:34 +0000] [1] [INFO] ์์ ์ ์ฌ์ฉ: ๋๊ธฐํ
E [2018-08-09 21:46:34 +0000] [1] [INFO] ๋ฃ๊ธฐ: http://0.0.0.0 :4040 (1)
E [2018-08-09 21:46:34 +0000] [1] [DEBUG] Arbiter ๋ถํ ๋จ
E [2018-08-09 21:46:34 +0000] [1] [INFO] ๊ธฐ๋์ฝ ์์ 19.7.1
E raw_paste_global_conf: []
์ ์ ์ํธ: TLSv1
E do_handshake_on_connect: ๊ฑฐ์ง
E suppress_ragged_eofs: ์ฐธ
E ca_certs: ์์
์ ์ cert_reqs: 0
E SSL_๋ฒ์ : 2
์ ์ ์ธ์ฆ์ ํ์ผ: ์์
E ํค ํ์ผ: ์์
E proxy_allow_ips: ['127.0.0.1']
E proxy_protocol: ๊ฑฐ์ง
E on_exit:
E nworkers_changed:
E ์์
์_์ข
๋ฃ:
E child_exit:
์ ์ ์ฐํธ ์์ฒญ:
E ์ฌ์ ์์ฒญ:
E pre_exec:
E ์์
์_์ค๋จ:
E ์์
์_int:
E post_worker_init:
์ ์ ํฌ์คํธ_ํฌํฌ:
E pre_fork:
E when_ready:
E on_reload:
E on_starting:
E ๋ถ์ฌ๋ฃ๊ธฐ: ์์
E ํ์ด์ฌ ๊ฒฝ๋ก: ์์
E default_proc_name: art.wsgi
E proc_name: ์์
E statsd_prefix:
E statsd_host: ์์
E enable_stdio_inheritance: ๊ฑฐ์ง
E syslog_facility: ์ฌ์ฉ์
E syslog_prefix: ์์
E ์์คํ ๋ก๊ทธ: ๊ฑฐ์ง
E syslog_addr: udp://localhost :514
E logconfig: ์์
E logger_class: gunicorn.glogging.Logger
E capture_output: ๊ฑฐ์ง
E ๋ก๊ทธ ์์ค: ๋๋ฒ๊ทธ
E ์ค๋ฅ ๋ก๊ทธ: -
E access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%( ์ฒ๋ผ"
์ ์ ์ก์ธ์ค ๋ก๊ทธ: -
E forwarded_allow_ips: ['127.0.0.1']
E secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
E tmp_upload_dir: ์์
E ์ด๊ธฐ ๊ทธ๋ฃน: False
์ ๋ง์คํฌ: 0
E ๊ทธ๋ฃน: 0
์ ์ ์ฌ์ฉ์: 0
E worker_tmp_dir: ์์
E pidfile: ์์
E raw_env: []
E ๋ฐ๋ชฌ: ๊ฑฐ์ง
E chdir: /usr/src/app
E sendfile: ์์
E preload_app: ๊ฑฐ์ง
E check_config: ๊ฑฐ์ง
E ๋ถ์ถ: ๊ฑฐ์ง
E reload_engine: ์๋
E ์ฌ์ฅ์ : ๊ฑฐ์ง
E limit_request_field_size: 8190
E limit_request_fields: 100
E limit_request_line: 4094
์ ์ ํต์ผ๋ผ์ด๋ธ: 2
E Graceful_timeout: 30
์ ์ ํ์์์: 1200
E max_requests_jitter: 0
E max_requests: 0
E ์์ ์_์ฐ๊ฒฐ: 1000
E ์ค๋ ๋: 1
E worker_class: ๋๊ธฐํ
์ ์ ์์ ์: 7
์ ์ ๋ฐฑ๋ก๊ทธ: 2048
์ ์ ๋ฐ์ธ๋: ['0.0.0.0:4040']
์ ์ ๊ตฌ์ฑ: ์์
E [2018-08-09 21:46:34 +0000] [1] [DEBUG] ํ์ฌ ๊ตฌ์ฑ:
```
์ด๋ฒ์๋ ๋ฌธ์ ๋ฅผ ์ฌํํ๊ธฐ ์ํด ์ฝ๊ฐ ๊ณ ์ฌํ์ง๋ง ์ต์ gunicorn ๋ฒ์ 19.9.0์๋ ์ฌ์ ํ ์์ต๋๋ค.
๊ทธ๊ฒ์ ์ฌํํ๋ ๋จ๊ณ๋ ์ด ๊ฒ์๋ฌผ ์์ ์ค๋ช
ํ ๊ฒ๊ณผ ์ ํํ ๋์ผํฉ๋๋ค.
๋ด ์์คํ
์ Arch Linux x86_64 GNU/Linux(์ปค๋ 4.17.2-1-ARCH), Python 3.6.5์
๋๋ค.
๋ค์์ ์๋ก์ด ๋ก๊ทธ ์ถ์ ์
๋๋ค.
~$ย gunicorn -b 0.0.0.0:5000 --log-level=debug hello
[2018-08-10 09:48:40 +0200] [23114] [DEBUG] Current configuration:
config: None
bind: ['0.0.0.0:5000']
backlog: 2048
workers: 1
worker_class: sync
threads: 1
worker_connections: 1000
max_requests: 0
max_requests_jitter: 0
timeout: 30
graceful_timeout: 30
keepalive: 2
limit_request_line: 4094
limit_request_fields: 100
limit_request_field_size: 8190
reload: False
reload_engine: auto
reload_extra_files: []
spew: False
check_config: False
preload_app: False
sendfile: None
reuse_port: False
chdir: /home/dima/lerning/python/modules/gunicorn
daemon: False
raw_env: []
pidfile: None
worker_tmp_dir: None
user: 1000
group: 985
umask: 0
initgroups: False
tmp_upload_dir: None
secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
forwarded_allow_ips: ['127.0.0.1']
accesslog: None
disable_redirect_access_to_syslog: False
access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"
errorlog: -
loglevel: debug
capture_output: False
logger_class: gunicorn.glogging.Logger
logconfig: None
logconfig_dict: {}
syslog_addr: udp://localhost:514
syslog: False
syslog_prefix: None
syslog_facility: user
enable_stdio_inheritance: False
statsd_host: None
statsd_prefix:
proc_name: None
default_proc_name: hello
pythonpath: None
paste: None
on_starting: <function OnStarting.on_starting at 0x7f5f8b9dad08>
on_reload: <function OnReload.on_reload at 0x7f5f8b9dae18>
when_ready: <function WhenReady.when_ready at 0x7f5f8b9daf28>
pre_fork: <function Prefork.pre_fork at 0x7f5f8b4ec0d0>
post_fork: <function Postfork.post_fork at 0x7f5f8b4ec1e0>
post_worker_init: <function PostWorkerInit.post_worker_init at 0x7f5f8b4ec2f0>
worker_int: <function WorkerInt.worker_int at 0x7f5f8b4ec400>
worker_abort: <function WorkerAbort.worker_abort at 0x7f5f8b4ec510>
pre_exec: <function PreExec.pre_exec at 0x7f5f8b4ec620>
pre_request: <function PreRequest.pre_request at 0x7f5f8b4ec730>
post_request: <function PostRequest.post_request at 0x7f5f8b4ec7b8>
child_exit: <function ChildExit.child_exit at 0x7f5f8b4ec8c8>
worker_exit: <function WorkerExit.worker_exit at 0x7f5f8b4ec9d8>
nworkers_changed: <function NumWorkersChanged.nworkers_changed at 0x7f5f8b4ecae8>
on_exit: <function OnExit.on_exit at 0x7f5f8b4ecbf8>
proxy_protocol: False
proxy_allow_ips: ['127.0.0.1']
keyfile: None
certfile: None
ssl_version: 2
cert_reqs: 0
ca_certs: None
suppress_ragged_eofs: True
do_handshake_on_connect: False
ciphers: TLSv1
raw_paste_global_conf: []
[2018-08-10 09:48:40 +0200] [23114] [INFO] Starting gunicorn 19.9.0
[2018-08-10 09:48:40 +0200] [23114] [DEBUG] Arbiter booted
[2018-08-10 09:48:40 +0200] [23114] [INFO] Listening at: http://0.0.0.0:5000 (23114)
[2018-08-10 09:48:40 +0200] [23114] [INFO] Using worker: sync
[2018-08-10 09:48:40 +0200] [23117] [INFO] Booting worker with pid: 23117
[2018-08-10 09:48:40 +0200] [23114] [DEBUG] 1 workers
[2018-08-10 09:48:45 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:48:54 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:00 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:18 +0200] [23117] [DEBUG] Closing connection.
[2018-08-10 09:49:18 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:23 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:37 +0200] [23117] [DEBUG] Closing connection.
[2018-08-10 09:49:37 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:50 +0200] [23117] [DEBUG] Closing connection.
[2018-08-10 09:51:11 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:51:13 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:51:43 +0200] [23114] [CRITICAL] WORKER TIMEOUT (pid:23117)
[2018-08-10 09:51:43 +0200] [23117] [INFO] Worker exiting (pid: 23117)
[2018-08-10 09:51:44 +0200] [23229] [INFO] Booting worker with pid: 23229
ํ
์คํธํ๊ธฐ ์ ์ Chromium์์ http://0.0.0.0 :5000/์ ์น๊ณ ์์์ต๋๋ค.
์๋๋ ์ ํํ ํ๊ฒฝ์ ๋ณผ ์ ์๋๋ก Pipfile๊ณผ Pipfile.lock์ ๋ด์ฉ์
๋๋ค.
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
flask = "*"
gunicorn = "*"
[dev-packages]
[requires]
python_version = "3.6"
{
"_meta": {
"hash": {
"sha256": "81cb5d5f0b11719d8d9c5ec9cc683fdcf959c652fda256d5552a82d0f459a99c"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.6"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"click": {
"hashes": [
"sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d",
"sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"
],
"version": "==6.7"
},
"flask": {
"hashes": [
"sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48",
"sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"
],
"index": "pypi",
"version": "==1.0.2"
},
"gunicorn": {
"hashes": [
"sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471",
"sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3"
],
"index": "pypi",
"version": "==19.9.0"
},
"itsdangerous": {
"hashes": [
"sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519"
],
"version": "==0.24"
},
"jinja2": {
"hashes": [
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
],
"version": "==2.10"
},
"markupsafe": {
"hashes": [
"sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
],
"version": "==1.0"
},
"werkzeug": {
"hashes": [
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
],
"version": "==0.14.1"
}
},
"develop": {}
}
์ฐธ๊ณ ๋ก ์ ๋ ์ด ์คํจ๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ๋งค์ฐ ์ ๊ธฐ์ ์ผ๋ก ๋ณด๊ณ ์์ต๋๋ค.
nohup gunicorn -w 8 --access-logfile=- --bind 127.0.0.1:5000 wsgi &
๋๋ ๋จ์ง wsgi.py๊ฐ ์์ต๋๋ค.
from chart_api import application
if __name__ == "__main__":
application.run()
๋ด๊ฐ ์๋ํ๊ฑฐ๋ ์คํํ๊ธฐ๋ฅผ ์ํ๋ ๊ฒ์ด ์๊ฑฐ๋ ๋ด๊ฐ ํ์ธํ๊ธฐ๋ฅผ ์ํ๋ ๋ก๊ทธ์ ์ธ๋ถ ์ฌํญ์ด ์์ผ๋ฉด ์๋ ค์ฃผ์ญ์์ค. GCP VM์์ ํ๋ผ์คํฌ๋ฅผ ์คํํ๊ณ ์์ต๋๋ค.
๋ฆ์ ๋ต๋ณ ์ฃ์กํฉ๋๋ค. ๋๋ ๊ทธ๊ฒ์ ์คํํ๊ณ ์๋ค
gunicorn --log-file=/home/ubuntu/log/gunicorn.log predictor_ api:app -b localhost:5000 &
๋๋ gevent ์ค์ ๋ฑ์ ์ฌ์ฉํ์ง๋ง ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ํ์ํ ๊ฒ์ ๋์์ธ์ ๋ณ๊ฒฝํ์ต๋๋ค. ๋ฐ๋ผ์ ์์ ๊ธฐ๋ณธ ์ค์ ๋ ์คํจํ์ง๋ง ์ด๊ฒ์ gevent๊ฐ ์๋ ๊ฒ์ผ๋ก ์์๋ฉ๋๋ค.
ํ์ด์ฌ ๋ฒ์ 3.6
ํ๊ฒฝ: aws tensorflow_p36 ์ต์ ํ(์ฐ๋ถํฌ)
nginx๋ ํ๋ผ์คํฌ ์ฑ์ ์คํํ๋ gunicorn ์์ ์์ต๋๋ค.
ํ๋ผ์คํฌ ๋ฒ์ 1.0.2
nginx ๋ฒ์ 1.10.3
gunicorn ๋ฒ์ 19.9.0
์ด๋ก ์ธํด ๋ฐ์ํ ์ ์๋ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ nginx ์๊ฐ ์ด๊ณผ๋ ๋ณ๊ฒฝํ์ต๋๋ค.
gunicorn ์๋ฒ์ ๋์ผํ ๋ฌธ์ ์ ์ง๋ฉด
# gunicorn ApplicationServer :app -b 0.0.0.0:6001 -w 8 --threads 4 --backlog 2048 \
# --timeout 120 --graceful-timeout 60 --access-logfile logs/access.log \
ํ๋ผ์คํฌ==0.12.1
gunicorn==19.7.1
์์ ๋ช ๋ น์ผ๋ก ์๋ฒ๋ฅผ ์์ํ๋ฉด ๋ด ์์คํ ์ด ์ ์ ์ ์ง๋๊ณ ์์ ์ pid๊ฐ ๊ณ์ ๋ถํ ๋์ง๋ง ์๊ฐ ์ ํ์ 120์ด๋ก ์ ์งํ๊ณ ์๋ฒ๊ฐ ๋จ์ผ ์์ฒญ์ ์๋ฝํ์ง ์์ต๋๋ค.
์ด ๋ฌธ์ ์ ๋ํ ์ ๋ฐ์ดํธ๊ฐ ์์ต๋๊น? ๋๋ ๊ฐ์ ๋ฌธ์ ๊ฐ์๋ค
[์ค์] ์์ ์ ์๊ฐ ์ด๊ณผ
Docker ์ด๋ฏธ์ง์์ ์ด๊ฒ์ ์ฑ๊ณต์ ์ผ๋ก ์ฌํํ ์ฌ๋์ด ์๋์ง ๊ถ๊ธํ์ญ๋๊น?
๋ํ gunicorn -k gevent --threads 4๋ก ์์ํ๋ ๊ธฐ์กด ์ ํ๋ฆฌ์ผ์ด์ ์์ datadog์ ddtrace-run ์์ ์๋ฅผ ๊ตฌํํ๋ ค๊ณ ํ ๋ ์ด๊ฒ์ ๋ด ๋๋ค.
๋๋ ๋ณธ ์ ์๋ SystemExit์ ์๊ธด ์์ทจ...
[2018-11-07 11:11:50 +0000] [15987] [INFO] Booting worker with pid: 15987
[2018-11-07 11:11:50 +0000] [15977] [DEBUG] 1 workers
[2018-11-07 11:12:20 +0000] [15977] [CRITICAL] WORKER TIMEOUT (pid:15987)
Exception SystemExit: 1 in <bound method LibevLoop._loop_will_run of <cassandra.io.libevreactor.LibevLoop object at 0x7f3cb66d4a50>> ignored
์์ ์ ์์ ์ค๋ ๋ ์๋ฅผ ์ผ์น์์ผ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
workers = (2 * cpu_count) + 1
์ ์ค์ ํ๊ณ ์ค๋ ๋๋ฅผ ์ค์ ํ์ง ์์์ต๋๋ค.
threads = workers
๋ณ๊ฒฝํ๋ฉด ๋ชจ๋ ๊ฒ์ด ์ ๋๋ก ์๋ํ๊ธฐ ์์ํ์ต๋๋ค. ๋ง์ผ์ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ ์ด๊ฒ์ด ๋๊ตฐ๊ฐ์๊ฒ ๋์์ด ๋๋ค๋ฉด.
์ด๊ฒ์ด ์ง๊ธ์ ๋ชจ์ต์ด๋ค.
def run(host='0.0.0.0', port=8080, workers=1 + (multiprocessing.cpu_count() * 2)):
"""Run the app with Gunicorn."""
if app.debug:
app.run(host, int(port), use_reloader=False)
else:
gunicorn = WSGIApplication()
gunicorn.load_wsgiapp = lambda: app
gunicorn.cfg.set('bind', '%s:%s' % (host, port))
gunicorn.cfg.set('workers', workers)
gunicorn.cfg.set('threads', workers)
gunicorn.cfg.set('pidfile', None)
gunicorn.cfg.set('worker_class', 'sync')
gunicorn.cfg.set('keepalive', 10)
gunicorn.cfg.set('accesslog', '-')
gunicorn.cfg.set('errorlog', '-')
gunicorn.cfg.set('reload', True)
gunicorn.chdir()
gunicorn.run()
AWS Elastic Beanstalk์์ ๋จ์ผ Docker ์ปจํ ์ด๋๋ก Django๋ฅผ ์คํํ ๋ ์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค. ๋ด EC2 ์ธ์คํด์ค๊ฐ ๋ด RDS ์ธ์คํด์ค์ ํต์ ํ ์ ์๋๋ก ๋ณด์ ๊ทธ๋ฃน์ ์์ ํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค. ๋๋ ์ด๊ฒ์ด ์ด ๋ฌธ์ ์ ๋ํ 99%์ ์ฌ๋๋ค์ ์ํ ํด๊ฒฐ์ฑ ์ด ์๋ ์๋ ์๋ค๋ ๊ฒ์ ์๊ณ ์์ง๋ง, ๋ค๋ฅธ ์ฌ๋๋ค์ด ์ด ํ ๋ผ๊ตด์ ๋น ์ง๋ ๋ฐ ์๊ฐ์ ๋ญ๋นํ์ง ์๋๋ก ๋๊ธฐ ์ํด ์ด ๋ฉ๋ชจ๋ฅผ ๋จ๊น๋๋ค.
์ ๊ฒฝ์ฐ์๋ systemctl daemon-reload
์ํํ์ฌ ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์์ต๋๋ค.
๊ฐ๋จํ ๋งํด์ 30์ด์ ๊ธฐ๋ณธ ์๊ฐ ์ ํ์ ์๊ณ ์์์ง๋ง ๋ณ๊ฒฝ ์ฌํญ์ ์๋น์ค์ ์ ์ฉํ๊ธฐ ์ํด ์์คํ
๋ฐ๋ชฌ์ ๋ค์ ๋ก๋ํด์ผ ํ๋ค๋ ๊ฒ์ ์ ๋๊น์ง ๋ณ๊ฒฝํ ์ ์์์ต๋๋ค.
@bigunyak @benoitc @tilgovi
๊ธด ๊ตฌ๊ธ ๊ตฌ์ค ์ถ์ ๊ณผ ๋ช ๊ฐ์ง ์คํ ํ์ ๋๋ ์ด ๋ฌธ์ ์ ๊ทผ๋ณธ ์์ธ์ด ํฌ๋กฌ "์ฌ์ ์ฐ๊ฒฐ/์์ธก ์๋น์ค"(Chrome๊ณผ Chromium ๋ชจ๋์์ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ฑํ๋จ)๋ผ๊ณ ์๊ฐํฉ๋๋ค.
@jeiting ์ ์ด ๋ฌธ์ ์ ๋ํด ์ ์ผ์ต๋๋ค.
https://hackernoon.com/chrome-preconnect-breaks-singly-threaded-servers-95944be16400
์ถ๊ฐ ์ฝ๊ธฐ:
https://github.com/corydolphin/flask-cors/issues/147
https://github.com/pallets/flask/issues/2169
TLDR
์ด๋ค ๊ฒฝ์ฐ์๋ Chrome/Chromium์ด ์ด๋ฆฌ๊ณ "๋น" TCP ์ฐ๊ฒฐ์ด ์ ์ง๋ฉ๋๋ค(์ฆ, ๊ณง ๋ค๋ฅธ ๋ฆฌ์์ค๋ฅผ ๊ฐ์ ธ์ฌ ๊ฒ์ด๋ผ๊ณ ์์ธก). "๋น" TCP ์ฐ๊ฒฐ์ด ๋จผ์ gunicorn ์๋ฒ์ ๋๋ฌํ๋ฉด "๋น" ์์ฒญ์ ์ฒ๋ฆฌํ๋ ์์
์๊ฐ ์๊ฐ ์ด๊ณผ๋ ๋๊น์ง ํฌ๋กฌ์ ํ์ "์ค์ " ์์ฒญ์ด "๋น" ์์ฒญ ๋ค์ ๋ฉ์ถ ์ ์์ต๋๋ค. ์ด๋ gunicorn์์ ๋จ์ผ ๋๊ธฐํ ์์
์๋ง ์คํํ๋ ๊ฒฝ์ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ๋ ํฝ๋๋ค. ๊ทธ๋ฌ๋ ๋ด ์คํ์ ๋ฐ๋ฅด๋ฉด ์ฌ๋ฌ ๋๊ธฐํ ์์
์๋ฅผ ์คํํ๋ ๊ฒฝ์ฐ์๋ ๋ฐ์ํ ์ ์์ต๋๋ค.
๋ด ํ๊ฒฝ
FROM ubuntu:18.04
...
RUN pip3 install Flask==1.0.2
RUN pip3 install gunicorn==19.9.0
RUN pip3 install flask-cors==3.0.6
......
์คํ 1
Gunicorn ๊ตฌ์ฑ: ๋๊ธฐํ ์์
์ 1๊ฐ(๊ธฐ๋ณธ 30์ด ์ ํ ์๊ฐ)
Firefox: ๊ฑฐ์ ๋ชจ๋ ๋ฐ์ ํ์ด์ง ๋ก๋์์ CORS OPTIONS ์์ฒญ์ด 5์ด ๋์ ์ฐจ๋จ๋ ๋ค์ ์ฑ๊ณตํฉ๋๋ค.
Chromium: ๋ชจ๋ ๋ฐ์ ํ์ด์ง ๋ก๋์์ CORS OPTIONS ์์ฒญ์ด 1.5๋ถ ๋์ ์ฐจ๋จ๋ฉ๋๋ค!!!! ๊ทธ๋ฆฌ๊ณ ์ฑ๊ณตํฉ๋๋ค.
Chromium(์์ธก ์๋น์ค ๋นํ์ฑํ๋จ): ๋ชจ๋ ๊ฒ์ด ์ ๋ก๋๋จ
Chrome: ๋ชจ๋ ๊ฒ์ด ์ ๋ก๋๋ฉ๋๋ค.
์คํ 2
Gunicorn ๊ตฌ์ฑ: 4๊ฐ์ ๋๊ธฐํ ์์
์(๊ธฐ๋ณธ 30์ด ์ ํ ์๊ฐ)
Firefox: ๋ชจ๋ ๊ฒ์ด ์ ๋ก๋๋ฉ๋๋ค.
Chromium: ์ธ ๋ฒ์งธ ๋ฐ์ ํ์ด์ง ๋ก๋๋ง๋ค CORS OPTIONS ์์ฒญ์ด 30์ด ๋์ ์ฐจ๋จ๋ ๋ค์ ์ฑ๊ณตํฉ๋๋ค.
Chromium(์์ธก ์๋น์ค ๋นํ์ฑํ๋จ): ๋ชจ๋ ๊ฒ์ด ์ ๋ก๋๋จ
Chrome: ๋ชจ๋ ๊ฒ์ด ์ ๋ก๋๋ฉ๋๋ค.
์คํ 3
Gunicorn ๊ตฌ์ฑ: 8๊ฐ์ ๋๊ธฐํ ์์
์(๊ธฐ๋ณธ 30์ด ์ ํ ์๊ฐ)
Firefox: ๋ชจ๋ ๊ฒ์ด ์ ๋ก๋๋ฉ๋๋ค.
Chromium: ๋ชจ๋ ๊ฒ์ด ์ ๋ก๋๋ฉ๋๋ค.
Chrome: ๋ชจ๋ ๊ฒ์ด ์ ๋ก๋๋ฉ๋๋ค.
์คํ 4
threaded=True
ํ๋ผ์คํฌ ๊ฐ๋ฐ ์๋ฒ ์คํ
Firefox: ๋ชจ๋ ๊ฒ์ด ์ ๋ก๋๋ฉ๋๋ค.
Chromium: ๋ชจ๋ ๊ฒ์ด ์ ๋ก๋๋ฉ๋๋ค.
Chrome: ๋ชจ๋ ๊ฒ์ด ์ ๋ก๋๋ฉ๋๋ค.
์คํ ์์ฝ
ํด๊ฒฐ์ฑ
ํ๋ก๋์
์์: ๊ฐ์ฅ ์ฌ์ด ์์ ์ nginx๋ฅผ gunicorn ์์ ๋๋ ๊ฒ์
๋๋ค. nginx๊ฐ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ์ด์ ๋ฅผ ์ดํดํ๋ ค๋ฉด ์ด๋ฅผ ์ค๋ช
ํ๋ ๋ฉ์ง ๊ธฐ์ฌ๊ฐ ์์ต๋๋ค. https://www.brianstorti.com/the-role-of-a-reverse-proxy-to-protect-your-application-against - ๋๋ฆฐ ํด๋ผ์ด์ธํธ/
In dev: ๊ฐ์ฅ ์ฌ์ด ์์ ์ threaded=True
flask dev ์๋ฒ๋ฅผ ์คํํ๋ ๊ฒ์
๋๋ค. ๋๋ Chrome/Chromium์์ ์์ธก ์๋น์ค๋ฅผ ๋นํ์ฑํํ ์ ์์ต๋๋ค.
gunicorn ๋๋ฒ๊ทธ ๊ฐ์ ์ฌํญ
์์ผ๋ก ์ด์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ๋๋ฒ๊ทธํ๋ ๋ฐ ๋์์ด ๋๋๋ก ๋๊ธฐํ ์์
์์์ select()
๋ฐ accept()
ํธ์ถ ์์ ๋๋ฒ๊ทธ ๋ก๊ทธ ๋ฌธ์ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
https://github.com/benoitc/gunicorn/blob/e974f30517261b2bc95cfb2017a8688f367c8bf3/gunicorn/workers/sync.py#L26
https://github.com/benoitc/gunicorn/blob/e974f30517261b2bc95cfb2017a8688f367c8bf3/gunicorn/workers/sync.py#L34
์ด๊ฒ์ ์์
์๊ฐ ์ TCP ์ฐ๊ฒฐ์ ์๋ฝํ์ง๋ง ๋ฐ์ดํฐ๋ฅผ ์์ ํ์ง ์์์์ ๋ณด์ฌ์ค๋๋ค.
@asnisarenko ์ํผ ์ฐ๊ธฐ, ๊ฐ์ฌํฉ๋๋ค. #1929๋ ๋จ์ผ ์ค๋ ๋ ์๋ฒ์์ ์ ์ฌํ ์ฆ์์ ๋ํ๋ด๋ ๋๋ฆฐ ํด๋ผ์ด์ธํธ์ ๋ ๋ค๋ฅธ ํน์ดํ ๊ฒฝ์ฐ์ ๋๋ค. ์ด ๊ฒฝ์ฐ TLS๊ฐ ์๋ ํฌํธ์ ๋ํ TLS ํธ๋์ ฐ์ดํฌ๋ ํฉ๋ฆฌ์ ์ธ ํค๋๋ฅผ ๋น ๋ฅด๊ฒ ๋ณด๋ด์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ ์ฐ๊ธฐ๊ฐ ๋๋ฆฐ ํด๋ผ์ด์ธํธ์ฒ๋ผ ๋ณด์ ๋๋ค. .
๋จ์ผ ์ค๋ ๋ ๋๊ธฐํ ์์ ์์ ๊ฒฝ์ฐ ํฉ๋ฆฌ์ ์ธ ์๊ฐ ๋ด์ ๋ชจ๋ ํค๋๋ ์๋์ง๋ผ๋ ์ฒซ ๋ฒ์งธ ์์ฒญ ํค๋ ํ์ ๋ณด๋ด์ง ๋ชปํ๋ ํด๋ผ์ด์ธํธ์ ๋ํด ์๋ก์ด ์กฐ์ ๊ฐ๋ฅ, ์ ๊ทน์ ์ธ ํด๋ผ์ด์ธํธ ์ญ์ ๊ฐ ํ์ํ ๊ฒ์ด๋ฏ๋ก Gunicorn์ผ ์ ์์ต๋๋ค.
์ฑ์์ ์ด๋ฐ ์ผ์ด ๋ฐ์ํ๋ฉด ์์ ์ง๋จ ์ฝ๋๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค.
def trace_on_abort():
import signal
import traceback
def print_trace(sig, frame):
print(''.join(traceback.format_stack(frame)))
signal.signal(signal.SIGABRT, print_trace)
์ฑ์ด ์ค๋จ๋ ์์น๊ฐ ํ์๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
์๋ฅผ ๋ค์ด, ์ด๋ป๊ฒ ๋ ๋ก ๊ด๋ฆฌ import flask
์ ์ gevent.monkey.patch_all()
์ ๋์ ํ๋ผ์คํฌ์ app._before_request_lock
์๋ gevent ์ ๊ธ ์์ฃ (์ฆ, ์ผ๋ฐ ํจ์น threading.Lock
). ์ด๋ฌํ ๊ฒฝ์ฐ ์ฑ ์์ ์ ๋ ๊ฐ์ ์์ฒญ์ด ์ฐ์์ ์ผ๋ก ๋ฐ์ํ๋ฉด ์ฑ์ด ์ค๋จ๋ฉ๋๋ค(๋ ๋ฒ์งธ ์์ฒญ์ ์ ์ฒด ์ค๋ ๋๋ฅผ ์ ๊ธ๋๋ค). ๊ทธ๋ฌ๋ ์ด๊ฒ์ ๋ด ๋ฒ๊ทธ์์ผ๋ฉฐ ๊ทํ์ ๋ฒ๊ทธ๋ ๋ค๋ฅผ ์ ์์ต๋๋ค.
@asnisarenko ์ ์ค๋จ์ด ๋ฐ์ํ๋์ง ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ๋ชจ๋ ์์
์๊ฐ ํ๋ ฅํ์ฌ ์์ฒ ๊ฐ์ ์ฐ๊ฒฐ์ ์ฒ๋ฆฌํ ์ ์๊ธฐ ๋๋ฌธ์ ์ฐ๊ฒฐ๋น ์์
์๊ฐ ํ์ํ์ง _์์ต๋๋ค_(์ฒ๋ฆฌ ์ฝ๋๊ฐ CPU๋ฅผ ๋
์ ํ์ง ์๊ฑฐ๋ ์ ์ฒด ์ค๋ ๋๋ฅผ ์ ๊ทธ์ง ์๋ ํ). ํนํ, ๋ธ๋ผ์ฐ์ ๊ฐ ์์ฒญ์ ์ค๋จํ๋ฉด ์์ผ์์ gunicorn read()
๊ฐ ์์ ๋ ๊ทธ๋ฆฐ๋ ์ ์ฐจ๋จํ์ง๋ง read
๋ ์์ญ์ด ํจ์น๋์ด์ผ ํ๋ฏ๋ก ๋ค๋ฅธ ๊ทธ๋ฆฐ๋ .
@iconst
์ด ๋ฌธ์ ๋ ๊ธฐ๋ณธ ๊ตฌ์ฑ์ผ๋ก gunicorn์ ์คํํ๋ ๊ฒ์ ๋ํ ๊ฒ์
๋๋ค. ๊ธฐ๋ณธ ์์
์ ํด๋์ค๋ sync
http://docs.gunicorn.org/en/stable/settings.html#worker -class์
๋๋ค.
sync
์์
์๋ pre-fork ๋ชจ๋ธ์ ์ฌ์ฉํ๊ณ ๊ฐ ์์
์๋ ํ ๋ฒ์ ํ๋์ TCP ์ฐ๊ฒฐ/์์ฒญ์ ์ฒ๋ฆฌํฉ๋๋ค.
์ด ๋ฌธ์ ์ ์์ธ์ด ๋ฌด์์ธ์ง ๋ชจ๋ฅด์ง๋ง ๊ธฐ๋ณธ sync
์์
์ ์ ํ์์ eventlet
ํ๋ฉด ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์์ต๋๋ค.
CMD pipenv run gunicorn webapp -b 0.0.0.0:8080 -k eventlet
ํ์ด์ ๋น๋๋ค.
์ด๊ฒ์ ๋์๊ฒ๋ง ๋์์ด ๋ ์ ์์ง๋ง ๋ด ์ชฝ์์ ์ด ๋ฌธ์ ๋ฅผ ๋๋ฒ๊น ํ๋ ๋ฐ 7์๊ฐ์ด ๊ฑธ๋ ธ์ผ๋ฏ๋ก(EC2์ Docker์์ ์คํ๋๋ Flask/Gunicorn ์ฑ) ์ด ๊ณจ์นซ๊ฑฐ๋ฆฌ๋ฅผ ์์์ ์ฌ๋๋ค์๊ฒ ๋์ด์ค ์ ์๋ค๋ฉด ์์ ์น๋ฆฌ์ ๋๋ค.
์ปจํ ์ด๋ ๋ฉ๋ชจ๋ฆฌ ์ ํ์ด ๋๋ฌด ๋ฎ์ต๋๋ค.
์์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ๋ฉด ๋ฉ๋ชจ๋ฆฌ ์ ํ์ ๋ ๋๊ฒ ์ค์ ํ๋ ค๊ณ ํ์ง๋ง ํ์ฌ๋ก์๋ ์ ํ์ด ์์ต๋๋ค.
๊ฐ์ฌ ํด์
def trace_on_abort(): import signal import traceback def print_trace(sig, frame): print(''.join(traceback.format_stack(frame))) signal.signal(signal.SIGABRT, print_trace)
๋น์ ์ ๋๋ฅผ ๋ง์ด ๋์์ฃผ์ธ์. ์ํ))))
์ด trace_on_abort()
๋ฐฉ๋ฒ์ ์ด๋๋ก ๊ฐ๋๊น? ์ฑ ์ฝ๋ ํ์ผ์์? ์ฃผ์์ด ํ์ํฉ๋๊น?
@mattg-vbt ๋๋ฒ๊ทธํด์ผ ํ ๋ ์ฑ ์์ ๋ถ๋ถ์ ์ด๊ฒ์ ์ถ๊ฐํ๊ณ ๋๋ฒ๊น ์ด ๋๋๋ฉด ์ ๊ฑฐํ์ญ์์ค.
@ikonst ์ด๊ฒ์ ๋ด ์ฑ์ ์ถ๊ฐํ์ง๋ง ์ ์คํ๋ ๊ฒ์ ๋ณด์ง ๋ชปํ์ต๋๋ค. ์์ ์ ์๊ฐ ์ด๊ณผ๊ฐ ๋ฐ์ํ์ง๋ง ์ด ๋ฐฉ๋ฒ์ ์ ์ค๋์ง ์์ต๋๋ค.
@mattg-vbt kill -ABRT $pid
๋ฅผ ์ํํ์ฌ print_trace
ํจ์๊ฐ ํธ์ถ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๊น? (์ด ์์ด๋์ด๋ ์์
์๊ฐ ์๊ฐ ์ด๊ณผ๋ ๋ werkzeug์์ SIGABRT๋ฅผ ์ป์ ์ ์๋ค๋ ๊ฒ์
๋๋ค. ํ์ง๋ง ๋จผ์ ํธ์ถ๋์๋์ง ํ์ธํ๊ฒ ์ต๋๋ค.)
@asnisarenko ์ฐ๋ฆฌ ์ฌ์ด์ ๋ ์ ํตํ ๊ฒฝ์ฐ procfile์ ์ด๋ป๊ฒ ์ ๋ฐ์ดํธํฉ๋๊น?
web gunicorn app:app -k gevent --worker-connections 1000
?
@SumNeuron
๋๊ธฐํ ์์
์ ๋์ gevent ์์
์๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์์์ผ ํฉ๋๋ค. ๋ฐ๋ผ์ ๊ฒ์ ํ ๋ช
๋ น์ด ๊ด์ฐฎ์ ๊ฒ ๊ฐ์ต๋๋ค.
์ด๊ธฐํํ ๋๋ง gevent ์์
์์ ํจ๊ป ์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ฑ์ ์์ํ๊ธฐ ์ ์ ์ผ๋ถ ์์
์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ์ฝ๊ฐ ์ฑ๊ฐ์ ์ผ์
๋๋ค. ๊ทธ๋ฌ๋ ์ง๊ธ์ ๋์ ์๊ฐ ์ ํ์ ์ค์ ํ๊ณ ์์ต๋๋ค.
์ฌํ ๊ฐ๋ฅํ ํ
์คํธ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฌ๊ธฐ์ ๊ฒ์ํ์ต๋๋ค. https://github.com/zamponotiropita/test-gunicorn-worker-timeout -> test_0 ์คํจ, test_1 ๋ฐ test_2 ํต๊ณผ
@zamponotiropita ํฌํฌํ๊ธฐ ์ ์ ์์ ์๋ณ ๋๋ ์ฑ๋ณ๋ก ์ํํ์๊ฒ ์ต๋๊น?
@ikonst run.sh
์คํ ํ์ผ์ ํ์ธํ์ญ์์ค. ์์
์๋น์
๋๋ค. ๋ฌธ์ ๋ ๋ฏธ๋ฆฌ ๋ก๋ํ ๋ ๋ฐ์ํ์ง ์์์ง๋ง ๋ฏธ๋ฆฌ ๋ก๋ํ ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฐ๊ฒฐํ๋ ๋ฐ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค. ์ฑ ๊ฐ์ฒด(๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ๊ณผ ํจ๊ป)๊ฐ ๋ถ๊ธฐํ ๋ ๋ณต์ฌ๋๊ณ ํ๋ก์ธ์ค๋ฅผ ์ ๋ฌํ๊ธฐ ๋๋ฌธ์
๋๋ค. -> ๋ด ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค. ๋ง์คํฐ์ ์์
์์ ๋์ผํ ์ฐ๊ฒฐ ๋ฐ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ฐพ์ ์ ์์ต๋๋ค.
๋น์ทํ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. Flask๋ฅผ ์ฌ์ฉํ์ฌ ์ฆ์์์ ๋ง์ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๋ ค๊ณ ํฉ๋๋ค.
์ด ๋ฐฉ๋ฒ์ --timeout
์ ์ค์ ๋ ๊ฐ์ด ๋ง๋ฃ๋ ํ ์์
์๊ฐ ์๊ฐ ์ด๊ณผ๋๊ธฐ ๋๋ฌธ์ ์คํจํฉ๋๋ค. ์ฌํํ ์ ์๋ ์ต์ํ์ ์:
test_gunicorn_timeout.py
import flask
from time import sleep
app = flask.Flask(__name__)
@app.route('/')
def gunicorn_timeout():
def generator():
for _ in range(10):
yield b'Yet another line...'
sleep(2)
return flask.Response(generator(), mimetype='text/plain')
๊ทธ๋ฐ ๋ค์ gunicorn --timeout 10 test_gunicorn_timeout:app
ํ๊ณ 10์ด ํ์ localhost:8000
์์ฒญํ๋ฉด
[CRITICAL] WORKER TIMEOUT
.
๋ํ -k gevent
๋ฐ -k eventlet
์คํ์ ์๋ํ์ง๋ง ์๋ฌด ๊ฒ๋ ๋ณ๊ฒฝ๋์ง ์์์ต๋๋ค.
์ ๋ ์๋์ฐ 10 ํ๋ก๋ฅผ ์ฐ๊ณ ์์ต๋๋ค. ๋์ปค ์์ฑ์ผ๋ก
gunicorn app -b 0.0.0.0:8000 -k gevent
๋ด ํ์ด์ฌ ์ปจํ
์ด๋์ gevent๋ฅผ ์ค์นํ์ฌ ๋๋ฅผ ์ํด ์ผํ์ต๋๋ค.
์ ๋ฒคํธ ์ค์น ๋ฐฉ๋ฒ
๊ทธ๋ฐ ๋ค์
gunicorn --timeout 10 test_gunicorn_timeout:app
ํ๊ณ 10์ด ํ์localhost:8000
์์ฒญํ๋ฉด
[CRITICAL] WORKER TIMEOUT
.๋ํ
-k gevent
๋ฐ-k eventlet
์คํ์ ์๋ํ์ง๋ง ์๋ฌด ๊ฒ๋ ๋ณ๊ฒฝ๋์ง ์์์ต๋๋ค.
@ltskv
[CRITICAL] WORKER TIMEOUT ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ์ฑ ์ ์ฐพ์์ต๋๊น?
heroku(gunicorn ์ฌ์ฉ)์ ๋ฐฐํฌํ๋ ค๋ ํ๋ผ์คํฌ ์คํธ๋ฆฌ๋ฐ ์๋ํฌ์ธํธ์ ๋น์ทํ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ๊ฑฐ๊ธฐ์์ ํ๋ก์ ํ๋ก ํธ์๋๋ ์ผ๋ถ ๋ฐ์ดํฐ๊ฐ 30์ด ์ด๋ด์ ์ ์ก๋๋ ํ ์ฐ๊ฒฐ์ ์ ์งํด์ผ ํ์ง๋ง ์ฌ์ ํ ์คํ ์ค์ด๊ณ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๊ณ ์์์๋ 30์ด ์ด๋ด์ ์๋ฃ๋์ง ์์ผ๋ฉด gunicorn์ด ํ๋ก์ธ์ค๋ฅผ ์ข ๋ฃํ๋ ๊ฒ์ฒ๋ผ ๋ณด์ ๋๋ค.
gunicorn ๋ฌธ์๋ ์ด ์์ ์์ ๋์๊ฒ ์์ ํ ๋ช
ํํ์ง ์์ต๋๋ค. --timeout์ ๊ฒฝ์ฐ Workers silent for more than this many seconds are killed and restarted.
๋ผ๊ณ ํ์๋์ง๋ง ์์
์๋ ์ฌ์ ํ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ์ง๋ง 30์ด ํ์ ์ฌ๋งํ๋ ๊ฒ ๊ฐ์ต๋๊น?
gunicorn ๋ฌธ์๋ ์ด ์์ ์์ ๋์๊ฒ ์์ ํ ๋ช ํํ์ง ์์ต๋๋ค. --timeout์ ๊ฒฝ์ฐ ์ด ๋ช ์ด ์ด์ ์นจ๋ฌตํ๋ ์์ ์๊ฐ ์ข ๋ฃ๋๊ณ ๋ค์ ์์๋ฉ๋๋ค. ๊ทผ๋ฐ ์์ปค๋ค์ด ๋ฐ์ดํฐ๋ฅผ ์์ฐํ๋๋ฐ 30์ด๊ฐ ์ง๋๋ฉด ์ฃฝ๋๊ฑฐ ๊ฐ์๋ฐ์?
๋ฌธ์๋ฅผ ๊ฐ์ ํด์ผ ํ๋ค๋ @kurt-hictic. ๋ฌต์์ด๋ ์์ ํ์ผ์ ํตํด ์์ ์์ ํต์ ํ๋ ์ค์ฌ์ ํ๋ก์ธ์ค์ ๊ด์ ์์ ์นจ๋ฌต์ ์๋ฏธํฉ๋๋ค. ์์ ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋ ์ค์ด๋ฉด ํด๋น ํ์ผ์ ์ ๋ฐ์ดํธํ์ง ์์ต๋๋ค. ์ค์ฌ์์ ๊ด์ ์์ ์์ ์๋ ํํธ๋นํธ๋ฅผ ๋์น๊ณ ์์ต๋๋ค.
#1974๋ ์ฐธ์กฐํ์ญ์์ค.
๋ค๋ฅธ ์์ ์๊ฐ ์์ฒญ์ ์ฒ๋ฆฌํ ๋์๋ ์์ ํ์ผ์ ํํธ๋นํธํ๋ฏ๋ก ๊ธฐ๋ณธ ์์ ์๊ฐ ์๋ ๋ค๋ฅธ ์์ ์๋ฅผ ์ฌ์ฉํ๋ ๋๊ธฐ ์์ ์๋ ์คํธ๋ฆฌ๋ฐ ํฐ ๋ณธ๋ฌธ ๋ฌธ์ ๋ฅผ ์ํํด์ผ ํฉ๋๋ค.
@kurt-hectic -k gevent
์ต์
์ ๋ค์ ํ ๋ฒ ํ์ธํ๊ณ ์์ฑ๊ธฐ ๋ฐ๋ณต ์ฌ์ด์ sleep(0)
์ฝ์
ํ๋๋ฐ ์ค์ ๋ก ํจ๊ณผ๊ฐ ์์์ต๋๋ค. ๋๋ ์ง๋ฌธ์ ๊ฒ์ํ์ง๋ง).
--์๊ฐ ์ด๊ณผ=5
์ด๊ฒ์ด ์ด ๋ฌธ์ ์ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์์ธ์ ๋๋ค.
๋ด ์๋ฃจ์ ์ด ๋์์ด ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ๋๋ ๋ฉฐ์น ์ ์ ์ด ์ค์ํ ์์ ์ ์๊ฐ ์ด๊ณผ ๋ฌธ์ ๋ฅผ ๋ง๋ฌ๊ณ ๋ช ๊ฐ์ง ์๋ฃจ์ ์ ์๋ํ์ต๋๋ค. ์ด์ ์ ์๋ํฉ๋๋ค.
๋ด ์ดํด์ ํด๊ฒฐ์ฑ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์๋น์ค๋ฅผ ์์ํ๊ธฐ ์ํด tensorflow ๋ฐฑ์๋์ ๊ฐ์ ํจํค์ง๋ฅผ ๋ก๋ํ๋ ๋ฐ ๋ ๋ง์ ์๊ฐ์ด ํ์ํ๊ธฐ ๋๋ฌธ์ ์์ ์๋ฅผ ๋ถํ ํ์ง ๋ชปํฉ๋๋ค. ๋ฐ๋ผ์ ๋๋ฆฐ ์ฑ ๋ถํ ์๊ฐ์ด ๋ฐ์ํ๋ฉด gunicorn์์ ์ฌ์ ๋ก๋ ์ต์ ์ ํ์ฑํํด ๋ณด์ญ์์ค(https://devcenter.heroku.com/articles/python-gunicorn#advanced-configuration ์ฐธ์กฐ).
gunicorn hello:app --preload
๊ธฐ๋ณธ ์๊ฐ ์ด๊ณผ๋ 30์ด์ ๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์ด API๋ฅผ ์๋ฃํ๋ ๋ฐ ์ค์ ๋ก ๋ง์ ์๊ฐ์ด ํ์ํ ๊ฒฝ์ฐ ์๊ฐ ์ด๊ณผ๋ฅผ ๋๋ฆฌ์ญ์์ค.
gunicorn hello:app --timeout 10
๊ทธ๋ฌ๋ ๋ด ๊ด์ ์์ ๋ณผ ๋ API๊ฐ ์๋ฃํ๋ ๋ฐ 1๋ถ ์ด์์ด ํ์ํ ๊ฒฝ์ฐ์๋ ์๋ฏธ๊ฐ ์์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ฝ๋์์ ์ฝ๊ฐ์ ๋ฐ์ ์ ์๋ํ์ญ์์ค.
๋๋ ์ค๋ ๊ฐ์ ๋ฌธ์ ์ ์ง๋ฉดํ๋ค. ์ ๊ฒฝ์ฐ์๋ API๊ฐ ๋ฐ์ดํฐ๋ฅผ ๊ณ์ฐํ๊ณ ํด๋ผ์ด์ธํธ๋ก ๋ฐํํ๋ ๋ฐ ์ฝ 1๋ถ์ด ์์๋์ด CRITICAL WORKER TIMEOUT ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค. ๋๋ gunicorn์ ๋ํ ์๊ฐ ์ด๊ณผ ํ๋๊ทธ๋ฅผ 1๋ถ ์ด์์ผ๋ก ๋๋ ค ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค. ์๋ํ์ง๋ง ๋ฌธ์ ๊ฐ ๋ค์ ๋ฐ์ํ๋ ๊ฒ์ ๋ณด์ง ๋ชปํ์ต๋๋ค. ๋์์ด ๋์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ๋๋ uvicorn.workers.UvicornWorker๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
gnuicorn์ ์์ ์๋ฅผ ์ถ๊ฐํ์ฌ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค.
web: gunicorn --workers=3 BlocAPI:app --log-file -
์ด์ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์ด.
๊ต์ฐฉ ์ํ๊ฐ ๋ฐ์ํ๋์? ์ฑ์ด ์์ฒด์ ์ผ๋ก ์์ฒญ์ ํฉ๋๊น?
2020๋ 1์ 5์ผ ์ผ์์ผ 10:52 alpinechicken์์ ์๋ฆผ @github.com์ด ์์ฑํ์ต๋๋ค.
gnuicorn์ ์์ ์๋ฅผ ์ถ๊ฐํ์ฌ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค.
์น: gunicorn --workers=3 BlocAPI:app --log-file -
์ด์ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์ด.
โ
๋น์ ์ด ๋๊ธ์ ๋ฌ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ณ GitHub์์ ํ์ธํ์ธ์.
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJVQRCW3C63EZJWIN5DQ4G3WTA5CNFSM4FDLD5PKYY3PNVWWissueK3TUL52HS4DFVEXG43VMVBW63
๋๋ ๊ตฌ๋ ์ทจ์
https://github.com/notifications/unsubscribe-auth/AAAEQJXZM4NLK56DZMFSZALQ4G3WTANCNFSM4FDLD5PA
.
์, ํ ๊ฒฝ๋ก๊ฐ ๋ค๋ฅธ ๊ฒฝ๋ก๋ฅผ ํธ์ถํฉ๋๋ค. ๊ทธ๊ฒ ๋์๊ฐ์?
์ด๋ ์ต์ํ ๋ ๋ช
์ ์์
์๊ฐ ํ์ํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์๋ฒ๊ฐ
์ด์ค ์๋ฌผ์ . ์์ฒญ์ ์๋ฒ๊ฐ ๋ ๋ฒ์งธ ์๋ต์ ์๋ตํ ๋๊น์ง ๋๊ธฐํฉ๋๋ค.
์์ฒญ(๋๊ธฐ์ด์ ์์).
์์ ์๋น ํ๋์ ๋์ ์์ฒญ์ ๋ฐ์ต๋๋ค.
2020๋ 1์ 6์ผ ์์์ผ, 02:45 alpinechicken, [email protected] ์์ฑ:
์, ํ ๊ฒฝ๋ก๊ฐ ๋ค๋ฅธ ๊ฒฝ๋ก๋ฅผ ํธ์ถํฉ๋๋ค. ๊ทธ๊ฒ ๋์๊ฐ์?
โ
๋น์ ์ด ๋๊ธ์ ๋ฌ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ณ GitHub์์ ํ์ธํ์ธ์.
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJSFEFBBI6AMZJCM4C3Q4KLOJA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVEXG43VMXVW63LNMV
๋๋ ๊ตฌ๋ ์ทจ์
https://github.com/notifications/unsubscribe-auth/AAAEQJXTCPOFIZJU5PUPOODQ4KLOJANCNFSM4FDLD5PA
.
์ ์ดํด๊ฐ ๋ฉ๋๋ค. ๊ฐ์ฌ ํด์!
2020๋ 1์ 7์ผ ํ์์ผ ์ค์ 6์ 23๋ถ์ bobf [email protected]์์ ๋ค์๊ณผ ๊ฐ์ด ์ผ์ต๋๋ค.
์ด๋ ์ต์ํ ๋ ๋ช ์ ์์ ์๊ฐ ํ์ํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์๋ฒ๊ฐ
์ด์ค ์๋ฌผ์ . ์์ฒญ์ ์๋ฒ๊ฐ ๋ ๋ฒ์งธ ์๋ต์ ์๋ตํ ๋๊น์ง ๋๊ธฐํฉ๋๋ค.
์์ฒญ(๋๊ธฐ์ด์ ์์).์์ ์๋น ํ๋์ ๋์ ์์ฒญ์ ๋ฐ์ต๋๋ค.
2020๋ 1์ 6์ผ ์์์ผ, 02:45 alpinechicken, [email protected] ์์ฑ:
์, ํ ๊ฒฝ๋ก๊ฐ ๋ค๋ฅธ ๊ฒฝ๋ก๋ฅผ ํธ์ถํฉ๋๋ค. ๊ทธ๊ฒ ๋์๊ฐ์?
โ
๋น์ ์ด ๋๊ธ์ ๋ฌ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ณ GitHub์์ ํ์ธํ์ธ์.
<
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJSFEFBBI6AMZJCM4C3Q4KLOJA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVREXG43VMXHJ63LDNLOX
,
๋๋ ๊ตฌ๋ ์ทจ์
<
https://github.com/notifications/unsubscribe-auth/AAAEQJXTCPOFIZJU5PUPOODQ4KLOJANCNFSM4FDLD5PA.
โ
๋น์ ์ด ๋๊ธ์ ๋ฌ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ณ GitHub์์ ํ์ธํ์ธ์.
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAH2WRPVPVO2EJ53BKQW5B3Q4OHLRA5CNFSM4FDLD5PKYY3PNVWQWK3TUL52HS4DFVEXG43NVMVBW
๋๋ ๊ตฌ๋ ์ทจ์
https://github.com/notifications/unsubscribe-auth/AAH2WRM2LLIB4O6OHCU5UG3Q4OHLRANCNFSM4FDLD5PA
.
์์ ์ ํด๋์ค', '๋๊ธฐํ')
์์ ์ ์์ ์ค๋ ๋ ์๋ฅผ ์ผ์น์์ผ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
workers = (2 * cpu_count) + 1
์ ์ค์ ํ๊ณ ์ค๋ ๋๋ฅผ ์ค์ ํ์ง ์์์ต๋๋ค.
threads = workers
๋ณ๊ฒฝํ๋ฉด ๋ชจ๋ ๊ฒ์ด ์ ๋๋ก ์๋ํ๊ธฐ ์์ํ์ต๋๋ค. ๋ง์ผ์ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ ์ด๊ฒ์ด ๋๊ตฐ๊ฐ์๊ฒ ๋์์ด ๋๋ค๋ฉด.์ด๊ฒ์ด ์ง๊ธ์ ๋ชจ์ต์ด๋ค.
def run(host='0.0.0.0', port=8080, workers=1 + (multiprocessing.cpu_count() * 2)): """Run the app with Gunicorn.""" if app.debug: app.run(host, int(port), use_reloader=False) else: gunicorn = WSGIApplication() gunicorn.load_wsgiapp = lambda: app gunicorn.cfg.set('bind', '%s:%s' % (host, port)) gunicorn.cfg.set('workers', workers) gunicorn.cfg.set('threads', workers) gunicorn.cfg.set('pidfile', None) gunicorn.cfg.set('worker_class', 'sync') gunicorn.cfg.set('keepalive', 10) gunicorn.cfg.set('accesslog', '-') gunicorn.cfg.set('errorlog', '-') gunicorn.cfg.set('reload', True) gunicorn.chdir() gunicorn.run()
gunicorn ๋ฌธ์์ ๋ฐ๋ฅด๋ฉด ๋ ์ด์์ ์ค๋ ๋๊ฐ ์ธ๊ธ๋๋ฉด ์์
์ ํด๋์ค๋ฅผ sync์์ gthread๋ก ๋ณ๊ฒฝํฉ๋๋ค.
์ถ์ :-
๋๊ธฐํ ์์
์ ์ ํ์ ์ฌ์ฉํ๋ ค๊ณ ํ๊ณ ์ค๋ ๋ ์ค์ ์ 1 ์ด์์ผ๋ก ์ค์ ํ๋ฉด gthread ์์
์ ์ ํ์ด ๋์ ์ฌ์ฉ๋ฉ๋๋ค.
๋ด ๊ฒฝ์ฐ:
ํ๊ฒฝ: Ubuntu18.04+ gunicorn+ nginx +flask
๋ด ๊ฐ์ ํ๊ฒฝ์ pip install gunicorn[gevent]
gunicorn -b localhost:8000 -w 4 web:app
์ gunicorn -b localhost:8000 -k gevent web:app
ํจ๊ณผ๊ฐ์๋ค.
์๋ก์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐ ๋ง์ ๋์์ ์ฃผ์ ๋ชจ๋ ๋ถ๋ค๊ป ๊ฐ์ฌ๋๋ฆฝ๋๋ค. ์ ์ ํ๋ค๊ณ ์๊ฐ๋๋ ๊ฒฝ์ฐ ์ด ๋ฌธ์ ์ ๊ณ์ ๊ฒ์ํ์ญ์์ค.
๊ทธ๋ฌ๋ ์ฌ๊ธฐ Gunicorn์ ๋ฒ๊ทธ๊ฐ ์๋ค๊ณ ์๊ฐํ์ง ์๊ณ ์ทจํด์ผ ํ ์กฐ์น๊ฐ ์๋ค๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ ์ด ๋ฌธ์ ๋ฅผ ๋ซ์ต๋๋ค. ์ด๋ป๊ฒ๋ ์ด์ ๋ํ ๋ฌธ์๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ๊ฐ์ ํ๋ ค๋ PR์ ๊ฒํ ํ๋ ๋ฐ ๊ธฐ๊บผ์ด ๋์์ ๋๋ฆฌ๊ฒ ์ต๋๋ค. ๋ก๊ทธ ๋ฉ์์ง.
์ ์๋๋ฅผ ์คํดํ์ง ๋ง์์ฃผ์ธ์. Gunicorn์ ๋ฒ๊ทธ๊ฐ ์์ฌ๋๊ณ ๊ณ์ ๋ ผ์ํ๊ณ ์ถ๋ค๋ฉด ๊ทธ๋ ๊ฒ ํ์ญ์์ค. ๋ฌธ์ ๋ฅผ ์ฌํํ๋ ์์ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์ ํฐ์ผ์ ์ฌ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด ์์ ์์ ์ด ๋ฌธ์ ์๋ ๋๋ฌด ๋ง์ ๋ค๋ฅธ ๋ฌธ์ , ํด๊ฒฐ ๋ฐฉ๋ฒ ๋ฐ ๋ํ๊ฐ ์์ด ๋งค์ฐ ์ฝ๊ธฐ ์ฝ์ต๋๋ค.
๋ฒํผ๋ง ์ญ๋ฐฉํฅ ํ๋ก์ ์์ด Gunicorn์ ์คํํ๋ฉด ์ฌ๋ฌ ๊ฐ์ง ์ด์ ๋ก ๊ธฐ๋ณธ ๋๊ธฐํ ์์ ์๋ก ์๊ฐ ์ด๊ณผ๊ฐ _๋ฐ์_ํฉ๋๋ค. ์ผ๋ฐ์ ์ธ ๊ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๋น๋๊ธฐ ๋๋ ์ค๋ ๋ ์์
์ ์ ํ์ผ๋ก ์ ํํ๊ฑฐ๋ Gunicorn์ ๋ฒํผ๋ง ์ญ๋ฐฉํฅ ํ๋ก์ ๋ค์ ๋ฐฐ์นํ ์ ์์ต๋๋ค. ์๊ฐ ์ด๊ณผ๊ฐ ์ธ๋ถ API์ ๋ํ ๋๋ฆฐ ํธ์ถ์ ์ํํ๊ฑฐ๋ ์์๋๋ก ์ค์ํ ์์
์ ์ํํ๋ ์์ฒด ์ฝ๋๋ก ์ธํ ๊ฒ์์ ์๊ณ ์๋ค๋ฉด --timeout
์ต์
์ ๋๋ฆด ์ ์์ต๋๋ค.
์ด๊ฒ์ ์ต์ํ ๋ ๋ช ์ ์์ ์๊ฐ ํ์ํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์๋ฒ๊ฐ ๊ต์ฐฉ ์ํ์ ๋น ์ง ๊ฒ์ ๋๋ค. ์์ฒญ์ ์๋ฒ๊ฐ ๋ ๋ฒ์งธ ์์ฒญ(๋๊ธฐ์ด์ ์ถ๊ฐ๋จ)์ ์๋ตํ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค. ์์ ์๋น ํ๋์ ๋์ ์์ฒญ์ ๋ฐ์ต๋๋ค.
โฆ
2020๋ 1์ 6์ผ ์์์ผ, 02:45 alpinechicken, @ . * > ์ผ๋ค: ๋ค, ํ ๋ผ์ฐํธ๊ฐ ๋ค๋ฅธ ๋ผ์ฐํธ๋ฅผ ํธ์ถํฉ๋๋ค - ๊ทธ๊ฒ ๋์๊ฐ์?
๋ผ์ฐํธ์ ๋ฐํ๊ฐ์ผ๋ก '๋ฆฌ๋๋ ํธ' ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒฝ์ฐ๊ฐ ์ฌ๊ธฐ์ ํด๋นํฉ๋๊น?
๋ผ์ฐํธ์ ๋ฐํ๊ฐ์ผ๋ก '๋ฆฌ๋๋ ํธ' ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒฝ์ฐ๊ฐ ์ฌ๊ธฐ์ ํด๋นํฉ๋๊น?
์๋์. ํ๋ผ์คํฌ ๋ฆฌ๋๋ ์ ์ HTTP ๋ฆฌ๋๋ ์ ์ผ๋ก ์๋ตํ๊ณ ์์ ์๋ ์ ์์ฒญ์ ์์ ๋กญ๊ฒ ์๋ฝํ ์ ์์ต๋๋ค. ํด๋ผ์ด์ธํธ๋ ์ด ์๋ต์ ๋ณด๊ณ ์์ ์๊ฐ ์ค๋น๋ ๋๋ง๋ค ์ด ์์ฒญ์ ์์ ํ ๋ ๋ ๋ค๋ฅธ ์์ฒญ์ ํฉ๋๋ค.
gnuicorn์ ์์ ์๋ฅผ ์ถ๊ฐํ์ฌ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค.
web: gunicorn --workers=3 BlocAPI:app --log-file -
์ด์ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์ด.
์ด๊ฒ์ workers=1 + (multiprocessing.cpu_count() * 2)
.. ๋ฅผ ์ค์ ํ @anilpai ์ฃผ์๊ณผ ๊ด๋ จ์ด ์์ต๋๊น?
๋๋ ์ด๊ฒ๊ณผ ๋น์ทํ ๋ฌธ์ ๊ฐ ์์๋ค. ์์ฉ ํ๋ก๊ทธ๋จ ์ง์ ์ ์ ์ค๋ฅ๊ฐ ์๋ ๊ฒ์ผ๋ก ๋ํ๋ฌ์ต๋๋ค. ๋๋ฒ๊น ์์ ๋๋ ๋ณธ์ง์ ์ผ๋ก gunicorn์์ ํ๋ผ์คํฌ ์ฑ์ ์์ํ๋ ๊ฒ ๊ฐ์์ต๋๋ค. ๊ทธ ํ ์์ ์๋ 30์ด๋ง๋ค ์๊ฐ ์ด๊ณผ๋๋ ๋ฌดํ ์ฐ๊ฒฐ ๋ฃจํ์ ๋ค์ด๊ฐ์ต๋๋ค.
์ด๊ฒ์ด ์์ ๋ชจ๋ ์ฌ์ฉ์์๊ฒ ์ํฅ์ ๋ฏธ์น์ง๋ ์์ง๋ง ์ผ๋ถ ์ฌ์ฉ์์๊ฒ๋ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค.
gunicorn module.wsgi
์คํ ์ค์ธ module/wsgi.py
ํ์ผ์์ -
application = my_create_app_function()
application.run(host="0.0.0.0")
๋ด๊ฐ ํ์ด์ผ ํ๋ ๋ฐ๋ฉด์ -
application = my_create_app_function()
if __name__ == "__main__":
application.run(host="0.0.0.0")
๊ธฐ๋ณธ์ ์ผ๋ก gunicorn์ ์ฌ์ฉํ ๋ application.run()
๋ฅผ ํธ์ถํ๊ณ ์ถ์ง ์์ต๋๋ค. gunicorn ์๋์ __name__
๋ "__main__"
๊ฐ ์๋์ง๋ง Flask์ ์์ผ๋ฏ๋ก ๋ก์ปฌ์์ ๋๋ฒ๊ทธํ ์ ์์ต๋๋ค.
gunicorn ๋ฌธ์์์ ์ด์ ๋ํ ์ฐธ์กฐ๋ฅผ ์ฐพ์ ์ ์์ง๋ง ์ผ๋ฐ์ ์ธ ์ค๋ฅ ์ฌ๋ก๋ผ๊ณ ์๊ฐํ ์ ์์ผ๋ฏ๋ก ๊ฒฝ๊ณ ๊ฐ ํ์ํ ์ ์์ต๋๋ค.
์ด๊ฒ์ ์ฌ์ ํ โโ๋ฐ์ํ๊ณ ์์ต๋๋ค. Gunicorn ํธ์ถ์ --preload
๋ฅผ ์ถ๊ฐํ๋ฉด ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์์ต๋๋ค.
์ด ๋ฒ๊ทธ๊ฐ ์์ง ์์ ๋์ง ์์๋์? ๋๋ ์ด ์ ํํ ํ๋์ ๊ด์ฐฐํ๊ณ ์๋ค.
Gunicorn์ systemd์์ ๋ค์๊ณผ ๊ฐ์ด ์์ํฉ๋๋ค.
[Service]
PIDFile = /run/gunicorn.pid
WorkingDirectory = /home/pi/pyTest
ExecStart=/usr/local/bin/gunicorn app:app -b 0.0.0.0:80 --pid /run/gunicorn.pid
RuntimeDirectory=/home/pi/pyTest
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
User=root
Group=root
ExecReload = /bin/kill -s HUP $MAINPID
ExecStop = /bin/kill -s TERM $MAINPID
ExecStopPost = /bin/rm -rf /run/gunicorn
PrivateTmp = true
์์ ์ ํ๋ก์ธ์ค๊ฐ ์ง์์ ์ผ๋ก ์๊ฐ ์ด๊ณผ๋๊ณ ๋ค์ ์์๋ฉ๋๋ค.
Jul 10 15:19:20 raspberryVM gunicorn[10941]: [2020-07-10 15:19:20 -0700] [10941] [CRITICAL] WORKER TIMEOUT (pid:10944)
Jul 10 15:19:20 raspberryVM gunicorn[10941]: [2020-07-10 15:19:20 -0700] [10944] [INFO] Worker exiting (pid: 10944)
Jul 10 15:20:15 raspberryVM gunicorn[10941]: [2020-07-10 15:20:15 -0700] [10985] [INFO] Booting worker with pid: 10985
app.py๋ ์ฌ์ํ Flask ์ฑ์ ๋๋ค.
์ด ๋ฌธ์ ๋ Don't Fix๋ก ์ข ๋ฃ๋์์ต๋๊น?
๋๋ ๋ํ ๊ฐ์ ๋ฌธ์ ๊ฐ ์์๋ค
๊ทธ๋ฌ๋ ๋๋ฒ๊น
ํ Im์ gunicorn์ด Django App์ ์์ํ๋ ๋์ ์ข
์์ฑ ์ค ํ๋๊ฐ ์์ ์๊ฐ๋ณด๋ค ์ค๋ ๊ฑธ๋ฆฐ๋ค๋ ๊ฒ์ ์ ์ ์์์ต๋๋ค(์ ๊ฒฝ์ฐ์๋ ์ธ๋ถ DB ์ฐ๊ฒฐ). ์ด๋ก ์ธํด gunicron
์์
์๊ฐ ์๊ฐ ์ด๊ณผ๋์์ต๋๋ค
์ฐ๊ฒฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ฉด ์๊ฐ ์ด๊ณผ ๋ฌธ์ ๋ ํด๊ฒฐ๋์์ต๋๋ค ...
์ด๊ฒ์ ๋์ ๊ฒฝ์ฐ๊ฐ ์๋ ๊ฒ์ด๋ค. ์ข ์์ฑ ์์ด "Hello, World" ์ ํ์ ์ฑ์ผ๋ก ํ ์คํธํ์ต๋๋ค. ๊ทธ๋์ ๋๋ ์ฌ์ ํ ์ด๊ฒ์ ๋ํด ์์ํดํ์ง๋ง ์ค๋ ์คํ๋๋ ์ค๋ ๋๋ก Gunicorn์ ๊ฐ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ ๊ฒ ๊ฐ์ต๋๋ค. ์์ ์ ํ๋ก์ธ์ค๊ฐ ๋ค์ ์์๋์ด ์ฅ๊ธฐ ์คํ ์ค๋ ๋๋ฅผ ์ข ๋ฃํฉ๋๋ค.
@leonbrag
์ด๊ฒ์ gunicorn ๋ฒ๊ทธ๊ฐ ์๋ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. ์ค๋ ๋์์ ์์ ๋ด ์๊ฒฌ์ ์ฐธ์กฐํ์ญ์์ค. ๋ธ๋ผ์ฐ์ ๊ฐ ๋น "์์" TCP ์ฐ๊ฒฐ์ ๋ณด๋ด๊ณ ๋น TCP ์ฐ๊ฒฐ๋ก๋ถํฐ ๋ณดํธํ์ง ์๊ณ ๋ช ๊ฐ์ ๋๊ธฐํ ์์
์๋ก gunicorn์ ์คํํ๋ ๋ถ์์ฉ์
๋๋ค.
๊ธด(์๊ตฌ) ์์ ์ ์ค๋ ๋๋ก Gunicorn ํ๋ผ์คํฌ ์ฑ์ ์ค์ ํ๋ ์ ์ ํ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ฃผ๋ ์ฐธ์กฐ ์ํคํ ์ฒ/๋์์ธ์ด ์์ต๋๊น?
์ด๊ฒ์ด ๋ฒ๊ทธ๊ฐ ์๋ ๊ฒฝ์ฐ Gunicorn ์ํคํ ์ฒ/๋์์ธ์ ์ํฐํฉํธ ๋๋ ์ ํ์ผ๋ก ๋ณด์ ๋๋ค.
๋๊ธฐํ ์์ ์๊ฐ ์์ํ ์คํ๋์ง ์๊ณ ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ์ ์๋ฝํ์ง ์๋ ์ด์ ๋ ๋ฌด์์ ๋๊น? ์ด๋ฌํ ์์ ์๋ ํ์์ ๋ฐ๋ผ ์์ผ์ ๋ซ์ง๋ง ์ข ๋ฃ ์์ด ๊ณ์ ์คํ๋ฉ๋๋ค(๋ฐ๋ผ์ ์์ ์ ์ค๋ ๋๋ ๊ณ์ ์คํ๋จ).
@leonbrag
ํด๊ฒฐํ๋ ค๋ ๋ฌธ์ ์ ๋ํด ๋ ๊ตฌ์ฒด์ ์ด์ด์ผ ํฉ๋๋ค.
์ด ์ค๋ ๋์์ ๋ ผ์๋ ๋ฌธ์ ๋ ๊ฐ๋ฐ ํ๊ฒฝ์์ ๋ฐ์ํ๋ฉฐ ๊ฐ์ฅ ์ฌ์ด ํด๊ฒฐ์ฑ ์ ๋๊ธฐํ ์์ ์๋ฅผ ๋ ์ถ๊ฐํ๊ฑฐ๋ ์ค๋ ๋ ์์ ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค.
ํ๋ก๋์
์ค์ ์์ ์ด ๋ฌธ์ ๋ฅผ ํผํ๋ ค๋ฉด gevent ์์
์๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ nginx๋ฅผ gunicorn ์์ ๋ฐฐ์นํ ์ ์์ต๋๋ค.
์ผ๋ถ PaaS๋ ์ด๋ฏธ nginx๋ฅผ ๋์ปค ์ปจํ
์ด๋ ์์ ๋ฐฐ์นํ๋ฏ๋ก ๊ฑฑ์ ํ ํ์๊ฐ ์์ต๋๋ค. ๋ค์ ํ ๋ฒ, ์๋ฃจ์
์ ์ปจํ
์คํธ์ ์ธ๋ถ ์ฌํญ์ ๋ฐ๋ผ ๋ค๋ฆ
๋๋ค.
์ด๊ฒ์ ์ข์ ๋
์์
๋๋ค.
https://www.brianstorti.com/the-role-of-a-reverse-proxy-to-protect-your-application-against-slow-clients/
๋ฌธ์์์ ๋์์ธ ํ์ด์ง๋ฅผ ํ์ธํ ์ ์์ต๋๋ค. ๋น๋๊ธฐ ์์
์๋ ํ๋์
๋๋ค.
๊ธด ์์
์ ์คํํ๋ ๋ฐฉ๋ฒ.
2020๋ 8์ 8์ผ ํ ์์ผ 18:00 leonbrag [email protected]์์ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ์ต๋๋ค.
์ ์ ํ ์ค์ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ฃผ๋ ์ฐธ์กฐ ์ํคํ ์ฒ/๋์์ธ์ด ์์ต๋๊น?
๊ธด(์๊ตฌ) ์์ ์ ์ค๋ ๋๊ฐ ์๋ Gunicorn ํ๋ผ์คํฌ ์ฑ?์ด๊ฒ์ด ๋ฒ๊ทธ๊ฐ ์๋๋ผ๋ฉด, ๊ทธ๊ฒ์ ์ํฐํฉํธ ๋๋ ์ ํ ์ฌํญ์ผ๋ก ๋ณด์ ๋๋ค.
Gunicorn ์ํคํ ์ฒ/๋์์ธ.๋๊ธฐํ ์์ ์๊ฐ ์์ํ ์คํ๋์ง ์๊ณ ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ์ ์๋ฝํ์ง ์๋ ์ด์ ๋ ๋ฌด์์ ๋๊น? ๊ทธ๋ฐ
์์ ์๋ ํ์์ ๋ฐ๋ผ ์์ผ์ ๋ซ์ง๋ง ์ข ๋ฃํ์ง ์๊ณ ๊ณ์ ์คํํฉ๋๋ค.
(๋ฐ๋ผ์ ์์ ์ ์ค๋ ๋๋ ๊ณ์ ์คํ๋ฉ๋๋ค).โ
๋น์ ์ด ์ธ๊ธ๋์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ณ GitHub์์ ํ์ธํ์ธ์.
https://github.com/benoitc/gunicorn/issues/1801#issuecomment-670944797 ,
๋๋ ๊ตฌ๋ ์ทจ์
https://github.com/notifications/unsubscribe-auth/AAADRIWRQGIP3R5PMVJ5ENTR7VZA3ANCNFSM4FDLD5PA
.>
๋ด ๋ชจ๋ฐ์ผ์์ ๋ณด๋ธ
์น: gunicorn --workers=3 app:app --timeout 200 --log-file-
--timeout์ ์ฆ๊ฐ์์ผ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค.
Docker ๊ด๋ จ tmpfs ๋ฌธ์ ๋ #1388๋ ์ฐธ์กฐํ์ธ์.
์ค, Randall์๊ฒ ๊ฐ์ฌํฉ๋๋ค. Docker์์ gunicorn์ ์คํํ ๋ gunicorn ์ธ์์ --worker-tmp-dir /dev/shm
๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ์์์ต๋๋ค.
BTW๋ gunicorn ์บ์์ 64Mb๋ก ์ถฉ๋ถํฉ๋๊น?
์ด์ํ๊ฒ๋ --worker-tmp-dir /dev/shm
ํ์ง๋ง ์ฌ์ ํ ๋ค์์ ์์ ํ๊ณ ์์ต๋๋ค.
[2020-11-27 21:01:42 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:17)
/dev/shm
๊ฐ ramfs์ธ์ง ํ์ธํ๊ธฐ ์ํด ๋ฒค์น๋งํนํ์ต๋๋ค.
๋งค๊ฐ๋ณ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
command: /bin/bash -c "cd /code/ && pipenv run gunicorn --worker-tmp-dir /dev/shm conf.wsgi:application --bind 0.0.0.0:8022 --workers 5 --worker-connections=1000"
์ถ์ : ์ ๋ PyPy๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
@attajutt ์๊ฐ ์ ํ์ ํ๋ฅญํ์ง๋ง gunicorn ๋ง์คํฐ ํ๋ก์ธ์ค๊ฐ 1000์ด ํ์๋ง ์์ ์ ํ๋ก์ธ์ค์์ ์ค๋จ์ ๊ฐ์งํ๊ณ ๋ง์ ์์ฒญ์ ๋์น ์ํ์ด ์์ต๋๋ค. ๋ํ ์ฌ๋ฌ ์์ ์ ์ค ํ๋๋ง ๋์ผ๋ฉด ๊ฐ์งํ๊ธฐ ์ด๋ ค์ธ ๊ฒ์ ๋๋ค. ์ ์ด๋ 1000์ ํ์ง ์๊ฒ ์ต๋๋ค.
@ivictbor lmk์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค. 1000์ ์ฐธ๊ณ ์ฉ์ ๋๋ค. ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ์ผ๋จ ๋ก๋๋๋ฉด ์ฑ์ด ๋กค๋ง๋ฉ๋๋ค. ์๋ฒฝํ๊ฒ ์ ์คํ๋๊ณ ์์ต๋๋ค.
์ด ์ค๋ฅ ๋ฌธ์ ๋ ์์๊ณ ์ฌ๋ฌ ๋ฒ ํ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊ฒ์ผ๋ก ๋ํ๋ฌ์ต๋๋ค.
GAE์ ๊ฐ์ ํด๋ผ์ฐ๋์ ์ฑ์ ๋ฐฐํฌํ๋ฉด ํํธ ์ค๋ฅ๊ฐ ํ์๋์ง ์์ต๋๋ค.
์ด ์ฌ๋ก ์๋ฃจ์
์ ์ฌ์ฉํ์ฌ ์ค๋ฅ๋ฅผ ํ๋ฉดํํ๋ ค๊ณ ์๋ํ ์ ์์ต๋๋ค. https://stackoverflow.com/questions/38012797/google-app-engine-502-bad-gateway-with-nodejs
502 ์๋ชป๋ ๊ฒ์ดํธ์จ์ด๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ
์๋ง๋ 2๊ฐ์ง ๊ฐ๋ฅ์ฑ์ด ์์ ๊ฒ์
๋๋ค:
์ฌ๊ธฐ์ ์ค๋ช ๋ ์์ ํ sulution: https://www.datadoghq.com/blog/nginx-502-bad-gateway-errors-gunicorn/
[CRITICAL] WORKER TIMEOUT ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ฌ๋์ ์์ ํ ์ ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
์ด ์ค๋ ๋๋ฅผ ์ฐพ๋ ์ฌ๋๋ค์๊ฒ ๋ ๋ค๋ฅธ ๊ฐ๋ฅ์ฑ์ ์ถ๊ฐํ๋ ์ค...
์ด๊ฒ์ ๋ํ ๋์ปค๊ฐ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ํด ๋๋ฌด ๋ฎ์ ๋ฆฌ์์ค ์ ์ฝ์ ๋ถ๊ณผํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ๋ค์๊ณผ ๊ฐ์ ์ ์ฝ ์กฐ๊ฑด์ด ์์์ต๋๋ค.
services:
web_app:
image: blah-blah
deploy:
resources:
limits:
cpus: "0.25"
memory: 128M
gunicorn
๋ํด ๋๋ฌด ๋ฎ์๊ธฐ ๋๋ฌธ์ ์ ์ฝ ์กฐ๊ฑด์ ์ ๊ฑฐํ ๋๊น์ง ๊ณ์ [CRITICAL] WORKER TIMEOUT
์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.
gunicorn์ ๊ฒฝ์ฐ ์ด ๋ฆฌ์์ค๋ ์๋ฒฝํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋น์ ์ ์ ๋ง๋ก ํ ํ์๊ฐ ์์ต๋๋ค
์์
์ ์์ ๊ทํ์ ์์
์ ํ์ํ ๋ฆฌ์์ค์ ๋ํ ํ๋ฉด
์ ํ๋ฆฌ์ผ์ด์
. 128M ๋ฐ 0.25cpu๋ ์น ์์ฉ ํ๋ก๊ทธ๋จ์ ๋ํด ์ ๋ง ๋ฎ์ ๊ฒ์ฒ๋ผ ๋ณด์
๋๋ค.
Python์ผ๋ก ์์ฑ๋์์ต๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ์ต์ํ 1๊ฐ์ ์ฝ์ด /vcpu๊ฐ ํ์ํ๊ณ
์ต์ 512MB์ RAM.
2021๋ 3์ 26์ผ ๊ธ์์ผ 02:14, Colton Hicks @ . * > ์ด:
์ด ์ค๋ ๋๋ฅผ ์ฐพ๋ ์ฌ๋๋ค์๊ฒ ๋ ๋ค๋ฅธ ๊ฐ๋ฅ์ฑ์ ์ถ๊ฐํ๋ ์ค...
์ด๊ฒ์ ๋์ปค๊ฐ ๋ค์๊ณผ ๊ฐ์ ๋ฆฌ์์ค ์ ์ฝ์ ๋ถ๊ณผํจ์ผ๋ก์จ ๋ฐ์ํ ์๋ ์์ต๋๋ค.
์น ์์ฉ ํ๋ก๊ทธ๋จ์ ๋ํด ๋๋ฌด ๋ฎ์ต๋๋ค. ์๋ฅผ ๋ค์ด ๋๋ ๋ค์์ ๊ฐ์ง๊ณ ์์๋ค
์ ์ฝ:์๋น์ค:
web_app:
์ด๋ฏธ์ง: ใ ใ ใ ใ
๋ฐฐํฌ:
์์:
์ ํ:
CPU: "0.25"
๋ฉ๋ชจ๋ฆฌ: 128M๊ทธ๋ฆฌ๊ณ ์ด๊ฒ๋ค์ ๋ถ๋ช ํ gunicorn์ ๋ํด ๋๋ฌด ๋ฎ์์ผ๋ฏ๋ก ๋๋ ์ง์์ ์ผ๋ก [CRITICAL]์ ์ป์์ต๋๋ค.
์ ์ฝ ์กฐ๊ฑด์ ์ ๊ฑฐํ ๋๊น์ง WORKER TIMEOUT ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.โ
๋น์ ์ด ์ธ๊ธ๋์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ณ GitHub์์ ํ์ธํ์ธ์.
https://github.com/benoitc/gunicorn/issues/1801#issuecomment-807855647 ,
๋๋ ๊ตฌ๋ ์ทจ์
https://github.com/notifications/unsubscribe-auth/AAADRITPZB7BMA6QW7LFNVLTFPNV3ANCNFSM4FDLD5PA
.>
๋ด ๋ชจ๋ฐ์ผ์์ ๋ณด๋ธ
--timeout=1000์ด ์ ์๊ฒ ์ผํ์ต๋๋ค. ๋ฌธ์ ๋ CPU ๋ฆฌ์์ค๊ฐ ๋ฎ์ GCP ๋จธ์ ์ด์์ต๋๋ค. ๊ธฐ๋ณธ ์๊ฐ ์ด๊ณผ๋ก ๋ก์ปฌ ์ปดํจํฐ์์ ์ ๋๋ก ์๋ํ์ต๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
gevent์ ํจ๊ป gunicorn์ ์ฌ์ฉํด๋ ๋ฒ๊ทธ๊ฐ ์์ ๋์ง ์์์ต๋๋ค.