it-swarm-vi.tech

Apache + Tomcat có vấn đề giao tiếp. Thông báo lỗi không rõ ràng. Đưa xuống các trang web được lưu trữ dưới Tomcat

Cài đặt :
[.__.] Fedora 8
[.__.] Apache 2.2.8
[.__.] Tomcat 5.5.8
[.__.] Apache đang chuyển tiếp các yêu cầu bằng AJP.

Vấn đề :
[.___.] Sau một khoảng thời gian nhất định (không có hằng số nào, có thể trong khoảng một hoặc hai giờ hoặc một hoặc nhiều ngày) Tomcat sẽ ngừng hoạt động. Hoặc là nó dừng đáp ứng, hoặc nó đưa ra 'Dịch vụ tạm thời không khả dụng'.

Chẩn đoán :
[.__.] Có hai máy chủ có cùng thiết lập. Một trang web có lưu lượng truy cập cao hơn (một vài yêu cầu mỗi giây), một yêu cầu lưu lượng truy cập thấp (một số ít yêu cầu cứ sau vài phút). Cả hai trang web là các cơ sở mã hoàn toàn khác nhau, nhưng chúng thể hiện các vấn đề tương tự.

Trên máy chủ đầu tiên, khi sự cố xảy ra, tất cả các luồng bắt đầu được đưa lên cho đến khi đạt đến giới hạn (MaxThreads 200). Tại thời điểm đó, máy chủ không còn phản hồi (và đi kèm với trang không có dịch vụ sau một thời gian dài).

Trên máy chủ thứ hai, khi sự cố xảy ra, các yêu cầu sẽ mất nhiều thời gian và khi chúng được thực hiện, tất cả những gì bạn thấy là trang không có dịch vụ.

Khác với việc đề cập đến vấn đề MaxThreads, nhật ký Tomcat không chỉ ra bất kỳ vấn đề cụ thể nào có thể gây ra sự cố này.

Tuy nhiên, trong nhật ký Apache, chúng ta thấy các thông báo ngẫu nhiên đề cập đến AJP. Đây là một mẫu thông báo ngẫu nhiên mà chúng ta thấy (không theo thứ tự cụ thể):

[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)

Một điều kỳ lạ khác mà chúng tôi nhận thấy trên máy chủ lưu lượng cao hơn là ngay trước khi sự cố bắt đầu xảy ra, các truy vấn cơ sở dữ liệu mất nhiều thời gian hơn trước (2000-5000 ms so với thông thường 5-50ms). Điều này chỉ tồn tại trong 2-4 giây trước khi thông báo MaxThreads xuất hiện. Tôi cho rằng đây là kết quả của việc máy chủ đột nhiên xử lý quá nhiều dữ liệu/lưu lượng/luồng.

Thông tin cơ bản :
[.__.] Hai máy chủ này đã chạy mà không gặp vấn đề gì trong một thời gian. Các hệ thống đã thực sự thiết lập từng cái bằng cách sử dụng hai NIC trong thời gian đó. Họ tách giao thông nội bộ và bên ngoài. Sau khi nâng cấp mạng, chúng tôi đã chuyển các máy chủ này sang các NIC đơn (điều này được khuyến nghị cho chúng tôi vì lý do bảo mật/đơn giản). Sau thay đổi đó, các máy chủ bắt đầu gặp những vấn đề này.

Độ phân giải :
[.___.] Giải pháp rõ ràng sẽ là quay trở lại thiết lập hai NIC. Vấn đề với điều đó là nó sẽ gây ra một số phức tạp với thiết lập mạng và có vẻ như bỏ qua vấn đề. Chúng tôi muốn thử và chạy nó trên một thiết lập NIC.

Googling các thông báo lỗi khác nhau không cung cấp bất cứ điều gì hữu ích (giải pháp cũ hoặc không liên quan đến vấn đề của chúng tôi).

Chúng tôi đã thử điều chỉnh thời gian chờ khác nhau nhưng điều đó chỉ khiến máy chủ chạy lâu hơn một chút trước khi chết.

Chúng tôi không chắc chắn nơi để tìm chẩn đoán vấn đề hơn nữa. Chúng tôi vẫn đang nắm bắt được ống hút về vấn đề có thể là gì:

1) Thiết lập với AJP và Tomcat không chính xác hoặc lỗi thời (nghĩa là lỗi đã biết?)
[.___.] 2) Thiết lập mạng (hai NIC so với một NIC) đang gây ra sự cố nhầm lẫn hoặc thông lượng.
[.__.] 3) Bản thân các trang web (không có mã chung, không có nền tảng nào được sử dụng, chỉ là cơ bản Java với các máy chủ và JSP)

Cập nhật 1 :
[.__.] Theo lời khuyên hữu ích của David Pashley, tôi đã thực hiện một dấu vết ngăn xếp/luồng trong suốt vấn đề. Những gì tôi tìm thấy là tất cả 200 chủ đề ở một trong các trạng thái sau:

"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]

Thật kỳ lạ, chỉ có một chủ đề trong số 200 chủ đề ở trạng thái này:

"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]

Có thể là trình điều khiển Oracle trong luồng này đang buộc tất cả các luồng khác phải đợi nó hoàn thành. Vì một số lý do, nó phải bị kẹt trong trạng thái đọc này (máy chủ không bao giờ tự phục hồi, nó yêu cầu khởi động lại).

Điều này cho thấy rằng nó phải liên quan đến mạng giữa máy chủ và cơ sở dữ liệu hoặc chính cơ sở dữ liệu. Chúng tôi đang tiếp tục nỗ lực chẩn đoán, nhưng bất kỳ lời khuyên nào cũng hữu ích.

22
Jordy Boom

Hóa ra phiên bản này (lớp 12 - khá cũ) của trình điều khiển Oracle có nhiều lỗi khác nhau gây ra sự bế tắc (như đã thấy trong trạng thái TP-Processor2 được trích dẫn ở trên). Nó không hoạt động cho đến khi chúng tôi chuyển sang môi trường mới. Nâng cấp lên phiên bản mới nhất (ojdbc14) đã giải quyết vấn đề trên máy chủ chính.

9
Jordy Boom

Từ mô tả, tôi đề nghị vấn đề có thể là do các truy vấn cơ sở dữ liệu mất quá nhiều thời gian. Nếu các truy vấn mất nhiều thời gian hơn, yêu cầu sẽ mất nhiều thời gian hơn và do đó bạn sẽ có nhiều truy vấn hơn chạy cùng một lúc. Như bạn đang thấy, bạn đang chạy ra khỏi chủ đề Tomcat. Khi bạn giải quyết vấn đề với cơ sở dữ liệu, bạn sẽ ổn thôi.

  • Nhận một dấu vết ngăn xếp, bằng cách sử dụng jstack hoặc sử dụng kill -3 $ process_id. Xem những gì chủ đề của bạn đang làm khi nó chết. Nếu tất cả họ đang chờ đợi trên cơ sở dữ liệu, đó là một con trỏ tốt cho lý thuyết của tôi. Tất cả họ có thể đang chờ đợi trên một số khóa.
  • Cài đặt LambdaProbe. Nó là vô giá để tìm hiểu những gì Tomcat của bạn đang làm.
  • Nâng cấp Tomcat của bạn. 5.5.8 là vô cùng cũ. Tôi nghĩ rằng họ bây giờ vào ngày 5.5.27.
6
David Pashley

Thêm ConnectionTimeout và keepAliveTimeout vào trình kết nối AJP của bạn được tìm thấy trong /etc/Tomcat7/server.xml.

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

Thông tin về trình kết nối AJP tại https://Tomcat.Apache.org/Tomcat-7.0-doc/config/ajp.html

  • connectionTimeout = Số mili giây Trình kết nối này sẽ đợi, sau khi chấp nhận kết nối, cho dòng URI yêu cầu được trình bày. Giá trị mặc định cho các trình kết nối giao thức AJP là -1 (tức là vô hạn).

  • keepAliveTimeout = Số mili giây Trình kết nối này sẽ đợi một yêu cầu AJP khác trước khi đóng kết nối. Giá trị mặc định là sử dụng giá trị đã được đặt cho thuộc tính ConnectionTimeout.

Nếu các giá trị ConnectionTimeout và keepAliveTimeout không được xác định, thì các kết nối AJP sẽ được duy trì ở mức vô hạn. Gây ra nhiều luồng, luồng tối đa mặc định là 200.

Tôi khuyên bạn nên cài đặt psi-thăm dò - một trình quản lý và giám sát nâng cao cho Apache Tomcat, rẽ nhánh từ Lambda thăm dò. https://code.google.com.vn/p/psi-probe/

5
paalfe

Do cách thức hoạt động của AJP, các kết nối liên tục giữa Apache (sử dụng mod_proxy_ajp hoặc mod_jk) chỉ có thể được đóng an toàn bởi máy khách. Trong trường hợp này, máy khách là công nhân Apache mở ra và sau đó giữ kết nối với Tomcat cho cuộc sống cho quy trình worker.

Do hành vi này, bạn không thể có nhiều công nhân Apache hơn các luồng công nhân Tomcat. Làm như vậy sẽ khiến các nhân viên http bổ sung không thể kết nối với Tomcat (vì hàng đợi chấp nhận đã đầy) và sẽ đánh dấu phần phụ trợ của bạn là DOWN!

4
Dave Cheney

Tôi đã có kết quả tốt hơn với mod_proxy thay vì mod_ajp về độ ổn định, vì vậy hãy thử giải pháp đó. Nó không xâm lấn - tốt nhất là nó sẽ giải quyết vấn đề và tệ nhất là nó sẽ loại trừ mod_ajp.

Mặt khác, âm thanh như Tomcats của bạn ngừng đáp ứng và tất cả các chuỗi yêu cầu được gắn kết. Yêu cầu nhóm phát triển của bạn xem xét những gì đang diễn ra - lấy một luồng xử lý và gửi nó cho họ sẽ hữu ích.

2
Robert Munteanu

Điều đầu tiên tôi nghĩ đến khi tôi nghe rằng một máy chủ chạy được một lúc, đột nhiên chậm lại và sau đó bắt đầu gặp sự cố dịch vụ là nó đã hết RAM và phá hủy trao đổi. Tôi không rõ ràng về việc các lỗi AJP mà bạn thấy có thể dẫn đến thời gian chờ hay không, nhưng có vẻ như nó không hoàn toàn vô lý; mặc dù vậy, không thấy bất kỳ cách rõ ràng nào nó sẽ kết nối với NIC, mặc dù vậy, trong mọi trường hợp, tôi khuyên bạn nên có một hình ảnh về những gì đang xảy ra với việc sử dụng bộ nhớ của bạn khi những sự kiện này xảy ra.

Nếu bạn sắp hết RAM, bạn có thể cần phải tắt Apache MaxClients và tăng ListenBacklog.

Nhân tiện, cảm ơn vì đã làm cho câu hỏi của bạn được tổ chức tốt và đầy đủ.

1
chaos

Tôi đã có lỗi đăng nhập tương tự trong môi trường Redhat với proxy_ajp và Tomcat. Đã giải quyết bằng cách cập nhật gói httpd:

yum update httpd

từ:

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

đến:

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

Sau đó khởi động lại Apache, tiếp theo là khởi động lại Tomcat.

Điều đó đã sửa nó cho tôi!

1
Bass