Gunicorn: Herokuμ—μ„œ >13k 응닡을 λ°˜ν™˜ν•  λ•Œ POST μ‹€νŒ¨

에 λ§Œλ“  2014λ…„ 08μ›” 04일  Β·  34μ½”λ©˜νŠΈ  Β·  좜처: benoitc/gunicorn

μ•ˆλ…•ν•˜μ„Έμš”, Flask + Gunicorn + Herokuλ₯Ό μ‚¬μš©ν•˜λŠ” ν”„λ‘œλ•μ…˜μ—μ„œ 이 λ¬Έμ œκ°€ λ°œμƒν–ˆμ§€λ§Œ μ›μΈμ΄λ‚˜ ν•΄κ²° 방법을 찾지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€.

POST λ§€κ°œλ³€μˆ˜κ°€ μžˆλŠ” νŠΉμ • POST μš”μ²­μ˜ 경우 Heroku λΌμš°ν„°μ˜ H18 였λ₯˜(sock=backend)와 ν•¨κ»˜ μš”μ²­μ΄ μ‹€νŒ¨ν•˜μ—¬ μ„œλ²„κ°€ μ†ŒμΌ“μ„ λ‹«μ•„μ„œλŠ” μ•ˆ 될 λ•Œ μ†ŒμΌ“μ„ λ‹«μ•˜μŒμ„ λ‚˜νƒ€λƒ…λ‹ˆλ‹€.

μš°λ¦¬λŠ” μ•½ 13k ν‘œμ‹œλ‘œ 쒁힐 λ•ŒκΉŒμ§€ μ‹€νŒ¨ν•œ μ—”λ“œν¬μΈνŠΈμ˜ 응닡 크기λ₯Ό 쀄이기 μ‹œμž‘ν–ˆμŠ΅λ‹ˆλ‹€. 13k λ―Έλ§Œμ„ 보내면 응닡이 항상 μž‘λ™ν•©λ‹ˆλ‹€. 13k 이상을 보내면 응닡이 거의 항상 μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

이λ₯Ό μž¬ν˜„ν•˜λŠ” μ½”λ“œλŠ” https://github.com/erjiang/gunicorn-issue μ—μ„œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 리포지토리λ₯Ό Heroku에 μžˆλŠ” κ·ΈλŒ€λ‘œ λ°°ν¬ν•˜κ³  README의 지침을 λ”°λ₯΄μ„Έμš”.

( Feedback Requested unconfirmed help wanted - Bugs -

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

https://github.com/erjiang/gunicorn-issue (gunicorn 19.9.0, Python 2.7.14, sync worker, --workers 4 μ‚¬μš©)μ—μ„œ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜μ—¬ μž¬ν˜„ν•  수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. 참고둜 gunicorn의 μ•‘μ„ΈμŠ€ 둜그 좜λ ₯은 HTTP 200을 λ°˜ν™˜ν–ˆλ‹€κ³  λ³΄κ³ ν•©λ‹ˆλ‹€.

Python 3.7.3 + gunicorn master 둜 μ—…λ°μ΄νŠΈν•˜κ³  --workers 1 μ€„μ΄λŠ” 것은 μž¬ν˜„μ„±μ— 영ν–₯을 λ―ΈμΉ˜μ§€ μ•Šμ•˜μ§€λ§Œ 동기화 μž‘μ—…μžμ—μ„œ gevent둜 μ „ν™˜ν•˜λ©΄ 였λ₯˜κ°€ 덜 자주 λ°œμƒν•©λ‹ˆλ‹€(μ—¬μ „νžˆ λ°œμƒν–ˆμ§€λ§Œ). --log-level debug μ‚¬μš©ν•΄λ„ μ€‘μš”ν•œ 것은 λ‚˜νƒ€λ‚˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€(μš”μ²­ 쀑 μœ μΌν•œ μΆ”κ°€ 좜λ ₯은 [DEBUG] POST /test1 ν–‰μ΄μ—ˆμŠ΅λ‹ˆλ‹€).

λ‹€μŒμœΌλ‘œ --spew μ‹œλ„ν–ˆμ§€λ§Œ λ¬Έμ œκ°€ 더 이상 μž¬ν˜„λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 이것은 μΆ”κ°€ν•˜λ €κ³  μ €λ₯Ό 주도 time.sleep(1) μ „κ³Ό resp.close() 여기에 μœ μ‚¬ 문제λ₯Ό λ°©μ§€ν•˜λŠ”ν•©λ‹ˆλ‹€.

λ”°λΌμ„œ close() μ‹œκ°„μ— μ†ŒμΌ“ 보내기 버퍼가 λΉ„μ–΄ μžˆμ§€ μ•Šμ„ 수 μžˆμœΌλ―€λ‘œ 응닡이 손싀될 수 μžˆμŠ΅λ‹ˆλ‹€.

μ°Έκ³ : close() λŠ” μ—°κ²°κ³Ό κ΄€λ ¨λœ λ¦¬μ†ŒμŠ€λ₯Ό ν•΄μ œν•˜μ§€λ§Œ 연결을 μ¦‰μ‹œ 닫을 ν•„μš”λŠ” μ—†μŠ΅λ‹ˆλ‹€. μ μ‹œμ— 연결을 μ’…λ£Œν•˜λ €λ©΄ shutdown() 전에 close() shutdown() λ₯Ό ν˜ΈμΆœν•˜μ‹­μ‹œμ˜€.

(https://docs.python.org/3/library/socket.html#socket.socket.close μ°Έμ‘°)

여기에 sock.close() μ•žμ— sock.shutdown(socket.SHUT_RDWR) ( docs )λ₯Ό μΆ”κ°€ν•˜λ©΄ λ¬Έμ œκ°€ ν•΄κ²°λ˜μ—ˆμŠ΅λ‹ˆλ‹€. λŒ€μ•ˆ μˆ˜μ •μ€ μ•„λ§ˆλ„ SO_LINGER λ₯Ό μ‚¬μš©ν•˜λŠ” 것일 수 μžˆμ§€λ§Œ, μ œκ°€ 읽은 바에 λ”°λ₯΄λ©΄ μž₯단점이 μžˆμŠ΅λ‹ˆλ‹€.

이 μ£Όμ œμ— λŒ€ν•œ λ¬Έμ„œλŠ” μ°ΎκΈ° μ–΄λ ΅μ§€λ§Œ λ‹€μŒμ„ μ°Ύμ•˜μŠ΅λ‹ˆλ‹€.
https://stackoverflow.com/questions/8874021/close-socket-directly-after-send-unsafe
https://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable

도움이 되기λ₯Ό λ°”λžλ‹ˆλ‹€ :-)

λͺ¨λ“  34 λŒ“κΈ€

정말 μœ μš©ν•œ λ³΄κ³ μ„œ, @erjiang κ°μ‚¬ν•©λ‹ˆλ‹€.

ν…ŒμŠ€νŠΈν•  heroku 계정이 μ—†μŠ΅λ‹ˆλ‹€. 그런 계정을 가진 μ‚¬λžŒμ΄ ν…ŒμŠ€νŠΈν•  수 μžˆμŠ΅λ‹ˆκΉŒ? cc @tilgovi @kennethreitz

κΈ°μ˜μ§€λ§Œ μ•„λ§ˆ 곧 얻을 수 없을 κ²ƒμž…λ‹ˆλ‹€.

λΉ λ₯Έ μ˜¨μ „μ„± κ²€μ‚¬λ‘œ λ‘œμ»¬μ—μ„œ μ‹€ν–‰ν•˜κ³  μ›¨μ΄νŠΈλ¦¬μŠ€μ™€ gunicorn을 λΉ„κ΅ν•˜κΈ° μœ„ν•΄ curl둜 λͺ‡ 가지λ₯Ό ν™•μΈν–ˆμŠ΅λ‹ˆλ‹€.

  • [x] μ½˜ν…μΈ  길이 동일
  • [x] λ™μΌν•œ λ³Έλ¬Έ λ‚΄μš©
  • [x] λ™μΌν•œ 전솑 인코딩(λ‘˜ 쀑 ν•˜λ‚˜κ°€ 청크λ₯Ό μ§€μ •ν•˜μ§€ μ•Šκ³  λ‘˜ λ‹€ Content-Length μ‚¬μš©)

λ‹€μŒμœΌλ‘œ TCP μˆ˜μ€€μ—μ„œ 차이가 μžˆλŠ”μ§€ κΆκΈˆν•©λ‹ˆλ‹€. λ‚˜λŠ” 그것듀을 tcpdumpν•˜κ³  λΉ„λ¦°λ‚΄κ°€ λ‚˜λŠ” 것을 μ•Œμ•„μ°¨λ¦΄ κ²ƒμž…λ‹ˆλ‹€.

λ‚˜λŠ” 같은 컬 λΌμΈμœΌλ‘œλ„ gunicorn이 연결을 λŠμ§€ 만 μ›¨μ΄νŠΈλ¦¬μŠ€κ°€ μ—΄μ–΄ λ‘‘λ‹ˆλ‹€. 아직 κ·Έ λ‹¨μ„œκ°€ μ—†μ§€λ§Œ λ‚΄κ°€ λ³Ό 수 μžˆμ—ˆλ˜ 것은 _μœ μΌν•œ_ λ‹€λ₯Έ μ μ΄μ—ˆμŠ΅λ‹ˆλ‹€.

@tilgovi μ›¨μ΄νŠΈλ¦¬μŠ€μ—κ²Œ λ³΄μ΄λŠ” λ™μž‘μ„ μŠ€λ ˆλ“œ μž‘μ—…μžλ‘œ μž¬ν˜„ν•  수 μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. μ–΄μ¨Œλ“  μ΄λ ‡κ²Œ μ²˜λ¦¬ν•΄μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€ :)

μ•ˆλ…•ν•˜μ„Έμš” μ—¬λŸ¬λΆ„,
같은 λ¬Έμ œκ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. 이 문제λ₯Ό 더 μžμ„Ένžˆ κ²€ν† ν•  κΈ°νšŒκ°€ μžˆμœΌμ‹ κ°€μš”?
@tilgovi @erjiang @benoitc

건배
격언

@maximkgn ν”ŒλΌμŠ€ν¬λ„ μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆκΉŒ? μžμ„Έν•œ λ‚΄μš©μ€?

μž₯κ³  1.7을 μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.
μš°λ¦¬λŠ” 항상 13k보닀 κΈ΄ νŠΉμ • 포슀트 응닡을 가지고 μžˆμ—ˆκ³  ~0.5의 νŠΉμ • ν™•λ₯ λ‘œ ν΄λΌμ΄μ–ΈνŠΈμ˜ 응닡은 13k보닀 μ•½κ°„ μž˜λ ΈμŠ΅λ‹ˆλ‹€. heroku λ‘œκ·Έμ—μ„œ λ™μΌν•œ h18 였λ₯˜λ₯Ό λ³΄μ•˜κ³  Python μ½”λ“œμ—μ„œ 였λ₯˜κ°€ λ°œμƒν•˜μ§€ μ•ŠλŠ”μ§€ ν™•μΈν•œ ν›„ heroku와 Python μ‚¬μ΄μ˜ gunicorn κ³„μΈ΅μ—μ„œ λ°œμƒν•œλ‹€κ³  결둠을 λ‚΄λ €μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€.
μš°λ¦¬κ°€ waitress/uwgi둜 μ „ν™˜ν–ˆμ„ λ•Œ 버그가 λ°œμƒν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

@maximkgn --threads 섀정을 μ‚¬μš©ν•˜λ©΄ μ–΄λ–»κ²Œ λ©λ‹ˆκΉŒ?

λˆ„κ΅¬λ“ μ§€ 이것을 ν…ŒμŠ€νŠΈ ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

ν”ŒλΌμŠ€ν¬μ™€ gunicorn(ν…ŒμŠ€νŠΈ 버전 19.3 및 19.4.5)에 λ™μΌν•œ λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€. @benoitc 1, 2 및 4 μŠ€λ ˆλ“œ(

μ–΄λ–€ μ‹μœΌλ‘œλ“  이것을 ν…ŒμŠ€νŠΈν•˜λŠ” 데 도움을 쀄 수 μžˆλŠ”μ§€ μ•Œλ €μ£Όμ‹­μ‹œμ˜€.

@cbaines μš”μ²­μ΄ μ–΄λ–»κ²Œ μƒκ²Όλ‚˜μš”?

FriendpasteλŠ” 1백만 개 μ΄μƒμ˜ κ²Œμ‹œλ¬Όμ„ μˆ˜λ½ν•  수 μžˆμŠ΅λ‹ˆλ‹€.... κ·Έλž˜μ„œ gunicorn λ‚΄λΆ€μ—λŠ” μ œν•œμ΄ μ—†μŠ΅λ‹ˆλ‹€.

닡이 μ—†μ—ˆμŠ΅λ‹ˆλ‹€. μž¬ν˜„ν•  수 μ—†μœΌλ―€λ‘œ 문제λ₯Ό λ‹«μŠ΅λ‹ˆλ‹€. ν•„μš”ν•œ 경우 자유둭게 λ‹€μ‹œ μ—½λ‹ˆλ‹€.

Flask 1.0.2 및 gunicorn 19.9.0을 ν¬ν•¨ν•˜λ„λ‘ 쒅속성을 μ—…λ°μ΄νŠΈν•œ 후에도 계속 μž¬μƒλ©λ‹ˆλ‹€. ν•˜μ§€λ§Œ 이것에 λŒ€ν•΄ Heroku의 λˆ„κ΅°κ°€μ˜ 관심을 λ°›λŠ” 것이 쒋을 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. 그듀은 ν—Œμ‹ μ μΈ Python μ‚¬λžŒλ“€μ΄ μžˆλ‹€κ³  λ“€μ—ˆμŠ΅λ‹ˆλ‹€.

μ—¬κΈ°μ—μ„œ μ΅œμ‹  컀밋을 μ°Έμ‘°ν•˜μ‹­μ‹œμ˜€: https://github.com/erjiang/gunicorn-issue/

λ˜ν•œ μ •κΈ°μ μœΌλ‘œ λŒ€κ·œλͺ¨ GET μš”μ²­μ— λŒ€ν•΄ 이 H18 였λ₯˜λ₯Ό μˆ˜μ‹ ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

μ›¨μ΄νŠΈλ¦¬μŠ€λ‘œ μ „ν™˜ν•˜λ©΄ λ¬Έμ œκ°€ ν•΄κ²°λ˜μ—ˆμŠ΅λ‹ˆλ‹€. gunicorn이 그것을 μƒμ„±ν•˜λŠ” μ΄μœ λŠ” ν™•μ‹€ν•˜μ§€ μ•Šμ§€λ§Œ λ™μΌν•œ μ •ν™•ν•œ μ½”λ“œκ°€ μ‹€ν–‰λ˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

응닡 본문은 21.54KBμž…λ‹ˆλ‹€.

Flask 1.0.2 및 gunicorn 19.9.0을 ν¬ν•¨ν•˜λ„λ‘ 쒅속성을 μ—…λ°μ΄νŠΈν•œ 후에도 계속 μž¬μƒλ©λ‹ˆλ‹€. ν•˜μ§€λ§Œ 이것에 λŒ€ν•΄ Heroku의 λˆ„κ΅°κ°€μ˜ 관심을 λ°›λŠ” 것이 쒋을 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. 그듀은 ν—Œμ‹ μ μΈ Python μ‚¬λžŒλ“€μ΄ μžˆλ‹€κ³  λ“€μ—ˆμŠ΅λ‹ˆλ‹€.

μ—¬κΈ°μ—μ„œ μ΅œμ‹  컀밋을 μ°Έμ‘°ν•˜μ‹­μ‹œμ˜€: https://github.com/erjiang/gunicorn-issue/

Herokuμ—μ„œ 지원 티켓을 λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€. μœ μš©ν•œ 것이 있으면 μ—¬κΈ°μ—μ„œ μ—…λ°μ΄νŠΈν•  κ²ƒμž…λ‹ˆλ‹€.

@benoitc λŠ” @erjiang 이 μž¬ν˜„ κ°€λŠ₯ν•œ 예λ₯Ό μ œκ³΅ν•œ κ²ƒμ²˜λŸΌ λ³΄μž…λ‹ˆλ‹€. 이 백업을 μ—΄ 수 μžˆμŠ΅λ‹ˆκΉŒ?

λ‹€μ‹œ μ—΄μ—ˆμŠ΅λ‹ˆλ‹€. λ‚΄κ°€ 슀슀둜 ν• λ‹Ήν•˜κ³  κ°€λŠ₯ν•œ ν•œ μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

Flask 1.0.2 및 gunicorn 19.9.0을 ν¬ν•¨ν•˜λ„λ‘ 쒅속성을 μ—…λ°μ΄νŠΈν•œ 후에도 계속 μž¬μƒλ©λ‹ˆλ‹€. ν•˜μ§€λ§Œ 이것에 λŒ€ν•΄ Heroku의 λˆ„κ΅°κ°€μ˜ 관심을 λ°›λŠ” 것이 쒋을 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. 그듀은 ν—Œμ‹ μ μΈ Python μ‚¬λžŒλ“€μ΄ μžˆλ‹€κ³  λ“€μ—ˆμŠ΅λ‹ˆλ‹€.
μ—¬κΈ°μ—μ„œ μ΅œμ‹  컀밋을 μ°Έμ‘°ν•˜μ‹­μ‹œμ˜€: https://github.com/erjiang/gunicorn-issue/

Herokuμ—μ„œ 지원 티켓을 λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€. μœ μš©ν•œ 것이 있으면 μ—¬κΈ°μ—μ„œ μ—…λ°μ΄νŠΈν•  κ²ƒμž…λ‹ˆλ‹€.

herokuμ—μ„œ λ‹΅μž₯을 λ°›μ•˜μŠ΅λ‹ˆκΉŒ?

https://github.com/erjiang/gunicorn-issue (gunicorn 19.9.0, Python 2.7.14, sync worker, --workers 4 μ‚¬μš©)μ—μ„œ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜μ—¬ μž¬ν˜„ν•  수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. 참고둜 gunicorn의 μ•‘μ„ΈμŠ€ 둜그 좜λ ₯은 HTTP 200을 λ°˜ν™˜ν–ˆλ‹€κ³  λ³΄κ³ ν•©λ‹ˆλ‹€.

Python 3.7.3 + gunicorn master 둜 μ—…λ°μ΄νŠΈν•˜κ³  --workers 1 μ€„μ΄λŠ” 것은 μž¬ν˜„μ„±μ— 영ν–₯을 λ―ΈμΉ˜μ§€ μ•Šμ•˜μ§€λ§Œ 동기화 μž‘μ—…μžμ—μ„œ gevent둜 μ „ν™˜ν•˜λ©΄ 였λ₯˜κ°€ 덜 자주 λ°œμƒν•©λ‹ˆλ‹€(μ—¬μ „νžˆ λ°œμƒν–ˆμ§€λ§Œ). --log-level debug μ‚¬μš©ν•΄λ„ μ€‘μš”ν•œ 것은 λ‚˜νƒ€λ‚˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€(μš”μ²­ 쀑 μœ μΌν•œ μΆ”κ°€ 좜λ ₯은 [DEBUG] POST /test1 ν–‰μ΄μ—ˆμŠ΅λ‹ˆλ‹€).

λ‹€μŒμœΌλ‘œ --spew μ‹œλ„ν–ˆμ§€λ§Œ λ¬Έμ œκ°€ 더 이상 μž¬ν˜„λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 이것은 μΆ”κ°€ν•˜λ €κ³  μ €λ₯Ό 주도 time.sleep(1) μ „κ³Ό resp.close() 여기에 μœ μ‚¬ 문제λ₯Ό λ°©μ§€ν•˜λŠ”ν•©λ‹ˆλ‹€.

λ”°λΌμ„œ close() μ‹œκ°„μ— μ†ŒμΌ“ 보내기 버퍼가 λΉ„μ–΄ μžˆμ§€ μ•Šμ„ 수 μžˆμœΌλ―€λ‘œ 응닡이 손싀될 수 μžˆμŠ΅λ‹ˆλ‹€.

μ°Έκ³ : close() λŠ” μ—°κ²°κ³Ό κ΄€λ ¨λœ λ¦¬μ†ŒμŠ€λ₯Ό ν•΄μ œν•˜μ§€λ§Œ 연결을 μ¦‰μ‹œ 닫을 ν•„μš”λŠ” μ—†μŠ΅λ‹ˆλ‹€. μ μ‹œμ— 연결을 μ’…λ£Œν•˜λ €λ©΄ shutdown() 전에 close() shutdown() λ₯Ό ν˜ΈμΆœν•˜μ‹­μ‹œμ˜€.

(https://docs.python.org/3/library/socket.html#socket.socket.close μ°Έμ‘°)

여기에 sock.close() μ•žμ— sock.shutdown(socket.SHUT_RDWR) ( docs )λ₯Ό μΆ”κ°€ν•˜λ©΄ λ¬Έμ œκ°€ ν•΄κ²°λ˜μ—ˆμŠ΅λ‹ˆλ‹€. λŒ€μ•ˆ μˆ˜μ •μ€ μ•„λ§ˆλ„ SO_LINGER λ₯Ό μ‚¬μš©ν•˜λŠ” 것일 수 μžˆμ§€λ§Œ, μ œκ°€ 읽은 바에 λ”°λ₯΄λ©΄ μž₯단점이 μžˆμŠ΅λ‹ˆλ‹€.

이 μ£Όμ œμ— λŒ€ν•œ λ¬Έμ„œλŠ” μ°ΎκΈ° μ–΄λ ΅μ§€λ§Œ λ‹€μŒμ„ μ°Ύμ•˜μŠ΅λ‹ˆλ‹€.
https://stackoverflow.com/questions/8874021/close-socket-directly-after-send-unsafe
https://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable

도움이 되기λ₯Ό λ°”λžλ‹ˆλ‹€ :-)

전체 STR:

  1. https://signup.heroku.com μ—μ„œ 무료 Heroku 계정을 λ§Œλ“œμ‹­μ‹œμ˜€.
  2. Heroku CLI μ„€μΉ˜(https://devcenter.heroku.com/articles/heroku-cli μ°Έμ‘°)
  3. heroku login μ‚¬μš©ν•˜μ—¬ CLI에 λ‘œκ·ΈμΈν•©λ‹ˆλ‹€.
  4. git clone https://github.com/erjiang/gunicorn-issue && cd gunicorn-issue
  5. heroku create (이것은 λ¬΄μž‘μœ„λ‘œ μƒμ„±λœ 이름을 가진 무료 Heroku 앱을 μƒμ„±ν•˜κ³  heroku λΌλŠ” git remoteλ₯Ό κ΅¬μ„±ν•©λ‹ˆλ‹€)
  6. git push heroku master
  7. curl --data "foo=bar" https://YOUR_GENERATED_APP_NAME.herokuapp.com/test1 (75% 이상 μ‹€νŒ¨)
  8. μ™„λ£Œλ˜λ©΄ heroku destroy λ₯Ό μ‹€ν–‰ν•˜μ—¬ 앱을 μ‚­μ œν•©λ‹ˆλ‹€.

@edmorley 같은 @tilgovi μ‚¬μš΄λ“œλŠ” 무엇이 잘λͺ»λ˜μ—ˆλŠ”μ§€μ˜ κ·ΈλŸ΄λ“―ν•œ μ„€λͺ…을 μƒμ‚°ν–ˆλ‹€. μ˜¬λ°”λ₯Έ μˆ˜μ • 사항이 무엇인지 μ‚΄νŽ΄λ³΄κ³  μ•Œ 수 μžˆμŠ΅λ‹ˆκΉŒ? sock.shutdown() λ₯Ό μΆ”κ°€ν•˜κΈ° μœ„ν•΄ PR을 μ œμΆœν•  μˆ˜λ„ μžˆμ§€λ§Œ 이것이 μ˜¬λ°”λ₯Έ μˆ˜μ •μΈμ§€ λ˜λŠ” λ‹€λ₯Έ 상황에 뢀정적인 영ν–₯을 미칠지 μ—¬λΆ€λ₯Ό 말할 만큼 μΆ©λΆ„νžˆ λͺ¨λ¦…λ‹ˆλ‹€.

μ•ˆλ…•ν•˜μ„Έμš”, 503KB 응닡 크기둜 λ™μΌν•œ λ¬Έμ œκ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. 응닡 λ°μ΄ν„°λŠ” JSON λ°°μ—΄μž…λ‹ˆλ‹€.
κ΄€μ°°λœ λ™μž‘ 은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  1. 잘린 응닡 본문이 ν‘œμ‹œλ˜κ³  http ν΄λΌμ΄μ–ΈνŠΈ(Chrome, curl)κ°€ μ—¬μ „νžˆ 응닡을 기닀리고 μžˆμŠ΅λ‹ˆλ‹€.
  2. μš”μ²­μ˜ ~75%λŠ” 120-130초 μ‚¬μ΄μ˜ 응닡 μ‹œκ°„μ„ κ²½ν—˜ν•©λ‹ˆλ‹€. λ‚˜λ¨Έμ§€ μš”μ²­μ€ 400ms 이내에 ν•΄κ²°λ©λ‹ˆλ‹€.
  3. 응닡 크기가 μž‘μ€ μš”μ²­μ€ λΉ λ¦…λ‹ˆλ‹€.

λ‹€μŒ 두 가지 λͺ¨λ‘

  1. Windows 10μ—μ„œ 둜컬 Docker μ„€μΉ˜
  2. AWS ECSμ—μ„œ 도컀 μ»¨ν…Œμ΄λ„ˆ μ‹€ν–‰

λŸ°νƒ€μž„ ν™˜κ²½ μ„€μ •
meinheld-gunicorn-docker μ΄λ―Έμ§€λŠ” Python 3.6.7, Flask 1.0.2, flask-restplus 0.12.1, κ°„λ‹¨ν•œ Flask-caching을 μ‚¬μš© ν•˜μ—¬ _python3.6_으둜 νƒœκ·Έκ°€ μ§€μ •λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

Docker ꡬ성 : 3개의 CPU, RAM 1024MB

Gunicorn ꡬ성 :

  • μž‘μ—…μž = 2*CPU + 1(λ¬Έμ„œμ—μ„œ ꢌμž₯)
  • μŠ€λ ˆλ“œ=1(2*CPU μŠ€λ ˆλ“œμ™€ λ™μΌν•œ λ™μž‘)
  • worker_class=" egg:meinheld#gunicorn_worker "

https://github.com/benoitc/gunicorn/issues/2015μ—μ„œ λ‹€λ₯Έ μ‚¬λžŒμ΄ meinheld μž‘μ—…μž κ΅μˆ˜ν˜•μ— λ¬Έμ œκ°€ μžˆμ—ˆκ³  λ‹€λ₯Έ μž‘μ—…μž μœ ν˜•μ„ μ‚¬μš©ν•˜μ—¬ 문제λ₯Ό ν•΄κ²°ν–ˆμŠ΅λ‹ˆλ‹€. 일반적인 λ¬Έμ œκ°€ μžˆλŠ”μ§€ κΆκΈˆν•©λ‹ˆλ‹€. @stapetro λ‹€λ₯Έ μž‘μ—…μžλ₯Ό μ‹œλ„ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

μ•ˆλ…•ν•˜μ„Έμš” @jamadden μž…λ‹ˆλ‹€ .
κ·€ν•˜μ˜ μ œμ•ˆμœΌλ‘œ λ¬Έμ œκ°€ ν•΄κ²°λ˜μ—ˆμŠ΅λ‹ˆλ‹€. _gevent_ 및 _gthread_ μž‘μ—…μž ν΄λž˜μŠ€μ—λŠ” λ¬Έμ œκ°€ μ—†μŠ΅λ‹ˆλ‹€. λ‚˜λŠ” meinheldμ—μ„œ 멀리 μ΄μ‚¬ν–ˆμŠ΅λ‹ˆλ‹€. λΉ λ₯Έ λ‹΅λ³€κ³Ό 도움 κ°μ‚¬ν•©λ‹ˆλ‹€! :)

전체 STR:

  1. https://signup.heroku.com μ—μ„œ 무료 Heroku 계정을 λ§Œλ“œμ‹­μ‹œμ˜€.
  2. Heroku CLI μ„€μΉ˜(https://devcenter.heroku.com/articles/heroku-cli μ°Έμ‘°)
  3. heroku login μ‚¬μš©ν•˜μ—¬ CLI에 λ‘œκ·ΈμΈν•©λ‹ˆλ‹€.
  4. git clone https://github.com/erjiang/gunicorn-issue && cd gunicorn-issue
  5. heroku create (이것은 λ¬΄μž‘μœ„λ‘œ μƒμ„±λœ 이름을 가진 무료 Heroku 앱을 μƒμ„±ν•˜κ³  heroku λΌλŠ” git remoteλ₯Ό κ΅¬μ„±ν•©λ‹ˆλ‹€)
  6. git push heroku master
  7. curl --data "foo=bar" https://YOUR_GENERATED_APP_NAME.herokuapp.com/test1 (75% 이상 μ‹€νŒ¨)
  8. μ™„λ£Œλ˜λ©΄ heroku destroy λ₯Ό μ‹€ν–‰ν•˜μ—¬ 앱을 μ‚­μ œν•©λ‹ˆλ‹€.

λ‚΄ μ•±μ—μ„œ 맀우 μœ μ‚¬ν•œ λ™μž‘μ΄ μžˆμ—ˆκ³  curl --data λŒ€μ‹  curl -Hλ₯Ό μ‚¬μš©ν•  λ•Œ(GET μš”μ²­μ΄κΈ° λ•Œλ¬Έμ—) λ‚΄ μ•±(Django, Gunicorn, Heruko)μ—μ„œ μž‘λ™ν•œλ‹€λŠ” 것을 λ°œκ²¬ν–ˆμŠ΅λ‹ˆλ‹€. λ‚˜λŠ” gunicorn-issue μ•±μ—μ„œ ν…ŒμŠ€νŠΈν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. 이것이 λˆ„κ΅°κ°€μ—κ²Œ μœ μš©ν•  수 μžˆλ‹€κ³  μƒκ°ν–ˆμŠ΅λ‹ˆλ‹€.

@mikkelhn λ„€ . Flask/Flask RestPlus 및 Gunicorn이 μžˆλŠ” 앱은 λ‹€μŒκ³Ό 같이 μž‘λ™ν•©λ‹ˆλ‹€. POST μš”μ²­μ— μ‘λ‹΅ν•˜λ©΄ [νŽ˜μ΄λ‘œλ“œ > 13k인 경우] 503 였λ₯˜ κ°€ λ°œμƒν•˜μ§€λ§Œ 앱이 GET에 μ‘λ‹΅ν•˜λ©΄ 였λ₯˜ ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€ . μ •ν™•νžˆ 같은 μ½”λ“œ!
λˆ„κ΅¬λ“ μ§€μ΄ 맀우 μ„±κ°€μ‹  행동을 μ„€λͺ… ν•  수 μžˆμŠ΅λ‹ˆκΉŒ? μ›¨μ΄νŠΈλ¦¬μŠ€λ‘œ μ „ν™˜ν•˜λŠ” 것이 이 문제λ₯Ό ν•΄κ²°ν•˜λŠ” μœ μΌν•œ ν•΄κ²° λ°©λ²•μž…λ‹ˆκΉŒ? Gunicorn을 "μ†μœΌλ‘œ" μˆ˜μ •ν•˜λŠ” 것은 μ‹€ν–‰ κ°€λŠ₯ν•œ μ†”λ£¨μ…˜μ΄ μ•„λ‹ˆλΌκ³  μƒκ°ν•©λ‹ˆλ‹€...

λ‚˜λŠ” close() 전에 shutdown()을 ν˜ΈμΆœν•˜κΈ° μœ„ν•΄ PR을 μ—΄μ—ˆμŠ΅λ‹ˆλ‹€. μ†”μ§νžˆ Herokuμ—μ„œ Gunicorn이 기본적으둜 κ³ μž₯났을 λ•Œ Herokuκ°€ Gunicorn을 계속 μΆ”μ²œν•˜λŠ” 것은 μ•½κ°„ μ—‰λš±ν•©λ‹ˆλ‹€.

@erijang이 μ˜¬λ°”λ₯΄κ²Œ κΈ°μˆ ν•œ κ²ƒμ²˜λŸΌ Herokuκ°€ Gunicorn을 μ‚¬μš©ν•  수 없을 λ•Œ Gunicorn을 ꢌμž₯ν•˜λŠ” 경우: Gunicorn에 λŒ€ν•œ κ°„λ‹¨ν•˜κ³  μ‹€ν–‰ κ°€λŠ₯ν•œ λŒ€μ•ˆμ€ λ¬΄μ—‡μž…λ‹ˆκΉŒ(및 Herokuμ—μ„œ κ°€μž₯ 잘 κ΅¬μ„±ν•˜λŠ” 방법)?
AFAIK, λ§Žμ€ 고객이 Herokuλ₯Ό μ„ νƒν•˜λŠ” μ΄μœ λŠ” μ„œλ²„ μ•„ν‚€ν…μ²˜ 및 ꡬ성 μ„ΈλΆ€ 정보에 λŒ€ν•œ κΉŠμ€ 지식이 ν•„μš”ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€... :|

@RinaldoNani 무슨

@benoitc 이 λ¬Έμ œλŠ” λ‹€μŒμ—μ„œ μ–ΈκΈ‰ν•œ κ²ƒμ²˜λŸΌ μ—¬λŸ¬ μž‘μ—…μž μœ ν˜•μ— 영ν–₯을 μ€λ‹ˆλ‹€.
https://github.com/benoitc/gunicorn/issues/840#issuecomment -482491267

μ•ˆλ…•ν•˜μ„Έμš” @benoitcμž…λ‹ˆλ‹€. λ‚˜λŠ” 이전 κ²Œμ‹œλ¬Όμ—μ„œ μ–ΈκΈ‰ ν•œ 바와 같이, μš°λ¦¬λŠ” λ‚΄κ°€ 이해, Gunicorn 동기화 "μ›Ή"의 μ‚¬μš©μ„ μ œμ•ˆ, 파이썬 / ν”ŒλΌμŠ€ν¬ μ„œλ²„ μΈ‘ μ‘μš© ν”„λ‘œκ·Έλž¨ 배포에 λŒ€ν•œ κ΄€λ¦¬μ—κ²Œ Heroku의 지침 (와 λ‹€μŒ, Heroku가에 μ•„μ£Ό 간단 ν”ŒλΌμŠ€ν¬ / FlaskRestPlus μ‘μš© ν”„λ‘œκ·Έλž¨μ„ 배포 ν•œ λ…Έλ™μž ).

μ•±μ˜ λ™μž‘μ€ 이 μŠ€λ ˆλ“œμ˜ 제λͺ©μ„ λ°˜μ˜ν•©λ‹ˆλ‹€.

λ‘œμ»¬μ—μ„œ ν…ŒμŠ€νŠΈν•œ κ²°κ³Ό λͺ¨λ“  것이 잘 μž‘λ™ν•˜λ©° 앱은 문제 없이 20k μ΄μƒμ˜ JSON을 μ œκ³΅ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 앱이 Heroku에 배포되면 503 였λ₯˜ λ¬Έμ œκ°€ μ²΄κ³„μ μœΌλ‘œ λ°œμƒν•©λ‹ˆλ‹€. 말 κ·ΈλŒ€λ‘œ νŠΈλž˜ν”½μ΄ 없어도 좜λ ₯이 μ „λ‹¬λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
λ‹€λ₯Έ μ‚¬λžŒλ“€μ΄ μ§€μ ν–ˆλ“―μ΄ λ‘œκ·ΈλŠ” HTTP μˆ˜μ€€μ—μ„œ λͺ¨λ“  것이 정상인 κ²ƒμ²˜λŸΌ λ³΄μž…λ‹ˆλ‹€(200개의 응닡 μ½”λ“œκ°€ 기둝됨).
νŽ˜μ΄λ‘œλ“œκ°€ 13k 미만이면 Heroku/Gunicorn이 μ˜ˆμƒλŒ€λ‘œ POST에 μ‘λ‹΅ν•©λ‹ˆλ‹€.
μš°λ¦¬λŠ” POST(?!?) 끝점을 ν”Όν•˜κ³  λŒ€μ‹  GET을 μ‚¬μš©ν•œλ‹€λŠ” @mikkelhn 아이디어λ₯Ό λ”°λžκ³  이것은 문제λ₯Ό ν•΄κ²°ν•˜λŠ” (λ³„λ‘œ 쒋지 μ•Šμ€) 방법인 것 κ°™μŠ΅λ‹ˆλ‹€.

μš°λ¦¬λŠ” Gunicorn μ „λ¬Έκ°€κ°€ μ•„λ‹ˆλ©° μ†”μ§νžˆ 우리의 κ°„λ‹¨ν•œ μ‚¬μš© 사둀가 "μ¦‰μ‹œ" μž‘λ™ν•  것이라고 κΈ°λŒ€ν–ˆμŠ΅λ‹ˆλ‹€.
μ €ν¬μ—κ²Œ 도움이 될 μ œμ•ˆμ΄ μžˆμœΌμ‹œλ©΄ μ˜μ›νžˆ κ°μ‚¬ν•˜κ² μŠ΅λ‹ˆλ‹€. :)

@RinaldoNani Shot in the dark... μš”μ²­ 처리기 μ–΄λ”˜κ°€μ—μ„œ request.data λͺ¨λ‘ μ½μ–΄λ³΄μ‹­μ‹œμ˜€. 예λ₯Ό λ“€μ–΄:

@route('/whatever', methods=['POST'])
def whatever_handler():
    str(request.data)
    return flask.jsonify(...)

그것이 λ‹Ήμ‹ μ˜ 였λ₯˜μ— 영ν–₯을 μ€λ‹ˆκΉŒ?

μ €λŠ” μ§€κΈˆ 2μ£Ό λ„˜κ²Œ H18 문제둜 λΆ„μ£Όν•œ ν›„ μ˜€μ „ 1μ‹œμ— 이것을 μ“°κ³  μžˆμŠ΅λ‹ˆλ‹€(κ³΅μœ ν•˜κΈ°λ₯Ό 기닀릴 수 μ—†μ—ˆμŠ΅λ‹ˆλ‹€).

λ‚˜λŠ” κ±°λŒ€ν•œ 데이터 μ„ΈνŠΈλ‘œ μž‘μ—…ν•˜κ³  ν”Œλ‘―μ— 18Kμ—μ„œ 20K λ ˆμ½”λ“œμ— μ‘λ‹΅ν•©λ‹ˆλ‹€. H18은 맀우 μž„μ˜μ˜ 였λ₯˜λ‘œ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. λ•Œλ•Œλ‘œ 잘 μž‘λ™ν•˜μ§€λ§Œ λͺ¨λ“  λΈŒλΌμš°μ €μ—μ„œ "μ½˜ν…μΈ  헀더 길이가 μΌμΉ˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€"κ°€ λ°œμƒν•©λ‹ˆλ‹€. 이 λ¬Έμ œμ— λŒ€ν•΄ λ…Όμ˜λœ 거의 λͺ¨λ“  μ†”λ£¨μ…˜μ„ μ‹œλ„ν–ˆμ§€λ§Œ 운이 μ—†μ—ˆμŠ΅λ‹ˆλ‹€. λ‚΄κ°€ μ‹œλ„ν•œ 두 가지가 λ§ˆμΉ¨λ‚΄ μž‘λ™ν–ˆμŠ΅λ‹ˆλ‹€.

  1. POST μš”μ²­μ„ GET으둜 λ³€κ²½ν–ˆμŠ΅λ‹ˆλ‹€.
  2. λ‚΄ 데이터에 NaN/Null 값이 μžˆμœΌλ―€λ‘œ λͺ¨λΈμ„ λ³€κ²½ν•˜κ³  기본값을 μ œκ³΅ν–ˆμŠ΅λ‹ˆλ‹€. (λ‚˜λŠ” 이것이 문제λ₯Ό ν•΄κ²°ν–ˆλ‹€κ³  μƒκ°ν•œλ‹€)
    κ·Έ ν›„, λ‚˜λŠ”μ΄ 였λ₯˜κ°€ λ°œμƒν•˜λŠ” 것을 λ©ˆμ·„μŠ΅λ‹ˆλ‹€.
    이것이 λˆ„κ΅°κ°€λ₯Ό λ„μšΈ 수 있기λ₯Ό λ°”λžλ‹ˆλ‹€!
이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰