Reverse Proxy และ Load Balancing ด้วย Nginx: คำถามที่พบบ่อยและการตั้งค่าเชิงลึก

โดย วุฒิชัย ศรีวิชัย · 28 กรกฎาคม 2569
ภาพประกอบเรื่อง Reverse Proxy และ Load Balancing ด้วย Nginx: คำถามที่พบบ่อยและการตั้งค่าเชิงลึก
Reverse Proxy และ Load Balancing ด้วย Nginx: คำถามที่พบบ่อยและการตั้งค่าเชิงลึก

Reverse Proxy กับ Load Balancing มีความแตกต่างกันจริงๆ หรือแค่คำพูดเดียวกัน?

คำถามนี้อาจจะดูเรียบง่าย แต่จำนวนผู้ดูแลระบบที่ยังสับสนนั้นมีมากกว่าที่เราคิดเสียอีก Reverse Proxy และ Load Balancing เป็นสองแนวคิดที่แตกต่างกัน แม้ว่าบางครั้งเราอาจใช้เครื่องมือตัวเดียวกัน (เช่น Nginx) ในการทำงานทั้งสองอย่าง

Reverse Proxy คือเซิร์ฟเวอร์ที่ทำหน้าที่ยืนอยู่ตรงกลาง ระหว่างไคลเอนต์และเซิร์ฟเวอร์แบคเอนด์ กล่าวคือไคลเอนต์จะติดต่อ Reverse Proxy ก่อน แล้วค่อยโปรแกรม Reverse Proxyที่จะส่งคำขออนุญาตไปยังเซิร์ฟเวอร์แบคเอนด์ตามที่ระบุ ส่วนLoad Balancingคือการแจกจ่ายงานหรือคำขออนุญาตไปยังเซิร์ฟเวอร์หลายตัวเพื่อไม่ให้เซิร์ฟเวอร์ตัวใดตัวหนึ่งจัดการเรื่องสารภาพมากเกินไป

อยากคิดดูง่ายๆ ลองนึกภาพร้านอาหารอตัวอย่างนั้นกัน Reverse Proxy คือพนักงานต้อนรับที่อยู่ประตูห้องครัว - ไคลเอนต์ (ลูกค้า) ไม่เข้าห้องครัวโดยตรง แต่พนักงานต้อนรับคนนี้จะลำโพงคำขอไปให้พ่อครัว Load Balancing ส่วนอื่นคือการมีพ่อครัวหลายคน ดังนั้นเมื่อมีคำขออาหารเยอะๆ พนักงานต้อนรับจะแจกจ่ายงานไปให้พ่อครัวที่ไม่ว่างกว่าแทนที่จะให้เพียงคนเดียวคิดเสียจนถึง

ผมจะต้องติดตั้ง Nginx ให้มี Load Balancing ไหม หรือว่าเรื่องมันไปด้วยเอง?

ก่อนอื่น ให้ยุติภาพลวงตาออกไป: Nginx ไม่ได้มี Load Balancing "ไปด้วยเอง" คุณต้องตั้งค่าด้วยตนเองในไฟล์ config ของ Nginx

การตั้งค่า Load Balancing ใน Nginx นั้นทำโดยการสร้าง upstream block ที่ประกอบด้วยเซิร์ฟเวอร์แบคเอนด์หลายตัว ตัวอย่างเช่น:

  • upstream backend_servers { server 192.168.1.10:8080; server 192.168.1.11:8080; server 192.168.1.12:8080; }
  • จากนั้นให้อ้างอิง upstream นี้ในไฟล์ server block
  • Nginx จะแจกจ่ายคำขออนุญาตตามอัลกอริทึมที่คุณเลือก (round-robin เป็นค่าเริ่มต้น)

คำถามที่ตามมาคือ: "มีอัลกอริทึมอื่นๆ นอกจาก round-robin หรือไม่?" แน่นอนว่ามี คุณสามารถใช้ least_conn เพื่อส่งคำขออนุญาตไปยังเซิร์ฟเวอร์ที่มีการเชื่อมต่อน้อยที่สุด หรือใช้ ip_hash เพื่อให้ไคลเอนต์ IP เดียวกันไปยังเซิร์ฟเวอร์เดียวเสมอ ซึ่งมีประโยชน์กับการจัดการ Session

ถ้าเซิร์ฟเวอร์แบคเอนด์ตัวหนึ่งดับลงเฉพาะหนึ่งช่วว่าจะเกิดอะไรขึ้น Load Balancing จะรู้ได้อย่างไร?

นี่คือประเด็นสำคัญที่มักถูกมองข้าม Nginx มีกลไก health check ที่สามารถตรวจสอบสถานะของเซิร์ฟเวอร์แบคเอนด์ได้

ในเวอร์ชันของ Nginx แบบ Open Source ธรรมชาติแล้ว Health check จะทำงานได้เมื่อมีคำขออนุญาต - ถ้าเซิร์ฟเวอร์แบคเอนด์ตัวหนึ่งตอบไม่สำเร็จหรือหมดเวลารอ Nginx จะทำการถอดเซิร์ฟเวอร์นั้นออกจากการจัดสรรคำขออนุญาตชั่วคราว

คุณสามารถกำหนดพารามิเตอร์ได้ว่า:

  • max_fails: จำนวนครั้งที่ล้มเหลวก่อนที่จะถือว่าเซิร์ฟเวอร์ "อยู่ที่ด้านล่าง"
  • fail_timeout: ระยะเวลาที่จะถือว่าเซิร์ฟเวอร์อยู่ที่ด้านล่างก่อนพยายามอีกครั้ง

ตัวอย่าง: server 192.168.1.10:8080 max_fails=3 fail_timeout=30s; หมายความว่าหลังจากล้มเหลว 3 ครั้ง Nginx จะปล่อยให้เซิร์ฟเวอร์พักแบบ 30 วินาทีก่อนจะลองใหม่

แต่ต้องจำไว้ว่า: Health check แบบพื้นฐานนี้เป็นแบบ "reactive" ไม่ใช่ "proactive" - Nginx จะรู้ว่าเซิร์ฟเวอร์มีปัญหาเมื่อมีไคลเอนต์พยายามติดต่อไปแล้ว ถ้าต้องการตรวจสอบเชิงรุก (Proactive Health Check) จะต้องใช้ Nginx Plus ซึ่งเป็นเวอร์ชันชำระเงิน

การ Cache บนผลการทำงาน Reverse Proxy สามารถอาจจะช่วยเรื่องประสิทธิภาพได้ไหม แล้วมันจะทำให้ข้อมูลหมดสด?

ดีแล้วคุณเริ่มคิดแบบผู้เชี่ยวชาญแล้ว ใช่ - Nginx สามารถจัดเก็บข้อมูล (Cache) ผลลัพธ์จากเซิร์ฟเวอร์แบคเอนด์ได้ ซึ่งจะช่วยลดภาระของเซิร์ฟเวอร์แบคเอนด์ได้มากเมื่อมีคำขออนุญาตซ้ำๆ

การตั้งค่า Caching ใน Nginx คือการใช้ directive proxy_cache_path เพื่อระบุว่าจะเก็บข้อมูลไว้ที่ใดและอีกจำนวนเท่าไร ตัวอย่าง:

  • proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m;
  • levels=1:2 หมายถึงโครงสร้างโฟลเดอร์ที่ใช้เพื่อจัดเก็บข้อมูล
  • keys_zone=my_cache:10m กำหนดชื่อและขนาดของหน่วยความจำที่ใช้สำหรับ keys

สำหรับเรื่องข้อมูลเก่า (stale data) นั้น - ขึ้นอยู่กับวิธีการตั้งค่า Cache-Control headers จากเซิร์ฟเวอร์แบคเอนด์ คุณสามารถกำหนดได้ว่า Nginx ควรเก็บข้อมูลนานเท่าไหร่ผ่าน proxy_cache_valid directive

ตัวอย่างเช่น: proxy_cache_valid 200 10m; หมายความว่า HTTP status 200 จะถูกเก็บไว้ได้นาน 10 นาที มีอีกวิธีหนึ่งคือการใช้ proxy_cache_use_stale เพื่อบอก Nginx ว่าสามารถส่งข้อมูลเก่าได้ในสถานการณ์ที่เซิร์ฟเวอร์แบคเอนด์ไม่ตอบสนอง เช่น เมื่อกำลังอัพเดต cache

SSL/TLS Termination คืออะไร และมันสำคัญต่อการใช้ Reverse Proxy หรือไม่?

SSL/TLS Termination เป็นวลีที่อาจได้ยินในบริบท Reverse Proxy บ่อยครั้ง - หมายความว่า Reverse Proxy จะทำการถอดรหัส (Decrypt) การเชื่อมต่อ HTTPS ที่มาจากไคลเอนต์ แล้วตัดสินใจว่าจะส่งคำขออนุญาตไปยังเซิร์ฟเวอร์แบคเอนด์ที่ใด

เหตุใด SSL Termination จึงสำคัญ? เพราะลำดับของเหตุการณ์มี impact เยอะ:

  • ไคลเอนต์เชื่อมต่อ HTTPS ไปยัง Nginx (Reverse Proxy)
  • Nginx ถอดรหัส HTTPS แล้วเห็นคำขออนุญาตจริงของ HTTP
  • จากนั้น Nginx ค่อยส่งต่อไปยังเซิร์ฟเวอร์แบคเอนด์ (อาจเป็น HTTPS หรือ HTTP ตามที่คุณตั้งค่า)

ข้อดีคือ: ทำให้เซิร์ฟเวอร์แบคเอนด์ไม่ต้องประมวลผล SSL/TLS ซึ่งหนักมาก ลดภาระ CPU ลงอย่างเห็นได้ชัด ข้อเสีย: หากมีเซิร์ฟเวอร์แบคเอนด์หลายตัว คุณจะต้องทำการโปรแกรม Nginx เพื่อส่งต่อไปยังเซิร์ฟเวอร์ถูกต้อง เทคนิค SNI (Server Name Indication) ช่วยเรื่องนี้ได้ แต่ต้องคิดหน้าให้เพื่อไม่ให้สับสน

Connection Pooling และ Keepalive - มีความสำคัญต่อประสิทธิภาพ Load Balancer หรือไม่?

นี่คือหัวข้อที่มักถูกมองข้าม แต่ผู้ดูแลระบบที่รู้เรื่องจะรู้ว่ามันหลักมากเพียงใด

เมื่อ Nginx ส่งคำขออนุญาตไปยังเซิร์ฟเวอร์แบคเอนด์ หากเปิด HTTP Keepalive ไว้ มันจะไม่ปิดการเชื่อมต่อทันที แต่เก็บการเชื่อมต่อไว้เพื่อใช้ซ้ำในคำขออนุญาตถัดไป วิธีนี้ช่วยลดเวลาในการสร้างการเชื่อมต่อใหม่ (TCP Handshake)

ตั้งค่าผ่าน:

  • proxy_http_version 1.1; บอก Nginx ให้ใช้ HTTP/1.1 (ซึ่งรองรับ Keepalive ดี)
  • proxy_set_header Connection ""; ล้างค่า Connection header เพื่อไม่ให้ปิดการเชื่อมต่อ
  • keepalive 32; ในคำสั่ง upstream กำหนดว่าควรเก็บการเชื่อมต่อกี่ตัวไว้พร้อมใช้

ผล: ลด Latency แรกสำหรับคำขออนุญาตต่อๆ ไป และลดโหลด CPU บนเซิร์ฟเวอร์แบคเอนด์ ด้วยเพราะไม่ต้องสร้างการเชื่อมต่อใหม่บ่อยๆ ถ้าคุณมีลูกค้า (Traffic) ในปริมาณมหาศาล ความแตกต่างนี้จะเห็นได้จริงในการวัด

ถ้ามี IP Address หลายตัวที่ฝากระดับหัวข้อ (Upstream) ผมควรเลือก Sticky Sessions ไหม?

นี่เป็นคำถามที่แสดงถึงการเข้าใจเชิงลึก - แน่นอน Sticky Sessions มีประโยชน์ในบางสถานการณ์

Sticky Sessions (หรือ Session Persistence) หมายถึงการจัดทำให้ไคลเอนต์เดียวกันเชื่อมต่อไปยังเซิร์ฟเวอร์แบคเอนด์เดียวกันเสมอ ซึ่งมีประโยชน์เมื่อ:

  • เซิร์ฟเวอร์แบคเอนด์เก็บข้อมูล Session บนหน่วยความจำตัวเอง ไม่ได้แชร์ระหว่างเซิร์ฟเวอร์
  • แอปพลิเคชันต้องอาศัยข้อมูลท้องถิ่นบนเซิร์ฟเวอร์ (เช่น cache ระดับ Application)

ใน Nginx สามารถใช้ ip_hash directive เพื่อจัดเก็บ IP address ไคลเอนต์ และทำให้ทุกคำขออนุญาตจากไคลเอนต์เดียวกันไปยังเซิร์ฟเวอร์เดียวกัน ตัวอย่าง:

  • upstream backend { ip_hash; server backend1.example.com; server backend2.example.com; }

แต่ต้องระวังด้วย: Sticky Sessions อาจลดประสิทธิภาพของการแจกจ่ายโหลดได้ตัวอย่างเช่นถ้า IP address หนึ่งจำนวนมากไคลเอนต์ที่อยู่ด้านหลัง NAT proxy ทั้งหมดจะ hash ไปยังเซิร์ฟเวอร์เดียว วิธีที่ดีกว่ามักจะแก้ปัญหา Session จริงๆ - เช่น เก็บ Session บนฐานข้อมูลหรือ Redis - แล้วปล่อยให้ load balancerทำหน้าที่แจกจ่ายโหลดอย่างเป็นอิสระโดยไม่ต้องใส่ใจว่า Session อยู่ที่ไหน

มี Tool อื่นๆ นอกจาก Nginx ที่ให้ความสามารถ Reverse Proxy และ Load Balancing ไหม แล้วจะเลือกให้ถูกต้องได้อย่างไร?

ขึ้นอยู่กับว่าคุณมีความต้องการแบบไหน Nginx ไม่ใช่ตัวเลือกเดียว มีอื่นๆ เช่น HAProxy (ตัวเลือกที่นิยมสำหรับการ Load Balancing บน Linux) และ Caddy (ที่สมัยใหม่กว่า ใช้งานง่ายกว่า)

เลือก Nginx เมื่อ: คุณต้องการเซิร์ฟเวอร์เว็บสำหรับทำ Static Content พร้อมกับ Reverse Proxy/Load Balancing, ต้องการ Learning curve ที่ไม่หนักจนเกินไป, ต้องการ Community ใหญ่ที่มีเอกสารและตัวอย่างมากมาย

เลือก HAProxy เมื่อ: คุณต้องการการ Load Balancing ที่หลากหลายมากๆ ตัวอย่างเช่น Layer 4 load balancing (TCP/UDP) ที่ Nginx ต้องใช้ stream module, ต้องการความเร็วและประสิทธิภาพสูงสุด, ต้องการการ Monitoring และ Logging ที่ขั้นสูง

เลือก Caddy เมื่อ: คุณต้องการ Setup ที่เรียบง่ายและสมัยใหม่ auto HTTPS พร้อม Let's Encrypt, ต้องการไฟล์ Config ที่อ่านเข้าใจง่ายกว่า, ทำงานกับ Docker หรือ Container

จริงๆ แล้ว - ตัวเลือก "ถูกต้อง" ของคุณขึ้นอยู่กับสถานการณ์จริง ความสามารถของทีม และความต้องการเฉพาะเจาะจง ไม่มีโซลูชั่นเดียวที่ใช้ได้ทุกสถานการณ์

แสดงความคิดเห็น

ร่วมแสดงความคิดเห็นได้ที่ด้านล่าง — เราอ่านทุกความเห็น