429 Too Many Requests แปลว่ามีอะไรบางอย่างนับจำนวนคำขอของเรา แล้วตัดสินว่ามากเกินไป จึงหยุดให้บริการ ไม่มีอะไรพัง — นี่คือระบบทำงานตามที่ออกแบบไว้เป๊ะ ๆ และการออกแบบนั้นกำลังบอกเราตรง ๆ ว่าให้ช้าลง
ความยุ่งอยู่ตรงที่มันเกิดได้จากสามชั้นและหน้าตาเหมือนกันหมดเมื่อมองจากข้างนอก เว็บเซิร์ฟเวอร์ของเราเองจำกัดผู้เข้าชมได้ CDN หรือ WAF อย่าง Cloudflare จำกัดได้ก่อนที่คำขอจะมาถึงเราด้วยซ้ำ และ API ภายนอกที่โค้ดเราเรียกก็จำกัดเซิร์ฟเวอร์เราได้ — status code เดียวกัน แต่วิธีแก้คนละเรื่องทั้งสามอย่าง
ดังนั้นขั้นแรกที่มีประโยชน์จริงไม่ใช่การแก้อะไร แต่คือหาให้เจอว่าชั้นไหนเป็นคนนับ
ใครเป็นคนจำกัด
ระบุต้นทางให้ได้ก่อนแก้อะไรทั้งนั้น ตัว response มักบอกเราอยู่แล้วถ้าดูที่เฮดเดอร์แทนที่จะดูแค่หน้าเว็บ
| ต้นทาง | สังเกตยังไง | ไปแก้ที่ไหน |
|---|---|---|
| CDN / WAF (เช่น Cloudflare) | หน้า error มีแบรนด์ มี ray ID มีเฮดเดอร์ cf- | แดชบอร์ดของ CDN ไม่ใช่เซิร์ฟเวอร์เรา |
| เว็บเซิร์ฟเวอร์ของเรา | หน้า error เปล่า ๆ ของ Nginx/Apache หรือหน้าที่เราทำเอง | ไฟล์ตั้งค่า (limit_req, mod_evasive) |
| แอปพลิเคชันของเรา | body เป็น JSON ในรูปแบบ error ที่เราออกแบบเอง | โค้ดแอปและกฎจำกัดของมัน |
| API ปลายทาง | เฉพาะการเรียกจากฝั่งเซิร์ฟเวอร์ที่พัง ผู้เข้าชมปกติ | โค้ด client ของเรา — เพิ่ม backoff และแคช |
Retry-After: เฮดเดอร์ที่บอกว่าให้ทำอะไรต่อ
429 ที่เขียนมาดีจะมีเฮดเดอร์ Retry-After มาด้วย และมันคือข้อมูลที่มีประโยชน์ที่สุดใน response ทั้งหมด
มันมาได้สองรูปแบบ คือจำนวนวินาทีที่ต้องรอ หรือวันเวลาแบบ HTTP ที่ให้รอจนถึง ไม่ว่าแบบไหนก็คือเซิร์ฟเวอร์บอกเราตรง ๆ ว่าจะเริ่มรับคำขออีกครั้งเมื่อไหร่ ซึ่งดีกว่าเดาเองมาก
ถ้าเรากำลังเขียน client ให้อ่านและเคารพมัน การยิงซ้ำทันทีหลังได้ 429 คือพฤติกรรมที่ทำให้ IP ถูกบล็อกถาวรแทนที่จะแค่ถูกหน่วง เพราะเมื่อมองจากฝั่งเซิร์ฟเวอร์มันแยกไม่ออกจากการโจมตี
ถ้าเราเป็นฝ่ายส่ง 429 ก็ให้ส่งมันด้วย ถ้าไม่มี Retry-After client ที่เขียนดีจะต้องเดา ส่วน client ที่เขียนไม่ดีจะยิงเรารัวไม่หยุด
สาเหตุที่เจอบ่อย เรียงจากมากไปน้อย
- โค้ดเราเรียก API ในลูปโดยไม่คุมจังหวะ วนข้อมูลไม่กี่พันรายการแล้วยิง API รายการละครั้ง ชน rate limit ของเจ้าไหนก็ได้ภายในไม่กี่วินาที
- ไม่ได้แคชการเรียกซ้ำ ดึงอัตราแลกเปลี่ยนหรือข้อมูลสินค้าชุดเดิมทุกครั้งที่มีคนเปิดหน้า เท่ากับคูณจำนวนคำขอด้วยจำนวนผู้เข้าชม
- ระบบกันบอตเตือนผิดกับทราฟฟิกที่ถูกต้อง Cloudflare และเครื่องมือคล้ายกันบางครั้งจัดให้เครื่องมือมอนิเตอร์ ตัวอ่านฟีด หรือ crawler ที่ขยันแต่สุจริต เป็นการใช้งานผิดปกติ
- ใช้ IP ร่วมกับคนอื่น บน shared hosting หรือหลัง NAT ขององค์กร เราจะรับทั้งชื่อเสียงและจำนวนคำขอของทุกคนที่ใช้ IP เดียวกัน
- wp-cron หรือการ poll แบบเดียวกันบนเว็บที่คนเข้าเยอะ WordPress ยิง cron ตามจำนวนการเปิดหน้า เว็บที่ทราฟฟิกสูงจึงกลายเป็นคำขอภายในหลายร้อยครั้งต่อนาที
- ลูป retry ที่ไม่มี backoff 429 ครั้งแรกทำให้ยิงซ้ำ ซึ่งได้ 429 อีก ซึ่งทำให้ยิงซ้ำอีก — เปลี่ยนการถูกจำกัดชั่วครู่ให้กลายเป็นการถูกบล็อกยาว
- หน้าล็อกอินหรือฟอร์มถูกยิงรหัสผ่าน กรณีนี้ 429 กำลังทำหน้าที่ของมันอยู่ และสิ่งที่ควรทำคือปล่อยไว้
ถ้าโค้ดเราเป็นฝ่ายถูกจำกัด: ถอยให้ถูกวิธี
เมื่อเราเป็นฝั่ง client พฤติกรรมที่ถูกต้องเป็นเรื่องที่มีมาตรฐานชัดเจนอยู่แล้ว และคุ้มที่จะเขียนให้ถูกสักครั้ง
ใช้ exponential backoff พร้อม jitter รอ 1 วินาที แล้ว 2 แล้ว 4 แล้ว 8 — และบวกค่าสุ่มเล็กน้อยเข้าไปทุกครั้ง ค่าสุ่มสำคัญมาก เพราะถ้าไม่มี client ทุกตัวที่พังพร้อมกันจะยิงซ้ำพร้อมกัน กลายเป็นคลื่นที่ทำให้ทุกคนถูกจำกัดต่อไปเรื่อย ๆ
เคารพ Retry-After เมื่อมีมา มันสำคัญกว่าค่าที่เราคำนวณเอง เพราะเซิร์ฟเวอร์รู้ดีกว่าอัลกอริทึมของเรา
จำกัดจำนวนครั้งที่ยิงซ้ำ ลูป retry ไม่จำกัดเปลี่ยนการถูกจำกัดชั่วคราวให้เป็นการถูกบล็อกถาวร และปิดบังปัญหาที่แท้จริงไม่ให้เราเห็น
แคชให้หนัก คำขอที่ถูกที่สุดคือคำขอที่ไม่เคยถูกส่ง ข้อมูลที่เปลี่ยนรายชั่วโมงไม่จำเป็นต้องดึงใหม่ทุกครั้งที่มีคนเปิดหน้า และแคชสั้น ๆ มักแก้ปัญหา rate limit ได้หมดเลย
ยิงเป็นชุดถ้า API รองรับ คำขอเดียวเอาข้อมูลร้อยรายการ ดีกว่าคำขอร้อยครั้งเอารายการละอัน เพราะ API ส่วนใหญ่นับจำนวนคำขอ ไม่ได้นับจำนวนรายการ
ถ้าผู้เข้าชมของเราเป็นฝ่ายเจอ 429
- เช็กก่อนว่าเป็นเซิร์ฟเวอร์เราหรือ CDN หน้า error บอกได้ — หน้าที่มีแบรนด์และ ray ID คือ CDN ส่วนหน้าเปล่า ๆ คือเซิร์ฟเวอร์
- ดูรูปแบบคำขอจริงใน access log ก่อนจะไปผ่อนกฎอะไร ถ้าทราฟฟิกนั้นผิดปกติจริง แปลว่าลิมิตทำงานถูกแล้วและควรปล่อยไว้
- มองหาการเตือนผิดกับบอตที่ดี Googlebot เครื่องมือเช็ก uptime และตัวอ่านฟีดที่สุจริต อาจติดกฎที่เข้มเกินไป และการไปจำกัด Googlebot จะทำให้เสียอันดับ
- เช็กว่าเว็บเราเองไม่ได้เป็นคนสร้างโหลด ปลั๊กอินที่ poll endpoint ภายใน หรือ cron ที่ตั้งผิด กินโควตาหมดก่อนผู้เข้าชมจริงจะมาถึงได้
- เปิดแคชหน้าเว็บก่อนจะไปเพิ่มลิมิต หน้าที่ถูกแคชไม่เคยไปถึงตัวนับด้วยซ้ำ ซึ่งเป็นการแก้ที่เหตุไม่ใช่ที่อาการ
- ตั้งลิมิตแยกราย endpoint แทนที่จะตั้งรวม หน้าล็อกอินและ API สมควรถูกจำกัดเข้ม ส่วนหน้าเนื้อหาปกติมักไม่ต้องจำกัดเลย
ทำไมการเพิ่มลิมิตมักเป็นทางแก้ที่ผิด
สัญชาตญาณเมื่อเห็น 429 คือไปเพิ่มเพดาน บางครั้งก็ถูก แต่บ่อยกว่านั้นคือเปลี่ยนปัญหาหนึ่งให้กลายเป็นปัญหาที่แย่กว่า
rate limit มีไว้ปกป้องกำลังที่มีอยู่จำกัด การเพิ่มเพดานโดยไม่เพิ่มกำลังแปลว่าคำขอเหล่านั้นจะไหลเข้าไปถึงแอปพลิเคชัน กิน worker กิน RAM แล้วเราก็แลก 429 ที่สะอาด ๆ กับเว็บที่ช้าหรือ 503 แทน — ประสบการณ์ที่แย่กว่าและแพงกว่า
ลำดับที่ดีกว่าคือ แคชก่อนเพื่อให้คำขอส่วนใหญ่ไม่ไปถึงตัวนับ แก้สิ่งที่สร้างโหลดโดยไม่จำเป็น แล้วถ้าความต้องการจริงยังเกินลิมิตอยู่ ค่อยเพิ่มเพดานพร้อมเพิ่มกำลังให้พอรองรับ
ข้อยกเว้นคือลิมิตที่ตั้งไว้ต่ำเกินไปสำหรับทราฟฟิกปกติตั้งแต่แรก ถ้า access log แสดงว่าผู้เข้าชมทั่วไปเปิดเว็บตามปกติแล้วชนลิมิต นั่นคือการตั้งค่าผิด และการเพิ่มเพดานคือทางแก้ที่ถูกต้อง
อยากตั้งลิมิตเองแทนที่จะรับลิมิตของคนอื่น?
Cloud VPS NVMe มี IP ของตัวเองและสิทธิ์ root เต็ม — ตั้งแคชและลิมิตแยกราย endpoint ได้เอง เริ่ม ฿150/เดือน
คำถามที่พบบ่อย
ได้ 429 แล้วควรรอนานแค่ไหน
อ่านเฮดเดอร์ Retry-After มันบอกไว้ตรง ๆ ถ้าไม่มี ให้ใช้ exponential backoff พร้อม jitter คือ 1 วินาที แล้ว 2, 4, 8 โดยบวกค่าสุ่มเล็กน้อยทุกครั้ง ห้ามยิงซ้ำทันที เพราะนั่นคือสิ่งที่เปลี่ยนการถูกหน่วงชั่วคราวให้กลายเป็นการถูกบล็อก
429 เป็นความผิดเราหรือเซิร์ฟเวอร์
ปกติไม่มีฝ่ายไหนพัง มันแปลว่าอัตราการยิงของเราเกินที่อีกฝั่งอนุญาต ให้เช็กก่อนว่าโค้ดเรายิงซ้ำโดยไม่จำเป็นที่แคชช่วยได้ไหม ถ้างานเราต้องการอัตรานั้นจริง ๆ ก็ควรขยับแพ็กเกจ ไม่ใช่หาทางเลี่ยง
ทำไมยิงไปนิดเดียวก็ได้ 429
ส่วนใหญ่เพราะใช้ IP ร่วมกับคนอื่น — shared hosting, NAT ขององค์กร, หรือ exit node ของ VPN — และลิมิตนับที่ IP ไม่ได้นับที่ตัวเรา ลองด้วยเน็ตมือถือจะยืนยันได้เร็ว ๆ บางลิมิตก็นับรายบัญชีไม่ใช่ราย IP ให้เช็กด้วยว่ามีโปรเซสอื่นใช้ข้อมูลรับรองชุดเดียวกันอยู่ไหม
429 กระทบ SEO ไหม
กระทบถ้า Googlebot เป็นฝ่ายได้รับ Google ตีความ 429 ว่าให้ชะลอและจะลดอัตราการเก็บข้อมูล ถ้าเป็นต่อเนื่องหน้าเว็บจะหลุดจาก index ให้แน่ใจว่ากฎ rate limit ยกเว้น crawler ของเสิร์ชเอนจินที่ยืนยันตัวตนได้ และดูรายงาน Crawl stats ใน Search Console ว่ามี response แบบนี้พุ่งขึ้นไหม
GUIDES
บทความที่เกี่ยวข้อง
อ่านต่อในหัวข้อใกล้เคียง
401 Unauthorized คืออะไร? และทำไมชื่อมันหลอก
HTTP ตั้งชื่อสองตัวนี้สลับกัน 401 แปลว่า "ไม่รู้ว่าคุณเป็นใคร" ส่วน 403 คือ "รู้แล้วว่าเป็นใคร แต่ยังไงก็ไม่ให้" เข้าใจตรงนี้ก่อนจะรู้ทันทีว่าต้องไปแก้ครึ่งไหนของปัญหา
อ่านต่อ503 Service Unavailable คืออะไร? เมื่อเซิร์ฟเวอร์ยังอยู่แต่รับงานไม่ไหว
503 เป็น error ตัวเดียวในกลุ่ม 5xx ที่บางครั้งเป็นสิ่งที่เราตั้งใจให้เกิด บทความนี้อธิบายว่าเมื่อไหร่มันคือปัญหา เมื่อไหร่มันคือการทำงานที่ถูกต้อง และควรตั้งค่าอย่างไรตอนปิดปรับปรุง
อ่านต่อ502 Bad Gateway คืออะไร? เข้าใจว่าใครคุยกับใครไม่รู้เรื่อง
502 ไม่ได้แปลว่าเว็บพัง แต่แปลว่าเซิร์ฟเวอร์สองตัวคุยกันไม่รู้เรื่อง บทความนี้อธิบายว่าใครคือ gateway ใครคือปลายทาง สาเหตุที่พบบ่อย และลำดับการไล่ตรวจที่ใช้ได้จริง
อ่านต่อ