ฉันใช้เวลาค่อนข้างนานในการติดตามปัญหาในการผลิตเมื่อไม่นานมานี้ที่เซิร์ฟเวอร์ฐานข้อมูลหายไปอาจทำให้หยุดทำงานนานถึง 2 ชั่วโมง (รอpoll()
สายในไลบรารีไคลเอนต์ libpq นาน ๆ ) สำหรับไคลเอนต์ที่เชื่อมต่อ เมื่อขุดลงไปในปัญหาฉันรู้ว่าพารามิเตอร์ของเคอร์เนลเหล่านี้ควรปรับลงเพื่อให้การเชื่อมต่อ TCP ที่ขาดหายไปถูกสังเกตเห็นในเวลาที่เหมาะสม:
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_retries2 = 15
ทั้งสี่ข้างต้นเป็นค่าจากอูบุนตู 12.04 เครื่องและดูเหมือนว่าค่าเริ่มต้นเหล่านี้จะไม่เปลี่ยนแปลงจากปัจจุบันค่าเริ่มต้นของลินุกซ์
ดูเหมือนว่าการตั้งค่าเหล่านี้จะมีอคติอย่างมากต่อการเปิดการเชื่อมต่อที่มีอยู่และตระหนี่อย่างยิ่งกับโพรบ Keepalive AIUI ค่าเริ่มต้นtcp_keepalive_time
ของ 2 ชั่วโมงหมายถึงเมื่อเรารอการตอบสนองสำหรับโฮสต์ระยะไกลเราจะรออย่างอดทนเป็นเวลา 2 ชั่วโมงก่อนที่จะเริ่มใช้โพรบ Keepalive เพื่อตรวจสอบว่าการเชื่อมต่อของเรายังคงใช้ได้ และถ้าหากรีโมตโฮสต์ไม่ตอบสนองต่อโพรบ Keepalive เราจะลองโพรบ Keepalive 9 ครั้ง ( tcp_keepalive_probes
) เว้นระยะห่าง 75 วินาที ( tcp_keepalive_intvl
) ดังนั้นนั่นคืออีก 11 นาทีก่อนที่เราจะตัดสินใจว่าการเชื่อมต่อนั้นตายแล้วจริง ๆ
สิ่งนี้ตรงกับสิ่งที่ฉันเห็นในฟิลด์: ตัวอย่างเช่นถ้าฉันเริ่มpsql
เซสชันที่เชื่อมต่อกับอินสแตนซ์ PostgreSQL ระยะไกลโดยมีแบบสอบถามบางคำรอการตอบกลับเช่น
SELECT pg_sleep(30);
และจากนั้นให้เซิร์ฟเวอร์ระยะไกลตายอย่างน่ากลัว (เช่นลดทราฟฟิกไปยังเครื่องนั้น) ฉันเห็นเซสชั่น psql ของฉันรอนานถึง 2 ชั่วโมง 11 นาทีก่อนที่มันจะคิดว่าการเชื่อมต่อนั้นตายแล้ว ดังที่คุณอาจจินตนาการว่าการตั้งค่าเริ่มต้นเหล่านี้ทำให้เกิดปัญหาร้ายแรงสำหรับรหัสที่เราได้พูดคุยกับฐานข้อมูลในระหว่างนั้นกล่าวว่าเป็นเหตุการณ์ความล้มเหลวของฐานข้อมูล การลดลูกบิดเหล่านี้ช่วยได้มาก! และฉันเห็นว่าฉันไม่ได้อยู่คนเดียวในการแนะนำการปรับค่าเริ่มต้นเหล่านี้
ดังนั้นคำถามของฉันคือ:
- ค่าเริ่มต้นเป็นเช่นนี้มานานแค่ไหนแล้ว?
- เหตุผลดั้งเดิมที่ทำให้การตั้งค่า TCP เหล่านี้เป็นค่าเริ่มต้นคืออะไร
- Linux distros ใด ๆ เปลี่ยนค่าเริ่มต้นเหล่านี้หรือไม่
และประวัติอื่น ๆ หรือมุมมองเกี่ยวกับเหตุผลสำหรับการตั้งค่าเหล่านี้จะได้รับการชื่นชม
TCP_KEEPIDLE
, และTCP_KEEPCNT
TCP_KEEPINTVL
TCP_USER_TIMEOUT
ด้วยเช่นกันแทนที่จะตั้งค่าทั้งnet.ipv4.tcp_retries2
ระบบ ของการใช้งานจำนวนมากแน่นอน (เช่น PostgreSQL ในตัวอย่างของฉันที่นี่) ไม่สนับสนุนTCP_USER_TIMEOUT
เลย