ให้บริการการเข้ารหัสการถ่ายโอนแบบก้อนจากขวดถึง nginx

ฉันมีปัญหาบางอย่างในการให้บริการ Chunked Transfer Coding ผ่าน Nginx

ข้อมูลที่ให้บริการมาจากแอปขวดที่ทำงานผ่าน uwsgi นี่คือตัวอย่างคำตอบที่ uwsgi มอบให้กับคำขอ GET:

0000: 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK.
0010: 0a                                              .
<= Recv header, 28 bytes (0x1c)
0000: 54 72 61 6e 73 66 65 72 2d 45 6e 63 6f 64 69 6e Transfer-Encodin
0010: 67 3a 20 63 68 75 6e 6b 65 64 0d 0a             g: chunked..
<= Recv header, 32 bytes (0x20)
0000: 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 61 70 Content-Type: ap
0010: 70 6c 69 63 61 74 69 6f 6e 2f 6a 73 6f 6e 0d 0a plication/json..
<= Recv header, 32 bytes (0x20)
0000: 41 63 63 65 73 73 2d 43 6f 6e 74 72 6f 6c 2d 41 Access-Control-A
0010: 6c 6c 6f 77 2d 4f 72 69 67 69 6e 3a 20 2a 0d 0a llow-Origin: *..
<= Recv header, 75 bytes (0x4b)
0000: 41 63 63 65 73 73 2d 43 6f 6e 74 72 6f 6c 2d 41 Access-Control-A
0010: 6c 6c 6f 77 2d 48 65 61 64 65 72 73 3a 20 41 75 llow-Headers: Au
0020: 74 68 6f 72 69 7a 61 74 69 6f 6e 2c 20 43 6f 6e thorization, Con
0030: 74 65 6e 74 2d 54 79 70 65 2c 20 43 6f 6e 74 65 tent-Type, Conte
0040: 6e 74 2d 4c 65 6e 67 74 68 0d 0a                nt-Length..
<= Recv header, 80 bytes (0x50)
0000: 41 63 63 65 73 73 2d 43 6f 6e 74 72 6f 6c 2d 45 Access-Control-E
0010: 78 70 6f 73 65 2d 48 65 61 64 65 72 73 3a 20 20 xpose-Headers:  
0020: 57 57 57 2d 41 75 74 68 65 6e 74 69 63 61 74 65 WWW-Authenticate
0030: 2c 20 43 6f 6e 74 65 6e 74 2d 54 79 70 65 2c 20 , Content-Type, 
0040: 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 0d 0a Content-Length..
<= Recv header, 2 bytes (0x2)
0000: 0d 0a                                           ..
<= Recv data, 17 bytes (0x11)
0000: 63 0d 0a 7b 22 64 65 76 69 63 65 22 3a 20 5b 0d c..{"device": [.
...DATA...
01a0: 32 0d 0a 5d 0a 0d 0a 32 0d 0a 7d 0a 0d 0a       2..]...2..}...
<= Recv data, 5 bytes (0x5)
0000: 30 0d 0a 0d 0a                                  0....

การตอบสนองนี้จะเข้าสู่ซ็อกเก็ตยูนิกซ์ซึ่งถูกส่งไปยัง nginx ด้วยการกำหนดค่าต่อไปนี้:

server {
listen      80;
server_name  _;
client_max_body_size 4m;
chunked_transfer_encoding on;

location = /abc { rewrite ^ /abc/; }
location /abc { try_files $uri @abc; }
location @abc {
    include uwsgi_params;
uwsgi_param SCRIPT_NAME /abc;
    uwsgi_modifier1 30;
    uwsgi_pass unix:/path/to/socket.sock;
}

ปัญหาคือ Nginx ให้คำตอบนี้จริง ๆ :

<= Recv header, 17 bytes (0x11)
0000: 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK.
0010: 0a                                              .
== Info: Server nginx/1.4.6 (Ubuntu) is not blacklisted
<= Recv header, 30 bytes (0x1e)
0000: 53 65 72 76 65 72 3a 20 6e 67 69 6e 78 2f 31 2e Server: nginx/1.
0010: 34 2e 36 20 28 55 62 75 6e 74 75 29 0d 0a       4.6 (Ubuntu)..
<= Recv header, 37 bytes (0x25)
0000: 44 61 74 65 3a 20 54 75 65 2c 20 30 38 20 4a 75 Date: Tue, 08 Ju
0010: 6c 20 32 30 31 34 20 30 31 3a 30 32 3a 33 33 20 l 2014 01:02:33 
0020: 47 4d 54 0d 0a                                  GMT..
<= Recv header, 32 bytes (0x20)
0000: 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 61 70 Content-Type: ap
0010: 70 6c 69 63 61 74 69 6f 6e 2f 6a 73 6f 6e 0d 0a plication/json..
<= Recv header, 28 bytes (0x1c)
0000: 54 72 61 6e 73 66 65 72 2d 45 6e 63 6f 64 69 6e Transfer-Encodin
0010: 67 3a 20 63 68 75 6e 6b 65 64 0d 0a             g: chunked..
<= Recv header, 24 bytes (0x18)
0000: 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 6b 65 65 70 Connection: keep
0010: 2d 61 6c 69 76 65 0d 0a                         -alive..
<= Recv header, 32 bytes (0x20)
0000: 41 63 63 65 73 73 2d 43 6f 6e 74 72 6f 6c 2d 41 Access-Control-A
0010: 6c 6c 6f 77 2d 4f 72 69 67 69 6e 3a 20 2a 0d 0a llow-Origin: *..
<= Recv header, 75 bytes (0x4b)
0000: 41 63 63 65 73 73 2d 43 6f 6e 74 72 6f 6c 2d 41 Access-Control-A
0010: 6c 6c 6f 77 2d 48 65 61 64 65 72 73 3a 20 41 75 llow-Headers: Au
0020: 74 68 6f 72 69 7a 61 74 69 6f 6e 2c 20 43 6f 6e thorization, Con
0030: 74 65 6e 74 2d 54 79 70 65 2c 20 43 6f 6e 74 65 tent-Type, Conte
0040: 6e 74 2d 4c 65 6e 67 74 68 0d 0a                nt-Length..
<= Recv header, 79 bytes (0x4f)
0000: 41 63 63 65 73 73 2d 43 6f 6e 74 72 6f 6c 2d 45 Access-Control-E
0010: 78 70 6f 73 65 2d 48 65 61 64 65 72 73 3a 20 57 xpose-Headers: W
0020: 57 57 2d 41 75 74 68 65 6e 74 69 63 61 74 65 2c WW-Authenticate,
0030: 20 43 6f 6e 74 65 6e 74 2d 54 79 70 65 2c 20 43  Content-Type, C
0040: 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 0d 0a    ontent-Length..
<= Recv header, 2 bytes (0x2)
0000: 0d 0a                                           ..
<= Recv data, 926 bytes (0x39e)
0000: 33 39 32 0d 0a 63 0d 0a 7b 22 64 65 76 69 63 65 392..c..{"device
... DATA ...
0380: 0a 7d 0d 0a 32 0d 0a 5d 0a 0d 0a 32 0d 0a 7d 0a .}..2..]...2..}.
0390: 0d 0a 30 0d 0a 0d 0a 0d 0a 30 0d 0a 0d 0a       ..0......0....

โดยพื้นฐานแล้วมันจะรวมชิ้นส่วนทั้งหมดที่สร้างโดยแอปขวดและวางไว้ในชิ้นใหญ่ชิ้นเดียวที่เขาให้บริการในการเข้ารหัสการถ่ายโอนแบบชิ้น

ฟังก์ชั่นอื่นๆ ทั้งหมด (HTTP พื้นฐาน 1.0) ทำงานได้อย่างสมบูรณ์แบบ ดังนั้นฉันสงสัยว่าอะไรคือสาเหตุของพฤติกรรมนี้

tl; dr : NGINX แปลงรายการชิ้นส่วนเป็นรายการใหญ่เดียว และปล่อยให้เลขฐานสิบหกอยู่ตรงกลางของข้อมูล json ที่ให้บริการ


person sknat    schedule 08.07.2014    source แหล่งที่มา


คำตอบ (1)


เห็นได้ชัดว่า ปัญหานี้คล้ายกับปัญหาที่ฉันได้รับ

วิธีแก้ไขที่ฉันพบคือเปิดใช้งานการเข้ารหัสการถ่ายโอนบน nginx

chunked_transfer_encoding on;

จากนั้นเพื่อสตรีมแพ็กเก็ตไปยัง nginx ทีละรายการ: เป็นการเข้ารหัสการถ่ายโอนแบบก้อนโดยไม่มีเครื่องหมายขนาดฐานสิบหกและ CRLF

สิ่งที่เกิดขึ้น (ฉันคิดว่า) คือ nginx บัฟเฟอร์ข้อมูลด้านข้าง (ผ่านซ็อกเก็ตที่มันกำลังฟังอยู่) วิธีนี้จะช่วยป้องกันไม่ให้คุณใช้หน่วยความจำล้นในด้าน python/java ของคุณ (ฉันจะไม่ชำระประสิทธิภาพหน่วยความจำของ Python หรือ Java)

ฉันหวังว่าจะได้วิธีแก้ปัญหาที่ดีกว่า แต่สำหรับการสืบค้นที่ไม่ใหญ่/จำนวนมาก (ทั้งหมด ‹50Mb) ก็สามารถใช้ได้กับอินสแตนซ์ขนาดเล็ก ฉันจะให้หน้านี้อัปเดตด้วยการค้นพบใหม่

person sknat    schedule 11.11.2014