Apache + Tomcat มีปัญหาในการสื่อสาร ข้อความแสดงข้อผิดพลาดไม่ชัดเจน นำเว็บไซต์ที่โฮสต์ภายใต้ Tomcat


22

การติดตั้ง:
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache กำลังส่งต่อคำขอโดยใช้ AJP

ปัญหา:
หลังจากช่วงระยะเวลาหนึ่ง (ไม่มีค่าคงที่เลยอาจอยู่ระหว่างหนึ่งหรือสองชั่วโมงหรือหนึ่งวันหรือมากกว่านั้น) Tomcat จะลง ไม่ว่าจะหยุดตอบสนองหรือวาง 'บริการชั่วคราวไม่พร้อมใช้งาน' ทั่วไป

การวินิจฉัย:
มีเซิร์ฟเวอร์สองเครื่องที่มีการตั้งค่าเดียวกัน เว็บไซต์หนึ่งเป็นเว็บไซต์ที่มีปริมาณการใช้งานสูง (หลายคำขอต่อวินาที) ส่วนอีกเว็บไซต์หนึ่งมีปริมาณการใช้ข้อมูลต่ำ เว็บไซต์ทั้งสองนั้นมีฐานรหัสที่แตกต่างกันโดยสิ้นเชิง แต่มีปัญหาที่คล้ายกัน

บนเซิร์ฟเวอร์แรกเมื่อปัญหาเกิดขึ้นเธรดทั้งหมดจะเริ่มต้นรับอย่างช้า ๆ จนกว่าจะถึงขีด จำกัด (MaxThreads 200) ณ จุดนี้เซิร์ฟเวอร์จะไม่ตอบสนองอีกต่อไป (และเกิดขึ้นกับหน้าบริการไม่พร้อมใช้งานหลังจากช่วงเวลานาน)

บนเซิร์ฟเวอร์ที่สองเมื่อปัญหาเกิดขึ้นคำขอใช้เวลานานและเมื่อพวกเขาทำทั้งหมดที่คุณเห็นคือหน้าบริการไม่พร้อมใช้งาน

นอกเหนือจากการกล่าวถึงปัญหา MaxThreads บันทึก Tomcat ไม่ได้ระบุปัญหาเฉพาะใด ๆ ที่อาจทำให้เกิดปัญหานี้

อย่างไรก็ตามในบันทึก Apache เราเห็นข้อความแบบสุ่มที่อ้างถึง AJP นี่คือตัวอย่างข้อความสุ่มที่เราเห็น (ไม่มีคำสั่งซื้อเฉพาะ):

[error] (70007)The timeout specified has expired: ajp_ilink_receive() can't receive header
[error] (104)Connection reset by peer: ajp_ilink_receive() can't receive header
[error] proxy: AJP: disabled connection for (localhost)
[error] ajp_read_header: ajp_ilink_receive failed
[error] (120006)APR does not understand this error code: proxy: read response failed from 127.0.0.1:8009 (localhost)
[error] ap_proxy_connect_backend disabling worker for (localhost)

อีกอย่างที่เราสังเกตเห็นบนเซิร์ฟเวอร์ทราฟฟิกที่สูงกว่านั้นคือก่อนที่ปัญหาจะเกิดขึ้นการสืบค้นฐานข้อมูลจะใช้เวลานานกว่าก่อนหน้า (2,000-5,000 ms เทียบกับปกติ 5-50ms) ซึ่งจะใช้เวลา 2-4 วินาทีก่อนที่ข้อความ MaxThreads จะปรากฏขึ้น ฉันสมมติว่านี่เป็นผลมาจากเซิร์ฟเวอร์จัดการกับข้อมูล / ปริมาณการใช้ / เธรดมากเกินไป

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

การแก้ไข:
ทางออกที่ชัดเจนคือการย้ายกลับไปยังการตั้งค่าของ NIC สองตัว ปัญหาที่เกิดขึ้นคือมันจะทำให้เกิดปัญหาบางอย่างกับการตั้งค่าเครือข่ายและดูเหมือนว่าจะไม่สนใจปัญหา เราต้องการลองและทำให้มันทำงานในการตั้งค่า NIC เดียว

Googling ข้อความแสดงข้อผิดพลาดต่างๆไม่ได้ให้ประโยชน์อะไรเลย (ทั้งวิธีแก้ไขปัญหาเก่าหรือไม่เกี่ยวข้องกับปัญหาของเรา)

เราได้ลองปรับการหมดเวลาต่างๆ แต่นั่นทำให้เซิร์ฟเวอร์ทำงานได้นานขึ้นเล็กน้อยก่อนจะตาย

เราไม่แน่ใจว่าจะค้นหาปัญหาได้ที่ไหน เรายังคงเข้าใจถึงปัญหาที่อาจเป็นไปได้:

1) การตั้งค่าด้วย AJP และ Tomcat ไม่ถูกต้องหรือล้าสมัย (เช่นข้อบกพร่องที่รู้จักกัน?)
2) การตั้งค่าเครือข่าย (NIC สองตัวต่อหนึ่ง NIC) ก่อให้เกิดปัญหาความสับสนหรือปริมาณงาน
3) เว็บไซต์เหล่านั้น (ไม่มีรหัสทั่วไป, ไม่มีแพลตฟอร์มที่ใช้งาน, เพียงแค่โค้ด Java ขั้นพื้นฐานที่มี servlets และ JSP)

อัปเดต 1: ทำ
ตามคำแนะนำที่เป็นประโยชน์ของ David Pashley ฉันได้ทำการติดตามสแต็ก / เธรดดัมพ์ระหว่างปัญหา สิ่งที่ฉันพบคือกระทู้ทั้งหมด 200 หัวข้ออยู่ในสถานะใดสถานะหนึ่งต่อไปนี้:

"TP-Processor200" daemon prio=1 tid=0x73a4dbf0 nid=0x70dd waiting for monitor entry [0x6d3ef000..0x6d3efeb0]
at  oracle.jdbc.pool.OracleConnectionCacheImpl.getActiveSize(OracleConnectionCacheImpl.java:988)
- waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]

"TP-Processor3" daemon prio=1 tid=0x08f142a8 nid=0x652a waiting for monitor entry [0x75c7d000..0x75c7ddb0]
at oracle.jdbc.pool.OracleConnectionCacheImpl.getConnection(OracleConnectionCacheImpl.java:268)
- waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]

อยากรู้อยากเห็นเพียงหนึ่งกระทู้จากทั้งหมด 200 กระทู้อยู่ในสถานะนี้:

"TP-Processor2" daemon prio=1 tid=0x08f135a8 nid=0x6529 runnable [0x75cfe000..0x75cfef30]
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at oracle.net.ns.Packet.receive(Unknown Source)
at oracle.net.ns.DataPacket.receive(Unknown Source)
at oracle.net.ns.NetInputStream.getNextPacket(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
[further stack trace removed for brevity]

อาจเป็นไปได้ว่าไดรเวอร์ Oracle ในเธรดนี้บังคับให้เธรดอื่นทั้งหมดรอให้เสร็จสมบูรณ์ ด้วยเหตุผลบางอย่างมันจะต้องติดอยู่ในสถานะการอ่านนี้ (เซิร์ฟเวอร์ไม่เคยกู้คืนด้วยตนเองมันต้องเริ่มต้นใหม่)

สิ่งนี้ชี้ให้เห็นว่ามันจะต้องเกี่ยวข้องกับทั้งเครือข่ายระหว่างเซิร์ฟเวอร์และฐานข้อมูลหรือฐานข้อมูลเอง เรากำลังทำการวิเคราะห์อย่างต่อเนื่อง แต่เคล็ดลับใด ๆ จะเป็นประโยชน์


ก่อนอื่นนี่เป็นคำถามที่เขียนอย่างสุดยอด งานที่ยอดเยี่ยมในรายละเอียด! ประการที่สองคุณใช้ proxy_ajp หรือ mod_jk เพื่อเชื่อมต่อเซิร์ฟเวอร์ Apache และ Tomcat หรือไม่?
Ophidian

ฉันใช้ proxy_ajp เพื่อเชื่อมต่อทั้งสอง
Jordy Boom

การทดสอบความเครียด Do ใช้ล้อมjoedog.org/siege-home
paalfe

คำตอบ:


9

ปรากฎว่ารุ่นนี้ (คลาส 12 - ค่อนข้างเก่า) ของไดรเวอร์ Oracle มีข้อบกพร่องหลายอย่างในตัวซึ่งทำให้เกิดการหยุดชะงัก (ดังที่เห็นในสถานะ TP-Processor2 ที่ยกมาด้านบน) มันไม่ทำงานจนกว่าเราจะเปลี่ยนเป็นสภาพแวดล้อมใหม่ การอัพเกรดเป็นเวอร์ชั่นล่าสุด (ojdbc14) ได้แก้ไขปัญหาบนเซิร์ฟเวอร์หลักแล้ว


นี้นำฉันไปฉันวิธีการแก้ปัญหาที่ถูกต้อง: ฉันมีล็อคใน DB-แถว ... และไม่เคยได้รับข้อยกเว้นใด ๆ ใน App เซิร์ฟเวอร์
cljk

6

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

  • รับการติดตามสแต็กโดยใช้ jstack หรือใช้ kill -3 $ process_id ดูว่าหัวข้อของคุณกำลังทำอะไรเมื่อมันตาย หากพวกเขากำลังรออยู่ในฐานข้อมูลนั่นเป็นตัวชี้ที่ดีสำหรับทฤษฎีของฉัน พวกเขาอาจกำลังรอการล็อคอยู่
  • ติดตั้ง LambdaProbe มันประเมินค่าไม่ได้สำหรับการค้นหาสิ่งที่ Tomcat ของคุณทำ
  • อัพเกรด Tomcat ของคุณ 5.5.8 เก่ามากอย่างไม่น่าเชื่อ ฉันคิดว่าตอนนี้พวกเขาอยู่ที่ 5.5.27

เดวิดฉันได้อัปเดตคำถาม (ดูอัปเดต 1) พร้อมการค้นพบใหม่โดยอิงตามคำแนะนำการติดตามการถ่ายโอนข้อมูลเธรด / สแต็กของคุณ
Jordy Boom

ฉันขอแนะนำว่ากลุ่มการเชื่อมต่อฐานข้อมูลของคุณมีขนาดเล็กเกินไปเมื่อเทียบกับค่าการเชื่อมต่อสูงสุดของ Tomcat ดูเหมือนว่าเธรดส่วนใหญ่กำลังรอรับการเชื่อมต่อฐานข้อมูล
David Pashley

เหตุผลเดียวที่มีเธรดจำนวนมากเกิดขึ้นเนื่องจากเธรดที่ใช้โดยปกติถูกปล่อยให้รอจนเธรดหนึ่งพยายามอ่านจากซ็อกเก็ต จำนวนการเชื่อมต่อฐานข้อมูลที่ใช้ในเวลาใดก็ได้ระหว่าง 1 ถึง 3 ไม่จำเป็นต้องมีมากกว่านั้น
Jordy Boom

5

เพิ่ม connectionTimeout และ keepAliveTimeout ไปยังตัวเชื่อมต่อ AJP ของคุณที่พบใน /etc/tomcat7/server.xml

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" 
           connectionTimeout="10000" keepAliveTimeout="10000" />

ข้อมูลเกี่ยวกับตัวเชื่อมต่อ AJP ที่https://tomcat.apache.org/tomcat-7.0-doc/config/ajp.html

  • connectionTimeout = จำนวนมิลลิวินาทีตัวเชื่อมต่อนี้จะรอหลังจากยอมรับการเชื่อมต่อเพื่อให้มีการแสดงบรรทัด URI คำขอ ค่าเริ่มต้นสำหรับการเชื่อมต่อโปรโตคอล AJP คือ -1 (เช่นอนันต์)

  • keepAliveTimeout = จำนวนมิลลิวินาทีตัวเชื่อมต่อนี้จะรอการร้องขอ AJP อื่นก่อนที่จะปิดการเชื่อมต่อ ค่าดีฟอลต์คือใช้ค่าที่ตั้งค่าไว้สำหรับแอ็ตทริบิวต์ connectionTimeout

หากไม่ได้กำหนดค่า connectionTimeout และ keepAliveTimeout การเชื่อมต่อ AJP จะยังคงอยู่โดยไม่มีที่สิ้นสุด ทำให้เกิดเธรดจำนวนมากเธรดสูงสุดเริ่มต้นคือ 200

ฉันขอแนะนำให้ติดตั้ง psi-probe - ผู้จัดการขั้นสูงและการตรวจสอบสำหรับ Apache Tomcat แยกจาก Lambda Probe https://code.google.com/p/psi-probe/


4

เพราะผลงานทาง AJP, การเชื่อมต่อแบบถาวรระหว่าง Apache (ใช้อย่างใดอย่างหนึ่งหรือ mod_proxy_ajp mod_jk) เท่านั้นที่สามารถปิดได้อย่างปลอดภัยโดยลูกค้า ในกรณีนี้ลูกค้าเป็นผู้ปฏิบัติงาน Apache ที่เปิดแล้วถือเชื่อมต่อกับแมวตัวผู้สำหรับการใช้ชีวิตสำหรับขั้นตอนการปฏิบัติงาน

เนื่องจากพฤติกรรมนี้คุณจึงไม่สามารถมีคนงาน apache ได้มากกว่าคนงานของเธรด การทำเช่นนี้จะทำให้พนักงาน http เพิ่มเติมไม่สามารถเชื่อมต่อกับ Tomcat (เนื่องจากคิวการรับเต็ม) และจะทำเครื่องหมายแบ็กเอนด์ของคุณเป็น DOWN!


1
ขออภัยสำหรับความคิดเห็นหลังจากปีเหล่านี้ แต่สิ่งนี้ไม่สามารถรับประกันได้โดยการตั้งค่าสูงสุดในการกำหนดค่า ProxyPass เป็นจำนวน MaxThreads ของภาชนะ servlet?
Horst Gutmann

2

ฉันได้ผลลัพธ์ที่ดีขึ้นด้วย mod_proxy แทนที่จะเป็น mod_ajp ในแง่ของความเสถียรดังนั้นให้ลองใช้วิธีแก้ปัญหานั้น มันไม่รุกราน - ที่ดีที่สุดมันจะแก้ปัญหาและที่แย่ที่สุดมันจะแยกแยะ mod_ajp

นอกเหนือจากนั้นดูเหมือนว่า Tomcats ของคุณจะหยุดการตอบสนองและจะมีการโยงเธรดคำขอทั้งหมด ให้ทีมพัฒนาของคุณดูว่าเกิดอะไรขึ้นการจดเธรดทิ้งและส่งไปให้พวกเขาจะมีประโยชน์


ฉันรู้สึกว่า mod_proxy มีปัญหาเรื่องความยืดหยุ่นในการใช้งาน ดูเหมือนว่ามูลนิธิ Apache แนะนำ mod_jk ( wiki.apache.org/tomcat/FAQ/Connectors#Q2 )
Ophidian

มันไม่ให้เหนียวเหนอะ sesssion จริง แต่นอกเหนือจากนั้นฉันไม่เคยมีปัญหากับมัน
Robert Munteanu

1

สิ่งแรกที่ฉันคิดว่าเมื่อฉันได้ยินว่าเซิร์ฟเวอร์ทำงานอยู่ครู่หนึ่งก็ช้าลงและจากนั้นก็เริ่มมีความล้มเหลวของการบริการคือมันหมด RAM และ thrashing swap ฉันไม่ชัดเจนว่า AJP ความล้มเหลวที่คุณเห็นอาจเป็นผลมาจากการหมดเวลาหรือไม่ แต่ดูเหมือนจะไม่สมเหตุสมผลอย่างสมบูรณ์ ไม่เห็นวิธีที่ชัดเจนว่ามันจะเชื่อมต่อกับ NIC แม้ว่า ไม่ว่าในกรณีใด ๆ ฉันขอแนะนำให้คุณถ่ายรูปสิ่งที่เกิดขึ้นกับการใช้หน่วยความจำของคุณเมื่อมีเหตุการณ์เหล่านี้เกิดขึ้น

หากคุณกำลังวิ่งออกมาจาก RAM, คุณอาจจำเป็นต้องเปิดลง Apache ของคุณและเพิ่มของคุณMaxClientsListenBacklog

ยังไงก็ขอบคุณที่ทำให้คำถามของคุณเป็นระเบียบและสมบูรณ์


เมื่อฉันสังเกต 'ด้านบน' ขณะที่สิ่งนี้เกิดขึ้นการใช้หน่วยความจำยังคงค่อนข้างคงที่ อย่างน้อยก็ไม่มีหนามแหลม มีช่วงเวลาสั้น ๆ ของการใช้งาน CPU สูง
Jordy Boom

1

ฉันมีข้อผิดพลาดบันทึกคล้ายกันในสภาพแวดล้อม Redhat กับ proxy_ajp และ Tomcat แก้ไขโดยการอัพเดทแพ็คเกจ httpd:

yum update httpd

จาก:

  • httpd-devel-2.2.3-43.el5_5.3.x86_64
  • httpd-2.2.3-43.el5_5.3.x86_64

ไปที่:

  • httpd-2.2.3-45.el5_6.3.x86_64
  • httpd-devel-2.2.3-45.el5_6.3.x86_64

จากนั้นรีสตาร์ท apache แล้วตามด้วยการรีสตาร์ท Tomcat

นั่นแก้ไขให้ฉัน!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.