ฉันมีการตั้งค่าเช่นนี้บน Ubuntu
เบราว์เซอร์ --> HAProxy --> เซิร์ฟเวอร์ส่วนหลัง
เซิร์ฟเวอร์ส่วนหลังเป็นเว็บแอปพลิเคชัน ASP.NET Core
มันใช้งานได้ 99.9% ของเวลาทั้งหมดยกเว้นเมื่อไฟล์ไบนารีกำลังถูกอัปโหลด (POST อย่างง่ายพร้อมข้อมูลแบบฟอร์มหลายส่วน) ซึ่งในกรณีนี้ฉันได้รับข้อผิดพลาด:
System.IO.IOException: การสิ้นสุดของสตรีมโดยไม่คาดคิด เนื้อหาอาจถูกอ่านโดยคอมโพเนนต์อื่นแล้ว
ที่ Microsoft.AspNetCore.WebUtilities.MultipartReaderStream.ReadAsync (Byte[] บัฟเฟอร์, Int32 offset, Int32 นับ, CancellationToken cancelToken)
ที่ Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream.ReadAsync (Byte[] บัฟเฟอร์, Int32 offset, Int32 นับ, CancellationToken cancelToken)
ที่ Microsoft.AspNetCore.WebUtilities.StreamHelperExtensions.DrainAsync (สตรีมสตรีม, ArrayPool'1 bytePool, Nullable'1 จำกัด, CancellationToken cancelToken)
ที่ Microsoft.AspNetCore.Http.Features.FormFeature.InnerReadFormAsync (CancellationToken cancelToken)
ที่ Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenStore.GetRequestTokensAsync (HttpContext httpContext)
ที่ Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateRequestAsync (HttpContext httpContext)
ที่ Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.ValidateAntiforgeryTokenAuthorizationFilter.OnAuthorizationAsync (บริบทการอนุญาตตัวกรอง)
ที่ Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
ที่ Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker <InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
ที่ Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
ที่ Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke (บริบท HttpContext)
ดังนั้นฉันจึงพยายามตรวจสอบว่าทำไม
ฉันลองใช้แบ็กเอนด์ ASP.NET Core โดยตรง มันใช้งานได้
ดังนั้นฉันจึงบันทึกข้อมูลขาเข้าไปยังแบ็กเอนด์และพบว่าหากฉันทำโดยตรง ฉันจะได้รับส่วนหัวของคำขอที่คาดไว้ จากนั้นจึงได้รับไฟล์ที่อัปโหลดในเนื้อหา
จากนั้นฉันบันทึกข้อมูลขาเข้าไปยังแบ็กเอนด์ผ่าน HAProxy และข้อมูลหายไปครึ่งหนึ่ง
เช่น. ข้อมูลแรกที่เห็นโดยแบ็กเอนด์ดูเหมือนจะเป็น
04 E2 22 FC 60 FF 2B E1 BF 85 D2 75 F9 44 94 86
แต่นี่คือไบต์ประมาณครึ่งทางของไฟล์ของฉัน ซึ่งก็คือ 25,126 ไบต์ ฉันไม่เห็นข้อมูลส่วนหัวเลย
ฉันพร้อมที่จะยอมรับว่าการบันทึกของฉันไม่สมบูรณ์และไม่จำเป็นต้องถูกต้อง ดูเหมือนว่าคำขอจะถูกแบ่งออกเป็นสองส่วน หรือมีการเติมบัฟเฟอร์แล้วเขียนใหม่
ปัญหาคืออะไร
ทั่วโลก
chroot /var/lib/haproxy
บันทึก /dev/log ข้อมูล local0
ซ็อกเก็ตสถิติ /run/haproxy/admin.sock โหมด 660 ผู้ดูแลระบบระดับ
หมดเวลาสถิติ 30 วินาที
ผู้ใช้แฮพร็อกซี
ผู้ใช้กลุ่ม
ภูต
lua-โหลด /home/user/haproxy-mapping.lua
ssl-default-bind-ciphers ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:! DSS:!AESCCM
ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
tune.ssl.default-dh-param 2048
ค่าเริ่มต้น
เข้าสู่ระบบทั่วโลก
โหมด http
หมดเวลาเชื่อมต่อ 30,000
ลูกค้าหมดเวลา 50,000
หมดเวลาเซิร์ฟเวอร์ 50,000
ตัวเลือกไปข้างหน้าสำหรับ
ตัวเลือก http-server-close #have ลอง http-keep-alive ด้วย
ส่วนหน้า httpfront
โหมด http
ผูก *:80
รูปแบบการเปลี่ยนเส้นทาง https รหัส 301 ถ้า !{ ssl_fc }
ส่วนหน้า web_front_end
ผูก *:443 ssl crt /home/.....file.pem
โหมด http
เข้าสู่ระบบ /var/lib/haproxy/dev/log ข้อมูล local0
#จำกัดอัตรา
stick-table ประเภท ip ขนาด 100k หมดอายุ 600s store http_req_rate(60s) #store มากถึง 100k คำขอสำหรับ 60s ดูว่ามากกว่า 60s มีมากกว่า 600
http-ขอแทร็ก-sc0 src
http-request ปฏิเสธการปฏิเสธสถานะ 429 ถ้า { sc_http_req_rate(0) gt 600 }
# ตรวจสอบให้แน่ใจว่าเรามีสถานะที่สะอาดเพื่อเริ่มต้น
http-request del-header X-SERVER-SNI
# ตั้งค่าที่ต่อกันของค่า SNI เป็นส่วนหัวชั่วคราว
http-request set-header X-SERVER-SNI haproxy.%[ssl_fc_sni] ถ้า { พบ ssl_fc_sni -m }
# ตั้งค่าของส่วนหัวเป็นตัวแปรระดับธุรกรรม
http-request set-var(txn.fc_sni) ssl_fc_sni #hdr(X-SERVER-SNI) ถ้า { hdr(X-SERVER-SNI) -m พบ }
#ใช้รหัส Lua เพื่อกำหนดว่าจะส่งแบ็กเอนด์ใด
use_backend %[lua.legacy_new_backend]
แบ็กเอนด์แบ็กเอนด์โหนด_1_https
วงเวียนสมดุล
ตัวเลือกไปข้างหน้าสำหรับ
เซิร์ฟเวอร์ node1 127.0.0.1:446 ssl ตรวจสอบไม่มี sni var(txn.fc_sni)