Gunicorn: Flask ์•ฑ์„ โ€‹โ€‹์‹คํ–‰ํ•  ๋•Œ ์ค‘์š”ํ•œ ์ž‘์—…์ž ์‹œ๊ฐ„ ์ดˆ๊ณผ

์— ๋งŒ๋“  2018๋…„ 06์›” 05์ผ  ยท  82์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: benoitc/gunicorn

[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

์ด ์˜ˆ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ์™€ ์˜ˆ์ƒ๋˜๋Š” ์˜ค๋ฅ˜๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์„ค๋ช…ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ์–ด๋–ป๊ฒŒ ์ˆ˜์ •ํ•ฉ๋‹ˆ๊นŒ ๋˜๋Š” ์˜ˆ์ƒ๋˜๋Š” ๋™์ž‘์ธ ๊ฒฝ์šฐ ์‹ฌ๊ฐํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๊นŒ?

Investigation unconfirmed

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

gevent์™€ ํ•จ๊ป˜ gunicorn์„ ์‚ฌ์šฉํ•ด๋„ ๋ฒ„๊ทธ๊ฐ€ ์ˆ˜์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  82 ๋Œ“๊ธ€

์˜ค๋ฅ˜๊ฐ€ ์˜ˆ์ƒ๋˜์ง€๋Š” ์•Š์ง€๋งŒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์˜ˆ์ œ๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ํ™˜๊ฒฝ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค.

  • Gunicorn์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ํด๋ผ์ด์–ธํŠธ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
  • Gunicorn์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์—ญ๋ฐฉํ–ฅ ํ”„๋ก์‹œ(์žˆ๋Š” ๊ฒฝ์šฐ)๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๊ท€ํ•˜์˜ ํ™˜๊ฒฝ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค.

  • Gunicorn์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ํด๋ผ์ด์–ธํŠธ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
    => Chromium์—์„œ ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค. http://localhost :5000/
  • Gunicorn์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์—ญ๋ฐฉํ–ฅ ํ”„๋ก์‹œ(์žˆ๋Š” ๊ฒฝ์šฐ)๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
    => ํ”„๋ก์‹œ ์—†์Œ, Gunicorn + Flask๋งŒ ์žˆ์Œ

๋ฐฉ๊ธˆ ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ์„ค์ •์—์„œ ๋ฌธ์ œ๋ฅผ ์žฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

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(์˜ˆ์ •)์œผ๋กœ ์—…๋ฐ์ดํŠธํ–ˆ๊ณ  ์ž‘์—…์ž๋Š” ์˜ค๋ฅ˜ ์—†์ด ์„ฑ๊ณต์ ์œผ๋กœ ๋ถ€ํŒ…๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ:

  • ์šฐ๋ฆฌ๋Š” 4๋ช…์˜ ๋…ธ๋™์ž๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค
  • Django ์•ฑ์„ ์ •ํ™•ํžˆ 4๋ฒˆ ํ˜ธ์ถœํ•˜๋ฉด ๋‹ค์Œ ํ˜ธ์ถœ์ด ์‹œ๊ฐ„ ์ดˆ๊ณผ๋˜์–ด ๋กœ๊ทธ์— [CRITICAL WORKER TIMEOUT]์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
  • linux top ๋ช…๋ น์€ 4๊ฐœ์˜ gunicorn ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ƒ๋‹นํžˆ ๋†’์€ CPU ์†Œ๋น„๋กœ ๋ฉˆ์ถ˜ ๊ฒƒ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์•ฑ์„ ๋‹ค์‹œ ์˜จ๋ผ์ธ ์ƒํƒœ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด 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"
  • Pipfile.lock
{
    "_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 \

--error-logfile ๋กœ๊ทธ/error.log --log-level=info

ํ”Œ๋ผ์Šคํฌ==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์—์„œ ๋‹จ์ผ ๋™๊ธฐํ™” ์ž‘์—…์ž๋งŒ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋” ํฝ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚ด ์‹คํ—˜์— ๋”ฐ๋ฅด๋ฉด ์—ฌ๋Ÿฌ ๋™๊ธฐํ™” ์ž‘์—…์ž๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ํ™˜๊ฒฝ

  • ๋‚ด ๊ธฐ๋ณธ OS๋Š” Ubuntu 17์ž…๋‹ˆ๋‹ค.
  • ๋กœ์ปฌ ๋„์ปค ์ปจํ…Œ์ด๋„ˆ์—์„œ ์‹คํ–‰ ์ค‘์ธ ๋‚˜๋จธ์ง€ API๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. Dockefile์˜ ๊ด€๋ จ ๋ผ์ธ
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
......
  • 3๊ฐœ์˜ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค: Firefox 61.0.1, Chromium 67.0.3396.99, Chrome 70.0.3538.102
  • ๋‹ค๋ฅธ ํฌํŠธ์˜ ๋‹ค๋ฅธ ๋„์ปค ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ œ๊ณต๋˜๋Š” ๋ฐ˜์‘ ์•ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฐ˜์‘ ์•ฑ์€ ๋‚ด API์— ๋Œ€ํ•œ CORS AJAX ์š”์ฒญ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค(์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋‹ค๋ฅธ ๋กœ์ปฌ ํ˜ธ์ŠคํŠธ ํฌํŠธ๋กœ API ํ˜ธ์ถœ์„ ๋ณด๋‚ด๋Š” ๋™์•ˆ ํ•˜๋‚˜์˜ ๋กœ์ปฌ ํ˜ธ์ŠคํŠธ ํฌํŠธ์—์„œ ์ œ๊ณต๋˜๊ธฐ ๋•Œ๋ฌธ์— CORS ์š”์ฒญ์ž„).
  • ๋‚ด ์‹คํ—˜์—์„œ ํ•ญ์ƒ "์ฐจ๋‹จ"๋˜๋Š” ์š”์ฒญ์€ CORS OPTIONS ์š”์ฒญ์ž…๋‹ˆ๋‹ค(๋ธŒ๋ผ์šฐ์ €์—์„œ POST ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์„ ์š”์ฒญํ•˜๊ธฐ ์œ„ํ•ด ํŠธ๋ฆฌ๊ฑฐ๋จ). ๋ธŒ๋ผ์šฐ์ €๊ฐ€ POST ํ˜ธ์ถœ๋กœ ํ›„์† ์กฐ์น˜๋ฅผ ์ทจํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— OPTIONS ํ˜ธ์ถœ๋กœ ์˜ˆ์ธก ์—ฐ๊ฒฐ์„ ์‹œ๋„ํ•˜๋Š” ๊ฒƒ์ด ๋…ผ๋ฆฌ์ ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

์‹คํ—˜ 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: ๋ชจ๋“  ๊ฒƒ์ด ์ž˜ ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค.

์‹คํ—˜ ์š”์•ฝ

  • ํŒŒ์ด์–ดํญ์Šค์—๋„ ์˜ˆ์ธก ์„œ๋น„์Šค๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์ง€๋งŒ ๋” ์šฐ์•„ํ•ด ๋ณด์ธ๋‹ค. (์‹คํ—˜ 1)
  • Chromium์€ "์˜ˆ์ธก" ์—ฐ๊ฒฐ์„ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ๊ฐ€์žฅ ๊ณต๊ฒฉ์ ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. OPTIONS ์š”์ฒญ ์ค‘์— ์ตœ๋Œ€ 3-4๊ฐœ์˜ "์˜ˆ์ธก" ์—ฐ๊ฒฐ์„ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค(์‹คํ—˜ 1 ๋ฐ 2).
  • ๋†€๋ž๊ฒŒ๋„ Chrome์—๋„ ์˜ˆ์ธก ์„œ๋น„์Šค๊ฐ€ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์ง€๋งŒ ์‹คํ—˜์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค("์˜ˆ์ธก" ์—ฐ๊ฒฐ์˜ ์ˆœ์„œ ๋˜๋Š” ์ˆ˜๊ฐ€ Chromium๊ณผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Œ).

ํ•ด๊ฒฐ์ฑ…
ํ”„๋กœ๋•์…˜์—์„œ: ๊ฐ€์žฅ ์‰ฌ์šด ์ˆ˜์ •์€ 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

์ด๊ฒƒ์ด ์ด ๋ฌธ์ œ์˜ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ์›์ธ์ž…๋‹ˆ๋‹ค.

๋‚ด ์†”๋ฃจ์…˜์ด ๋„์›€์ด ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋ฉฐ์น  ์ „์— ์ด ์ค‘์š”ํ•œ ์ž‘์—…์ž ์‹œ๊ฐ„ ์ดˆ๊ณผ ๋ฌธ์ œ๋ฅผ ๋งŒ๋‚ฌ๊ณ  ๋ช‡ ๊ฐ€์ง€ ์†”๋ฃจ์…˜์„ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋‚ด ์ดํ•ด์™€ ํ•ด๊ฒฐ์ฑ…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. gunicorn์—์„œ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•ด ๋ณด์„ธ์š”.

์„œ๋น„์Šค๋ฅผ ์‹œ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด tensorflow ๋ฐฑ์—”๋“œ์™€ ๊ฐ™์€ ํŒจํ‚ค์ง€๋ฅผ ๋กœ๋“œํ•˜๋Š” ๋ฐ ๋” ๋งŽ์€ ์‹œ๊ฐ„์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž‘์—…์ž๋ฅผ ๋ถ€ํŒ…ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋Š๋ฆฐ ์•ฑ ๋ถ€ํŒ… ์‹œ๊ฐ„์ด ๋ฐœ์ƒํ•˜๋ฉด gunicorn์—์„œ ์‚ฌ์ „ ๋กœ๋“œ ์˜ต์…˜์„ ํ™œ์„ฑํ™”ํ•ด ๋ณด์‹ญ์‹œ์˜ค(https://devcenter.heroku.com/articles/python-gunicorn#advanced-configuration ์ฐธ์กฐ).

gunicorn hello:app --preload

  1. gunicorn์˜ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ๋Š˜๋ฆฌ์‹ญ์‹œ์˜ค.

๊ธฐ๋ณธ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋Š” 30์ดˆ์ž…๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด API๋ฅผ ์™„๋ฃŒํ•˜๋Š” ๋ฐ ์‹ค์ œ๋กœ ๋งŽ์€ ์‹œ๊ฐ„์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ๋Š˜๋ฆฌ์‹ญ์‹œ์˜ค.

gunicorn hello:app --timeout 10

๊ทธ๋Ÿฌ๋‚˜ ๋‚ด ๊ด€์ ์—์„œ ๋ณผ ๋•Œ API๊ฐ€ ์™„๋ฃŒํ•˜๋Š” ๋ฐ 1๋ถ„ ์ด์ƒ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” ์˜๋ฏธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์ฝ”๋“œ์—์„œ ์•ฝ๊ฐ„์˜ ๋ฐœ์ „์„ ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค.

  1. k8์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ yaml์—์„œ ์ปจํ…Œ์ด๋„ˆ/์ด๋ฏธ์ง€์— ๋Œ€ํ•œ timeoutSeconds๋ฅผ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์˜ค๋Š˜ ๊ฐ™์€ ๋ฌธ์ œ์— ์ง๋ฉดํ–ˆ๋‹ค. ์ œ ๊ฒฝ์šฐ์—๋Š” 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์„ ์‹คํ–‰ํ•˜๋ฉด ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ด์œ ๋กœ ๊ธฐ๋ณธ ๋™๊ธฐํ™” ์ž‘์—…์ž๋กœ ์‹œ๊ฐ„ ์ดˆ๊ณผ๊ฐ€ _๋ฐœ์ƒ_ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋Š๋ฆฐ ํด๋ผ์ด์–ธํŠธ
  • ๋ธŒ๋ผ์šฐ์ €์™€ ํ”„๋ก์‹œ์— ์˜ํ•ด ์—ด๋ ค ์žˆ๋Š” ์—ฐ๊ฒฐ ๋ฏธ๋ฆฌ ์—ฐ๊ฒฐ/ํ”„๋ฆฌํŽ˜์น˜
  • ์™ธ๋ถ€ API๋ฅผ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ CPU๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ์ž‘์—…์œผ๋กœ ์ธํ•œ ๊ธด ์‘๋‹ต

๋น„๋™๊ธฐ ๋˜๋Š” ์Šค๋ ˆ๋“œ ์ž‘์—…์ž ์œ ํ˜•์œผ๋กœ ์ „ํ™˜ํ•˜๊ฑฐ๋‚˜ 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๋กœ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๊นŒ?

gunicorn ์•ฑ:์•ฑ --timeout 1000
๋˜๋Š”
gunicorn ์•ฑ:app --preload

๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ–ˆ์Šต๋‹ˆ๋‹ค ... ๋‚˜๋Š” ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

์ด์ƒํ•˜๊ฒŒ๋„ --worker-tmp-dir /dev/shm ํ–ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ๋‹ค์Œ์„ ์ˆ˜์‹ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

[2020-11-27 21:01:42 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:17)

/dev/shm ๊ฐ€ ramfs์ธ์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋ฒค์น˜๋งˆํ‚นํ–ˆ์Šต๋‹ˆ๋‹ค.

image

๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    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์€ ์ฐธ๊ณ ์šฉ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์ผ๋‹จ ๋กœ๋“œ๋˜๋ฉด ์•ฑ์ด ๋กค๋ง๋ฉ๋‹ˆ๋‹ค. ์™„๋ฒฝํ•˜๊ฒŒ ์ž˜ ์‹คํ–‰๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์˜ค๋ฅ˜ ๋ฌธ์ œ๋„ ์žˆ์—ˆ๊ณ  ์—ฌ๋Ÿฌ ๋ฒˆ ํ›„์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒƒ์œผ๋กœ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค.

  1. ์—”์ง„์—‘์Šค ๊ตฌ์„ฑ
  2. ๊ตฌ๋‹ˆ์ฝ˜/์šฐ์‰ฌ๊ธฐ

GAE์™€ ๊ฐ™์€ ํด๋ผ์šฐ๋“œ์— ์•ฑ์„ ๋ฐฐํฌํ•˜๋ฉด ํžŒํŠธ ์˜ค๋ฅ˜๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ด ์‚ฌ๋ก€ ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜ค๋ฅ˜๋ฅผ ํ‘œ๋ฉดํ™”ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. https://stackoverflow.com/questions/38012797/google-app-engine-502-bad-gateway-with-nodejs

502 ์ž˜๋ชป๋œ ๊ฒŒ์ดํŠธ์›จ์ด๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ
์•„๋งˆ๋„ 2๊ฐ€์ง€ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค:

  1. gunicorn์ด ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค
  2. gunicorn์ด ์‹œ๊ฐ„ ์ดˆ๊ณผ๋˜์—ˆ์Šต๋‹ˆ๋‹ค

์—ฌ๊ธฐ์— ์„ค๋ช…๋œ ์™„์ „ํ•œ 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 ๋จธ์‹ ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋กœ ๋กœ์ปฌ ์ปดํ“จํ„ฐ์—์„œ ์ œ๋Œ€๋กœ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰